Re: АЦП - выбор лапки
Добавлено: Чт янв 23, 2014 20:45:43
Так а и сказал что благодарю за мысль - по аналогии я уже накручу то надо!!!
А у нас что, биты мультиплексора теперь раскиданы по всему регистру, что-ли? Каким местом здесь не тру?pyzhman писал(а):, что не есть трувэй.Код: Выделить всё
0b0010
kobzar писал(а):Ето не трувей которым пользуются только КВАВР-щеки!
Код: Выделить всё
#ifndef INIT_ADC_H_
#define INIT_ADC_H_
volatile unsigned int vuntADCdata00;
volatile unsigned int vuntADCdata01;
volatile unsigned int vuntADCdata02;
volatile unsigned char uchChangeADC;
void init_adc (void); //Функция инициализации АЦП
void change_adc(void); //Функция изменения АЦП
#endif /* INIT_ADC_H_ */Код: Выделить всё
#include <avr/io.h>
#include "init_adc.h"
#include <avr/interrupt.h>
ISR (ADC_vect)
{
if (uchChangeADC == 0)
vuntADCdata00 = (ADCL | ADCH << 8); // Считываем ADC PC0
else
if (uchChangeADC == 1)
vuntADCdata01 = (ADCL | ADCH << 8); // Считываем ADC PC1
else
vuntADCdata02 = (ADCL | ADCH << 8); // Считываем ADC PC2
}
void init_adc (void) //Функция инициализации АЦП
{
ADMUX |=(0 << REFS1) | (1 << REFS0) // Напряжение питания AVcc
| (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); //вход PC0
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);//20000мГц
ADCSRA |= (1 << ADEN) //Включение АЦП
| (1 << ADSC) //запуск преобразования
| (0 << ADATE) // 0 - Одиночное преобразование, 1 - настраеваемое преобразование (регистр ADCSRB (биты ADTS0-ADTS2))
| (1 << ADIE); //Разрешение прерывания от компаратора
uchChangeADC = 0;
}
void change_adc(void)//Функция изменения АЦП
{
if (uchChangeADC == 0)
{
ADMUX |=(0 << REFS1) | (1 << REFS0) // Напряжение питания AVcc
|(0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0); //вход PC1
uchChangeADC = 1;
}
else
{
if (uchChangeADC == 1)
{
ADMUX |=(0 << REFS1) | (1 << REFS0) // Напряжение питания AVcc
| (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0); //вход PC2
uchChangeADC = 2;
}
else
{
ADMUX |=(0 << REFS1) | (1 << REFS0) // Напряжение питания AVcc
| (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); //вход PC0
uchChangeADC = 0;
}
}
ADCSRA |=(1 << ADSC); //запуск преобразования
}Код: Выделить всё
void main (void)
{
init_adc();//инициализация ацп
while(1)
{
change_adc();//Функция должна менять лапку АЦП а я потом считываю значения из переменных vuntADCdata00 vuntADCdata01 и vuntADCdata02
}Код: Выделить всё
void change_adc(void)//Функция изменения АЦП
{
uchChangeADC++;
if (uchChangeADC == 3) {uchChangeADC=0;}
ADMUX |=(0 << REFS1) | (1 << REFS0) | (uchChangeADC << MUX0); // Напряжение питания AVcc
ADCSRA |=(1 << ADSC); //запуск преобразования
}Код: Выделить всё
int readADC(int ch)
{
unsigned char set_admux = ADMUX;
set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));
if (ch != 0)
{
set_admux |= (1<<ch-1);
}
ADMUX = set_admux;
char buffer[12];
_delay_ms(20);
ADCSRA |= (1 << ADSC); // Запускаем преобразование
while((ADCSRA & (1 << ADSC))); // Ждем окончания преобразования
int val = ADC;
itoa(val, buffer,10);
return buffer; // Возвращаем значение АЦП
}Код: Выделить всё
LcdClear();
for (int i=0;i<=2;i++)
{
LcdGotoXYFont(1,i+1);
LcdStr(FONT_1X,readADC(i));
}
LcdUpdate();
_delay_ms(1000);Мысль понятна. Я подобную манипуляцию с ADMUX не пробовал делать. Через 7 часов я доберусь до МК и программатора и обязательно попробую и отпишусь о результатах. Спасибо за помощь!zero648 писал(а):А если функцию так сделать:Код: Выделить всё
void change_adc(void)//Функция изменения АЦП { uchChangeADC++; if (uchChangeADC == 3) {uchChangeADC=0;} ADMUX |=(0 << REFS1) | (1 << REFS0) | (uchChangeADC << MUX0); // Напряжение питания AVcc ADCSRA |=(1 << ADSC); //запуск преобразования }
Не, не работает такой способ записи.DruidCat писал(а):Мысль понятна. Я подобную манипуляцию с ADMUX не пробовал делать. Через 7 часов я доберусь до МК и программатора и обязательно попробую и отпишусь о результатах. Спасибо за помощь!zero648 писал(а):А если функцию так сделать:Код: Выделить всё
void change_adc(void)//Функция изменения АЦП { uchChangeADC++; if (uchChangeADC == 3) {uchChangeADC=0;} ADMUX |=(0 << REFS1) | (1 << REFS0) | (uchChangeADC << MUX0); // Напряжение питания AVcc ADCSRA |=(1 << ADSC); //запуск преобразования }
Код: Выделить всё
#include <avr/io.h>
#include "init_adc.h"
#include <avr/interrupt.h>
ISR (ADC_vect)
{
if (uchChangeADC == 0)
vuntADCdata00 = (ADCL | ADCH << 8); // Считываем ADC PC0
else
if (uchChangeADC == 1)
vuntADCdata01 = (ADCL | ADCH << 8); // Считываем ADC PC1
else
vuntADCdata02 = (ADCL | ADCH << 8); // Считываем ADC PC2
}
void init_adc (void) //Функция инициализации АЦП
{
// ADMUX |=(0 << REFS1) | (1 << REFS0) // Напряжение питания AVcc (Нет необходимости в этой записи)
// | (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); //вход PC0 (Нет необходимости в этой записи)
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);//20000мГц
ADCSRA |= (1 << ADEN) //Включение АЦП
// | (1 << ADSC) //запуск преобразования (Нет необходимости в этой записи)
| (0 << ADATE) // 0 - Одиночное преобразование, 1 - настраевоемое преобразование (регистр ADCSRB (биты ADTS0-ADTS2))
| (1 << ADIE); //Разрешение прерывания от компаратора
uchChangeADC = 0;
}
void change_adc(void)//Функция изменения АЦП
{
if (uchChangeADC == 0)
{
ADMUX = 0х41; //вход PC1
uchChangeADC = 1;
}
else
{
if (uchChangeADC == 1)
{
ADMUX = 0x42; //вход PC2
uchChangeADC = 2;
}
else
{
ADMUX = 0x40; //вход PC0
uchChangeADC = 0;
}
}
[b] _delay_ms(1);[/b]//Без паузы не работает, у меня программа большая, поэтому 1 мс достаточно
ADCSRA |=(1 << ADSC); //запуск преобразования
}А если вот так тебе сделать?kobzar писал(а):Вобщем и целом, благодаря вашим советам получилось сделать выбор канала через свиг регистра!
Другими словами - правильно и без всяких там разных систем счисления! Я не стану утверждать что мой метод более или менее правильный чем предложенные ранее, просто я педант - и в процессе изучения Си для АВР-ок! Поставленная перед самим собой задача, была сделать и понять так как "Правильно" а не "Будет работать". Конечно я понимаю что со временем обьем полученных знаний умноженный на уровень лени приведет меня к тому что я буду на уровне подсознания оперировать двиочными и десятичными числам автоматом переводя их в названия выставленных битов ... но пока что - я вижу точно что я выставил и зачем! Кроме того меня спрашивали зачем заморачиваться с циклом? Ответ банален - сделав оди раз цыкл - мне больше не надо дописывать строки кода если я допустим захочу использовать 3,5,7 входов ацп! Мне достаточно будет просто изменить длину цикла![]()
Примитивная функция для опроса трех ног выглядит так (конечно при использовании более чем первые три входа функцию нужно будет модифицировать но ето выходит за рамки моей задачи)
И ее использование для вывода данных например на ЛЦД 3310 может иметь примитивный видКод: Выделить всё
int readADC(int ch) { unsigned char set_admux = ADMUX; set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0)); if (ch != 0) { set_admux |= (1<<ch-1); } ADMUX = set_admux; char buffer[12]; _delay_ms(20); ADCSRA |= (1 << ADSC); // Запускаем преобразование while((ADCSRA & (1 << ADSC))); // Ждем окончания преобразования int val = ADC; itoa(val, buffer,10); return buffer; // Возвращаем значение АЦП }
Ну а дальше добавим несколько замеров и вывод средне арифметического и так далее - но это уже совершенно другая сказка ....Код: Выделить всё
LcdClear(); for (int i=0;i<=2;i++) { LcdGotoXYFont(1,i+1); LcdStr(FONT_1X,readADC(i)); } LcdUpdate(); _delay_ms(1000);
Код: Выделить всё
unsigned int readADC(int ch)
{
unsigned char set_admux = ADMUX;
set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));
if (ch != 0)
{
set_admux |= (1<<ch-1);
}
ADMUX = set_admux;
_delay_ms(20);
ADCSRA |= (1 << ADSC); // Запускаем преобразование
while((ADCSRA & (1 << ADSC))); // Ждем окончания преобразования
return (ADCL | ADCH << 8); // Возвращаем значение АЦП
}Сделал, работает нормально. Задаю канал, делаю паузу на установку канала. Потом жду завершения преобразования. Снимаю показания. У меня глупый вопрос: если происходит прерывание, это ведь означает окончание преобразования? В справочнике написанно что Да.Alexeyslav писал(а): Сделай тестовую функцию без прерываний - задаешь канал, получаешь результат. И запусти подряд несколько измерений, потом по UART передать на терминал в протеусе будет наглядно видно.