реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> АЦП и ATmega48, как работать с несколькими каналами
Дмитрий_Мигачев
сообщение May 27 2006, 22:37
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 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");
}

}
но он матюгается на этот код, а как сделать правильней?


--------------------
Go to the top of the page
 
+Quote Post
Дмитрий_Мигачев
сообщение May 27 2006, 22:53
Сообщение #2


Частый гость
**

Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784



Вопрос конешно я задал довольно не понятно, но извините у нас уже просто почти 6 утра)


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение May 27 2006, 23:32
Сообщение #3


кекс
******

Группа: Свой
Сообщений: 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 );
Go to the top of the page
 
+Quote Post
Laksus
сообщение May 28 2006, 11:29
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 146
Регистрация: 16-05-05
Пользователь №: 5 069



Я не вникал в суть кода, но, по моему после первой
if() в SIGNAL(SIG_OVERFLOW1) не хватает }.

____________
Александр
2006 05 28
Go to the top of the page
 
+Quote Post
Laksus
сообщение May 28 2006, 11:59
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 146
Регистрация: 16-05-05
Пользователь №: 5 069



И еще парочка мыслей по "косметике".

1- asm("sei"); в конце обработчика прерывания, по моему, совсем не нужны.
Прерывния и так установятся.

2- для того, чтобы считать 16-битное значения в С,
излишне выражение
b=ADCL;
kanal1=(ADCH<<8)+b;
компилятор только запутывается.
Достаточно
kanal1=ADC ;
а компилятор сам разберется с верхними/нижними байтами и сделает в лучшем виде.

_____________
Александр
2006 05 28
Go to the top of the page
 
+Quote Post
Дмитрий_Мигачев
сообщение May 29 2006, 03:21
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 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");
}

}


--------------------
Go to the top of the page
 
+Quote Post
haker_fox
сообщение May 29 2006, 03:55
Сообщение #7


Познающий...
******

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



Первое, что бы я пожелал: оформляйте код в специальных тегах, вот так:
Код
int My_global;
unsigned char adc_chan;
unsigned short kanal1, kanal2;

SIGNAL(SIG_OVERFLOW1)
  {
    TCNT1=0xFFEB;
    switch(adc_chan)
      }  
         case 0:
         ADMUX=0;
         break;

         case 1:
         ADMUX=_BV(MUX2)+_BV(MUX1)+_BV(MUX0);
         break;
       }
    ADCSRA|=_BV(ADSC);
  }


SIGNAL(SIG_ADC)
  {
    switch(adc_chan)
      {
        case 0:
        kanal1=ADC;
        adc_chan++;
        break;

        case 1:
        kanal2=ADC;
        adc_chan=0;
        break;
      }
    ADCSRA&=~_BV(3);
  }


void idle_init(void)
  {
    SMCR=_BV(SE);
  }

void timer1_init(void)
  {
    TCCR1B=_BV(CS12)+_BV(CS10);
    TCNT1=0xFFEB;
    TIMSK1=_BV(TOIE1);
  }

int main(void)
  {
        ADCSRA=_BV(ADEN)+_BV(ADIF)+_BV(ADIE)+_BV(ADPS1)+_BV(ADPS0);  
    idle_init();
    timer1_init();
    adc_chan=0;
    while(1)
      {
        asm("sleep");
      }
  }


Ну примерно бы так я офоромил программу, правда еще надо комментарии дописать. Ну и на всякий случай на симуляторе прогнать: нет ли где ошибок)))


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Дмитрий_Мигачев
сообщение May 29 2006, 04:19
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784



Цитата(haker_fox @ May 29 2006, 10:55) *
Первое, что бы я пожелал: оформляйте код в специальных тегах, вот так:
...

Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan?

Сообщение отредактировал Дмитрий_Мигачев - May 29 2006, 04:22


--------------------
Go to the top of the page
 
+Quote Post
haker_fox
сообщение May 29 2006, 04:38
Сообщение #9


Познающий...
******

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



