ATmega8 2 АЦП

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
Angmar
Родился
Сообщения: 9
Зарегистрирован: Ср авг 01, 2012 15:06:31

Re: ATmega8 2 АЦП

Сообщение Angmar »

ILYAUL писал(а):

Код: Выделить всё

ADCSRA |= 0x40;
- Ошибка



Что пишет?
Хидеры "avr/io.h", "avr/iom8.h" и соответствующие им библиотеки присутствуют и целые?
Аватара пользователя
siamds
Встал на лапы
Сообщения: 99
Зарегистрирован: Вт мар 20, 2012 20:50:22
Откуда: Краснодар

Re: ATmega8 2 АЦП

Сообщение siamds »

Уважаемый shurikss123!
У меня появилось свободное время и если Вы желаете, я напишу для Вас программу обмена между ПК и МК. Напишите как можно подробней алгоритм работы устройства, которое Вы хотите контролировать, или контролировать и управлять.
На каждого Моцарта есть свой Сальери.
Аватара пользователя
shurikss123
Грызет канифоль
Сообщения: 271
Зарегистрирован: Пн окт 25, 2010 20:47:04
Откуда: Казахстан, Астана

Re: ATmega8 2 АЦП

Сообщение shurikss123 »

Angmar писал(а):
ILYAUL писал(а):

Код: Выделить всё

ADCSRA |= 0x40;
- Ошибка



Что пишет?
Хидеры "avr/io.h", "avr/iom8.h" и соответствующие им библиотеки присутствуют и целые?


Хидеры есть, компилятор по моему стежит
Изображение
Мастер на все руки, кручу, кручу, кручу и матерюсь
Повелитель паяльной станции, лома, и пинцета!!!
Bringer
Родился
Сообщения: 1
Зарегистрирован: Пн янв 23, 2012 10:45:29

Re: ATmega8 2 АЦП

Сообщение Bringer »

Попробовал прошивку ADC_Mega8.rar [158.87 KiB] на макетной плате.
пошла когда строку
register static unsigned char input_index=0;
заменил на
static unsigned char input_index=0;

использовал CodeVisionAVR C Compiler v: 2.05.03
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: ATmega8 2 АЦП

Сообщение ZiperRUS »

Здравствуйте велекодушно :)

Скачал проект написанный siamds всё работает и то что мне как раз нужно.))))
только непонятно мне как работает функция PripareData(CARDINAL Data) в этом проекте.

void PrepareData(CARDINAL Data)
{
BYTE i;
for(i=0; i<6; i++)
{
byDisplay[5-i] = Data % 10 + 48;
Data /= 10;
}
}



я так понимаю она принимает параметр значени от 0 до 1024 результат преобразования АЦП и заполняет буфер который потом выводиться на экран. непоминаю как работают выделенные строчки в ней :( кто знает разьесните поподробней пожалуйста так как планирую се такой измеритель спаять в блок питания и переделать переписать код под себя хочу очень даже сильно. ( не то чтоб уж так прям наглухо сильно , просто охото сильно знать принцип работы так как столнулся с ютим впервые за свои 28 лет жизни на плянете земля)


Зарание велекодушно благодарю.

проект прилогаю
Вложения
Volt.rar
(41.42 КБ) 225 скачиваний
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: ATmega8 2 АЦП

Сообщение ibiza11 »

byDisplay[5-i] = Data % 10 + 48;
эта строчка находит остаток от деления Data на 10, прибавляет к ней 0х30 и помещает результат в массив byDisplay[](Посмотрите таблицу знакогенератора дисплея. Код знака "0" соответствует числу 0х30)
после этой строчки содержимое Data не изменится.
Data /= 10;
а эта строчка уже делит содержимое Data на 10, после нее в Data будет лежать целочисленный результат деления Data на 10.

В итоге этот код в цикле заполняет массив byDisplay[] КОДАМИ цифр выводящихся на дисплей. В ячейках с меньшим индексом будут находится коды цифр старших знакомест.
Соответственно, если вывести на дисплей в таком порядке : byDisplay[0], byDisplay[1], byDisplay[2], byDisplay[3], byDisplay[4], byDisplay[5] - то на дисплее получим число, соответствующее значению переменной Data.
Ставим плюсы: )
pobeda
Родился
Сообщения: 1
Зарегистрирован: Ср дек 11, 2013 15:43:37

Re: ATmega8 2 АЦП

