Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: USART baud rate
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
HoboTech
Здравствуйте, нужна помощь вот в каком вопросе:
пишу инициализацию усарта для Mega48PA

Код
.equ    SYSCLK = 20000000;System Clock [Hz]
.equ    BaudSpeed0=1200    ;speed of UART  
.equ     bauddivider = (SYSCLK/(16*BaudSpeed0))-1

;************************************************************************
; USART0_Init
;
        lds    R16,PRR
        andi    R16,255-(1<<PRUSART0);USART0 wake up
        sts    PRR,R16

        ldi    R16,0b00000000    ;RXCn, TXCn, UDREn, FEn, DORn, UPEn, U2Xn, MPCMn
        sts    UCSR0A,R16

        ldi    R16,0b00011000    ;RXCIE,TXCIE,UDRIE,RXEN,TXEN,UCSZn2,RXB8,TXB8
        sts    UCSR0B,R16

        ldi    R16,0b00000110    ;-, UMSELn, UPMn1, UPMn0, USBSn, UCSZn1, UCSZn0, UCPOLn
        sts    UCSR0C,R16

        ldi    R16,High(bauddivider)
        sts    UBRR0H,R16
        ldi    R16,Low(bauddivider)
        sts    UBRR0L,R16    ;BaudRate Gen.


при симуляции в протеусе получаю:

Код
(AVR USART 0)Baud rate = 54212 b/s


частота 20МГц выставлена и для контроллера и для кварца.
Решил написать инициализацию усарта для 128 меги на С под ИАРом. Скорость установилась как и ожидалось - 1200

Ткните где я не прав
rezident
Цитата(HoboTech @ Dec 27 2010, 17:43) *
Ткните где я не прав
В использовании Протеуса.
В программах-моделировщиках и симуляторах можно обкатывать только программные алгоритмы. Работа с периферией проверяется в реальном железе.
HoboTech
Цитата(rezident @ Dec 27 2010, 15:58) *
В использовании Протеуса.
В программах-моделировщиках и симуляторах можно обкатывать только программные алгоритмы. Работа с периферией проверяется в реальном железе.


а каким способом проверить на какую я скорость его все таки в железе сконфигурировал? с мегой128 на скорости 1200 мега48-я не дружит
собсно потому и полез проверять на какую скорость кто сконфижен в протеусе
rezident
Цитата(HoboTech @ Dec 27 2010, 18:07) *
а каким способом проверить на какую я скорость его все таки в железе сконфигурировал? с мегой128 на скорости 1200 мега48-я не дружит
собсно потому и полез проверять на какую скорость кто сконфижен в протеусе
Для этого достаточно внимательно читать даташит, верить ему и также внимательно проверять написанные вами функции инициализации UART и системы тактирования. Никакой симулятор не заменит разум программиста. "Любая программа не умнее программиста, написавшего ее". wink.gif
нечитатель
Если, несмотря на внимательность, прочитание и доверяние, всё-таки хочется проверять:

- осциллографом: быстро и красиво;
- к компьютеру подключиться через порт типа "COM", смотреть программкой типа "терминал": уверены в корректности работы приёмника;
- передавать 0b01010101, 0b00010001, 0b00000001: частота следования единичек известна, приёмник в сколько раз быстрее или медленнее их...

... соединять ящик А с ящиком Б унылое занятие, когда нет уверенности в работоспособности хотя бы одного из них вместе с чётким пониманием оной.
DpInRock
В даташите черным по белому приведена таблица делителей для всех кварцев и прочая.

А два устройства могут не работать на одной скорости по двум десяткам причин.
V_G
Не скажу за мегу48 (не работал), но у меги128 есть одна не очень приятная особенность: младший байт регистра скорости обмена USART0 принадлежит пространству ввода/вывода и читается/пишется командами IN/OUT, а старший - адресному пространству памяти, и с ним работают через LDS/STS. Для младшего байта тоже можно использовать LDS/STS, но к адресу прибавлять 0x20.
HoboTech
Цитата(DpInRock @ Dec 27 2010, 15:21) *
В даташите черным по белому приведена таблица делителей для всех кварцев и прочая.


согласен, но про скорость 1200 там ничего не сказано

Даташит курил и верю ему, но хочется иметь понимание в каком случае тот же протеус привирает
Палыч
Цитата(V_G @ Dec 27 2010, 17:12) *
Не скажу за мегу48 (не работал), но у меги128 есть одна не очень приятная особенность...
C m48 в этом смысле - как раз "всё хорошо": все регистры USART0 доступны только через LDS/STS.


