Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с приемом данных USART в ATtiny2313
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Прораб счастья
Помогите, плиз, разобраться с проблемой!

Спаял схему, в которой данные в МК должны поступать по протоколу Модбас через ADM1485.
В CodeVisionAVR создаю проект, в котором настраиваю все параметры МК. Снизу часть сгенерированного текста, относящаяся к обработке прерывания:

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status= UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
...


Все вроде бы собрано правильно, но МК не хочет воспринимать данные. Для проверки срабатывания прерывания я включил в текст строку:

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status= UCSRA;
data=UDR;
PORTB.7=1;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
...


После прихода на МК посылки, PORTB.7 меняет свое состояние, что говорит об срабатывании прерывания. Но если я включаю строчку после проверки if:

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status= UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
PORTB.7=1;
...


, то МК перестает реагировать на пакеты.
Скорость передатчика и приемника выставлены одинаковыми. Я пробывал с разными скоростями. Пробывал и от внешнего кварца и от внутреннего генератора.
Где-то я прочел, что в этом условии проверяется наличие аппаратной ошибки. Получается, что МК плохой? Или еще какая-то другая причина может быть?
Vladimir_J
Доброе время суток !!!
1. После условия if есть открывающаяся { скобка - "Но если я включаю строчку после проверки .. то МК перестает реагировать на пакеты"
2. Посмотрите в настройках UART: длина пакета 8 или 9 бит, к-во стоповых бит и т.д.
Скорее в этом трабл.

С Уважением, Владимир.
Прораб счастья
Скобка - { есть, просто здесь я ее забыл поставить.

Длина пакета 8 бит установлена и на передающей и на принимающей стороне. Кол-во стоповых битов 2, но помоему они (стоповые биты) не должны влиять на начало приема.

По моему разумению, даже если установлены разные скорости обмена или(и) разная длина пакета в настройках, условие после if должно быть истина в любом случае при отсутствии аппаратной ошибки (если это она проверяется в условии).
У меня параметры приема и передачи идентичны.
GDI
Вы бы привели код полностью, чтоб никто не гадал, где вы там забыли или поленились скобку поставить.
Прораб счастья
Текст программы я не приводил, так как она мало отличается от сгенерированной CodeVisionAVR.

Красным выделены те строки, которые я добавляю. Они мне нужны для того, чтобы понять, что прием хотя бы начался (я не говорю уж о правильности полученной информации).



#include <tiny2313.h>
#include <stdio.h>
#include <delay.h>

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;







USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{

PORTB.7=1;
delay_ms(100);
PORTB.7=0;


rx_buffer[rx_wr_index]=data;
if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
if (++rx_counter == RX_BUFFER_SIZE)
{
rx_counter=0;
rx_buffer_overflow=1;
};
};
}




#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif

// Standard Input/Output functions
#include <stdio.h>

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x80;

PORTD=0x00;
DDRD=0x04;

// USART initialization
// Communication Parameters: 8 Data, 2 Stop, No Parity
// USART Receiver: On
// USART Transmitter: Off
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x90;
UCSRC=0x0E;
UBRRH=0x00;
UBRRL=0x33;

ACSR=0x80;

// Global enable interrupts
#asm("sei")

while (1)
{
// Place your code here

};
}
IVANS
1. Если данные передаются непрерывно, то задержка 100 мс внутри прерывания может вызвать переполнение (DATA_OVERRUN).
2. Могут быть банально перепутаны A и B проводники 485 - тогда ошибка кадрирования(FRAMING_ERROR)
IMHO
Прораб счастья
Подключение А и В я неоднократно проверял.
Насчет первого есть вопрос: прерывание вызывается единожды при начале приема пакета или каждый принятый бит вызывает прерывание? Или каждый принятый байт?
Задержка 100 мс стоит после того, как в регистр что-то записалось (видимо в UDR), т.е. то что записалось должно пройти проверку if-ом. Поправьте меня если я не прав!
defunct
Цитата(Прораб счастья @ Oct 29 2008, 12:28) *
После прихода на МК посылки, PORTB.7 меняет свое состояние, что говорит об срабатывании прерывания. Но если я включаю строчку после проверки if:, то МК перестает реагировать на пакеты.

Найдите какая именно ошибка возникает:
Код
if (status & FRAMING_ERROR)
   PORTB.7 = 1;
if (status & PARITY_ERROR)
   PORTB.6 = 1;
if (status & DATA_OVERRUN)
   PORTB.5 = 1;

от этого дальше будем плясать.


Цитата
По моему разумению, даже если установлены разные скорости обмена или(и) разная длина пакета в настройках, условие после if должно быть истина в любом случае при отсутствии аппаратной ошибки (если это она проверяется в условии).

По моему разумению если возникает ошибка - то первым делом надо ее идентифицировать и потом искать способы ее устранения. Ошибка это не значит "что МК плохой?"