Сообщение pobeda »

подскажите пожалуйста, может кто-нибудь поможет, очень нужно((((( есть программа, нужно каждую строчку откоментитть что она делает, понимаю что бред, но очень нужно
#include <mega8.h>
#asm
.equ __lcd_port=0x12 ;PORTD
#endasm
#define BYTE unsigned char
#define WORD unsigned short int
#define CARDINAL unsigned long int
#include <lcd.h>
char byDisplay[6]; // буфер данных, для вывода на экран
char Counter;
char Count =6;
CARDINAL U;
CARDINAL I_izm;
CARDINAL R;
void PrepareData(CARDINAL Data)
{
BYTE i;
for(i=0; i<6; i++)
{
byDisplay[5-i] = Data % 10 + 48;
Data /= 10;
}
}

//Вывод экранного буфера на дисплей
void PrintBuf(void)
{
int i;
for(i=0; i<7; i++)
{
lcd_putchar(byDisplay[i]);
}
}
#define ADC_VREF_TYPE 0xC0
unsigned int read_adc(unsigned char adc_input) // Чтение-Преобразование кода АЦП
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0x7f); // Выбираем канал для АЦП в adc_input,0x7f - источник опорного напряжения
ADCSRA|=0x40; // Старт преобразования
while ((ADCSRA & 0x10)==0); // Ждем конца преобразованиия флаг ADIF станет = 0
ADCSRA|=0x10;
return ADCW;
}
//Подпрограмма обработки прерывания по переполнению T1
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
WORD tmp;
TCNT1H=0xFF; // Перезагрузить значение Timer 1
TCNT1L=0x3C;
if (Counter++ >= Count)
{
Counter = 0;
lcd_gotoxy(0,0); //вывод напряжения

PrepareData(U / Count);
byDisplay[0] = byDisplay[2];
byDisplay[1] = byDisplay[3];
byDisplay[2] = '.';
byDisplay[3] = byDisplay[4];
byDisplay[4] = byDisplay[5];
byDisplay[5] = 'V';
byDisplay[6] = '';
PrintBuf();

lcd_gotoxy(0,1); //вывод тока измеренныя
PrepareData(I_izm / Count) ; // read_adc(0)/10.24*256
byDisplay[0] = byDisplay[2];
byDisplay[1] = byDisplay[3];
byDisplay[2] = '.';
byDisplay[3] = byDisplay[4];
byDisplay[4] = byDisplay[5];
byDisplay[5] = 'A';
byDisplay[6] = '';
PrintBuf();

lcd_gotoxy(7,0); //вывод сопротивления
PrepareData(R / Count) ; // read_adc(0)/10.24*256
byDisplay[0] = byDisplay[2];
byDisplay[1] = byDisplay[3];
byDisplay[2] = '.';
byDisplay[3] = byDisplay[4];
byDisplay[4] ='';
byDisplay[5] = 'O';
byDisplay[6] = 'm';
PrintBuf();

R = 0;
U = 0;
I_izm = 0;
}
else
{
U += read_adc(1) * 3; //читаю в переменную инфу из АЦП
I_izm += read_adc(0); // число в скобках обозначает номер входа
R +=(read_adc(1) * 3/read_adc(0))*100;//вычисляем сопротивление
};
}

void main(void) //Основная функция "main", с которой начинается выполнение всей
//программной процедуры
{
PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x00;

TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0xFA;
TCNT1L=0xE9;
TIMSK=0x04;
ACSR=0x80;
SFIOR=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x82;
lcd_init(16); //инициализация на 16 символов
#asm("sei")
while (1)
{
//Place your code here
};
}
kk042fjv
Грызет канифоль
Сообщения: 261
Зарегистрирован: Ср авг 01, 2012 10:45:42

Re: ATmega8 2 АЦП

Сообщение kk042fjv »

Здравствуйте!
Занимаюсь изучением АЦП. Писать программу для АЦП научился, теперь хочу научиться как делать усреднение показаний (например снимать штук 30 показаний и среднее выводить на экран). Может у кого-нибудь есть похожий исходник? Очень надо.
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: ATmega8 2 АЦП

Сообщение ibiza11 »

:shock: скоро начнут просить исходник "как сложить два числа"
Ставим плюсы: )
kk042fjv
Грызет канифоль
Сообщения: 261
Зарегистрирован: Ср авг 01, 2012 10:45:42

Re: ATmega8 2 АЦП

Сообщение kk042fjv »

ibiza11 писал(а)::shock: скоро начнут просить исходник "как сложить два числа"

Был бы программист не спрашивал бы
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: ATmega8 2 АЦП

Сообщение ibiza11 »

зуб даю, что вопросы опять возникнут, поскольку вы "не программист"

Код: Выделить всё

void adc_init(void){
   ADMUX = 0; // опора Vref, ADLAR = 0, канал = 0
   ADCSRA |= (1<<ADEN)|(1<<ADFR)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //вкл АЦП, Free Runnig Mode, предделитель 128
}
   
unsigned short get_adc_result(void){
   while(!(ADCSRA & (1<<ADIF))); // ожидание преобразования
   ADCSRA |= (1<<ADIF);          // сброс флага
   return (unsigned short)(ADCH<<8)|(ADCL);
}

void main(void){
   adc_init();
   unsigned short ADCResult, ADCSumm = 0;
   unsigned char i = 0;
   while(1){     
      while(i<30){
         ADCSum += get_adc_result();
         i++;
      }
      ADCSum /= 30;
      /* вот здесь надо забирать результат интегирования */
      i = 0;
      ADCSum = 0;     
   }
}
Ставим плюсы: )
Аватара пользователя
shadivl
Открыл глаза
Сообщения: 76
Зарегистрирован: Пт май 28, 2010 13:41:16
Откуда: Мариинск, Томск

