Неожиданный ответ Atmega16 через UART

8

Неожиданный ответ 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
    }
}

Настройка оборудования

Фото настройки оборудования

  • MCU: Atmega16;
  • Набор инструментов: Atmel Studio 7, мигает с помощью дракона AVR;
  • Электропитание: 5-вольтовое напряжение, взятое с разработанной университетом платы разработки (которая берется с компьютера USB) Керамический дисковый конденсатор емкостью 100 нФ для обхода линий электропередачи
  • Конвертер USB в последовательный: этот . TXD на преобразователе USB в последовательный порт, подключенный к RXD Atmega (контакт 15). RXD на преобразователе, подключенном к RXD на Atmega (контакт 14).
  • Терминальное программное обеспечение: PuTTY (со скоростью передачи 9600).

    Доказательства неправильных ответов

    Чтобы повторить, Atmega должен вернуть то, что было отправлено ему, т.е. OUTPUT должен быть точно таким же, как INPUT.

    PuTTY выход

    ВХОДВЫВОДе&е6Z>d0пространство0Икс8

    Захваты осциллографа

    Я использовал свой Picoscope с последовательным декодированием, чтобы проверить, что Atmega получает правильный вход, который, по-видимому, и есть. Например, когда я нажимаю клавишу «F», он принимается правильно. Выход по-прежнему «6» (или амперсанд «&» в некоторых случаях).

Захват области на выводе RX Atmega16, показывающий, что правильный код отправляется через программное обеспечение терминала ('f')

Захват области на выводе TX Atmega16, показывающий, что нежелательный ответ отправляется обратно ('6')

Исправление я наткнулся на то, что я не понимаю

Если я изменю скорость передачи данных на 2500in PuTTY, все будет отображаться правильно. Я выбрал это значение случайным образом, и я не знаю, почему это работает (это заставляет меня думать, что я где-то сделал ошибку, связанную с скоростью передачи данных, но я не вижу, где, учитывая, что я скопировал учебник почти точно ... Я думал).

Вопросов

  1. Что я сделал не так / что здесь происходит?
  2. Почему оригинальный учебник не #define F_CPU?
  3. Почему установка скорости 2500 в бод решает проблему? (Я подозреваю, что это будет дан ответ, если ответ на вопрос 1)
daviegravee
источник
2
Простое определение F_CPU для некоторого значения не заставляет микро работать на этой частоте. F_CPU должен быть определен как частота, с которой вы настраиваете микро для работы - но я не вижу никаких доказательств того, что вы настроили это где-либо ...
brhans
Хорошо написанный вопрос. Единственное, что могло бы его улучшить - это схема.
Блэр Фонвилль
+1 только для таблицы . LATЕИкс
Арсенал
Я заметил, что у вас нет внешнего кристалла на вашем макете. Вы используете внутренние часы RC? На какой частоте вы ожидаете процессор?
scotty3785
Благодаря вашей дискуссии о F_CPU я провел некоторое расследование, поиграл и опубликовал решение. Я думаю, это очевидно для вас (как и для меня сейчас ), но это может помочь кому-то еще.
Давиеграве

Ответы:

0

Я понял это! Благодаря комментариям о F_CPU в ответ на ФП я провел некоторое расследование (это может быть очевидно для всех вас).

Краткое описание решения

Atmega16 не работал на частоте, которую я думал, потому что я не понимал, как изменить частоту системы. Проверяя предохранители в Atmel Studio, я мог видеть, что я работал на частоте 2 МГц (насколько я знаю, это не стандартная тактовая частота, но я не буду вдаваться в это), а не 7,3728 МГц, как в учебном пособии.

F_CPU не меняет тактовую частоту MCU (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
    }
}

Подробнее

Желаемый бодрейт против того, что на самом деле делал Atmega

Желаемая скорость передачи (из учебника) была 9600, это скорость, которую я использовал в PuTTY. Фактическая скорость передачи данных может быть рассчитана с использованием выделенного уравнения в таблице 60 (стр. 147) таблицы данных Atmega16.

Таблица уравнений для расчета скорости передачи данных и UBRR из таблицы данных Atmega16 на стр. 147

В этом примере кода BAUD_PRESCALEявляется УБРиР в расчет. BAUD_PRESCALEоценивается как 47 со значениями, определенными для F_CPUи USART_BAUDRATE.

БОДзнак равноеоsс16(УБРиР+1)
БОДзнак равно2,000,00016(47+1)
БОД2,604

И это было корнем проблемы. Atmega16 работал на частоте 2 МГц, что означало, что значение f_ {osc} отличалось от учебного примера, что привело к скорости передачи данных 2604, а не 9600.

Обратите внимание, что f_osc - это фактическая системная частота MCU, которая не определяется F_CPU.

Таким образом, это также отвечает на мой 3-й вопрос: изменение скорости передачи данных до 2500, к счастью, было достаточно близко к рабочей скорости передачи MCU, чтобы терминал мог правильно интерпретировать результаты.

Изменение частоты 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 МГц.

Резюме ответов на мои собственные вопросы

  1. Что я сделал не так / что здесь происходит? Ответ : На самом деле в учебнике не изменилась тактовая частота на тактовую частоту, что привело к скорости передачи, отличной от ожидаемой, из-за чего программное обеспечение терминала (PuTTY) не синхронизировалось с MCU.
  2. Почему оригинальный учебник не #define F_CPU? Ответ : Все еще не совсем уверен, но я предполагаю, что он определен в make-файле, который не указан в руководстве, и что автор не использовал IDE, такую ​​как Atmel Studio.
  3. Почему установка скорости 2500 в бод решает проблему? (Я подозреваю, что это будет дан ответ, если ответ на вопрос 1) Ответ : К счастью, угадал число, близкое к скорости передачи Atmega16
daviegravee
источник