Re: АЦП у Мега8
Добавлено: Чт янв 17, 2013 10:02:55
Все понятно теперь я разобрался
Спасибо за помощь
Спасибо за помощь
Код: Выделить всё
void adcInit()
{
ADMUX = 0;
ADCSRA |= (1<<ADPS2) | (1<<ADPS0); /* Делитель ADC = 32 */
ADCSRA |= (1<<ADEN); /* Включаем ADC */
return;
}
uint16_t getAverage32()
{
uint8_t i;
int16_t adc_result, result;
uint32_t total = 0;
for (i = 0; i < 32; i++) {
ADCSRA |= (1<<ADSC); /* Запускаем преобразование */
while (ADCSRA & (1<<ADSC)); /* Ждём конца измерений */
adc_result = ADCL;
adc_result |= (ADCH << 8);
total += adc_result;
}
result = total >> 5; /* Делим результат на 32 */
return;
}Спасибо что откликнулись.WiseLord писал(а):Самый простой вариант - как-то так:В коде выше делается просто: 32 измерения, сложили, поделили, дальше - снова 32 измерения, сложили, поделили...Код: Выделить всё
void adcInit() { ADMUX = 0; ADCSRA |= (1<<ADPS2) | (1<<ADPS0); /* Делитель ADC = 32 */ ADCSRA |= (1<<ADEN); /* Включаем ADC */ return; } uint16_t getAverage32() { uint8_t i; int16_t adc_result, result; uint32_t total = 0; for (i = 0; i < 32; i++) { ADCSRA |= (1<<ADSC); /* Запускаем преобразование */ while (ADCSRA & (1<<ADSC)); /* Ждём конца измерений */ adc_result = ADCL; adc_result |= (ADCH << 8); total += adc_result; } result = total >> 5; /* Делим результат на 32 */ return; }
А можно сделать и интереснее. Чтобы всегда иметь реально усреднение последних 32 измерений.
1. Создать массив из 32 элементов для хранения последних измерений.
2. Запускать преобразование по таймеру (период таймера должен быть больше, чем скорость ADC-преобразования).
3. Когда преобразование заканчивается, ADC вызывает прерывание, в обработчике которого считывается значение из ADC и сохраняется в ячейку массива. Следующее преобразование - в другую ячейку, и так далее по циклу.
4. Функция getAverage32 будет просто считать среднее значение массива.
Достоинство - преобразования делаются независимо, сами по себе, и в массиве всегда хранятся последние несколько значений, среднее от которых доступно в любой момент времени, без ожидания измерений.
В прерывании, помимо прочего, нужно взводить флаг готовности данных, который гасится в теле getAverage32, а вызов ее осуществлять по взведенному флагу.WiseLord писал(а): А можно сделать и интереснее. Чтобы всегда иметь реально усреднение последних 32 измерений.
1. Создать массив из 32 элементов для хранения последних измерений.
2. Запускать преобразование по таймеру (период таймера должен быть больше, чем скорость ADC-преобразования).
3. Когда преобразование заканчивается, ADC вызывает прерывание, в обработчике которого считывается значение из ADC и сохраняется в ячейку массива. Следующее преобразование - в другую ячейку, и так далее по циклу.
4. Функция getAverage32 будет просто считать среднее значение массива.






Вы ничего не сказали, а ЧТО ВЫ СДЕЛАЛИ для этого.kk042fjv писал(а):Добрый день!
Так и не могу я добиться...
Код: Выделить всё
#include <mega8.h>
#asm
.equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
#include <delay.h>
#include <stdio.h>
char lcd_buffer[30];
void main(void)
{
int data;
float V;
ACSR=0x80;
SFIOR=0x00;
ADMUX=0;
ADCSRA=0x85;
lcd_init(16);
lcd_clear();
while (1)
{
delay_ms(20);
ADCSRA |= 0x40;
while((ADCSRA&0x10) == 0);
ADCSRA |= 0x10;
data = ADCW;
V = (float) data*0.0048828125;
sprintf(lcd_buffer, " %1.2f ",V);
lcd_gotoxy(5,0);
lcd_puts(lcd_buffer);
};
}Код: Выделить всё
50505050505050Код: Выделить всё
#define ADC_start_ch 0 // канал с которого начать измерение 0..7
#define ADC_ch 8 // количество измеряемых каналов 1..8
#define ADC_aver 32 // усреднений 1..256
void ADC_init(void);
void ADC_read(void);
unsigned int ADC_raw[ADC_ch][ADC_aver]; // 2-х мерный массив [канал0..7][ значение АЦП 0..1023]
unsigned int ADC_value[ADC_ch]; // усредненное значение по каждому каналу
unsigned long ADC_temp_buff[ADC_ch]; // буфер хранения суммы накопленных значений замеров по каждому каналу
unsigned char ADC_cur_ch; // текущий канал АЦП 0..7
unsigned char ADC_curr_aver; // текущий замер
#pragma vector = TIMER2_COMP_vect // прерывание по совпадению TCNT2 = OCR2 100 Гц
__interrupt void TIMER2_COMP(void)
{
BUT_Debrief(); // опрос кнопок
ADC_read(); // опрос АЦП
};
void ADC_init(void)
{
ADMUX = (0<<REFS1)|(0<< REFS0)|(0<< ADLAR)|(0<< 0)|(0<< MUX3)|(0<< MUX2)|(0<< MUX1)|(0<< MUX0);
ADCSR = (1<< ADEN)|(0<< ADSC)|(0<< ADFR)|(0<< ADIF)|(0<< ADIE)|(1<< ADPS2)|(1<< ADPS1)|(0<< ADPS0);
ADC_cur_ch = ADC_start_ch;
ADMUX = ADC_cur_ch|(ADMUX & 0xF0);
ADC_curr_aver=0; //
ADCSR |= (1<<ADSC); //start convertion
};
void ADC_read(void)
{
unsigned int ADC_temp;
if((ADCSR & (1<<ADSC)) == 0) //Adc complete
{
ADC_temp = ADCL;
ADC_temp |=(int) ADCH<<8;
ADC_temp_buff[ADC_cur_ch] += ADC_temp;
ADC_temp_buff[ADC_cur_ch] -= ADC_raw[ADC_cur_ch][ADC_curr_aver];
ADC_raw[ADC_cur_ch][ADC_curr_aver] = ADC_temp;
ADC_value[ADC_cur_ch] = ADC_temp_buff[ADC_cur_ch] / ADC_aver;
if(++ADC_cur_ch>=ADC_ch)
{
ADC_cur_ch = ADC_start_ch;
if (++ADC_curr_aver >= ADC_aver) ADC_curr_aver=0;
}
ADMUX = ADC_cur_ch|(ADMUX & 0xF0);
ADCSR |= (1<<ADSC); //start convertion
}
};
while (1)// основной цикл
{
//ADC_value[0..7]; усредненные значения по каждому каналу
}
}
Код: Выделить всё
...
delay_ms(20);
ADCSRA |= 0x40;
while((ADCSRA&0x10) == 0);
ADCSRA |= 0x10;
data = ADCW;
V = (float) data*0.0048828125;
sprintf(lcd_buffer, " %1.2f ",V);
lcd_gotoxy(5,0);
lcd_puts(lcd_buffer);
if (V < 1)
sprintf(lcd_buffer ,"ЗАРЯДКА", V);
else
sprintf(lcd_buffer ,"ok", V);
lcd_gotoxy(4,1);
lcd_puts(lcd_buffer);Так и сделал.КРАМ писал(а):добавить пробелы к "ОК" так, чтобы суммарная длина ОК и ЗАРЯДКА совпадала.