|
|
  |
АЦП и ATmega48, как работать с несколькими каналами |
|
|
|
May 27 2006, 22:37
|
Частый гость
 
Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784

|
Вообщем не могу понять как работать с несколькими каналами АЦП. Юзаю VMLab, он меня всем удовлетворяет, сейчас пишу тут одну вещь и встал...Дело в том что есть какой то пульт управления, и результаты с рычагов должны оцифровываться 50 раз в секунду, вообщем как я думал, по переполнению таймера счетчика, мы уходим в прерывание, где тама, тама производим необходимую настройку ацп, далее разрешаем прерывание по завершению АЦП и так с двумя каналами. Я думал что бы работать с двумя каналами необходимо завести переменную, к примеру в начеле она равна нулю, после первого АЦП она инкрементируется, и далее производиться обработка второго канала, но компилятор выдает ошибком, вообщем мне кажется что я выбрал не правильный путь, подскажите как сделать правильней Для понятливости того, что я написал приведу пример своего кода: ************************* ************************* unsigned char adc_chan, b; unsigned short kanal1, kanal2; SIGNAL(SIG_OVERFLOW1){ asm("nop"); TCNT1=0xFFEB; if (adc_chan==0) { ADCSRA=_BV(ADEN)+_BV(ADIF)+_BV(ADIE)+_BV(ADPS0); ADMUX=0; //ADC0 ADCSRA|=_BV(ADSC); asm("sei"); if (adc_chan==1) { ADCSRA=_BV(ADEN)+_BV(ADIF)+_BV(ADIE)+_BV(ADPS0); ADMUX=_BV(MUX2)+_BV(MUX1)+_BV(MUX0);//ADC7 ADCSRA|=_BV(ADSC); asm("sei"); } } SIGNAL(SIG_ADC){ if (adc_chan==0){ b=ADCL; kanal1=(ADCH<<8)+b; adc_chan++; } if (adc_chan==1){ b=ADCL; kanal2=(ADCH<<8)+b; adc_chan=0; } } void idle_init(void) { SMCR=_BV(SE); asm("sei"); } void timer1_init(void) { TCCR1B=_BV(CS12)+_BV(CS10);//CLK/1024 TCNT1=0xFFEB; TIMSK1=_BV(TOIE1); } // *********************************************************** // Main program // int main(void) { idle_init(); timer1_init(); adc_chan=0; while(1) { asm("sleep"); }
} но он матюгается на этот код, а как сделать правильней?
--------------------
|
|
|
|
|
May 27 2006, 23:32
|

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

|
пишем функцию Код #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; } и подставляем в нее номер канала как параметр. Channel0 = ReadAdc( 0 ); Channel2 = ReadAdc( 2 );
|
|
|
|
|
May 29 2006, 03:21
|
Частый гость
 
Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784

|
Всем спасибо за ответы, более или менее разобрался, было много недочетов в том коде, поскольку писал на сонную голову, вчера на работе переделывал, но код не рациональный, хотелось бы узнать, как сделать более правильный код: int My_global; unsigned char adc_chan, b; unsigned short kanal1, kanal2; SIGNAL(SIG_OVERFLOW1){ TCNT1=0xFFEB if (adc_chan==0) { ADCSRA=_BV(ADEN)+_BV(ADIF)+_BV(ADIE)+_BV(ADPS1)+_BV(ADPS0); ADMUX=0; ADCSRA|=_BV(ADSC); } if (adc_chan==1) { ADCSRA=_BV(ADEN)+_BV(ADIF)+_BV(ADIE)+_BV(ADPS1)+_BV(ADPS0); ADMUX=_BV(MUX2)+_BV(MUX1)+_BV(MUX0); ADCSRA|=_BV(ADSC); } } SIGNAL(SIG_ADC){ if (adc_chan==0){ b=ADCL; kanal1=(ADCH<<8)+b; adc_chan++; ADCSRA&=~_BV(3); return; } if (adc_chan==1){ b=ADCL; kanal2=(ADCH<<8)+b; adc_chan=0; ADCSRA&=~_BV(3); } } void idle_init(void) { SMCR=_BV(SE); asm("sei"); } void timer1_init(void) { TCCR1B=_BV(CS12)+_BV(CS10); TCNT1=0xFFEB; TIMSK1=_BV(TOIE1); } int main(void) { idle_init(); timer1_init(); adc_chan=0; while(1) { asm("sleep"); }
}
--------------------
|
|
|
|
|
May 29 2006, 04:19
|
Частый гость
 
Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784

|
Цитата(haker_fox @ May 29 2006, 10:55)  Первое, что бы я пожелал: оформляйте код в специальных тегах, вот так: ... Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan?
Сообщение отредактировал Дмитрий_Мигачев - May 29 2006, 04:22
--------------------
|
|
|
|
|
May 29 2006, 04:38
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
Цитата(Дмитрий_Мигачев @ May 29 2006, 13:19)  Цитата(haker_fox @ May 29 2006, 10:55)  Первое, что бы я пожелал: оформляйте код в специальных тегах, вот так: ...
Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan? Нет предела совершенству, конечно можно найти еще множество путей. Наличие переменной adc_chan не обязательно, можно использовать сразу регистр ADMUX - ведь в нем хранится номер канала.
--------------------
Выбор.
|
|
|
|
|
May 29 2006, 09:50
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Дмитрий_Мигачев @ May 29 2006, 07:19)  Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan? Необязательно ожидать завершения операции от АЦП. Особенно в Вашем случае (50 раз в секунду). Алгоритм работы такой: 1) АЦП запускается в "автоматическом" режиме без генерации прерываний. 2) Организуется прерывание по таймеру. 3) В данном прерывании: a) Читается текущее значение б) Пререключается слудующий канал. ВНИМАНИЕ! Не наоборот!
|
|
|
|
|
May 29 2006, 15:12
|

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

|
Цитата(Дмитрий_Мигачев @ May 29 2006, 17:48)  Вот и изучаю, как правильней с этим работать тут много путей в равной степени правильных. Однозначно сказать, что такой-то путь самый правильный нельзя.. Простой путь я вам описал. (в обработчике прерывания таймера осуществлять одиночное преобразование и сразу считывать результат). Чуть более эффективный - ваш (с двумя прерываниями). Еще более эффективный - настроить АЦП на работу в автоматическом режиме с запуском от таймера и генерацией прерывания по окончанию преобразования. (выбросить прерывание таймера). Вопрос только в том, нужно ли усложнять жизнь если производительности МК хватает для реализации даже самого простого из правильных путей?
|
|
|
|
|
May 29 2006, 15:56
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Дмитрий_Мигачев @ May 29 2006, 17:26)  Вообще я хотел сделать так, чтобы оцифровка каналов, начиналась каждые 50 секунд, мне так не обходимо.
Я думал надо делать так: 1) Организуется прерывание по таймеру(50 раз в сек) 2) В данном прерывании устанавливается канал для оцифровки 3) Запускаем АЦП 4) По завершению АЦП возникает прерывание в котором, я сохраняю всю информацию за исключением двух младших равзрядов Перечитайте ещё раз мой пост выше. Мой алгоритм эффективней т.к не требует ожидания от ацп! Поясню детальнее. Напимер у Вас 10 каналов. Инициализируем таймер на 50/10=5сек. В прерывании алгоритм такой: 1) Считываем значение предыдущего канала 2) Изменяем канал 3) выходим
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|