Цитата(HoboTech @ Dec 27 2010, 17:31) *
...но хочется иметь понимание в каком случае тот же протеус привирает
Если уж на МК существуют Errata, то для симуляторов, наверное, даже не стоит выискивать "особенности работы" в части работы периферии... Когда-то давно, я сам пытался составить подобный список, но довольно быстро понял, что занятие это - бессмысленное: в одном и том же симуляторе для разных МК - свои "особенности". И как только накопится небольшой список таких "особенностей" - выходит новая версия симулятора, где устранены одни ошибки и привнесены новые.
DpInRock
В любом случае - использовать протеус в роли отладчика - на русском языке выражения не подберешь, а в ангийском - таких и вовсе нет.
777777
Цитата(V_G @ Dec 27 2010, 17:12) *
Не скажу за мегу48 (не работал), но у меги128 есть одна не очень приятная особенность: младший байт регистра скорости обмена USART0 принадлежит пространству ввода/вывода и читается/пишется командами IN/OUT, а старший - адресному пространству памяти, и с ним работают через LDS/STS. Для младшего байта тоже можно использовать LDS/STS, но к адресу прибавлять 0x20.

Ужас... И в такой обстановке кто-то еще пишет программы на ассемблере?
HoboTech
Зашил в мегу8:

Код
#include <ioavr.h>

#define F_CPU 14745600
#define BAUD 1200


void USART_Init()
{
  UCSRB = (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN); //enable interrupts during recieve/transmit, enable recieve, enable transmit
  UCSRC = (1<<UCSZ1)|(1<<UCSZ0); //asynchronous mode, 8 data, 1 stop bit

  UBRRH = ((F_CPU/(16*BAUD)-1)>>8);
  UBRRL = ((F_CPU/(16*BAUD)-1)&0xFF);
}


int main( void )
{
  USART_Init();
  asm("sei");
  
  for(;;)
  {
    while ( !( UCSRA & (1<<UDRE)) )
;
    UDR = 0xAA;
    for(long i = 0; i<7372;i++);
  }

}


