Подключение двух каналов АЦП

Модератор: boogyman

Подключение двух каналов АЦП

Сообщение:#1  Сообщение vsv » 08 фев 2012, 11:48

Возникла проблема с двумя каналами АЦП
При включении второго канала (ADC1)полностью игнорируется первый канал (ADC0)
(запись переменных происходит по значениям второго канала).
Симулировал в протеуc
Может где напутал?
Текст программы

#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#define sei()
/* Главная функция */
int main (void)
{ //начало главной функции

DDRD = 0xFF; //порт Д выход
PORTD = 0x00; // состояние 0
DDRB = 0x00; //порт B вход
PORTB = 0xFF; //подключаем нагрузочные резисторы
/* включение АЦП,делитель 32*/
ADCSRA |= (1 << ADEN)|(1 << ADPS2)|(0 << ADPS1)|(1 << ADPS0);
ADMUX |= (0 << REFS1)|(0 << REFS0); // внешний ИОН
while(1)
{ // начало бесконечного цикла
/* авто */
if(PINB == 0b11011111) // авто,движение по АЦП
{
sei(); // разрешаем прерывания
ADMUX |=(0 << MUX0)|(0 << MUX1)|(0 << MUX2)|(0 << MUX3); // вход АЦП ADC0
unsigned int u;// инициализируем переменную u (значение датчика)
ADCSRA |= (1 << ADSC); //Начинаем преобразование
if ((ADCSRA&(1 << ADIF))== 0); //Ждем окончания преобразования
{
u = (ADCL|ADCH << 8); //записываем значение в регистр
Аватара пользователя
vsv
Новичок
 
Сообщения: 2
Зарегистрирован: 08 фев 2012, 11:15
ТегиAtmega8, вольтметр, АЦП

Re: Подключение двух каналов АЦП

Сообщение:#2  Сообщение AntonChip » 08 фев 2012, 16:33

Я так понял это не полный код, где обработчик прерывания.., на будущее вставляй код между тегами [codе]..[/codе]
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#3  Сообщение AntonChip » 09 фев 2012, 13:44

Вот код двухканального вольтметра сделанного по аналогии выложенного на сайте
Код: Выделить всё
/***Двухканальный цифровой вольтметр***/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//------------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp                     
const char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};

volatile unsigned char segcounter = 0;
volatile int display_1 = 0, display_2 = 0;

//Прерывание по переполнению таймера2
ISR (TIMER2_OVF_vect)
{   
   PORTD = 0x00;
   PORTB = ~(1 << segcounter);
   
   switch (segcounter)
   {   
      case 0:
         PORTD = SEGMENTE[display_1 % 1000/100];
         break;   
      case 1:
         PORTD = (SEGMENTE[display_1 % 100/10])|0x80; //добавляем точку
         break;      
      case 2:
         PORTD = SEGMENTE[display_1 % 10];
         break;
      case 3:
         PORTD = SEGMENTE[display_2 % 1000/100];
         break;
      case 4:
         PORTD = SEGMENTE[display_2 % 100/10]|0x80; //добавляем точку
         break;   
      case 5:
         PORTD = SEGMENTE[display_2 % 10];
         break;
   }
   if ((segcounter++)>5) segcounter = 0;      
}

//Прерывание по окончанию преобразования АЦП

volatile unsigned long value_1, value_2;
volatile unsigned int adc_counter;

ISR (ADC_vect)
{
    ADCSRA = 0;
    if ((ADMUX&0x0F) == 1)
    {
      ADMUX = 0;
        value_1 += ADC*24/45;
     }
    else
    {
      ADMUX = (1 << MUX0);
        value_2 += ADC*24/45;   
      adc_counter++;
    }
ADCSRA = (1 << ADEN) // разрешение АЦП
       |(1 << ADSC) // запуск преобразования
      |(1 << ADFR) // непрерывный режим работы АЦП
        |(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64 (частота АЦП 125kHz)
      |(1 << ADIE); // разрешение прерывания
}

/***Главная функция***/
int main (void)
{
   DDRD = 0xFF;
   DDRB = (1 << PB5)|(1 << PB4)|(1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0);
    PORTD = 0x00;   
    PORTB = 0x00;

    TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
   TCCR2 |= (1 << CS21);  //предделитель на 8
   
    ADCSRA = (1 << ADEN) // разрешение АЦП
           |(1 << ADSC) // запуск преобразования
          |(1 << ADFR) // непрерывный режим работы АЦП
            |(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64 (частота АЦП 125kHz)
          |(1 << ADIE); // разрешение прерывания

    ADMUX = (1 << MUX0);
   
   _delay_ms(50);

   sei(); //глобально разрешаем прерывания
 
   while(1)
   {

    if (adc_counter > 400) // вычисляем среднее значение АЦП
      {
         display_1 = (value_1/adc_counter);
         display_2 = (value_2/adc_counter);
         adc_counter = 0;
         value_1 = 0;
         value_2 = 0;
      }   
    _delay_ms(100);
    }
}

01.jpg
Схема
Вложения
ADCvoltmeter_2ch.rar
Проект AvrStudio и Proteus
(72.58 КБ) Скачиваний: 2291
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#4  Сообщение vsv » 09 фев 2012, 20:18

Спасибо огромное.
А то жизнь заставляет изучать программирование, информации мало - учусь по примерам
Аватара пользователя
vsv
Новичок
 
Сообщения: 2
Зарегистрирован: 08 фев 2012, 11:15

Re: Подключение двух каналов АЦП

Сообщение:#5  Сообщение Назим » 09 фев 2012, 22:42

Привет всем. Огромное спасибо за уроки. В знак благодарности несклько раз ткнул по объявлениям Я.директа. :D
У меня возникли несколько вопросов. Не стал новую тему заводить. Тема вот эта: АЦП микроконтроллеров AVR. Делаем цифровой вольтметр 0 - 25V

Цитата: существует способ представить число 2,75 по другому, например: (ADC*11)/4
1. а как представить другие (разные) цифры, например, 1,8 - 3,86 - 4,61?
2. ADS=252 как сделать так, чтобы на индикаторе показывал, например 10,8
т.е. как рассчитать этот (разные) коэффициент(ы)?
Аватара пользователя
Назим
Новичок
 
Сообщения: 2
Зарегистрирован: 09 фев 2012, 21:52

Re: Подключение двух каналов АЦП

Сообщение:#6  Сообщение AntonChip » 11 фев 2012, 07:53

Назим писал(а):Привет всем. Огромное спасибо за уроки. В знак благодарности несклько раз ткнул по объявлениям Я.директа. :D
У меня возникли несколько вопросов. Не стал новую тему заводить. Тема вот эта: АЦП микроконтроллеров AVR. Делаем цифровой вольтметр 0 - 25V

Цитата: существует способ представить число 2,75 по другому, например: (ADC*11)/4
1. а как представить другие (разные) цифры, например, 1,8 - 3,86 - 4,61?
2. ADS=252 как сделать так, чтобы на индикаторе показывал, например 10,8
т.е. как рассчитать этот (разные) коэффициент(ы)?

Cначала высчитай коэффициент 252/108 = 2.3, т.е для вывода 108 надо 252/2.3, а коэф. 2.3 можно представить по разному
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#7  Сообщение Назим » 11 фев 2012, 11:53

Понятно.
А 2,3 можно предстваить как (ADC*23)/10? 4,73 (ADC*473)/10 - такие цифры допустимы при написании кода?
Аватара пользователя
Назим
Новичок
 
Сообщения: 2
Зарегистрирован: 09 фев 2012, 21:52

Re: Подключение двух каналов АЦП

Сообщение:#8  Сообщение AntonChip » 11 фев 2012, 15:36

Назим писал(а):Понятно.
А 2,3 можно предстваить как (ADC*23)/10? 4,73 (ADC*473)/10 - такие цифры допустимы при написании кода?

можно, только 4,73 (ADC*473)/100, и обращай внимание на тип переменных, char, long и т.д
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#9  Сообщение boogyman » 11 окт 2012, 22:40

Добавил еще один канал, получился 3-х канальный измеритель на трех трехразрядных индикаторах, кому надо пишите, выложу
Аватара пользователя
boogyman
Модератор
 
Сообщения: 183
Зарегистрирован: 25 дек 2011, 21:48
Откуда: Москва

Re: Подключение двух каналов АЦП

Сообщение:#10  Сообщение AntonChip » 24 дек 2012, 21:54

По просьбам посетителей сайта выкладываю пример кода программы одноканального вольтметра с выводом показаний на LCD 16x02. Принцип работы тот же, что и в обучающей статье http://radioparty.ru/index.php/prog-avr/program-c/288-lesson-adc-avr-voltmeter, отличие только в выводе показаний.
Код: Выделить всё
/*** Использование АЦП. Цифровой вольтметр на LCD ***/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Функции работы с LCD
#define RS PD0
#define EN PD2
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')
{  lcd_data(*string);
string++;
}
}
// Функция вывода символа типа int
void LCDWriteInt(int val,unsigned int field_length)
{
char str[5]={0,0,0,0,0};
int i=4,j=0;
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length==-1)
while(str[j]==0) j++;
else
j=5-field_length;
if(val<0) lcd_data('-');
for(i=j;i<5;i++)
{
lcd_data(48+str[i]);
}
}
// Функция инициализации LCD
void lcd_init(void)
{
PORTD = 0x00;
DDRD = 0xFF;

_delay_ms(50); // Ожидание готовности ЖК-модуля

// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);

// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5);

lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}

volatile unsigned long value;
volatile unsigned int adc_counter;

/***Прерывание по окончанию преобразования АЦП***/
ISR (ADC_vect)
{
value = value + (ADC*11/4);
adc_counter++;
}

/***Главная функция***/
int main (void)
{
volatile int display = 0;

ADCSRA = (1 << ADEN) // разрешение АЦП
        |(1 << ADSC) // запуск преобразования
        |(1 << ADFR) // непрерывный режим работы АЦП
        |(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64 (частота АЦП 125kHz)
   |(1 << ADIE); // разрешение прерывания

ADMUX = (1 << REFS1)|(1 << REFS0) // внутренний ИОН 2,56V
        |(0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(0 << MUX0); // вход ADC0
   
_delay_ms(50);

sei(); // глобально разрешаем прерывания

lcd_init(); // Инициализация LCD
 
while(1)
{
if(adc_counter > 300) // вычисляем среднее значение АЦП
{
display = value/adc_counter;
lcd_string(0x80,"U =   ,  V");
lcd_com(0x84);
LCDWriteInt(display/100, 2); // Выводим на экран целое значение
lcd_com(0x87);
LCDWriteInt(display%100, 2); // Выводим на экран значение после запятой
adc_counter = 0;
value = 0;
}     
_delay_ms(50);
}
}

Вложения
voltmeter_lcd.rar
Проект AVRStudio4 и Proteus
(49.02 КБ) Скачиваний: 2236
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#11  Сообщение Sergey F » 08 май 2014, 22:48

Пожалуйста!
Выложите код программы 4-х канального АЦП (2 канала для измерения напряжения и 2 канала для измерения тока).
Напряжение 0-30V, ток 0-10А.
Спасибо.
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#12  Сообщение boogyman » 12 май 2014, 21:43

Под какой индикатор выложить исходник?
Аватара пользователя
boogyman
Модератор
 
Сообщения: 183
Зарегистрирован: 25 дек 2011, 21:48
Откуда: Москва

Re: Подключение двух каналов АЦП

Сообщение:#13  Сообщение Sergey F » 12 май 2014, 22:43

boogyman писал(а):Под какой индикатор выложить исходник?

Под LCD 1602, но и если можно то и под 7-ми сегментный индикатор.
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#14  Сообщение boogyman » 17 май 2014, 17:12

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

Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// Функции работы с LCD
#define RS PD0
#define EN PD2
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}

// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')
{  lcd_data(*string);
string++;
}
}
// Функция вывода символа типа int
void LCDWriteInt(uint16_t value, uint8_t nDigit)
{
/* DISPLAY n-DIGIT INTEGER NUMER */
 switch(nDigit)
 {
  case 4: lcd_data((value/1000)+'0');
  case 3: lcd_data(((value/100)%10)+'0');
  case 2: lcd_data(((value/10)%10)+'0');
  case 1: lcd_data((value%10)+'0');
 }
}
// Функция инициализации LCD
void lcd_init(void)
{
PORTD = 0x00;
DDRD = 0xFF;

_delay_ms(50); // Ожидание готовности ЖК-модуля

// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);

// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5);

lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}

/***Главная функция***/
int main (void)
{
ADCSRA |= (1 << ADSC);
ADCSRA = (1 << ADEN) // разрешение АЦП
        |(1 << ADFR) // непрерывный режим работы АЦП
        |(1 << ADPS2)|(1 << ADPS1); // предделитель на 64 (частота АЦП 125kHz)

lcd_init(); // Инициализация LCD

lcd_string(0x80,"U1   ,   U2   , ");
lcd_string(0xC0,"U3   ,   U4   , ");

while(1)
{
ADMUX = 0;
ADCSRA |= (1 << ADSC);     
while((ADCSRA &(1 << ADIF)) == 0){}; // Ждём окончания конвертирования
ADCSRA |= (1 << ADIF); // Сбрасываем флаг записью 1
lcd_com(0x83);
LCDWriteInt(ADC/(11/4)/100, 2); // Выводим на экран целое значение
lcd_com(0x86);
LCDWriteInt(ADC/(11/4)%100, 2); // Выводим на экран значение после запятой

ADMUX = 1;
ADCSRA |= (1 << ADSC);     
while((ADCSRA &(1 << ADIF)) == 0){}; // Ждём окончания конвертирования
ADCSRA |= (1 << ADIF); // Сбрасываем флаг записью 1
lcd_com(0x8C);
LCDWriteInt(ADC/(11/4)/100, 2); // Выводим на экран целое значение
lcd_com(0x8F);
LCDWriteInt(ADC/(11/4)%100, 2); // Выводим на экран значение после запятой

ADMUX = 2;
ADCSRA |= (1 << ADSC);     
while((ADCSRA &(1 << ADIF)) == 0){}; // Ждём окончания конвертирования
ADCSRA |= (1 << ADIF); // Сбрасываем флаг записью 1
lcd_com(0xC3);
LCDWriteInt(ADC/(11/4)/100, 2); // Выводим на экран целое значение
lcd_com(0xC6);
LCDWriteInt(ADC/(11/4)%100, 2); // Выводим на экран значение после запятой

ADMUX = 3;
ADCSRA |= (1 << ADSC);     
while((ADCSRA &(1 << ADIF)) == 0){}; // Ждём окончания конвертирования
ADCSRA |= (1 << ADIF); // Сбрасываем флаг записью 1
lcd_com(0xCC);
LCDWriteInt(ADC/(11/4)/100, 2); // Выводим на экран целое значение
lcd_com(0xCF);
LCDWriteInt(ADC/(11/4)%100, 2); // Выводим на экран значение после запятой

_delay_ms(50);
}
}
Вложения
voltmeter_lcd.rar
Проект AVRStudio4 и Протеус
(46.74 КБ) Скачиваний: 1766
Аватара пользователя
boogyman
Модератор
 
Сообщения: 183
Зарегистрирован: 25 дек 2011, 21:48
Откуда: Москва

Re: Подключение двух каналов АЦП

Сообщение:#15  Сообщение Sergey F » 17 май 2014, 22:53

Спасибо!
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#16  Сообщение Sergey F » 06 дек 2014, 23:37

Вот код для четырехканального вольтметра, но в нем необходимо поменять коэффициенты для измерения напряжения и тока, а также сделать отдельную функцию измерения по канала

А можно производить процесс измерения (4 канала) в прерывании?
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#17  Сообщение AntonChip » 07 дек 2014, 17:34

Конечно можно, также в прерывании нужно поочередно менять канал АЦП
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

Re: Подключение двух каналов АЦП

Сообщение:#18  Сообщение Sergey F » 07 дек 2014, 21:29

AntonChip писал(а):Конечно можно, также в прерывании нужно поочередно менять канал АЦП

Спасибо за ответ.
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#19  Сообщение Sergey F » 20 дек 2014, 15:09

Здравствуйте.
Собрал схему вольтметра (1 канал) на LCD, проверил в протеусе - работает, на макете - нет (каша на дисплее).
В чем может быть проблема?
Исходник и протеус во вложении.
Вложения
Вольтметр LCD.rar
(68.37 КБ) Скачиваний: 1481
Аватара пользователя
Sergey F
Любитель
 
Сообщения: 13
Зарегистрирован: 13 мар 2014, 14:33

Re: Подключение двух каналов АЦП

Сообщение:#20  Сообщение AntonChip » 20 дек 2014, 21:49

Эти строчки я бы убрал до while(1)
Код: Выделить всё
lcd_string(0x80, "    VOLTAGE     ");
lcd_string(0xC0, "      ,  V      ");
Аватара пользователя
AntonChip
Администратор
 
Сообщения: 193
Зарегистрирован: 24 дек 2011, 21:11
Откуда: Киров

След.

Вернуться в Микроконтроллеры AVR

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Rambler's Top100