collapse

* Posts Recentes

Emulador NES em ESP32 por dropes
[22 de Abril de 2024, 14:14]


Arame de Estendal por almamater
[18 de Abril de 2024, 16:16]


O que é isto ? por SerraCabo
[12 de Abril de 2024, 14:20]


Amplificador - Rockboard HA 1 In-Ear por almamater
[11 de Abril de 2024, 20:46]


Meu novo robô por josecarlos
[29 de Março de 2024, 18:30]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]

Autor Tópico: API HardwareSerial Arduino  (Lida 3222 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline TigPT

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 5.372
    • Tiago Rodrigues
API HardwareSerial Arduino
« 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:
  • void begin(long);
  • uint8_t available(void);
  • int read(void);
  • void flush(void);
  • virtual void write(unit8-t);
  • Print::write(const char *str);
  • Print::write(const unit8_t *buffer, size_t size);

A classe HardwareSerial deriva da class Print, por sua vez esta fornece os seguintes métodos:
  • void print(char);
  • void print(const char[]);
  • void print(uint8_t);
  • void print(int);
  • void print(unsigned int);
  • void print(long);
  • void print(unsigned long);
  • void print(long, int);
  • void print(double);
  • void println(void);
  • void println(char);
  • void println(const char[]);
  • void println(uint8_t);
  • void println(int);
  • void println(unsigned int);
  • void println(long);
  • void println(unsigned long);
  • void println(long, int);
  • void println(double);

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:
  • void printNumber(unsigned long, uint8_t);
  • void printFloat(double, uint8_t);


Na class “Print” encontra-se ainda definidos dois métodos “write()” cujo seu funcionamento passo a explicar:
  • write(cons char *str): este método fica num “while” enquanto “str” for diferente de “\0”, por cada ciclo envia 1 “char” para o canal serie e incrementa o ponteiro para “str”.
  • write(const uint8_t *buffer, size_t size): este método permite colocar no canal série um array(buffer), enquanto o seu “size” for diferente de 0. Em cada ciclo do “while” o ponteiro é incrementado e o “size” é decrementado.

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.

  • void begin(long);
  • uint8_t available(void);
  • int read(void);
  • void flush(void);


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:
  • unit8_t no arduino não é nada mais que um unsigned char;
  • size_t no arduino não é nada mais que um unsigned int;
  • virtual: permite que um método tenha uma funcionalidade diferente na class derivada;

Obrigado por partilhares o teu trabalho Miguel!

Offline tcustodio

  • Mini Robot
  • *
  • Mensagens: 344
  • "beware of programmers who carry a soldering iron"
    • Youtube
Re:API HardwareSerial Arduino
« Responder #1 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)
Tiago Custódio,
- Não me dêem álcool se estiver um piano por perto.