/**
* @file usart.c
* @author Giovani Baratto ([email protected])
* @brief Programa para para comandar um LED pela porta serial: ao enviar o
* caractere '1' o LED é acesso e ao enviar o caractere '0' o LED é desligado.
* Quando o LED muda de estado, enviamos uma mensagem pela interface serial,
* mostrando que o LED está acesso ou apagado.
* @version 0.1
* @date 2023-04-17
*/
#include <stdint.h> // usamos o tipo uint8_t
#define __AVR_ATmega2560__ // programa desenvolvido para o microcontrolador ATmega2560
#include <avr/io.h> // cabeçalho com as definições das entradas e saídas do microcontrolador
#include <avr/pgmspace.h> // Usamos funções para acessar a memória flash
#ifndef F_CPU // se não foi definida a frequência de relógio do microcontrolador
#define F_CPU 16000000UL // definimos a frequência de relógio da placa Arduino Mega: 16 MHz
#endif // F_CPU
/*
Configura o periférico USART no modo assíncrono e quadros no formato 8N1. A taxa de transmissão é 57600 BAUD,
considerando uma frequência de relógio de 16 MHz. Habilita a USART para receber e transmitir (full-duplex). Veja
página 206 do manual de especificações do ATMega2560
*/
void USART0_configura(void)
{
UBRR0 = 0x022; // UBRR0H = 0 e UBRR0H = 0x22
UCSR0A = 0x02; // RXC0=0, TXC0=0, UDRE0=0, FE0=0, DOR0=0, UPE0=0, U2X0=1 e MPCM0 = 0
UCSR0B = 0x18; // RXCIE0=0, TXCIE0=0, UDRIE0=0, RXEN0=1, TXEN0=1, UCSZ0[2]=0, RXB80=0 e TXB80=0
UCSR0C = 0x06; // UMSEL0[1:0]=00, UPM0[1:0]=00, USBS0=0, UCSZ0[1:0]=11 e UCPOL0=0
}
/**
* Transmite um byte (dado) pela USART0. Veja a página 207 do manual de especificações do ATmega2560
* dado: O byte qye será transmitido.
*/
void USART0_transmite(uint8_t dado)
{
while (!(UCSR0A & (1 << UDRE0))) // esperamos o buffer de transmissão ficar vazio
;
UDR0 = dado; // colocamos o dado a ser transmitido no buffer de transmissão
}
//
/*
* Recebe um byte da USART0. Retornamos um byte recebido da USART0. Veja a página 210 do manual de
* especificações do ATMega2560.
*/
uint8_t USART0_recebe(void)
{
while (!(UCSR0A & (1 << RXC0))) // espera o dado ser recebido
;
return UDR0; // retorna o dado recebido no buffer de recepção
}
/**
* Transmite pela USART os bytes da string str, armazenada na memória SRAM
* str: Ponteiro para uma string armazenada na memória RAM
*/
void USART0_transmite_string_RAM(uint8_t *str)
{
uint8_t ch;
// Este laço while é executado até encontrarmos o caractere ch = 0x00, marcando o final da string
while ((ch = *str++)) // carregamos um caractere da string e apontamos para o próximo caractere
{
USART0_transmite(ch); // transmite o caractere pelo terminal TX da USART0
}
}
/**
* Transmite pela USART os bytes da string str, armazenada na memória FLASH
* str: Ponteiro para uma string armazenada na memória FLASH
*/
void USART0_transmite_string_FLASH(uint8_t *str)
{
uint8_t ch;
// Este laço while é executado até que o caractere ch = 0x00, marcando o final da string.
// Os caracteres são lidos da memória FLASH.
while ((ch = pgm_read_byte(str++))) // carregamos um caractere da string e apontamos para o próximo caractere
{
USART0_transmite(ch); // transmite o caractere pelo terminal TX da USART0
}
}
// Declaração e atribuição de uma string na memória FLASH
const char string_flash[] PROGMEM = "String na memória flash\n";
// Declaração e atribuição de uma string na memória FLASH
const char string_RAM[] = "String na memória RAM.\n";
/**
* Procedimento principal. Alteramos o estado de um LED em PB7 com comandos enviados pela USART0. O LED é acesso
* quando é enviado o caractere '1'. O LED é apagado quando enviamos o caractere '0'. Mensagem são enviadas pela
* USART0 quando o estado do LED é alterado ou quando um comando não é reconhecido. Este procedimento não retorna.
*/
int main(void)
{
uint8_t ch; // Armazenamos o caractere recebido pela USART0
DDRB = DDRB | (1 << DDB7); // fazemos PB7 uma saí
USART0_configura(); // configuramos a interface serial USART0
USART0_transmite_string_FLASH(PSTR("Entre com um comando: '0' apaga o LED, '1' acende o LED.\n"));
while (1)
{
ch = USART0_recebe(); // realizamos a leitura de um caractere pela USART0
switch (ch) // verificamos o caractere recebido
{
case '0': // se for recebido o caractere 0
USART0_transmite_string_FLASH(PSTR("0 : LED desligado\n")); // envia mensagem
PORTB = PORTB & (~(1 << PORTB7)); // apagamos o LED
break;
case '1': // se for recebido o caractere 0
USART0_transmite_string_FLASH(PSTR("1 : LED ligado\n")); // envia mensagem
PORTB = PORTB | (1 << PORTB7); // acendemos o LED
break;
case '\n': // se for recebido o caractere nova linha
break; // ignore o caractere
default: // se for recebido outro caractere
USART0_transmite(ch); // transmite caractere
USART0_transmite_string_FLASH(PSTR(" : comando desconhecido\n")); // envia mensagem
}
};
return 0;
}