Последовательная работа двух каналов АЦП на Атмега8

Здесь принимаются все самые невообразимые вопросы... Главное - не стесняйтесь. Поверьте, у нас поначалу вопросы были еще глупее :)
Ответить
Родился
Сообщения: 13
Зарегистрирован: Ср апр 15, 2020 12:28:32

Сообщение andreybolo »

Всем привет! Прошу вашей помощи в настройке АЦП на атмега 8.
Проблема следующая - если настраиваю работу АЦП на 1 канал, то все работает корректно. Если пробую подключить измерение по второй ножке, то перестают работать оба канала АЦП.
Где у меня ошибка, подскажите, пожалуйста.
Читал сообщения с подобной проблемой на других форумах, но все равно не разобрался.

#define F_CPU 1000000L // частота процессора
#include <avr/io.h>
#include <util/delay.h> // без этой библиотеки не работают часы задержки
#include <avr/interrupt.h> // подключение библиотеки прерывания


int main(void)
{

DDRC = 0b00000000; // инициирование портов D0 на работу на вход
PORTC &= ~(1<<1)|(1<<2);
DDRB = 0b11111111;
ADCSRA |= (1<<ADFR) ; // команда постоянного опроса АЦП
ADCSRA |= (1<<ADPS1) | (1<<ADPS0) ; ADCSRA &= ~(1<<ADPS2); // установка частоты дискретизации, делим частоту процессора на 8
ADMUX |= (1<<REFS1) | (1<<REFS0); //устанавливаем опорное напряжение 2,56 В от внутреннего источника питания
ADMUX &= ~(1<<ADLAR); //Правосторонее выравнивание

//подключение таймера
TCCR0 = 0b00000101; // деление частоты процессора на 1024 (см. даташит)
TCNT0 = 0; // обнуление счетчика
int z = 0; //ввод переменной

// настройка ШИМ
TCCR1A |= (1<<COM1A1); TCCR1A &= ~(1<<COM1A0); //Включение порта А1 на работу ШИМ, без инверсии
TCCR1A &= ~(1<<WGM11) | (1<<WGM10); // включение работы ШИМ в режиме контроля частоты и напряжения
TCCR1B &= ~(1<<WGM12) ; TCCR1B |= (1<<WGM13); // включение работы ШИМ в режиме контроля частоты и напряжения
TCCR1B |= (1<<CS12); TCCR1B &= ~(1<<CS11)|(1<<CS10); //устанавливаем частоту работы ШИМ. Делим частоту работы процессора (1 млн) на 256
#define out OCR1A //задающее напряжение в двоичной системе от 0...97
#define inlet ADC // ADC в пределах 0...1024
ICR1 = 50; //делитель разрядов
out = 2; //задающее напряжение
while (1)
{
if (TCNT0 == 255) //на 255 счете Z увеличится на 1, счетчик обнулится.
{
z++;
TCNT0 = 0;
}
if (z > 0) //когда z перевалит за 100, z обнулится
{
z=0;
}

// включение счетчика номер 1, ножка 1
ADMUX &= ~(1<<MUX3)| (1<<MUX2)| (1<<MUX1) ; ADMUX |= (1<<MUX0); //Назначение ножки на которой будет производиться измерение
ADCSRA |= (1<<ADSC); //старт преобразования
ADCSRA |= (1<<ADEN) ; // команда включения АЦП

if (ADCSRA & (1<<4))
{
if (inlet > 950)
{
out = 40;
}
else
out = 10;
}
ADCSRA |= (1<<4);

ADMUX &= ~(1<<MUX0)| (1<<MUX2)| (1<<MUX3) ; ADMUX |= (1<<MUX1); //Назначение ножки на которой будет производиться измерение
ADCSRA |= (1<<ADSC); //старт преобразования
ADCSRA |= (1<<ADEN) ; // команда включения АЦП

if (ADCSRA & (1<<4))
{
if (inlet > 950)
{
PORTB |= (1<<3);
}
else
PORTB &= ~(1<<3);
}
ADCSRA |= (1<<4);
}
}
Реклама
Самсусамыч

Сообщение Самсусамыч »

При ваших настройках ADC и измерении по первому каналу мультиплексора, регистр ADMUX будет равен 0хС0, при измерении по второму каналу - ADMUX = 0хС1, при измерении по третьему каналу - ADMUX = 0хС2, и тд. Так вот переход с канала на канал необходимо производить в прерывании по завершении измерения АЦП, после того как данные считаны. Один из способов переключения каналов можно сделать вот как: скопировать регистр ADMUX в любой рабочий регистр, прибавить к этому регистру единицу, затем проверить данный регистр чтобы он не вышел за пределы используемых каналов и если всё нормуль, то скопировать полученное значение данного регистра обратно в регистр ADMUX. Затем выйти из прерывания… то есть если используется всего два канала, то после прибавления очередной единицы к рабочему регистру, значение не должно быть больше 0хС1. Если оно стало больше 0хС1, то в регистр ADMUX записываем первоначальное значение (0хС0) – соответствующее измерению на первом канале мультиплексора. :)
Реклама
Родился
Сообщения: 13
Зарегистрирован: Ср апр 15, 2020 12:28:32

Сообщение andreybolo »

Спасибо за помощь! Не все понял из вашего совета, но понял, что нужно последовательно включать каналы. Реализовал через Switch, получилось ,все работает :)
Итоговый код прикрепляю:
int adc_0 =0;
int adc_1 =0;
ADMUX |=(1<<REFS0)|(1<<REFS1)|(1<<MUX2)|(1<<MUX1); // установка опорного напряжения для АЦП
ADCSRA |=(1<<ADEN) |(1<ADPS2)|(1<ADPS1) |(1<<ADPS0); // активация АЦП, установка режима непрерывного преобразования, установка коэффициента деления предделителя АЦП 2

//==== ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЯ ================//

port_ini();
LCD_ini();

while(1)
{

//==== РАБОТА АЦП ====//
/* switch (ADMUX) // переключение между каналами с помощью оператора switch
{
case 0xC6://когда ADMUX==0xс6
{
ADCSRA |=(1<<ADSC);
// старт АЦП
while ( !(ADCSRA & (1<<ADIF)));
// ждем конца АЦП
adc_0 = ADC;
// записываем значение АЦП
ADC=0;

// сбрасываем регистр АЦП
ADMUX=0xC7; //изменяем канал
break;
}
case 0xC7:
{
ADCSRA |=(1<<ADSC);
// старт АЦП
while ( !(ADCSRA & (1<<ADIF)));
// ждем конца АЦП
adc_1 = ADC;
// записываем значение АЦП
ADC=0;
// сбрасываем регистр АЦП
ADMUX=0xC6; //изменяем канал
break;
}
Ответить

Вернуться в «Теория»