Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прием данных USART
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
messenger
Из заособенностей работы ответной стороны принял решение не использовать перывания USART
контроллер ATMega 64
скорость 4800
COM1
CodeVision AVR
используются перывания только от таймера Т1(16bit) где Т1 останавливается и флаг RxTimOvf=1 (по умолчанию 0)

Проблема передаю с ПК посылку 123456, принимаю 126
передаю с ПК посылку 123456789, принимаю 129
флаг DOR говорит о переполнении буфера приемника, т.е. данные вовремя не считались?Почкму так?

#define FRAMING_ERROR_1 (1<<FE1)
#define PARITY_ERROR_1 (1<<UPE1)
#define DATA_OVERRUN_1 (1<<DOR1)
#define DATA_REGISTER_EMPTY_1 (1<<UDRE1)
#define RX_COMPLETE_1 (1<<RXC1)


void READ_MASS_RS_1()
{
char status, data;
flag_stop_timer=0;
flag_eroor_rs=0;
RxTimOvf=0;

for (temp_1_i=0;temp_1_i<22;temp_1_i++)
{reading_mass_rs_1[temp_1_i]=0;} //Обнуление массива

// Reinitialize Timer1 value
TIMSK=(0<<TOIE1); // запретить прерывание от счетчика № T1
TCNT1H=0x00;TCNT1L=0x00; //Таймаут max для Т1
TIMSK=(1<<TOIE1); // разрешить прерывание от счетчика № T1

for (temp_1_i=0;temp_1_i<20;temp_1_i++)
{

while ((((status=UCSR1A) & RX_COMPLETE_1)==0)&& RxTimOvf==0);
data=UDR1;
if (RxTimOvf ==0) //Есть данные, И если тайм-аут НЕ истек "заходим"
{

if ((status & (FRAMING_ERROR_1| PARITY_ERROR_1 | DATA_OVERRUN_1)==0) && (RxTimOvf ==0))
{reading_mass_rs_1[temp_1_i]=data;}
else
{ flag_eroor_rs=1;//При чтении пакета были ошибки }

}

}




for (temp_1_i=0;temp_1_i<22;temp_1_i++)
{putchar1(reading_mass_rs_1[temp_1_i]);} //Смотрим что пришло

}
Палыч
Возможно:
1. Ошибка в функции putchar1
2. Данные принимаются с ошибкой. Чтобы проверить последнее следует либо проинициализировать массив reading_mass_rs_1 неким значением, отличным от нуля (например, символом 'X'). либо сохранять значение принятого байта, несмотря на ошибку в status (он же - UCSR1A).
messenger
Цитата(Палыч @ Jan 18 2012, 16:27) *
Данные принимаются с ошибкой.

Да.. горит переполнение буфера приемника- данные вовремя не забрали, но почему?
Палыч
Цитата(messenger @ Jan 18 2012, 17:43) *
Да.. горит переполнение буфера приемника- данные вовремя не забрали, но почему?
Как Вы определили, что "Data OverRun" ? Такой же эффект может быть и при "Frame Error".
Попробуйте временно комментировать строку
Код
TIMSK=(1<<TOIE1); // разрешить прерывание от счетчика № T1

и передать 22 символа. Что будет возвращено?
messenger
если исключить из условия проверку на переполнение, то в принятом буфере лежат 3 символа,остальное пусто. Если не исключать то все пусто. Если не использовать таймер а просто ждать прихода символа то отправив один символ с ПК - принимаем один в буфер... все работает. Причем отправляю ,например, 123456789 а из трех принятых 129
Палыч
Цитата(messenger @ Jan 18 2012, 20:06) *
если исключить из условия проверку на переполнение, то в принятом буфере лежат 3 символа,остальное пусто. Если не исключать то все пусто. Если не использовать таймер а просрочки ждать то 1отправил-1принял... все работает. Причем отправляю ,например, 123456789 а из трех принятых 129

Путано объясняете... Ничего не понял...
Если убрать проверку status, сохранять значение data в буфере всегда, то что будет возвращать?
messenger
129 принимает
Палыч
Приведите код инициализации таймера и процедуру обработки прерывания
messenger
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare C Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x01; //без делителя
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;


//Timer1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TIMSK=(0<<TOIE1); //запретить прерывание от счетчика № 0
RxTimOvf=1;
flag_timer_1_set=1;//Используется в задержках(паузах)
}//void

Палыч
Маленькая ошибочка при определении тайм-аута.
В функции READ_MASS_RS_1 перед разрешением прерывания от таймера необходимо сбросить флаг TOV1
_Артём_
Цитата(messenger @ Jan 18 2012, 20:54) *
TIMSK=(0<<TOIE1); //запретить прерывание от счетчика № 0