Тыкаю осциллографом в это тельце и вижу: длительность одного бита - 1мс. Почесал репу, заменил формулу для расчета UBRR на
Код
  UBRRH = ((((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL) >> 8);
  UBRRL = ((((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL) & 0xff);


Опять тыкаю осциллографом в это тельце и вижу: длительность одного бита примерно 840мкс (1200 б/с).

Как так? Формула из даташита в первом случае не дает требуемого результата, в то время как вторая формула, честно подсмотренная где-то в нете, дает почти чистенькие 1200 б/с...
demiurg_spb
Это некрасиво:
Цитата(HoboTech @ Dec 28 2010, 12:14) *
Код
UBRRH = ((((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL) >> 8);
UBRRL = ((((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL) & 0xff);

Вот так без тавтологии будет.
Код
#define BYTE0(X)                    ((uint8_t)((X)>>0))
#define BYTE1(X)                    ((uint8_t)((X)>>8))
#define BYTE2(X)                    ((uint8_t)((X)>>16))
#define BYTE3(X)                    ((uint8_t)((X)>>24))

void uart_init_tx_8n1(void)
{
    static const uint16_t ubrr = (F_CPU + 8UL * BAUD) / (16UL * BAUD) - 1UL; // эта формула верна ???

    UCSRA = 0;
    UCSRB = 0;
    UCSRC = (1<<UCSZ0)|(1<<UCSZ1);

    UBRRH = BYTE1(ubrr);
    UBRRL = BYTE0(ubrr);


    UCSRB = (1<<TXEN);
}

void uart_tx_byte(uint8_t x)
{
    while (!( UCSRA & (1<<UDRE)))   {;}

    UDR = x;
}
HoboTech
Цитата(demiurg_spb @ Dec 28 2010, 11:44) *
Код
static const uint16_t ubrr = (F_CPU + 8UL * BAUD) / (16UL * BAUD) - 1UL; // эта формула верна ???



Я ж говорю - честно высмотрел на просторах интернета эту запись. В 2-х прошивках на 128 и 8 мегах работает так точно. А в 48 меге что формула из даташита, что мой вариант дают в протеусе разные скорости, очень далекие от ожидаемых. Собсно из-за этого и поднял тему.
MrYuran
Цитата(HoboTech @ Dec 28 2010, 12:14) *
Как так? Формула из даташита в первом случае не дает требуемого результата, в то время как вторая формула, честно подсмотренная где-то в нете, дает почти чистенькие 1200 б/с...

Чудеса целочисленного деления/округления...
Если честно посчитаете вашу формулу на калькуляторе, как раз около 1000 и получается (1040, если точно).
В другой формуле применено округление до ближайшего целого.
Плюс, не забываем про UL, иначе при переполнении 2-байтового int вообще чёрт те что может получиться

PS: отставить, это коэффициент деления 1040 получился...
Значит, скорее всего второй вариант.
demiurg_spb
Цитата(HoboTech @ Dec 28 2010, 13:00) *
Я ж говорю - честно высмотрел на просторах интернета эту запись.
Ааа, ну тогда прощайте, дорогой товарищ! Счастливой безумной отладки!
Метценгерштейн
Дабы не плодить темы, задам здесь свой вопрос.

Хочу на ATmega8 при кварце 4 Мгц, запустить USART на 115200.

В регистр
UBRRL записываю число 1, согласно таблице 61 на стр. 160 в даташите на мегу8.

Там указана погрешность 8,5 % при этом. Подключившись TeraTern, на этой скорости, я не вижу отчетливо передачу- прет абракадабра. Как только скорость ставлю 9600, принимается текст без искажений.

Из-за чего проблема? Что 8,5% искажения? Надо подбирать кварц для 0% искажений?
rx3apf
Цитата(Метценгерштейн @ Jan 11 2011, 00:53) *
Из-за чего проблема? Что 8,5% искажения?

"Ну а сам-то как думаешь ?" (с)
Цитата
Надо подбирать кварц для 0% искажений?

По крайней мере 2% желательно, если уж нет возможности выбрать из стандартного ряда 3.6864-7.3728-...
Xenia
Цитата(Метценгерштейн @ Jan 11 2011, 00:53) *
Из-за чего проблема? Что 8,5% искажения? Надо подбирать кварц для 0% искажений?

Чтобы было 0% искажений, то надо подбирать кварц с такой частотой, чтобы она НАЦЕЛО (т.е. без остатка) делилась на нужную вам частоту в бодах 115200. Если это условие будет соблюдено, то МК сможет выбрать целочисленный делитель (а дробного у него не может быть), чтобы из кварцованной частоты получить рабочую. А если нацело не разделится, то частное придется округлить до целого делителя, и тогда рабочая частота будет получаться не точно, а с искажением.

Например, кварцевые частоты 3.6864 МГц и 7.3728 МГц отлично делятся без остатка не только на 115200, но и на все более низкие бодовые частоты:
3686400 / 115200 = 32
7372800 / 115200 = 64
А раз так, то частоту 115200 можно получить из частоты кварца после деления ее на 32 или 64. При этом результат 115200 получится точно.

Но вот мы берем кварц на 4 МГц и обнаруживаем, что:
4000000 / 115200 = 34.72
тогда как делитель может быть только целочисленный. Придется тогда нам округлить 34.72 до ближайшего целого, т.е. до 35. Однако с таким делителем вместо нужной вам частоты 115200, получится частота:
4000000 / 35 = 114285
которая на те 8% меньше нормы. А если бы округлили в меньшую сторону - до 34, то тогда искажение стало бы еще больше, только в сторону увеличения:
4000000 / 34 = 117647
Т.е. куда не кинь, всюду клин.

Я когда-то тоже не знала про эту кухню и сильно удивлялась, отчего кварцы делают на такие "кривые" частоты sm.gif. А как стала с USART работать, так сразу поняла причину. Впрочем, с ошибкой до 2% обычно всё устойчиво работает, хотя в даташите требуют не более пол процента. Ну а 8% - это, конечно, перебор.
Marchello
При скорости 114285 ошибка будет 0,8%, при 117647 - чуть больше 2%.

В принципе ничего криминального.

rezident
Цитата(Marchello @ Jan 11 2011, 12:22) *
При скорости 114285 ошибка будет 0,8%, при 117647 - чуть больше 2%.

В принципе ничего криминального.

Это ошибка битового интервала, но в UART синхронизация посимвольная. На символьном интервале ваши числа нужно умножать на длину символа. Типично длина симовла 10-11 бит (старт-бит, 8 бит данных, стоп-бит, иногда еще и бит parity). Вот и получается ошибка на символьном интервале -7,9% и 21% соответственно. Чисто теоретически на некоторых типах UART ошибка на символьном интервале может достигать 50%, но зависит это от конкретной реализации UART и реальной погрешности тактовых генераторов на обеих сторонах линии связи.
Метценгерштейн
Да, спасибо всем за подробные объяснения. Буду кварц ставить другой.
Похоже, 8%- это действительно перебор.
DpInRock
Вообще кварц не ставьте и будет вам щастья.
xemul
Цитата(Xenia @ Jan 11 2011, 02:04) *
Но вот мы берем кварц на 4 МГц и обнаруживаем, что:
4000000 / 115200 = 34.72
тогда как делитель может быть только целочисленный

и, в данном случае, кратный степени 2
Цитата
Придется тогда нам округлить 34.72 до

32
Цитата
Однако с таким делителем вместо нужной вам частоты 115200, получится частота:

4000000 / 32 = 125000
Цитата
которая на те 8%

больше нормы.
ну и т.д. ...

2rezident: относительная ошибка останется одинаковой и на битовом, и на символьном интервале.

2Метценгерштейн: как вариант, убрать кварц и калибровать внутренний генератор по COM-порту. Где-то в аппнотах был пример по auto-baud.
Метценгерштейн
Замена кварца на 3.6864 помогла. Похоже, 8% погрешность на самом деле много.
Вопрос снят.
ViKo
Цитата(rezident @ Jan 11 2011, 13:45) *
Это ошибка битового интервала, но в UART синхронизация посимвольная

Дело не в символьной синхронизации, а в том, что синхронизируется UART по стартовому биту в начале приема символа. И к концу приема набегает погрешность. Если частота кварца сдвинута на 3%, то к 10-му биту момент выборки бита сдвинется на 30%. Еще нужно учесть, что обычно выборок бита берется несколько, сдвинутых по времени, и бит определяется мажоритарным способом. Поэтому при большей погрешности уже нельзя будет правильно определить последние биты в передаваемом слове.
rezident
Цитата(xemul @ Jan 11 2011, 18:09) *
2rezident: относительная ошибка останется одинаковой и на битовом, и на символьном интервале.
Отнюдь! Ошибки битового интервала на символьном интервале суммируются. Считаем время передачи символа из 10 бит
10/114285=87,5мкс
10/115200=86,8мкс
(86,8мкс-87,5мкс)*115200*100%=-8% к концу 10-го битового интервала (стоп-бит). А следом за ним (без какой-либо паузы) может идти очередной старт-бит следующего символа.
Цитата(ViKo @ Jan 11 2011, 20:42) *
Дело не в символьной синхронизации, а в том, что синхронизируется UART по стартовому биту в начале приема символа.
А это не то же самое? Однократная синхронизация на периоде времени приема всего символа это разве не (по)символьная синхронизация? laughing.gif
Цитата(ViKo @ Jan 11 2011, 20:42) *
Еще нужно учесть, что обычно выборок бита берется несколько, сдвинутых по времени, и бит определяется мажоритарным способом.
Не во всех типах UART используется именно такой способ. Поэтому я и сделал оговорку ранее.
ViKo
Цитата(rezident @ Jan 11 2011, 22:52) *
А это не то же самое? Однократная синхронизация на периоде времени приема всего символа это разве не (по)символьная синхронизация? laughing.gif

Я понимаю символьную синхронизацию как синхронизацию по передаваемому символу, например, 0x55. То есть, приняли символ "U" (0x55) - значит, это начало передаваемого сообщения.
rezident
Цитата(ViKo @ Jan 12 2011, 14:45) *
Я понимаю символьную синхронизацию как синхронизацию по передаваемому символу, например, 0x55. То есть, приняли символ "U" (0x55) - значит, это начало передаваемого сообщения.
Это уже относится к протоколу связи, который поверх физического интерфейса "гуляет". Выше же обсуждался физический последовательный асинхронный интерфейс на базе UART.
ViKo
Цитата(rezident @ Jan 12 2011, 15:42) *
Это уже относится к протоколу связи, который поверх физического интерфейса "гуляет". Выше же обсуждался физический последовательный асинхронный интерфейс на базе UART.

Вот именно sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.