Цитата(Дмитрий_Мигачев @ May 29 2006, 13:19) *
Цитата(haker_fox @ May 29 2006, 10:55) *

Первое, что бы я пожелал: оформляйте код в специальных тегах, вот так:
...

Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan?


Нет предела совершенству, конечно можно найти еще множество путей. Наличие переменной adc_chan не обязательно, можно использовать сразу регистр ADMUX - ведь в нем хранится номер канала.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 29 2006, 09:50
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(Дмитрий_Мигачев @ May 29 2006, 07:19) *
Ну я понял, что вы изменили, спасибо, но вопрос другой, это оптимальный вариант работы с АЦП (именно в моем случае с двумя каналами), или можно найти другие пути, обязательно наличие следящей переменной adc_chan?


Необязательно ожидать завершения операции от АЦП. Особенно в Вашем случае (50 раз в секунду). smile.gif

Алгоритм работы такой:
1) АЦП запускается в "автоматическом" режиме без генерации прерываний.
2) Организуется прерывание по таймеру.
3) В данном прерывании:
a) Читается текущее значение
б) Пререключается слудующий канал.
ВНИМАНИЕ! Не наоборот!
Go to the top of the page
 
+Quote Post
Дмитрий_Мигачев
сообщение May 29 2006, 14:26
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784



Вообще я хотел сделать так, чтобы оцифровка каналов, начиналась каждые 50 секунд, мне так не обходимо.

Я думал надо делать так:
1) Организуется прерывание по таймеру(50 раз в сек)
2) В данном прерывании устанавливается канал для оцифровки
3) Запускаем АЦП
4) По завершению АЦП возникает прерывание в котором, я сохраняю всю информацию за исключением двух младших равзрядов


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение May 29 2006, 14:43
Сообщение #12


кекс
******

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



Цитата(Дмитрий_Мигачев @ May 29 2006, 17:26) *
Я думал надо делать так:
1) Организуется прерывание по таймеру(50 раз в сек)
2) В данном прерывании устанавливается канал для оцифровки
3) Запускаем АЦП
4) По завершению АЦП возникает прерывание в котором, я сохраняю всю информацию за исключением двух младших равзрядов


Просто в прерывании таймера запускайте одиночное преобразование АЦП и считывайте показания.
Не думаю, что для решения вашей задачи нужно вообще шаманить с прерываниями от АЦП.
Go to the top of the page
 
+Quote Post
Дмитрий_Мигачев
сообщение May 29 2006, 14:48
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 110
Регистрация: 28-02-06
Из: Россия г. Омск
Пользователь №: 14 784



Вообще это часть моей задачи. Я хочу сделать радиоуправляемую модель, с 2 пропорциональными и 3 дискретными каналами. Приемопередающий модуль DP1203. Вот и изучаю, как правильней с этим работать

Сообщение отредактировал Дмитрий_Мигачев - May 29 2006, 14:49


--------------------
Go to the top of the page
 
+Quote Post
defunct
сообщение May 29 2006, 15:12
Сообщение #14


кекс
******

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



Цитата(Дмитрий_Мигачев @ May 29 2006, 17:48) *
Вот и изучаю, как правильней с этим работать

тут много путей в равной степени правильных.
Однозначно сказать, что такой-то путь самый правильный нельзя..

Простой путь я вам описал. (в обработчике прерывания таймера осуществлять одиночное преобразование и сразу считывать результат).
Чуть более эффективный - ваш (с двумя прерываниями).
Еще более эффективный - настроить АЦП на работу в автоматическом режиме с запуском от таймера и генерацией прерывания по окончанию преобразования. (выбросить прерывание таймера).

Вопрос только в том, нужно ли усложнять жизнь если производительности МК хватает для реализации даже самого простого из правильных путей?
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 29 2006, 15:56
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 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) выходим
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 08:25
Рейтинг@Mail.ru


Страница сгенерированна за 0.01484 секунд с 7
ELECTRONIX ©2004-2016