Перейти к содержанию
    

Некорректная отправка USART на ATmega328p

Всем категорически безошибочного кода!

Второй день бьюсь над передачей данных по USART. Исключил все промежуточные звенья, упростил до минимума и не понимаю, где ошибка.

 

int main(void)
{
	uint16_t ui16_ubrr;

	ui16_ubrr = F_CPU / 9600 / 16 - 1;
	UBRR0H = (unsigned char)( ui16_ubrr >> 8 );
	UBRR0L = (unsigned char) ui16_ubrr;
	UCSR0C = (0 << USBS0)|(3 << UCSZ00); // 1 Stop-bits, 8 Data-bits
	UCSR0B = _BV(TXEN0);
	
	// Wait for empty transmit buffer
	while ( !( UCSR0A & (1<<UDRE0)) ) ;
		
	UDR0 = 'G'; // 0x47
	
	// Wait for empty transmit buffer
	while ( !( UCSR0A & (1<<UDRE0)) ) ;
	
	UDR0 = 'H'; //0x48
}

То есть, убрал вообще всё. Прерывания не разрешены. F_CPU=4000000UL. В UBRR0 попадает число 25, прямо как в табличке в ДШ. Согласно этой же табличке, отклонение 0.2% из допустимых +-2%

При этом получаю не ожидаемые 0x47,0x48 а вместо них - 0x87,0x98

Пытался отправить "всю ASCII". Реализовал цикл 0...255 и смотрел, что приходит. Получил крайне странный результат. Полученная последовательность была такой:

0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x18, 0x19, 0x1A, ... , 0x1F, 0x20, 0x21, ... , 0x27, 0x38, 0x39, ... , далее аналогично до 0xFF, 0x00 и сначала.

У кого был подобный прецедент? Удалось ли решить? Может ли это быть какая-то особенность или "косяк" в самом МК?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Скорости не совпадают. Например, из-за того что запрограммирован "Fuse bit" CKDIV8, оли вообще Fuses установлены по умолчанию, и поэтому МК тактируется совсем не от предполагаемого вами источника. Или имеет место ошибка в программе. Если есть осциллограф, можете определить реальную скорость на порту, это облегчит поиск причины описанной вами проблемы ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Just now, kovigor said:

Скорости не совпадают. Например, из-за того что запрограммирован "Fuse bit" CKDIV8, оли вообще Fuses установлены по умолчанию, и поэтому МК тактируется совсем не от того источника, который вы предполагаете. Ну или ошибка в программе ...

Пробовал на разных скоростях: 2400, 4800, 19200. На остальных процент ошибки вне допустимого. Даже пробовал 250k (ошибка 0%), хотя выше 14400 обычно стараюсь не подниматься - для решаемых задач хватает. Результат одинаковый (читать - такой же). Фузы выставлены, CKDIV8 точно нет. Осциллографом не отслеживал, но запускал таймер, моргал раз в секунду светодиодом, подсчитывал количество за минуту - тактовая больше похожа на те самые 4МГц... Весь код закомментирован, осталось только то, что приведено в первом посте плюс директивы #include...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, kovigor said:

в таких случаях пользуюсь осциллографом

Непосредственно на TX линии? Или речь о контроле тактёра?

 

P.S.: пробовал пускать два стоповых бита, но результат тот же. Неужели такое бывает непосредственно внутри кристалла? Ощущение, что при передаче 4 бит всегда "тащит" за собой установку 5го...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, на ней. Просто встаньте на нее осциллографом и зациклите программу на передаче одного и того же символа, а именно - 0x55 или 0xAA. Сразу многое прояснится - вы сможете определить длительность бита и даже их количество. Подойдет любой осциллограф, но лучше, конечно же, цифровой. Я раньше обходился и советскими аналоговыми.

 