Сомнительное действие: написано вроде так "//запретить прерывание от счетчика № 0"
но комментарий неверный, т.к. TIMSK=(0<<TOIE1); эквивалентно TIMSK=0, что означает запрет врех прерываний разрешаемых через TIMSK, в том числе и от таймера T0 (для Atmega64/128).
Правильно так:
Код
TIMSK&=~(1<<TOIE1);
// и на выходе
TIMSK|=(1<<TOIE1);


Проблема наверно не в этом, но потенциально - это грабля.
=GM=
1. Как вы синхронизируете начало таймаута и начало передачи символа с ПК?

2. Зачем вы трижды проверяете таймаут (RxTimOvf==0) во время приёма одного байта, достаточно одной проверки в while. Возможно будет достаточно одной проверки в конце цикла передачи всех байт
messenger
"перед разрешением прерывания от таймера необходимо сбросить флаг TOV1"- обязательно сделаю, только не раньше вечера

с Т0 это конечно ошибочка. Там д.б. Т1

а как нужно синхронизировать?у меня нет ,наверно, синхронизации. Просто жду по таймеру много больше. Это же не критично?

RxTimOvf проверяю дважды. Первый раз что бы не повиснуть, второй что бы понять успела ли посылка набрать 22 символа.
Палыч
Цитата(messenger @ Jan 19 2012, 08:00) *
...успела ли посылка набрать 22 символа.

Хотя это не решит проблему, но: Ваша программа принимает только 20 символов из 22.

for (temp_1_i=0;temp_1_i< 20 ;temp_1_i++)

Цитата(messenger @ Jan 19 2012, 08:00) *
а как нужно синхронизировать?у меня нет ,наверно, синхронизации.

Сброс флага TOV (это - Вы добавите) и регистра TCNT (это - уже есть) в функции READ_MASS_RS_1 перед ожиданием прихода в USART символов и будет синхронизацией.
=GM=
Цитата(messenger @ Jan 19 2012, 04:00) *
а как нужно синхронизировать?у меня нет ,наверно, синхронизации. Просто жду по таймеру много больше. Это же не критично?

RxTimOvf проверяю дважды. Первый раз что бы не повиснуть, второй что бы понять успела ли посылка набрать 22 символа.

1. Проверяете вы трижды: в операторе while, операторе if, и ещё раз в операторе if. 2-я и 3-я проверки бесполезны и даже вредны, поскольку в 1-ой проверке таймаута не было, принятый байт вы считали, но таймер1 тикает дальше и таймаут может наступить и вы запишете ошибку приёма, хотя никакой ошибки не было.

2. Синхронизировать нужно и вот почему. Вы запускаете программу в МК, запускается таймаут помимо всего прочего, затем вы нажимаете кнопку на ПК и начинаете передачу вашего пакета. Таймaут у вас заканчивается то раньше, то позже, отсюда все ваши беды. Уберите таймаут из цикла вообще, примите весь пакет, затем проверьте, был ли таймаут или нет. Засинхронизировать просто - примите 1-й байт от ПК, после него запустите таймаут.

3. Вообще, какая-то логика программы у вас странная. По программе, передав 123456, вы должны бы получить в буфере 120006, а вы пишете, что приняли 126, так не должно быть. Похоже, после приёма первых 2-х символов у вас пресловутый таймаут и наступает.
messenger
Спасибо большое всем за ответы!
Прошу поясните "2. Синхронизировать нужно и вот почему. Вы запускаете программ.." в части

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

"Засинхронизировать просто - примите 1-й байт от ПК, после него запустите таймаут." Данное понятие синхронизации мен не понятно. Режим то асинхронный.
Палыч
Про синхронизацию

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

Как, вероятно, происходит работа устройств сейчас:
1. Вы включаете приёмное устройство (подаёте на него питание). МК начинает работать. Производится инициализация устройств МК (таймера, USART). Передаётся управление функции READ_MASS_RS_1. Она (функция) взводит прерывание от таймера (прерывание наступит через какое время? "...много больше чем требуется на передачу пакета". Это сколько? Секунда? Две? 10?), и ждёт приема N байтов...
2. В это время Вы набираете (?) некие символы на терминале (на терминале ли?) и нажимаете (?) кнопку "отправить" (??? В этом пункте сплошные вопросы из-за отсутствия информации...).
3. П.2 занимает у Вас некоторое время.
4. Вполне вероятно, что это время больше, чем величина тайм-аута.
5. МК по тайм-ауту прекратил приём байтов (вероятно, ещё до того, как Вы отправили все данные).
6. ... что происходит далее - сказать нельзя из-за отсутствия информации...
=GM=
Какая у вас тактовая частота процессора?
messenger
я к сожалению до сих пор не исправил описанные вчера ошибки поэтому прошу не читать пост до завтра

ниже как пояснение
рабочая частота МК 1 МГЦ
делитель в таймере =1
время таймера 65,5 мс

