Resposta inesperada do Atmega16 sobre o UART
Breve resumo do problema
Eu exibi um Atmega16 com um código que deveria resultar no envio do Atmega16 para qualquer caractere que eu enviar através de um terminal. Eu recebo uma resposta, mas raramente é o personagem que enviei. Consigo ver a saída correta alterando a taxa de transmissão, mas não entendo por que a taxa de transmissão correta funciona.
Mais detalhes
Estou tentando aprender mais sobre programação de firmware no meu tempo livre, porque gosto bastante. Até agora, na programação de firmware que fiz na uni, recebemos arquivos de código de esqueleto que fazem grande parte da interface periférica e configurados para nós, mas eu mesmo gostaria de aprender isso. Eu tenho algumas perguntas sobre o que estou fazendo aqui espalhadas por todo o post, mas vou descrevê-las no final. Se você perceber algum mal-entendido ou possíveis lacunas em meu conhecimento, eu apreciaria muito qualquer contribuição que você possa ter.
O código
O código que atualizei no meu Atmega16 está quase na linha do tutorial 'Usando o USART no AVR-GCC' encontrado nesta página . Tudo o que eu adicionei é o #define para F_CPU. O código original não tinha um #define para F_CPU, portanto meu código não seria compilado no AtmelStudio 7. Alguém poderia explicar por que o autor não teria definido F_CPU em seu arquivo original? Suponho que eles possam estar usando alguma outra ferramenta ou compilador que não seja o Atmel Studio 7, mas não posso dizer com certeza.
#include <avr/io.h>
#define F_CPU 7372800 //this was chosen because the tutorial states this is the frequency we want to operate at
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)
int main ( void )
{
char ReceivedByte ;
UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
for (;;) // Loop forever
{
while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}
}
A configuração do hardware
- MCU: Atmega16;
- Conjunto de ferramentas: Atmel Studio 7, piscando com o dragão AVR;
- Fonte de alimentação: barramento de 5V retirado de uma placa de desenvolvimento fornecida pela universidade (retirada do USB do computador). Capacitor de disco de cerâmica de 100nF usado para contornar as linhas de energia da placa de ensaio
- Conversor USB para serial: Este . TXD no conversor USB para serial conectado ao RXD Atmega (pino 15). RXD no conversor conectado ao RXD no Atmega (pino 14).
Software do terminal: PuTTY (com taxa de transmissão de 9600).
Evidência de respostas incorretas
Para reiterar, o Atmega deve retornar o que foi enviado a ele, ou seja, OUTPUT deve ser exatamente o mesmo que INPUT.
Saída PuTTY
Capturas de osciloscópio
Eu usei meu Picoscope com decodificação serial para verificar se o Atmega está recebendo a entrada correta, o que parece ser. Por exemplo, quando pressiono a tecla 'f', ela é recebida corretamente. A saída ainda é um '6' (ou um e comercial '&' na ocasião).
Uma correção que me deparei que eu não entendo
Se eu alterar a taxa de transmissão para 2500in PuTTY, tudo será exibido corretamente. Escolhi esse valor aleatoriamente e não sei por que ele funciona (isso me leva a acreditar que cometi um erro em algum lugar relacionado à taxa de transmissão, mas não vejo onde, pois copiei o tutorial quase exatamente ... pensamento).
Questões
- O que eu fiz de errado / o que está acontecendo aqui?
- Por que o tutorial original não # define F_CPU?
- Por que definir a taxa de transmissão para 2500 corrige o problema? (Eu suspeito que isso será respondido se a pergunta 1 for respondida)
Respostas:
Eu descobri isso! Graças aos comentários sobre o F_CPU em resposta ao OP, investiguei (isso pode ser óbvio para todos).
Breve resumo da solução
O Atmega16 não estava funcionando na frequência que eu pensava, porque não sabia como alterar a frequência do sistema. Ao verificar os fusíveis no Atmel Studio, pude ver que eu estava funcionando a 2 MHz (essa não é a freqüência padrão do relógio, tanto quanto sei, mas não vou entrar nisso), e não 7.3728MHz como no tutorial.
F_CPU não altera a frequência do relógio do MCU (o Atmega16). A frequência do Atmega16 não foi alterada para 7.3728MHz, pois era necessário para que o exemplo de código funcionasse. Ele ainda estava funcionando na frequência definida pelos fusíveis (neste caso, 2MHz, mais sobre isso abaixo), de modo que o cálculo em papel da taxa de transmissão desejada difere do que realmente foi usado.
Código de trabalho
Mais detalhes
Taxa de transmissão desejada versus o que o Atmega era realmente fazendo
A taxa de transmissão desejada (do tutorial) foi 9600, que é a taxa de transmissão que usei no PuTTY. A taxa de transmissão real pode ser calculada usando a equação destacada na Tabela 60 (página 147) da folha de dados do Atmega16.
No exemplo de código,
BAUD_PRESCALE
é UBRR no cálculo.BAUD_PRESCALE
é avaliado como 47 com os valores definidos paraF_CPU
eUSART_BAUDRATE
.E essa foi a raiz do problema. O Atmega16 estava operando a 2 MHz, o que significava que o valor de f_ {osc} era diferente do exemplo do tutorial, o que resultou em uma taxa de transmissão de 2.604 em comparação a 9.600.
Observe que f_osc é a frequência real do sistema do MCU, que não é determinada por
F_CPU
.Portanto, isso também responde à minha terceira pergunta: alterar a taxa de transmissão para 2.500 por sorte foi suficientemente próximo da taxa de operação do MCU para que o terminal pudesse interpretar corretamente os resultados.
Alterando a frequência do MCU
Para alterar a frequência do MCU no AtmelStudio 7, vá:
A frequência usada no exemplo não é uma freqüência de relógio interno padrão, então eu vou ficar com 2MHz.
Resumo das respostas para minhas próprias perguntas
fonte