Подключение двух каналов АЦП
Модератор: boogyman
Подключение двух каналов АЦП
Возникла проблема с двумя каналами АЦП
При включении второго канала (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); //записываем значение в регистр
При включении второго канала (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); //записываем значение в регистр
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
Я так понял это не полный код, где обработчик прерывания.., на будущее вставляй код между тегами [codе]..[/codе]
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
Вот код двухканального вольтметра сделанного по аналогии выложенного на сайте
Код: Выделить всё
/***Двухканальный цифровой вольтметр***/
#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);
}
}
- Вложения
-
- ADCvoltmeter_2ch.rar
- Проект AvrStudio и Proteus
- (72.58 КБ) 4035 скачиваний
Re: Подключение двух каналов АЦП
Спасибо огромное.
А то жизнь заставляет изучать программирование, информации мало - учусь по примерам
А то жизнь заставляет изучать программирование, информации мало - учусь по примерам
Re: Подключение двух каналов АЦП
Привет всем. Огромное спасибо за уроки. В знак благодарности несклько раз ткнул по объявлениям Я.директа.
У меня возникли несколько вопросов. Не стал новую тему заводить. Тема вот эта: АЦП микроконтроллеров AVR. Делаем цифровой вольтметр 0 - 25V
Цитата: существует способ представить число 2,75 по другому, например: (ADC*11)/4
1. а как представить другие (разные) цифры, например, 1,8 - 3,86 - 4,61?
2. ADS=252 как сделать так, чтобы на индикаторе показывал, например 10,8
т.е. как рассчитать этот (разные) коэффициент(ы)?
У меня возникли несколько вопросов. Не стал новую тему заводить. Тема вот эта: АЦП микроконтроллеров AVR. Делаем цифровой вольтметр 0 - 25V
Цитата: существует способ представить число 2,75 по другому, например: (ADC*11)/4
1. а как представить другие (разные) цифры, например, 1,8 - 3,86 - 4,61?
2. ADS=252 как сделать так, чтобы на индикаторе показывал, например 10,8
т.е. как рассчитать этот (разные) коэффициент(ы)?
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
Cначала высчитай коэффициент 252/108 = 2.3, т.е для вывода 108 надо 252/2.3, а коэф. 2.3 можно представить по разномуНазим писал(а):Привет всем. Огромное спасибо за уроки. В знак благодарности несклько раз ткнул по объявлениям Я.директа.
У меня возникли несколько вопросов. Не стал новую тему заводить. Тема вот эта: АЦП микроконтроллеров AVR. Делаем цифровой вольтметр 0 - 25V
Цитата: существует способ представить число 2,75 по другому, например: (ADC*11)/4
1. а как представить другие (разные) цифры, например, 1,8 - 3,86 - 4,61?
2. ADS=252 как сделать так, чтобы на индикаторе показывал, например 10,8
т.е. как рассчитать этот (разные) коэффициент(ы)?
Re: Подключение двух каналов АЦП
Понятно.
А 2,3 можно предстваить как (ADC*23)/10? 4,73 (ADC*473)/10 - такие цифры допустимы при написании кода?
А 2,3 можно предстваить как (ADC*23)/10? 4,73 (ADC*473)/10 - такие цифры допустимы при написании кода?
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
можно, только 4,73 (ADC*473)/100, и обращай внимание на тип переменных, char, long и т.дНазим писал(а):Понятно.
А 2,3 можно предстваить как (ADC*23)/10? 4,73 (ADC*473)/10 - такие цифры допустимы при написании кода?
Re: Подключение двух каналов АЦП
Добавил еще один канал, получился 3-х канальный измеритель на трех трехразрядных индикаторах, кому надо пишите, выложу
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
По просьбам посетителей сайта выкладываю пример кода программы одноканального вольтметра с выводом показаний на LCD 16x02. Принцип работы тот же, что и в обучающей статье http://radioparty.ru/index.php/prog-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 КБ) 3831 скачивание
Re: Подключение двух каналов АЦП
Пожалуйста!
Выложите код программы 4-х канального АЦП (2 канала для измерения напряжения и 2 канала для измерения тока).
Напряжение 0-30V, ток 0-10А.
Спасибо.
Выложите код программы 4-х канального АЦП (2 канала для измерения напряжения и 2 канала для измерения тока).
Напряжение 0-30V, ток 0-10А.
Спасибо.
Re: Подключение двух каналов АЦП
Под какой индикатор выложить исходник?
Re: Подключение двух каналов АЦП
Под LCD 1602, но и если можно то и под 7-ми сегментный индикатор.boogyman писал(а):Под какой индикатор выложить исходник?
Re: Подключение двух каналов АЦП
Вот код для четырехканального вольтметра, но в нем необходимо поменять коэффициенты для измерения напряжения и тока, а также сделать отдельную функцию измерения по каналам.
Код: Выделить всё
#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 КБ) 3401 скачивание
Re: Подключение двух каналов АЦП
Спасибо!
Re: Подключение двух каналов АЦП
Вот код для четырехканального вольтметра, но в нем необходимо поменять коэффициенты для измерения напряжения и тока, а также сделать отдельную функцию измерения по канала
А можно производить процесс измерения (4 канала) в прерывании?
А можно производить процесс измерения (4 канала) в прерывании?
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
Конечно можно, также в прерывании нужно поочередно менять канал АЦП
Re: Подключение двух каналов АЦП
Спасибо за ответ.AntonChip писал(а):Конечно можно, также в прерывании нужно поочередно менять канал АЦП
Re: Подключение двух каналов АЦП
Здравствуйте.
Собрал схему вольтметра (1 канал) на LCD, проверил в протеусе - работает, на макете - нет (каша на дисплее).
В чем может быть проблема?
Исходник и протеус во вложении.
Собрал схему вольтметра (1 канал) на LCD, проверил в протеусе - работает, на макете - нет (каша на дисплее).
В чем может быть проблема?
Исходник и протеус во вложении.
- Вложения
-
- Вольтметр LCD.rar
- (68.37 КБ) 3159 скачиваний
- AntonChip
- Администратор
- Сообщения: 265
- Зарегистрирован: 24 дек 2011, 22:11
- Откуда: Киров
- Контактная информация:
Re: Подключение двух каналов АЦП
Эти строчки я бы убрал до while(1)
Код: Выделить всё
lcd_string(0x80, " VOLTAGE ");
lcd_string(0xC0, " , V ");