Цитата
У меня параметры приема и передачи идентичны.

Это ничем не подтвержденный факт. Раз не работает - значит есть проблема, в том числе параметры приема-передачи могут отличаться.
Polaris
Цитата(Прораб счастья @ Oct 29 2008, 13:19) *
Подключение А и В я неоднократно проверял.
Насчет первого есть вопрос: прерывание вызывается единожды при начале приема пакета или каждый принятый бит вызывает прерывание? Или каждый принятый байт?
Задержка 100 мс стоит после того, как в регистр что-то записалось (видимо в UDR), т.е. то что записалось должно пройти проверку if-ом. Поправьте меня если я не прав!

Прерывание в документе обозначается USART0, Rx Complete и вызывается, соответственно, после окончания приема всего байта. Насколько я понмю, в CodeVision запрещаются прерывания после вызова прерывания (хотя и в самой архитектуре AVR при входе в прерывание дальнейший вызов прерывания по умолчанию также блокируеся), так что задержки такой величины в прерываниях - это очень плохой тон, скорее всего, Вы пропускаете данные, на что потом и указывает DATA_OVERRUN. Чем вызвана первая ошибка - видимо, ошибкой формата пакета.
Прораб счастья
defunct:

Спасибо! Сегодня посмотрю smile.gif
SysRq
Цитата(Прораб счастья @ Oct 29 2008, 14:19) *
...прерывание вызывается... каждый принятый байт.

Ага.

Управляете ADM1485 правильно? Для приёма на RE и DE надо выставить низкий уровень (в коде этого момента не видать без схемы).
Кварц 8 МГц?
=GM=
Цитата(Прораб счастья @ Oct 29 2008, 10:11) *
UCSRC=0x0E;

Вполне возможно, что эта строчка в инициализации приводит к ошибке. Для записи в UCSRC надо старший бит установить в 1, т.е. UCSRC=0x8E. В прерывании вы зачем-то проверяете паритет, а этой строчкой вы паритет запрещаете. Тогда получается, что МК получает байты с паритетом, но интерпретирует бит паритета, как стоп-бит, отсюда могут возникать ошибки FE - Frame Error.
Прораб счастья
Цитата(Polaris @ Oct 29 2008, 14:48) *
Прерывание в документе обозначается USART0, Rx Complete и вызывается, соответственно, после окончания приема всего байта. Насколько я понмю, в CodeVision запрещаются прерывания после вызова прерывания (хотя и в самой архитектуре AVR при входе в прерывание дальнейший вызов прерывания по умолчанию также блокируеся), так что задержки такой величины в прерываниях - это очень плохой тон, скорее всего, Вы пропускаете данные, на что потом и указывает DATA_OVERRUN. Чем вызвана первая ошибка - видимо, ошибкой формата пакета.