И еще, как-то случилось так, что некорректно работал в сторону машины передатчик на MAX232 (я забыл подпаять к нему один из конденсаторов). Так что схему, монтаж и собственно выход передатчика тоже проверьте ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо, спасибо за совет по контролю обвязки. Сейчас кристалл так ведет себя на двух отладочных платах, в том числе, на STK500. С другим МК проблемы не возникают. К сожалению, под руками нет другой mega328, чтобы исключить сам контроллер

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

No comments. Вчитываться в даташиты и чужой код у меня нет возможности. Я вам дал простейший рецепт - используйте осциллограф. Если его нет, напроситесь на чай с печеньками к знакомому, у которого он таки есть, это сэкономит вагон сил и времени.

 

"Исключать" контроллер нечего. Я не представляю себе, что нужно с ним сделать, чтобы UART начал выдавать битые посылки. Разве что подпалить порт или запитать его нештатным напряжением. При чем тут напряжение ? Как-то запитал AT89C51 от 3.3В, а ему требуется минимум четыре. Все работало, но ... некорректно работала команда ADD (т.е. при суммировании получались неверные результаты). Исправилось это подъемом питающего напряжения до соотв. уровня ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, тут [пока] других ошибок не обнаружено, за исключением, получается, "битого" регистра UDR0 (кстати, в ДШ он почему-то просто UDR и это не единственное "несовпадение" между ДШ и данными в AtmelStudio именно по этому МК, раньше подобного не замечал, но и диапазон контроллеров, с которыми работал, не так уж широк). Получается, вне зависимости от того, отправляю я или получаю, посылка превращается: 0b???10??? -> 0b???11??? и, аналогично, 0b???01??? -> 0b???11???. При этом корректно ходят байты 0b???00???

Для меня просто удивление вызвало, что такое может быть только с конкретным регистром. В моем восприятии, почему-то либо не должно работать совсем, либо... :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

No comments, еще раз. У вас чисто программистский подход. В случае с персоналками это проходит. А вот в случае с МК - далеко не всегда. Я вам предложил начать с самого простого, а "большую науку" оставить на потом. Ваше дело - игнорировать мой совет или воспользоваться им ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, gretis сказал:

То есть, убрал вообще всё. Прерывания не разрешены

Вы про какие прерывание пишите, про Rx TX буфер тоже отключили, тогда зачем проверяете 1<<UDRE0?

В чистом виде без буфера пробовали передавать?

На всякий настройки чистого USART

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 9600
UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (0<<U2X0) | (0<<MPCM0);
UCSR0B=(0<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
UBRR0H=0x00;
UBRR0L=0x33;

 ну и соотвевенно отправляёте символы через printf/puts/putchar не знаю какие есть в вашем компиляторе.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, ikm said:

В чистом виде без буфера пробовали передавать?



 ну и соотвевенно отправляёте символы через printf/puts/putchar не знаю какие есть в вашем компиляторе.

 

В чистом виде, непосредственно кладу в регистр, без всяких printX/putX/... даже по одному байтику, без всяких ожиданий, прерываний, проверок... результат один и тот же. Сейчас собираюсь идти вынимать осциллограф, чтобы убедиться в том, что baudrate правильный.

Да уж. Давно так не проваливался )) Как студент на первом экзамене... На одной отладке пока неясно, в чем была причина, на STK500 стоял джампер, переключающий тактёр не на том положении. Скорее от безысходности (до осциллографа еще не добрался, он дома, а я еще нет). Раскопал arduino платку и на 16МГц при той же ошибке все заработало... По крайней мере, дело было не в регистре. Да... Спасибо kovigor за настойчивость проверить осциллографом. Я даже уже нашел, как :) надо непрерывно слать 'U' и это будет соответствовать коду 010101.... при 9600-8-N-1
В данный момент подозрения с контроллера сняты, вопрос решен. Стоило только о форуме вспомнить. А сколько времени потеряно!... Да уж. Посыпаю голову пеплом

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, gretis said:

Я даже уже нашел, как :) надо непрерывно слать 'U' и это будет соответствовать коду 010101.... при 9600-8-N-1

Да, именно так, вы все правильно поняли ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...