LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: TigPT em 05 de Agosto de 2009, 12:28

Título: API HardwareSerial Arduino
Enviado por: TigPT em 05 de Agosto de 2009, 12:28
Miguel Boavida começou recentemente a trabalhar com Arduino e numa das suas investigações sobre esta plataforma, resolveu tomar umas notas, o que acabou por dar um excelente manual de consulta que vou transpor e anexar o pdf para os que preferirem imprimir.


API HardwareSerial Arduino

Métodos fornecidos na class HardwareSerial:

A classe HardwareSerial deriva da class Print, por sua vez esta fornece os seguintes métodos:

Estes métodos print, basicamente fazem todos o mesmo, permitem imprimir na consola variáveis de tipos diferentes. O método println() envia para a consola os comandos de “return carrier” (‘\r’) e “new line” (‘\n’). É de acrescentar que quando estamos a utilizar os comandos “print…(…)” na verdade o que estamos a fazer é chamar o método “write(unit8_t c)” que permite processar a variável passada como parâmetro. Logo sabendo exactamente como cada um dos métodos “write()” funciona, torna-se desnecessário gastar espaço de memória com o chamamento da maior parte dos métodos “print()”, salve excepção aqueles que têm como parâmetros “long” ou “double”, que requerem a utilização dos dois métodos privados existentes na função.
Para além destes métodos anteriores a class Print fornece ainda outros 2 métodos privados que servem de auxiliares aos métodos print, estes são:


Na class “Print” encontra-se ainda definidos dois métodos “write()” cujo seu funcionamento passo a explicar:

Estes dois métodos são os mesmos utilizados na class “HardwareSerial” juntamente com o “write(unit8_t c)” que imprime um “char” no serial. Como foi dito anteriormente para os métodos “print()” também os dois métodos de “write(…)” indicados anteriormente chamam o método “write(unit8_t c)”.
   

A esta altura devem-se estar a questionar, ai e tal isto é tudo muito bonito, mas afinal como é que se escreve um “char” no canal serie, já sabemos que existem métodos para isso, mas como é que o “char” chega ao canal? Pois bem, quando utilizamos o método “write(unit8_t c)”, este no final da seu código efectua a seguinte instrução “*_udr = c;”, “_udr” é um ponteiro para um parâmetro (“volatile uint8_t *udr”) passado à class “HardwareSerial” a quando do chamamento do seu construtor. O ponteiro “*udr”, aponta para o “UDR register”, o “UDR register” é na verdade dois registos físicos separados que partilham o mesmo endereço de I/O. Quando se pretende escrever para o canal serial, na verdade estamos a escrever no “UDR” e quando se pretende ler do canal serial, estamos a ler do “UDR”. Para colocar os dados no canal, existe um “shift register” de transmissão, que após ter “shiftado” os dados encarrega-se de fazer “set” ao bit Tx. Para ler do canal existe um “shift register” de recepção, que após receber um “char”, shifta-o para o registo UDR e faz “set” ao bit Rx.
   Passo agora a explicar o funcionamento dos métodos existentes na class “HardwareSerial”, que ainda não foram referidos.



O método “begin(long)”, é utilizado para iniciar a porta serial com o baud rate passado como parâmetro. Baud rate é o número de símbolos transferidos por segundo.
Para armazenar o baud rate, é efectuado o seguinte cálculo “((F_CPU / 16 + speed / 2) / speed - 1)”, onde F_CPU é a frequência do Arduino, no caso do mega será 16MHz, e o speed é o valor do baud rate passado ao “begin”. O byte de maior peso é armazenado no registo “UBRRH” e o byte de menor peso é armazenado no registo “UBRRL”. Após este armazenamento é iniciada a UART, através da macro “sbi”, que recebe dois parâmetros, o primeiro é o “porto” e o segundo é o “bit” a escrever no porto. Para iniciar a UART é chamada a macro “sbi” três vezes, “sbi(*_ucsrb, _rxen)” activa o “rx”, “sbi(*_ucsrb, _txen)” activa o “tx” e “sbi(*_ucsrb, _rxcie)” que activa a interrupção de recepção. No caso do Arduino Mega como existem quatro UARTS diferentes, estas operações são efectuas sobre o canal serial que chamou a função begin().
   “Available(void)”, retorna o número de “char()” que existem no buffer para ler. Por forma a evitar que os dados já lidos sejam contabilizados é efectuado o módulo entre ((“size”+”head”-“tail”)%”size”) que retorna a diferença entre o “head” e o “tail”, o “size” é somado para contemplar as alturas em que o ring buffer dá a volta e que o “tail” é maior que o “head”.   
   
O Arduino disponibiliza um método flush(), que supostamente limpa a UART, mas na verdade o que acontece é que o “tail” é igualado ao “head”, dando a entender ao método “read()”, que não existem dados para ler.
   O método “read(void)”, efectua leituras do ring buffer da UART correspondente, através da posição do “tail” e incrementa-o uma vez a cada leitura, quando o “tail” ficar igual ao “head” então não existem mais dados para ler. Para dar a volta ao ring buffer quando este está cheio, é efectuado o módulo entre o “head” e o tamanho do buffer, o mesmo é feito para o “tail”. Quando o “head” ou o “tail” tiverem o valor 128, o módulo entre os mesmos e o “size” vai ser igual a 0, assim sendo a próxima actualização será para a posição inicial do ring buffer. O “head” é actualizado sempre que se acrescenta um “char” ao buffer, isto é feito automaticamente pelo micro, sempre que é gerada uma interrupção de recepção na UART. Este processo para além de actualizar o “head” também armazena os “char” recebidos. Este método é não bloqueante, quando não existem caracteres para ler do buffer retorna -1.
No Arduino Mega, são disponibilizadas 4 UARTS, cada uma com registos físicos diferentes e cada uma com o seu próprio ring buffer de 128bytes.
Definições:

Obrigado por partilhares o teu trabalho Miguel!
Título: Re:API HardwareSerial Arduino
Enviado por: tcustodio em 05 de Agosto de 2009, 14:47
cheira-me que vou aplicar este conhecimento aqui nas funções midi, para evitar ciclos perdidos desnecessariamente. vou ver se escrevo directamente para o udr  8)