Réponse Atmega16 inattendue sur UART
Bref résumé du problème
J'ai flashé un Atmega16 avec du code qui devrait entraîner le renvoi par Atmega16 du caractère que je lui envoie via un terminal. J'obtiens une réponse, mais c'est rarement le personnage que j'ai envoyé. Je peux voir la sortie correcte en modifiant le débit en bauds mais je ne comprends pas pourquoi le bon débit en bauds fonctionne.
Plus de détails
J'essaie d'en savoir plus sur la programmation de microprogrammes à mon rythme, car je l'apprécie beaucoup. Jusqu'à présent, dans la programmation du firmware que j'ai faite à uni, nous avons reçu des fichiers de code squelette qui effectuent une grande partie de l'interface périphérique et configurés pour nous, mais je voudrais l'apprendre moi-même. J'ai quelques questions sur ce que je fais ici saupoudré tout au long du post mais je vais les détailler à la fin. Si vous relevez des malentendus ou des lacunes potentielles dans mes connaissances, j'apprécierais grandement toute contribution que vous pourriez avoir.
Le code
Le code que j'ai flashé sur mon Atmega16 est pris presque ligne pour ligne du tutoriel `` Utilisation de l'USART dans AVR-GCC '' sur cette page . Tout ce que j'ai ajouté est le #define pour F_CPU. Le code d'origine n'avait pas de # définition pour F_CPU, donc mon code ne se compilerait pas dans AtmelStudio 7. Quelqu'un pourrait-il expliquer pourquoi l'auteur n'aurait pas défini F_CPU dans son fichier d'origine? Je suppose qu'ils ont peut-être utilisé un autre outil ou compilateur qu'Atmel Studio 7, mais je ne peux pas le dire avec certitude.
#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
}
}
La configuration matérielle
- MCU: Atmega16;
- Chaîne d'outils: Atmel Studio 7, clignotant avec AVR dragon;
- Alimentation: rail 5 V provenant d'une carte de développement fournie par l'université (qui provient de l'ordinateur USB). Condensateur à disque en céramique 100nF utilisé pour le bypass sur les lignes électriques de la maquette
- Convertisseur USB vers série: celui-ci . TXD sur le convertisseur USB vers série connecté à RXD Atmega (broche 15). RXD sur le convertisseur connecté à RXD sur Atmega (broche 14).
Logiciel du terminal: PuTTY (avec un débit en bauds de 9600).
Preuve des réponses incorrectes
Pour réitérer, l'Atmega devrait retourner ce qui lui a été envoyé, c'est-à-dire que OUTPUT devrait être exactement la même chose que INPUT.
Sortie PuTTY
Captures d'oscilloscope
J'ai utilisé mon Picoscope avec décodage série pour vérifier que l'Atmega reçoit la bonne entrée, ce qui semble être le cas. Par exemple, lorsque j'appuie sur la touche «f», il est correctement reçu. La sortie est toujours un «6» (ou une esperluette «&» à l'occasion).
Une solution sur laquelle je suis tombé et que je ne comprends pas
Si je change la vitesse de transmission en 2500T PuTTY, tout s'affiche correctement. J'ai choisi cette valeur au hasard et je ne sais pas pourquoi cela fonctionne (cela me porte à croire que j'ai fait une erreur quelque part avec le débit en bauds mais je ne vois pas où étant donné j'ai copié le tutoriel presque exactement ... Je pensée).
Des questions
- Qu'est-ce que j'ai fait de mal / qu'est-ce qui se passe ici?
- Pourquoi le didacticiel d'origine n'est-il pas #define F_CPU?
- Pourquoi la définition du débit en bauds à 2500 résout-elle le problème? (Je soupçonne que ce sera répondu si la question 1 est répondue)
Réponses:
Je l'ai compris! Grâce aux commentaires sur F_CPU en réponse à l'OP, j'ai fait quelques recherches (cela pourrait être évident pour vous tous).
Bref résumé de la solution
L'Atmega16 ne fonctionnait pas à la fréquence que je pensais que c'était parce que je ne comprenais pas comment changer la fréquence de son système. En vérifiant les fusibles dans Atmel Studio, j'ai pu voir que je fonctionnais à 2 MHz (ce n'est pas la fréquence d'horloge standard pour autant que je sache, mais je ne vais pas entrer dans le détail ), et pas 7,3728 MHz comme le tutoriel.
F_CPU ne modifie pas la fréquence d'horloge du MCU (l'Atmega16). La fréquence de l'Atmega16 n'a pas été changée à 7,3728 MHz comme cela était nécessaire pour que l'exemple de code fonctionne. Il fonctionnait toujours à la fréquence définie par les fusibles (2 MHz dans ce cas, plus de détails ci-dessous), de sorte que le calcul papier de la vitesse de transmission souhaitée diffère de ce qui a été réellement utilisé.
Code de travail
Plus de détails
Baudrate désiré vs ce que le Atmega était en fait en train de faire
La vitesse de transmission souhaitée (du didacticiel) était de 9600, qui est la vitesse de transmission que j'ai utilisée dans PuTTY. La vitesse de transmission réelle peut être calculée à l'aide de l'équation mise en évidence dans le tableau 60 (page 147) de la fiche technique Atmega16.
Dans l'exemple de code
BAUD_PRESCALE
est UBRR dans le calcul.BAUD_PRESCALE
est évalué à 47 avec les valeurs définies pourF_CPU
etUSART_BAUDRATE
.Et c'était la racine du problème. L'Atmega16 fonctionnait à 2 MHz, ce qui signifiait que la valeur de f_ {osc} était différente de l'exemple du didacticiel, ce qui a entraîné un débit en bauds de 2604 au lieu de 9600.
Notez que f_osc est la fréquence système réelle du MCU, qui n'est pas déterminée par
F_CPU
.Cela répond donc également à ma 3ème question: changer la vitesse de transmission à 2500 était heureusement assez proche de la vitesse de fonctionnement de la MCU pour que le terminal puisse interpréter correctement les résultats.
Modification de la fréquence du MCU
Pour changer la fréquence du MCU dans AtmelStudio 7, allez:
La fréquence utilisée dans l'exemple n'est pas une fréquence d'horloge interne standard, donc je vais m'en tenir à 2 MHz.
Résumé des réponses à mes propres questions
la source