Re: ATmega8 2 АЦП

Сообщение shadivl »

Здравствуйте.
Я делаю схему управления пятью сервоприводами на atmega8. На каждый привод приходится свой переменный резистор. Соответственно я должен снять данные с АЦП, обработать их и подать управляющий сигнал на сервы. Так вот, кусок программы, ответственный за управляющий сигнал, работает нормально, а вот с АЦП какие-то проблемы. То ли прерывание не срабатывает, то ли ещё что-то, но в Протеусе, да и в железе, на изменение сопротивления серва никак не реагировала. Помогите понять, в чём причина.
Сервы подключены к PD0-PD4, резисторы - к PC0-PC4. Пишу в CVAVR.
code.c
(2.94 КБ) 514 скачиваний
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Re: ATmega8 2 АЦП

Сообщение zero648 »

Наверное проблема здесь:
SIG[a]=65010-(ADCW*0,1221); //Чтение результата АЦП преобразования, 0,1221 - уравнивающий коэффициент

значение ADCW нужно сначала присвоить вещественной переменной, а уже потом работать с этой переменной, т.е. умножать на число с плавающей точкой, а иначе это умножение дает ноль и результат всегда один и тот же.
Аватара пользователя
shadivl
Открыл глаза
Сообщения: 76
Зарегистрирован: Пт май 28, 2010 13:41:16
Откуда: Мариинск, Томск

Re: ATmega8 2 АЦП

Сообщение shadivl »

Переписал, но никакой реакции. Я в конце добавил строку, которая инвертирует PB0 при срабатывании прерывания АЦП. Однако ничего не происходит, порт своё значение не меняет. Похоже, по какой-то причине прерывание не срабатывает.

Код: Выделить всё

interrupt [ADC_INT] void adc_isr(void)
{
float cont;
if (schet==12500) //считывние около 5 раз в секунду
    {cont=(float)ADCW;
    SIG[a]=65010-(int)(cont*0,1221); //Чтение результата АЦП преобразования, 0,1221 - уравнивающий коэффициент
    if (SIG[a]>63046) SIG[a]=63046; //ограничение длительности сигнала
    if (a==4){a=0;
              schet=0;} //Проверяем значение счётчика
        else a++;
    ADMUX=a; //Готовимся считывать сигнал с другого канала
    delay_us(10);  //Выдержка времени для стабилизации входного напряжения
    ADCSRA|=0x40; //Старт АЦП преобразования
    } 
else schet++;
PortB=(~PortB)&0b00000001;//Ирвертирование PB0 для проверки работы прерыванния
}
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: ATmega8 2 АЦП

Сообщение COKPOWEHEU »

shadivl писал(а):Похоже, по какой-то причине прерывание не срабатывает.

Код: Выделить всё