По этой логике получается: после приема одного байта идет первая проверка на корректность приема именно одного первого байта (if ((status &.......). Значит задержка в 100 мс еще не была задействована и условие (при правильном приеме) должно быть истина!


Цитата(SysRq @ Oct 29 2008, 14:52) *
Управляете ADM1485 правильно? Для приёма на RE и DE надо выставить низкий уровень (в коде этого момента не видать без схемы).
Кварц 8 МГц?


На входах RE и DE у меня выставлен 0 постоянно. ADM принимает данные - проверенно логическим анализатором.
Я пробывал с 10МГц-овым кварцем и с внутренним генератором 8МГц. Фьюз деления частоты на 8 отключен. Конечно настройки в передатчике соответствовали настройкам приемника.

Цитата(=GM= @ Oct 29 2008, 15:09) *
Вполне возможно, что эта строчка в инициализации приводит к ошибке. Для записи в UCSRC надо старший бит установить в 1, т.е. UCSRC=0x8E. В прерывании вы зачем-то проверяете паритет, а этой строчкой вы паритет запрещаете. Тогда получается, что МК получает байты с паритетом, но интерпретирует бит паритета, как стоп-бит, отсюда могут возникать ошибки FE - Frame Error.


Это сгенерированный CodeVisionAVR текст. Ничего, кроме строчек выделенных красным цветом я не добавлял и не менял.
SysRq
Цитата(=GM= @ Oct 29 2008, 15:09) *
Для записи в UCSRC надо старший бит установить в 1...
Увы, нет.

Цитата(=GM= @ Oct 29 2008, 15:09) *
...получается, что МК получает байты с паритетом, но интерпретирует бит паритета, как стоп-бит, отсюда могут возникать ошибки FE - Frame Error.
Цитирую datasheet: "If Parity Check is not enabled the UPE bit will always be read zero."

Остается пока теоретически возможность грешить на 10% нестабильность внутренного RC-генератора и неточность установки baudrate при кварце 10 МГц...
=GM=
Цитата(Прораб счастья @ Oct 29 2008, 12:19) *
Это сгенерированный CodeVisionAVR текст. Ничего, кроме строчек выделенных красным цветом я не добавлял и не менял

CodeVisionAVR тоже человек писал, Павел Гайдук, мог ошибиться(:-). Повторюсь
Цитата(=GM= @ Oct 29 2008, 12:09) *
Вполне возможно, что эта строчка в инициализации приводит к ошибке. В прерывании вы зачем-то проверяете паритет, а этой строчкой вы паритет запрещаете. Тогда получается, что МК получает байты с паритетом, но интерпретирует бит паритета, как стоп-бит, отсюда могут возникать ошибки FE - Frame Error.

С <7> битом UCSRC я ошибся, я всё время с ним ошибаюсь (просто у меня старая, но удобная книжка по авр с описанием процов, жалко выбрасывать). Шут с ним, с седьмым битом, не в нём дело, а дело в том, что при инициализации вы ЗАПРЕЩАЕТЕ паритет как класс, тем не менее, в своей программе вы проверяете бит паритета, спрашивается за каким шутом проверять, если вы его запретили принимать? Повторю ещё раз, если внешнее устройство передаёт вам биты с паритетом, а вы его запретили, то МК рассматривает переданные биты паритета как следующие за ними стоп-биты, а это приводит к ошибке FE, если конкретный бит паритета равен 0. Ответьте себе на вопрос, вы на МК передаёте биты с паритетом или нет?
Прораб счастья
Сегодня вечером заменю кварц на 7.3728МГц, проверю что вызывает ошибку (по совету defunct), ну и с этим паритетом покопаюсь...
=GM=
Цитата(SysRq @ Oct 29 2008, 12:52) *
Цитирую datasheet: "If Parity Check is not enabled the UPE bit will always be read zero."

Бит чётности читается 0, всё правильно, но если он физически передаётся другой стороной, то МК принимает его за стоп-бит, поскольку его инициализировали не принимать бит чётности.

На последовательности бит отлично видно, бит чётности передаётся, START-B0-B1-B2-B3-B4-B5-B6-B7-P-STOP1-STOP2, а МК думает, что уже идёт первый бит STOP1.
SysRq
Цитата(=GM= @ Oct 29 2008, 18:22) *
Бит чётности читается 0, всё правильно, но если он физически передаётся другой стороной, то МК принимает его за стоп-бит, поскольку его инициализировали не принимать бит чётности.

Вы правы, я прочитал начало фразы, а основную вашу мысль почему-то не воспринял. Решил, что автор все же занает что и как он передает. И написал о своем :)
Прораб счастья
Я, в общем-то, знаю что я передаю smile.gif
Посылка у меня без паритета. После проверки оказалось, что ошибка - FRAMING_ERROR. Пробывал менять местами А и В, но результат тот же...
SysRq
Попробуйте отправить неразрывно два байта: [0xFF][любой_байт_данных]. Если стартовый бит не всегда ловится, то здесь должен пойматься у второго байта четко.
=GM=
Цитата(Прораб счастья @ Oct 30 2008, 07:30) *
Посылка у меня без паритета. После проверки оказалось, что ошибка - FRAMING_ERROR

Если посылка без паритета, зачем тогда вы этот паритет проверяете?

Вы уверены, что правильно определяете ошибку приёма? ПМСМ, лучше вместо красного фрагмента в вашей программе, который даёт солидную задержку в прерывании,
Цитата(Прораб счастья @ Oct 29 2008, 10:11) *
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
PORTB.7=1;
delay_ms(100);
PORTB.7=0;

rx_buffer[rx_wr_index]=data;
};

поставить одну инструкцию PINB.7=1;, которая просто инвертирует пин Б7 при приёме текущего байта.

Если же у вас всё же появляется ошибка FE, то проверяйте скорости передачи приёма прямым измереним. Для начала можно соединить выход передатчика с входом приёмника.
IVANS
GM
может так?
PORTB.7=~PINB.7

Попробуй включить передатчик тиньки (и драйвер 485 на передачу), постоянно что-нибудь передавать и смотреть компутером. Т.о. будет ясно правильно ли выставлена скорость.
SysRq
Цитата(IVANS @ Oct 30 2008, 13:13) *
GM
может так?
PORTB.7=~PINB.7

Восстанавливаю (исчезла из-за падения форума) весьма полезную информацию от =GM= касательно особенностей упоминаемого в теме МК:
"Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn."
=GM=
Цитата(SysRq @ Nov 1 2008, 18:28) *
Восстанавливаю (исчезла из-за падения форума) весьма полезную информацию от =GM= касательно особенностей упоминаемого в теме МК:"Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn"

Вы знаете, эта особенность в настоящее время распространилась почти на все атмеловские МК, не только на этот. Для уточнения смотрите на описание портов конкретного МК, ну и ещё можно почитать про описание функции Read-Modify-Write.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.