описываемое устройство перед началом ожидания приема посылает запрос 1 символ "Q" котрый я вижу принятым в терминале (или в проутесе)
да с терминала я отправляю пакт 123456 (есть окошко куда он вписывается далее нажимается кнопка отправить, проверяю в проутесе и на рабочем железе реакция схожа)
вижу принятым в буфере 126хххх.. где х пустые места в массиве
далее опять идут QQQQQ
если нажать отправить то опять, как я понимаю по завершению таймаута, 126ххх..и QQQQQQ
по наличию Q визуально определяю был ли прием один или несколько, вижу один
_Ivana
А модно дилетанту встрять? rolleyes.gif

Если я правильно вас понял, вы по каким-то причинам не используете прерывания USART по приему, а просто опрашиваете его с определенной частотой по таймеру? Мне это напоминает анализ нажатия кнопок без прерываний по уровням на ногах, а с таким же "опросом клавиатуры" с определенной частотой. Так и опрашивайте USART всегда. Вообще всегда, и пусть ваш основной процесс крутится параллельно, а по таймеру вы заглядываете, не пришел ли очередной байт - ведь режим асинхронный. И не надо ничего ни с чем синхронизировать, а только складывать байты в мешок, можно кольцевой sm.gif А если вы асинхронно приходящие байты наделяете каким-то человеческим смыслом, мыслите в терминах "пакетов" и прочих условностей, тогда и сами эти "пакеты" лучше формировать как надо - с детерминирующими символами, определяющими начало и конец пакета, часто используются enter|return как детерминирующий конец. И тогда передающее устройство пусть хоть какие паузы делает в процессе передачи и между пакетами - вы их примете и обработаете нормально. Но не будете определять "конец пакета" по тому факту, что "то символы летели один за другим, а то у нас что-то долго ничего не приходит, значит наверное конец пакета". Или я не правильно понял вашу логику "пакетов"?
=GM=
Не понимаю, как вы посылаете 123456 и в приёмном буфере видите 126хххх, вы же обнуляете буфер перед приёмом. Значит вы должны видеть по крайней мере 126000, а лучше бы 120006.
messenger
сделал "2. Данные принимаются с ошибкой. Чтобы проверить последнее следует либо проинициализировать массив reading_mass_rs_1 неким значением, отличным от нуля (например, символом 'X'). либо сохранять значение принятого байта, несмотря на ошибку в status (он же - UCSR1A). "

никому не сказал. Извините. буфер не обнуляю а забиваю иксами

опрашивать USART всегда ен могу. Нужно еще обрабатывать принятое
_Ivana
Цитата
опрашивать USART всегда ен могу. Нужно еще обрабатывать принятое

Либо вы меня не поняли, либо одно из двух sm.gif
Сколько тактов у вас уйдет на разовый опрос USARTа? Правильно, мизер. И с точки зрения основной программы, у вас будет лежать где-то мешок, куда "сами собой" будут сыпаться принятые байты - и этой основной программе будет все равно как они туда сыпятся - по прерываниям от USART или по прерываниям от таймера его опрашивающего. А как придет байт конца "пакета" - тогда либо выставляется флаг "посылка пришла", либо вы выходите из спячки и начинаете обрабатывать принятое, а параллельно у вас принимается следующий пакет. И не надо "все бросать" и сидеть и ждать, когда же примется вся посылка, а потом что-то делать. И ещё - если вы не успеваете "обрабатывать принятое" при той скорости входящего потока, которую выдает ваше передающее устройство, то вас не спасут ни прерывания ни опрос ни вообще ничего.
messenger
Прошу еще помощи
Вот что я сделал на данный момент

void READ_MASS_RS_1()
{
char status, data;
flag_stop_timer=0;
flag_eroor_rs=0;
RxTimOvf=0;

for (temp_1_i=0;temp_1_i<20;temp_1_i++)
{reading_mass_rs_1[temp_1_i]='z';} //Обнуление массива

TIMSK &= ~(1<<TOIE1); //Запретить прер. переполнения T1
TCCR1B=0x04; //! Изменить делитель
TCNT1H=0x7F;TCNT1L=0xFF; //переполнение =1 сек
TIFR |= (1<<TOV1); //Сброс флага прер. переполнения T1
TIMSK |= (1<<TOIE1); //Разрешить прер. переполнения T1


for (temp_1_i=0;temp_1_i<20;temp_1_i++)
{
while (((((status=UCSR1A) & RX_COMPLETE_1)==0)) && RxTimOvf==0) ;
data=UDR1;
if (((status & (FRAMING_ERROR_1 | PARITY_ERROR_1 | DATA_OVERRUN_1 ))==0))
{reading_mass_rs_1[temp_1_i]=data;}
}


for (temp_1_i=0;temp_1_i<20;temp_1_i++)
{putchar1(reading_mass_rs_1[temp_1_i]);}

}





interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TIMSK &= ~(1<<TOIE1); //Запретить прер. переполнения T1
RxTimOvf=1;
flag_timer_1_set=1; //Используется в задержках(паузах)
}

основной цикл
void START()
{ delay_500_ms();
putchar1('X');
READ_MASS_RS_1();//В reading_mass_rs лежит все что пришло за таймут по RS


}

Я увеличил таймаут до 1 сек. Учел сделанные мне замечания.
Что получил. Если после прихода на терминал символа Х не посылать посылку то МК отвечает буфером из ХХХХ... (это нормально)
Если после прихода на терминал символа Х посылать посылку, например, 123456 то все ок
но если ее же послать в момент паузы т.е до прихода Х то с МК что то происходит и он шлет пустой буфер zzzzzzzzz..
исправить это не получается

я думал что это связано с наличием флагов ошибки USART пробовал обнулять status, не помогло
Палыч
Цитата(messenger @ Jan 20 2012, 18:39) *
если ее же послать в момент паузы т.е до прихода Х то с МК что то происходит и он шлет пустой буфер zzzzzzzzz..
Объяснить такое поведение программы - можно:
1 выполнение программы не дошло до функции READ_MASS_RS_1;
2 байты по USART доходят до МК, но программа их из UDR не "выгребает";
3 фиксируется DOR и RXC;
4 как только МК начинает выполнять READ_MASS_RS_1, то "замечает", что байт принят USART и забирает его, но по DOR в буфер не помещает;
5 дальше МК ждёт прихода следующего байта, не ничего не дожидается (все байты уже были переданы) и выходит из READ_MASS_RS_1 по тайм-ауту

Как это исправить? Трудный вопрос... Уж так Вы спроектировали Вашу программу, что без кардинальной переделки вряд-ли это возможно...

messenger
значит я правильно понял где ошибка, но почему нельзя флаги ошибки перед началом приема просто сбросить?

И конечно вопрос а как правильно? но без прерываний.

Может я и остановлюсь на этом варианте, т.к. второе устройство (датчик) не ответит пока не придет подтверждение и ен отправит до разряшения. Все дубово. А вто что будет если что то ложное придет...помеха какая, непонятно. Точнее понятно. Больше двух и будет плохо.
Палыч
Цитата(messenger @ Jan 20 2012, 19:52) *
значит я правильно понял где ошибка, но почему нельзя флаги ошибки перед началом приема просто сбросить?
Флаги-то сбросить можно... Но, все байты были благополучно отправлены до того, как их прихода ждал МК и, поэтому не забрал из UDR.
Цитата
A data overrun occurs when the receive buffer is full (two characters), it is a new character waiting in the Receive Shift Register, and a new start bit is detected.
Если на вход USART пришло 6 байт - куда "бедному" устройству их "складывать"?
messenger
Да мне их не нужно складывать. Просто проигнорировать все до старта таймера
Палыч
Цитата(messenger @ Jan 21 2012, 00:47) *
Просто проигнорировать все до старта таймера

Тогда, действительно, нужно сбросить все флаги, относящиеся к приёму. Выше Вы писали, что не получилось. Как это Вы делали? Нужно читать UDR до тех пор, пока RXC не станет нулем.
messenger

while (((status & (FRAMING_ERROR_1 | PARITY_ERROR_1 | DATA_OVERRUN_1 ))==0))
{data=UDR1;}

Я уже кажется понял ошибку.
Все огромное спасибо за поддержку!
=GM=
Никак вы не хотите расстаться с порочной конструкцией while (((((status=UCSR1A) & RX_COMPLETE_1)==0)) && RxTimOvf==0) ;
Получается, что вам всё едино, принят ли байт, таймаут ли наступил, всё равно вы байт читаете. На самом деле вам нужно ИЛИ принять байт ИЛИ завершить приём, если наступил таймаут.

Попробуйте так
Код
errcnt=0;
for(i=0;i<20;i++)
{
while(rxc==0)
{
  if(timout==1) break;
};
if(timout==1) break;
if(err) errcnt++;
rdms[i]=UDR1;
}


Здесь "timout" это ваш "RxTimOvf==1", а "err" - "status & (FRAMING_ERROR_1 | PARITY_ERROR_1 | DATA_OVERRUN_1 ))!=0". "errcnt" - счётчик ошибок в пакете.

Можно обойтись одним оператором if(timout==1) break, но тогда вместо break придётся использовать оператор goto, который в си персона нон грата...

Также посоветую вам избегать длинных названий, типа "temp_1_i" вместо просто "i"
messenger
Мне нравится. Я Вас сразу не понял.Думал повиснет.
while(rxc==0)
{
if(timout==1) break;
};
Попробую, но уже в ПНД
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.