interrupt [ADC_INT] void adc_isr(void)
{
float cont;
if (schet==12500) //считывние около 5 раз в секунду
    {
    ADCSRA|=0x40; //Старт АЦП преобразования
    } 
else schet++;
PortB=(~PortB)&0b00000001;//Ирвертирование PB0 для проверки работы прерыванния
}
То есть повторное преобразование запускаете только если schet строго равен 12500, при всех остальных значениях АЦП остановлен, не выполняет преобразований и не генерирует прерываний. Интересно, почему же они не возникают.
Аватара пользователя
shadivl
Открыл глаза
Сообщения: 76
Зарегистрирован: Пт май 28, 2010 13:41:16
Откуда: Мариинск, Томск

Re: ATmega8 2 АЦП

Сообщение shadivl »

Вытащил строку из условия - не работает

Код: Выделить всё

if (schet==12500) //считывние около 5 раз в секунду
    {cont=(float)ADCW;
    SIG[a]=65010-(int)(cont*0,1221); //Чтение результата АЦП преобразования, 0,1221 - уравнивающий коэффициент
    if (SIG[a]>63046) SIG[a]=63046; //ограничение длительности сигнала
    if (a==4){a=0;
              schet=0;} //Проверяем значение счётчика
        else a++;
    ADMUX=a; //Готовимся считывать сигнал с другого канала
    delay_us(10);  //Выдержка времени для стабилизации входного напряжения
    } 
else schet++;
PORTB=(~PORTB)&0b00000001;
ADCSRA|=0x40; //Старт АЦП преобразования


Попробовал вообще без переменной schet - тоже не работает

Код: Выделить всё

cont=(float)ADCW;
SIG[a]=65010-(int)(cont*0,1221); //Чтение результата АЦП преобразования, 0,1221 - уравнивающий коэффициент
if (SIG[a]>63046) SIG[a]=63046; //ограничение длительности сигнала
if (a==4) a=0; //Проверяем значение счётчика
    else a++;
ADMUX=a; //Готовимся считывать сигнал с другого канала
delay_us(10);  //Выдержка времени для стабилизации входного напряжения
PORTB=(~PORTB)&0b00000001;
ADCSRA|=0x40; //Старт АЦП преобразования
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: ATmega8 2 АЦП

Сообщение COKPOWEHEU »

Если АЦП настроен на непрерывное преобразование, зачем выставлять флаг начала?
В чем проверяете?
Задержка в прерывании не нужна.
Аватара пользователя
shadivl
Открыл глаза
Сообщения: 76
Зарегистрирован: Пт май 28, 2010 13:41:16
Откуда: Мариинск, Томск

Re: ATmega8 2 АЦП

Сообщение shadivl »

Проверяю в Proteus'е.
Proteus.rar
(38.45 КБ) 193 скачивания
TIOSA
Родился
Сообщения: 4
Зарегистрирован: Чт май 13, 2010 19:57:07

Re: ATmega8 2 АЦП

Сообщение TIOSA »

Ситуация следующая…. Взят код для двух каналов ADC для ATMega8…(от ув. siamds),
пытаюсь добавить вывод на LCD разницу значений (adc_data[0]- adc_data[1]). Помогите реализовать сие.
Вложения
ADC_Mega8.rar
(158.87 КБ) 154 скачивания
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: ATmega8 2 АЦП

Сообщение COKPOWEHEU »

Форматирование отсутствует
ADCSRA|=0x40; //Старт АЦП преобразования
Плохая идея использовать магические числа.
(ADC_VREF_TYPE & 0xff)
Это зачем? Тем более что очевидные вещи прокомментированы а физический смысл этой константы и допустимые значения - нет.
delay_us(10); //Выдержка времени для стабилизации входного напряжения
Задержки в прерывании - плохая идея.
register static unsigned char input_index=0;
резервировать регистр только для прерывания? Учитывая использование задержки - скорость не требуется, а тогда зачем?
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
А чего указали последний канал вместо количества? Остальные записи были бы проще. Другое дело что в общем случае между используемыми аналоговыми каналами могут быть цифровые.
ch_1= adc_data[0]; //Запись в переменную ch_1 результата ADC 1-го канала
ch_2= adc_data[1]; //Запись в переменную ch_2 результата ADC 2-го канала
А если в середине присвоения возникнет прерывание АЦП и изменит значение массива?
ADCSRA=0xCB;
Про магические числа я уже писал.
пытаюсь добавить вывод на LCD разницу значений (adc_data[0]- adc_data[1])
В чем конкретно проблема? Не можете вычислить разность? Не можете вывести знаковое число на дисплей?
Ответить

Вернуться в «AVR»