Неожиданный ответ Atmega16 через UART
Я прошил Atmega16 с кодом, который должен привести к тому, что Atmega16 отправит обратно любой символ, который я отправлю ему через терминал. Я получаю ответ, но это редко тот персонаж, которого я отправлял. Я вижу правильный вывод, изменяя скорость передачи данных, но я не понимаю, почему работает правильная скорость передачи данных.
Я пытаюсь узнать больше о программировании прошивки в свободное время, потому что мне это очень нравится. До сих пор при программировании прошивки, которое я делал в университете, нам давали файлы скелетного кода, которые выполняют множество периферийных интерфейсов и настраивают для нас, но я хотел бы изучить это сам. У меня есть несколько вопросов о том, что я здесь делаю, разбросанных по всему сообщению, но я перечислю их в конце. Если вы обнаружите какие-либо недоразумения или потенциальные пробелы в моих знаниях, я был бы очень признателен за любой ваш вклад.
Код, который я записал на свой Atmega16, взят почти построчно из руководства «Использование USART в AVR-GCC», которое можно найти на этой странице . Все, что я добавил, это #define для F_CPU. В исходном коде не было #define для F_CPU, поэтому мой код не компилировался в AtmelStudio 7. Может ли кто-нибудь объяснить, почему автор не определил F_CPU в исходном файле? Я предполагаю, что они могли использовать какой-то другой инструмент или компилятор, кроме Atmel Studio 7, но я не могу сказать наверняка.
#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
}
}
Программное обеспечение терминала: PuTTY (со скоростью 9600 бод).
Повторюсь, Atmega должен вернуть то, что ему было отправлено, т. е. ВЫХОД должен быть точно таким же, как ВХОД.
Я использовал свой пикоскоп с последовательным декодированием, чтобы убедиться, что Atmega получает правильный входной сигнал, каким он кажется. Например, когда я нажимаю клавишу «f», он принимается правильно. Вывод по-прежнему представляет собой «6» (или иногда амперсанд «&»).
Если я изменяю скорость передачи данных на 2500 в PuTTY, все отображается правильно. Я выбрал это значение наугад, и я не знаю, почему оно работает (это заставляет меня думать, что я где-то сделал ошибку, связанную со скоростью передачи, но я не вижу, где я почти точно скопировал руководство... Я подумал).
Я понял это! Благодаря комментариям о F_CPU в ответ на OP я провел небольшое расследование (это может быть очевидно для всех вас).
Atmega16 не работал на частоте, которую я думал, потому что я не понимал, как изменить ее системную частоту. Проверив предохранители в Atmel Studio, я увидел, что работаю на частоте 2 МГц (насколько мне известно, это не стандартная тактовая частота, но я не буду вдаваться в подробности), а не на 7,3728 МГц, как в учебнике.
F_CPU не изменяет тактовую частоту микроконтроллера (Atmega16). Частота Atmega16 не была изменена до 7,3728 МГц, поскольку это было необходимо для работы примера кода. Он по-прежнему работал на частоте, определяемой предохранителями (в данном случае 2 МГц, подробнее об этом ниже), поэтому бумажный расчет желаемой скорости отличается от того, что использовалось на самом деле.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 2000000 //THIS LINE IS **NOT** CHANGING THE FREQUENCY OF THE MCU: CHANGE MCU FREQUENCY IN FUSES
#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
}
}
Желаемая скорость (из учебника) была 9600, это скорость, которую я использовал в PuTTY. Фактическую скорость передачи данных можно рассчитать с помощью выделенного уравнения в Таблице 60 (стр. 147) таблицы данных Atmega16.
В примере кода BAUD_PRESCALE
это UBRR в расчете. BAUD_PRESCALE
оценивается как 47 со значениями, определенными для F_CPU
и USART_BAUDRATE
.
И это было корнем проблемы. Atmega16 работала на частоте 2 МГц, а это означало, что значение f_{osc} отличалось от значения в учебном примере, что приводило к скорости 2604 бод вместо 9600.
Обратите внимание, что f_osc — это фактическая системная частота MCU, которая не определяется параметром F_CPU
.
Так что это также отвечает на мой третий вопрос: изменение скорости передачи на 2500, к счастью, было достаточно близко к рабочей скорости MCU, чтобы терминал мог правильно интерпретировать результаты.
Чтобы изменить частоту MCU в AtmelStudio 7, перейдите:
Tools > Device programming > Fuses > Change SUT_CKSEL (or LOW.SUT_CKSEL in my case) to desired frequency (make sure you have read up on the side effects of this).
Частота, используемая в примере, не является стандартной внутренней тактовой частотой, поэтому я собираюсь придерживаться 2 МГц.
брахи
Блэр Фонвиль
Арсенал
Скотти3785
Дэвигрейви