|
Помогите найти ошибку в программе. Или глюк АЦП? |
|
|
|
Sep 14 2006, 20:46
|
Знающий
   
Группа: Свой
Сообщений: 559
Регистрация: 6-09-06
Пользователь №: 20 131

|
ПРоблемка у меня...Скорее всего с АЦП. Контроллер - ATMega32, частота кварца 16 МГц Задача такая - по оптическому каналу (лазер и фотодиод) передается байт. В этом же устройстве он принятый байт сравнивается с переданным и если байты одинаковы, возвращается 1. вот код Код #define MUX_STATE (0 << REFS1)|(0 << REFS0) #define ADC_STATE (1 << ADEN)|(0 << ADPS2)|(1 << ADPS1)|(1 <<ADPS0)
int ReadADC(unsigned char ChannelNum) { ADMUX = ChannelNum | MUX_STATE; ADCSRA = (1 << ADSC) | ADC_STATE; while ( (ADCSRA & ( 1 << ADIF))==0); return ADCW; }
send_pack(unsigned char byte) { char *text; int i,x; unsigned char _bit, recieved_byte; for (i=0;i<8;i++) // разбираем байт по битам { _bit=(byte >> i) & 0x01; //присваиваем переменной _bit значение очередного бита переменной byte if (_bit==1) { PORTD |= _BV(PD0); // бит равен 1, включаем лазер glcdFillRect(10,10+i*18,20,20+i*18,RED); }
if (_bit==0) { PORTD &= ~_BV(PD0); // 0, бит равен 0, выключаем лазер glcdFillRect(10,10+i*18,20,20+i*18,WHITE); } glcdWait(1000); //ждем-с...
x=ReadADC(0); запускаем АЦП и измеряем освещенность фотодиода.
sprintf(text," %i ",x); glcdMoveTo(60,10+i*18); glcdPrint(text, 0); if (x<50) // если освещенность низка - bit=0 { glcdFillRect(30,10+i*18,40,20+i*18,WHITE); _bit=0; } if (x>50) // если освещенность достаточна- bit=1 { glcdFillRect(30,10+i*18,40,20+i*18,RED); _bit=1; } recieved_byte |= _bit << i; // склеиваем из полученных битов байт } if (recieved_byte==byte) return 1; return 0;
} Но вот проблема... если в байте чередуются 1 и 0, то данные принимаются с точностью до наоборот. вот вам пример того, что выводится на экран: T- посылаемый бит R- принятый бит L- значение полученное с АЦП Код Для байта 0xFF: Для байта 0xAF: Для байта 0xAF: Для байта 0xFA:
T R L T R L T R L T R L
1 1 512 1 1 514 0 0 11 0 0 11 1 1 511 1 1 513 1 0 11 1 0 11 1 1 509 1 1 512 0 1 515 0 1 508 1 1 510 1 1 512 1 0 11 1 0 11 1 1 512 0 1 512 0 1 515 1 1 508 1 1 511 1 0 12 1 0 12 1 1 507 1 1 511 0 1 537 0 1 512 1 1 506 1 1 511 1 0 13 1 0 13 1 1 508 Небольшой анализ: 1.Подряд идущие биты анализируются нормально. 2.При переключении бита с 1 на 0 или обратно происходит как бы сдвиг, почему-то выводится все наоборот. 3. Первый неправильный "результат" (то есть когда после кучи единиц вдруг оказывается ноль или наоборот) всегда содержит предыдущее значение АЦП. 4. Два одинаковых бита подряд возвращат АЦП к нормальной работе. Комбинации с частотой работы АЦП ничего не дали. VCC, AVCC и AREF соединены одним проводником. P.S. Самое главное - я пишу в WinAVR. До этого аналогичный код был написан мной для CodeVision за полчаса и прекрасно работал...
|
|
|
|
|
Sep 14 2006, 22:21
|

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

|
Цитата glcdWait(1000); //ждем-с... Что за монстр такой? Не исключено что съеден оптимизатором. Здесь трабл вероятно. Цитата При переключении бита с 1 на 0 или обратно происходит как бы сдвиг, почему-то выводится все наоборот. Не "как бы сдвиг" а именно сдвиг, с отставанием в один бит. Причина - инертность лазера. Глюк в программе - не выдержана требуемая до начала преобразования задержка. Читайте не после изменения, а перед изменением, достоверней будет.
|
|
|
|
|
Sep 15 2006, 05:41
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
имхо, стОит посмотреть, какой код сгенерился для Код int ReadADC(unsigned char ChannelNum) { ... return ADCW; } , а именно порядок чтения ADCH и ADCL. Т.к. АЦП в данной программе по существу работает однобитовым компаратором (опуская детали, но без потери сути _bit = ADCW>50? 1: 0; кста, в оригинале случай x==50 вообще не обрабатывается  ), то можно сделать так: Код #define MUX_STATE (0 << REFS1)|(0 << REFS0)|(1 << ADLAR) ... uchar ReadADC(unsigned char ChannelNum) { ... return ADCH; }
|
|
|
|
|
Sep 15 2006, 07:16
|
Знающий
   
Группа: Свой
Сообщений: 559
Регистрация: 6-09-06
Пользователь №: 20 131

|
Господа. Я вижу что вы люди квалифицированные, но хотел бы обратить внимание на мой фразу о том, что данный код без проблем работал на CodeVision и многие грабли, на которые мне указывают, пройдены. Цитата Что за монстр такой? Не исключено что съеден оптимизатором. Здесь трабл вероятно.
Причина - инертность лазера. Глюк в программе - не выдержана требуемая до начала преобразования задержка. Какие только задержки я не ставил - и до и после - инертность кк лазера, так и фотодиода исключена. Впрочем, последую вашему совету и всесторонне проверю этот вариант. Ладно, попробую все отладить на проводах. Спасибо за советы.
|
|
|
|
|
Sep 15 2006, 08:34
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(-=Женек=- @ Sep 15 2006, 11:16)  Господа. Я вижу что вы люди квалифицированные, но хотел бы обратить внимание на мой фразу о том, что данный код без проблем работал на CodeVision и многие грабли, на которые мне указывают, пройдены. Если бы CodeVision и WinAVR генерили одинаковый код, оно и работало бы одинаково. Поэтому я и посоветовал проверить в ассемблерном коде, как читается АЦП и что возвращается из ReadADC. > If the result is left adjusted and no more than 8-bit precision is required, it is sufficient to > read ADCH. Otherwise, ADCL must be read first, then ADCH, to ensure that the content > of the Data Registers belongs to the same conversion.
|
|
|
|
|
Sep 15 2006, 09:04
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Код .... for (i=0;i<8;i++) // разбираем байт по битам { _bit=(byte >> i) & 0x01; //присваиваем переменной _bit значение очередного бита переменной byte ..... Внимательней посмотрите, что здесь происходит. Какому биту равен "_bit" при первой интерации цикла?
|
|
|
|
|
Sep 15 2006, 09:26
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(aesok @ Sep 15 2006, 13:04)  Код .... for (i=0;i<8;i++) // разбираем байт по битам { _bit=(byte >> i) & 0x01; //присваиваем переменной _bit значение очередного бита переменной byte ..... Внимательней посмотрите, что здесь происходит. Какому биту равен "_bit" при первой интерации цикла? Если не вдаваться в оптимальность кода, то все правильно, не пугайте автора  .
|
|
|
|
|
Sep 15 2006, 09:59
|
Знающий
   
Группа: Свой
Сообщений: 559
Регистрация: 6-09-06
Пользователь №: 20 131

|
Цитата Внимательней посмотрите, что здесь происходит. Какому биту равен "_bit" при первой интерации цикла? Господа, см мой код. На экранчике всякая операция с битами отображается по ходу дела. Цитата if (_bit==1) { PORTD |= _BV(PD0); // бит равен 1, включаем лазер glcdFillRect(10,10+i*18,20,20+i*18,RED); } По поводу отработки ваших советов: 1. Обнуление фотодиода не помогло. Проблема как выяснилось не в оптике, см ниже. 2. Последовательность ADCL и ADCH пока на проверял, сейчас займусь, просто не терпится выложить результаты сюда, дабы не было больше советов проверить оптику и правильность собственно алгоритма анализа битов. 3. Итак... переделал я код под провода. Два варианта: - сигнал по проводу подается на вход порта и анализируется как логический - сигнал по проводу подается на вход АЦП и анализируется полученное цифровое значение. Надо сказать, что я полностью отключил библиотеку LCD, дабы исключить какой-то конфликт, поэтому отображение информации я осуществляю свтодиодами - на моей отладочной плате их у каждого порта по 8 шт. Вот код: Код #include <inttypes.h> #include <stdio.h> #include <avr/io.h> #include <avr/delay.h> #include <avr/iom32.h> #define MUX_STATE (0 << REFS1)|(0 << REFS0) #define ADC_STATE (1 << ADEN)|(1 << ADPS2)|(1 << ADPS1)|(1 <<ADPS0)
int ReadADC(unsigned char ChannelNum) { ADMUX = ChannelNum | MUX_STATE; ADCSRA = (1 << ADSC) | ADC_STATE; while ( (ADCSRA & ( 1 << ADIF))==0); return ADCW; }
send_pack(unsigned char byte) { int i,x,j,b; unsigned char _bit, recieved_byte; for (i=0;i<8;i++) { _bit=(byte >> i) & 0x01; if (_bit==1) PORTD |= _BV(PD0); if (_bit==0) PORTD &= ~_BV(PD0); for (j=0;j<32000;j++) { for (b=0;b<10;b++) {} } //ЧТо-то Я не разобрался пока, как делать задержку в 1 сек функцией _delay_ms. Скучаю по CodeVision )) x=ReadADC(0); for (j=0;j<32000;j++) { for (b=0;b<10;b++) {} } // задержка
if (x>50) // это если испльзуем АЦП //if (PINA & _BV(PA7)) // А это если используем вход порта включенный на прием. { PORTC |= _BV(i); // отображаем текуший бит (ко всем выходам порта С подключены светодиоды) _bit=1; } if (x<51) //if (!(PINA & _BV(PA7))) { PORTC &= ~_BV(i); // отображаем текуший бит (ко всем выходам порта С подключены светодиоды) _bit=0; } for (j=0;j<32000;j++) { for (b=0;b<10;b++) {} } // подождем... recieved_byte |= _bit << i; // Клеим принятый байт... } if (recieved_byte==byte) return 1; return 0; }
void main() { int crc; DDRD |= _BV(PD0); DDRD |= _BV(PD7); DDRC = 0xFF; DDRA &= ~_BV(PA7); PORTD |=_BV(PD0);
crc=send_pack(0xFF); if (crc==1) { PORTD |= _BV(PD7); // если байт передан правильно, то зажигаем светодиод. } if (crc==0) { PORTD &= ~_BV(PD7); }
} Если сигнал подается с выхода одного порта на вход другого и анализируется логически - то все работает. Если же используется АЦП - результат идентичен. раскладки полученных битов даже приводить не буду, см. выше. Еще раз повторяю - данный алгоритм работал на CodeVision. Настройки АЦП те же были... И подскажите ламеру, как АСМовский код посмотреть? Нет его почему то в папке с проектом после компиляции...
|
|
|
|
|
Sep 15 2006, 10:05
|

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

|
Влияние ADCW (порядка считывания) можно легко устранить. Не думаю что вам нужна 10битная точность АЦП для определения есть/нет сигнала. Настройте АЦП в режиме ADLAR и считывайте только ADCH: Код #define U8 unsigned char #define MUX_STATE (0 << REFS1)|(0 << REFS0)|(1 << ADLAR)
U8 ReadADC(U8 ChannelNum) { ADMUX = ChannelNum | MUX_STATE; ADCSRA = (1 << ADSC) | ADC_STATE; while ( (ADCSRA & ( 1 << ADIF))==0); return ADCH; } также можно выполнять двойное или тройное преобразование, и брать средний результат.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|