Ten post poświęcę na opisanie sposobu komunikacja za pośrednictwem USART-u w mikrokontrolerze ATmega328p. Zostaną przedstawione zarówno funkcje wysyłające jak i odbierające dane. Po drobnych przeróbkach powinna ona działać z większość procesorów z tej rodziny.
Do testów wykorzystam płytkę Arduino nano. Piny PD0 (RX) oraz PD1(TX) zostały podłączone do wbudowanego konwertera UART - USB podpiętego do złącza mini USB.
Poniżej przedstawię wszystkie potrzebne funkcje wymagane do wykonania komunikacji z układem:
Na samym początku wprowadzam definicje potrzebnych bibliotek, następnie długość bufora oraz rodzaj zegara. Dalej zdefiniowane są rodzaje portu usartu (ten mikrokontroler posiada tylko jeden, ale w przypadku rozbudowy pod inną atmegę można dodać do typu wyliczeniowego).
Poniżej znajduje się funkcja inicjalizująca USART. W pierwszej kolejności zostaje wybrana prędkość na podstawie częstotliwości zegara
Przesłanie pojedynczego znaku:
Przesłanie ciągu znaków:
Dane wysyłane są aż do natrafienie na zakończenie bufora. Po nim dodawany jest znak kończący.
Odczytanie danych wykonywane jest w przerwaniu. Następuje przejście po każdym znaku aż do maksymalnej wielkości bufora.
Cały kod zebrany w pliku biblioteki:
Poniżej przedstawię wszystkie potrzebne funkcje wymagane do wykonania komunikacji z układem:
Na samym początku wprowadzam definicje potrzebnych bibliotek, następnie długość bufora oraz rodzaj zegara. Dalej zdefiniowane są rodzaje portu usartu (ten mikrokontroler posiada tylko jeden, ale w przypadku rozbudowy pod inną atmegę można dodać do typu wyliczeniowego).
- #include <avr/interrupt.h>
- #include <stdbool.h>
- //=================================================================
- #define TX_BUFFER_LEN 200
- #define RX_BUFFER_LEN 200 //Dlugosc bufora odebranych danych
- #define CLOCK_TYPE 1 //Rodzaj zegara
- //=================================================================
- typedef enum {
- USART_PORT_0 = 0, //Numer USART'a, ten mikrokontroler posiada jeden
- }USART_PORT;
- //=================================================================
- typedef enum { //Rodzaj zegara
- Clock_16Mhz = 0,
- Clock_8Mhz = 1,
- Clock_1Mhz = 2
- }CLOCK_TYPE_e;
- //=================================================================
- typedef enum {
- BaudRate_4800 = 0, //Baudrate
- BaudRate_9600 = 1,
- BaudRate_14400 = 2,
- BaudRate_19200 = 3,
- BaudRate_28800 = 4,
- BaudRate_38400 = 5,
- BaudRate_57600 = 6,
- BaudRate_115200 = 7,
- BaudRate_230400 = 8
- }BAUDRATE;
- //=================================================================
- typedef enum { //Znak zakonczenia wiadomosci
- END_NOP_ASCII = 0, //znak pusty
- END_CR_ASCII = 1, //znak 0x0D
- END_LF_ASCII = 2, //znak 0x0A
- END_CRLF_ASCII = 3 //znak 0x0D, 0x0A
- }RX_END_ASCII;
- //=================================================================
Poniżej znajduje się funkcja inicjalizująca USART. W pierwszej kolejności zostaje wybrana prędkość na podstawie częstotliwości zegara
- void USART_INIT(USART_PORT port, BAUDRATE baud)
- {
- uint8_t presc=0;
- if(CLOCK_TYPE == 0) // 16MHz
- {
- if(baud==BaudRate_4800) { presc=207; } //0.2%
- else if(baud==BaudRate_9600) { presc=103; } //0.2%
- else if(baud==BaudRate_14400) { presc=68; } //0.6%
- else if(baud==BaudRate_19200) { presc=51; } //0.2%
- else if(baud==BaudRate_28800) { presc=34; } //-0.8%
- else if(baud==BaudRate_38400) { presc=25; } //0.2%
- else if(baud==BaudRate_57600) { presc=16; } //2.1%
- else if(baud==BaudRate_115200) { presc=8; } //-3.5%
- else if(baud==BaudRate_230400) { presc=3; } //8.5%
- }
- else if(CLOCK_TYPE == 1) //8MHz
- {
- if(baud==BaudRate_4800) { presc=103; } //0.2%
- else if(baud==BaudRate_9600) { presc=51; } //0.2%
- else if(baud==BaudRate_14400) { presc=34; } //-0.8%
- else if(baud==BaudRate_19200) { presc=25; } //0.2%
- else if(baud==BaudRate_28800) { presc=16; } //2.1%
- else if(baud==BaudRate_38400) { presc=12; } //0.2%
- else if(baud==BaudRate_57600) { presc=8; } //-7%
- else if(baud==BaudRate_115200) { presc=3; } //8.5%
- else if(baud==BaudRate_230400) { presc=1; } //0%
- }
- else if(CLOCK_TYPE == 2) //1MHz
- {
- if(baud==BaudRate_4800) { presc=12; } //0.2%
- else if(baud==BaudRate_9600) { presc=6; } //-7%
- else if(baud==BaudRate_14400) { presc=3; } //8.5%
- else if(baud==BaudRate_19200) { presc=2; } //8.5%
- }
- if(port==USART_PORT_0)
- {
- //Ustawienie baudrate
- UBRR0H=0x00;
- UBRR0L=presc;
- //---------------------------
- UCSR0A=0x00;
- //---------------------------
- UCSR0B=0x00;
- UCSR0B|=0x80 | 0x10 | 0x08; //Rx przerwania on, rx enable, tx enalbe
- //---------------------------
- UCSR0C=0x00; // tryb asynchroniczny, bez przystosci, 1 bit stopu
- UCSR0C|=0x04 | 0x02; // 8 date bits
- //---------------------------
- }
- sei();
- }
Przesłanie pojedynczego znaku:
- void Stat_Send_Char(USART_PORT port_number, char data)
- {
- if(port_number==USART_PORT_0)
- {
- while(!(UCSR0A & 0x20));
- UDR0=data;
- }
- }
Przesłanie ciągu znaków:
- void USART_SEND(USART_PORT port_number, const char *buf, RX_END_ASCII end_sign)
- {
- uint8_t n;
- uint8_t c;
- for(n=0;n<=TX_BUFFER_LEN;n++)
- {
- c=buf[n];
- if(c==0) //Jesli natrafi na koniec bufora
- {
- if(end_sign==END_CR_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_CR);
- }
- else if(end_sign==END_LF_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_LF);
- }
- else if(end_sign==END_CRLF_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_CR);
- Stat_Send_Char(port_number, CHAR_LF);
- }
- break;
- }
- else
- {
- Stat_Send_Char(port_number, c);
- }
- }
- }
Dane wysyłane są aż do natrafienie na zakończenie bufora. Po nim dodawany jest znak kończący.
Odczytanie danych wykonywane jest w przerwaniu. Następuje przejście po każdym znaku aż do maksymalnej wielkości bufora.
- ISR(USART_RX_vect)
- {
- uint8_t recive_char;
- recive_char=UDR0;
- if(recive_char==CHAR_CR) { stat_ok=true; }
- else
- {
- if(stat_ok==false)
- {
- if(position_0<RX_BUFFER_LEN)
- {
- if((recive_char>=ASCII_MIN) && (recive_char<=ASCII_MAX))
- {
- buffer_0[position_0]=recive_char;
- buffer_0[position_0+1]=0x00;
- position_0++;
- }
- }
- }
- }
- Stat_Send_Char(USART_PORT_0, recive_char);
- }
Cały kod zebrany w pliku biblioteki:
- #include <avr/interrupt.h>
- #include <stdbool.h>
- //=================================================================
- #define TX_BUFFER_LEN 200
- #define RX_BUFFER_LEN 200 //Dlugosc bufora odebranych danych
- #define CLOCK_TYPE 1 //Rodzaj zegara
- //=================================================================
- typedef enum {
- USART_PORT_0 = 0, //Numer USART'a, ten mikrokontroler posiada jednen
- }USART_PORT;
- //=================================================================
- typedef enum {
- Clock_16Mhz = 0,
- Clock_8Mhz = 1,
- Clock_1Mhz = 2
- }CLOCK_TYPE_e;
- //=================================================================
- typedef enum {
- BaudRate_4800 = 0,
- BaudRate_9600 = 1,
- BaudRate_14400 = 2,
- BaudRate_19200 = 3,
- BaudRate_28800 = 4,
- BaudRate_38400 = 5,
- BaudRate_57600 = 6,
- BaudRate_115200 = 7,
- BaudRate_230400 = 8
- }BAUDRATE;
- //=================================================================
- typedef enum {
- END_NOP_ASCII = 0, //znak konczoncy pusty
- END_CR_ASCII = 1, //znak konczoncy 0x0D
- END_LF_ASCII = 2, //znak konczoncy 0x0A
- END_CRLF_ASCII = 3 //znak konczoncy 0x0D, 0x0A
- }RX_END_ASCII;
- //=================================================================
- void USART_INIT(USART_PORT port, BAUDRATE baud); //Inicjalizacja
- void USART_SEND(USART_PORT port, const char *ptr, RX_END_ASCII ende); //wyslanie danych
- //=================================================================
- //Funckje wewnetrzne
- static void Stat_Send_Char(USART_PORT port, char wert);
- //=================================================================
- #define CHAR_CR 0x0d
- #define CHAR_LF 0x0a
- #define ASCII_MIN 0x20 //Min spacja
- #define ASCII_MAX 0x7e //Max tylda
- uint8_t buffer_0[RX_BUFFER_LEN];
- uint8_t position_0 = 0;
- volatile bool stat_ok = false;
- //=================================================================
- void USART_INIT(USART_PORT port, BAUDRATE baud)
- {
- uint8_t presc=0;
- if(CLOCK_TYPE == 0) // 16MHz
- {
- if(baud==BaudRate_4800) { presc=207; } //0.2%
- else if(baud==BaudRate_9600) { presc=103; } //0.2%
- else if(baud==BaudRate_14400) { presc=68; } //0.6%
- else if(baud==BaudRate_19200) { presc=51; } //0.2%
- else if(baud==BaudRate_28800) { presc=34; } //-0.8%
- else if(baud==BaudRate_38400) { presc=25; } //0.2%
- else if(baud==BaudRate_57600) { presc=16; } //2.1%
- else if(baud==BaudRate_115200) { presc=8; } //-3.5%
- else if(baud==BaudRate_230400) { presc=3; } //8.5%
- }
- else if(CLOCK_TYPE == 1) //8MHz
- {
- if(baud==BaudRate_4800) { presc=103; } //0.2%
- else if(baud==BaudRate_9600) { presc=51; } //0.2%
- else if(baud==BaudRate_14400) { presc=34; } //-0.8%
- else if(baud==BaudRate_19200) { presc=25; } //0.2%
- else if(baud==BaudRate_28800) { presc=16; } //2.1%
- else if(baud==BaudRate_38400) { presc=12; } //0.2%
- else if(baud==BaudRate_57600) { presc=8; } //-7%
- else if(baud==BaudRate_115200) { presc=3; } //8.5%
- else if(baud==BaudRate_230400) { presc=1; } //0%
- }
- else if(CLOCK_TYPE == 2) //1MHz
- {
- if(baud==BaudRate_4800) { presc=12; } //0.2%
- else if(baud==BaudRate_9600) { presc=6; } //-7%
- else if(baud==BaudRate_14400) { presc=3; } //8.5%
- else if(baud==BaudRate_19200) { presc=2; } //8.5%
- }
- if(port==USART_PORT_0)
- {
- //Ustawienie baudrate
- UBRR0H=0x00;
- UBRR0L=presc;
- //---------------------------
- UCSR0A=0x00;
- //---------------------------
- UCSR0B=0x00;
- UCSR0B|=0x80 | 0x10 | 0x08; //Rx przerwania on, rx enable, tx enalbe
- //---------------------------
- UCSR0C=0x00; // tryb asynchroniczny, bez przystosci, 1 bit stopu
- UCSR0C|=0x04 | 0x02; // 8 date bits
- //---------------------------
- }
- sei();
- }
- //=================================================================
- void USART_SEND(USART_PORT port_number, const char *buf, RX_END_ASCII end_sign)
- {
- uint8_t n;
- uint8_t c;
- for(n=0;n<=TX_BUFFER_LEN;n++)
- {
- c=buf[n];
- if(c==0) //Jesli natrafi na koniec bufora
- {
- if(end_sign==END_CR_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_CR);
- }
- else if(end_sign==END_LF_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_LF);
- }
- else if(end_sign==END_CRLF_ASCII)
- {
- Stat_Send_Char(port_number, CHAR_CR);
- Stat_Send_Char(port_number, CHAR_LF);
- }
- break;
- }
- else
- {
- Stat_Send_Char(port_number, c);
- }
- }
- }
- //=================================================================
- void Stat_Send_Char(USART_PORT port, char data)
- {
- if(port==USART_PORT_0)
- {
- while(!(UCSR0A & 0x20));
- UDR0=data;
- }
- }
- //=================================================================
- ISR(USART_RX_vect)
- {
- uint8_t recive_char;
- recive_char=UDR0;
- if(recive_char==CHAR_CR) { stat_ok=true; }
- else
- {
- if(stat_ok==false)
- {
- if(position_0<RX_BUFFER_LEN)
- {
- if((recive_char>=ASCII_MIN) && (recive_char<=ASCII_MAX))
- {
- buffer_0[position_0]=recive_char;
- buffer_0[position_0+1]=0x00;
- position_0++;
- }
- }
- }
- }
- Stat_Send_Char(USART_PORT_0, recive_char);
- }