|
Проблема с приемом данных USART в ATtiny2313 |
|
|
|
Oct 29 2008, 09:28
|

Участник

Группа: Участник
Сообщений: 20
Регистрация: 28-10-08
Из: Москва
Пользователь №: 41 264

|
Помогите, плиз, разобраться с проблемой!
Спаял схему, в которой данные в МК должны поступать по протоколу Модбас через 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; ...
, то МК перестает реагировать на пакеты. Скорость передатчика и приемника выставлены одинаковыми. Я пробывал с разными скоростями. Пробывал и от внешнего кварца и от внутреннего генератора. Где-то я прочел, что в этом условии проверяется наличие аппаратной ошибки. Получается, что МК плохой? Или еще какая-то другая причина может быть?
|
|
|
|
|
Oct 29 2008, 10:11
|

Участник

Группа: Участник
Сообщений: 20
Регистрация: 28-10-08
Из: Москва
Пользователь №: 41 264

|
Текст программы я не приводил, так как она мало отличается от сгенерированной 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
}; }
|
|
|
|
|
Oct 29 2008, 10:49
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 2-12-04
Пользователь №: 1 296

|
1. Если данные передаются непрерывно, то задержка 100 мс внутри прерывания может вызвать переполнение (DATA_OVERRUN). 2. Могут быть банально перепутаны A и B проводники 485 - тогда ошибка кадрирования(FRAMING_ERROR) IMHO
|
|
|
|
|
Oct 29 2008, 11:47
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Прораб счастья @ 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 должно быть истина в любом случае при отсутствии аппаратной ошибки (если это она проверяется в условии). По моему разумению если возникает ошибка - то первым делом надо ее идентифицировать и потом искать способы ее устранения. Ошибка это не значит "что МК плохой?" Цитата У меня параметры приема и передачи идентичны. Это ничем не подтвержденный факт. Раз не работает - значит есть проблема, в том числе параметры приема-передачи могут отличаться.
|
|
|
|
|
Oct 29 2008, 11:48
|
Местный
  
Группа: Свой
Сообщений: 266
Регистрация: 8-12-05
Пользователь №: 11 964

|
Цитата(Прораб счастья @ Oct 29 2008, 13:19)  Подключение А и В я неоднократно проверял. Насчет первого есть вопрос: прерывание вызывается единожды при начале приема пакета или каждый принятый бит вызывает прерывание? Или каждый принятый байт? Задержка 100 мс стоит после того, как в регистр что-то записалось (видимо в UDR), т.е. то что записалось должно пройти проверку if-ом. Поправьте меня если я не прав! Прерывание в документе обозначается USART0, Rx Complete и вызывается, соответственно, после окончания приема всего байта. Насколько я понмю, в CodeVision запрещаются прерывания после вызова прерывания (хотя и в самой архитектуре AVR при входе в прерывание дальнейший вызов прерывания по умолчанию также блокируеся), так что задержки такой величины в прерываниях - это очень плохой тон, скорее всего, Вы пропускаете данные, на что потом и указывает DATA_OVERRUN. Чем вызвана первая ошибка - видимо, ошибкой формата пакета.
|
|
|
|
|
Oct 29 2008, 11:52
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

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

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

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

Участник

Группа: Участник
Сообщений: 20
Регистрация: 28-10-08
Из: Москва
Пользователь №: 41 264

|
Цитата(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 текст. Ничего, кроме строчек выделенных красным цветом я не добавлял и не менял.
|
|
|
|
|
Oct 29 2008, 12:52
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(=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 МГц...
|
|
|
|
|
Oct 29 2008, 13:16
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Прораб счастья @ Oct 29 2008, 12:19)  Это сгенерированный CodeVisionAVR текст. Ничего, кроме строчек выделенных красным цветом я не добавлял и не менял CodeVisionAVR тоже человек писал, Павел Гайдук, мог ошибиться(:-). Повторюсь Цитата(=GM= @ Oct 29 2008, 12:09)  Вполне возможно, что эта строчка в инициализации приводит к ошибке. В прерывании вы зачем-то проверяете паритет, а этой строчкой вы паритет запрещаете. Тогда получается, что МК получает байты с паритетом, но интерпретирует бит паритета, как стоп-бит, отсюда могут возникать ошибки FE - Frame Error. С <7> битом UCSRC я ошибся, я всё время с ним ошибаюсь (просто у меня старая, но удобная книжка по авр с описанием процов, жалко выбрасывать). Шут с ним, с седьмым битом, не в нём дело, а дело в том, что при инициализации вы ЗАПРЕЩАЕТЕ паритет как класс, тем не менее, в своей программе вы проверяете бит паритета, спрашивается за каким шутом проверять, если вы его запретили принимать? Повторю ещё раз, если внешнее устройство передаёт вам биты с паритетом, а вы его запретили, то МК рассматривает переданные биты паритета как следующие за ними стоп-биты, а это приводит к ошибке FE, если конкретный бит паритета равен 0. Ответьте себе на вопрос, вы на МК передаёте биты с паритетом или нет?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 29 2008, 15:22
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(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.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 29 2008, 15:40
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(=GM= @ Oct 29 2008, 18:22)  Бит чётности читается 0, всё правильно, но если он физически передаётся другой стороной, то МК принимает его за стоп-бит, поскольку его инициализировали не принимать бит чётности. Вы правы, я прочитал начало фразы, а основную вашу мысль почему-то не воспринял. Решил, что автор все же занает что и как он передает. И написал о своем :)
|
|
|
|
|
Oct 30 2008, 10:01
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Прораб счастья @ 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, то проверяйте скорости передачи приёма прямым измереним. Для начала можно соединить выход передатчика с входом приёмника.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Oct 30 2008, 10:13
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 2-12-04
Пользователь №: 1 296

|
GM может так? PORTB.7=~PINB.7
Попробуй включить передатчик тиньки (и драйвер 485 на передачу), постоянно что-нибудь передавать и смотреть компутером. Т.о. будет ясно правильно ли выставлена скорость.
|
|
|
|
|
Nov 1 2008, 18:28
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(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."
Сообщение отредактировал SysRq - Nov 1 2008, 18:30
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|