|
|
  |
Программирование АЦП на atmega16L-16AI, Помогите разобраться с считыванием данных с АЦП |
|
|
|
Apr 10 2011, 12:00
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Именно так. Достаточно битов регистра ADCL. Xenia, спасибо. Надо будет попробовать. Если я правильно понял, то нужно читать полый результат преобразования АЦП. Код #define ADC_VREF_TYPE 0x00
unsigned char read_adc(unsigned char adc_input) // Считывание 8 МЗР // преобразования АЦП { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); delay_us(10); // Задержка для стабилизации входного напряжения АЦП ADCSRA|=0b11100111; // Начало АЦП while ((ADCSRA & 0x10)==0); // Ожидание завершения преобразования ADCSRA|=0x10; // Сброс фалга прерывания return ADC; // Возвращает значение преобразования АЦП } Эта часть понятна. Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!? Если я напишу: Код adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5 То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся???
|
|
|
|
|
Apr 11 2011, 06:09
|
Местный
  
Группа: Участник
Сообщений: 235
Регистрация: 20-11-10
Пользователь №: 61 032

|
"Участники форума обязаны: ... 2.1в высказываться понятно, полно... в противном случае пост может быть расценен как текстовый мусор (флуд)". Опорное напряжение = 5 вольт. Такому напряжению на входе соответствовал бы максимальный код на выходе. На входе АЦП 2 вольта. Входное напряжение / опорное напряжение = выходной код / максимальный код, с точностью до http://electronix.ru/forum/index.php?showtopic=88341. Выходной код = максимальный код (двоичный) 11.1111.1111 Х входное 2 / опорное 5 = 01.1001.1001 (двоичный). [***] Высокая точность не нужна. Интересуют только младшие биты. Именно так. Достаточно битов регистра ADCL. 01.1001.1001 ~ 01.1001.1001 409 ~ 153 2 вольта ~ 0.75 вольта ... каким образом отчечь два бита старшего байта АЦП!? goto [***] А в рублях бы это выглядело как "зарплата тридцать тысяч (30000) приблизительно равна зарплате ноль ( 30000)", зато "почти одинаковы зарплаты 8300 и 65300". --- Надо ждать, пока кто-нибудь выскажется наконец понятно и полно. Если ещё актуально. Или начиная с 204 220 страницы читать.
Сообщение отредактировал нечитатель - Apr 11 2011, 06:52
|
|
|
|
|
Apr 11 2011, 08:06
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(abitwise @ Apr 10 2011, 16:00)  Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!? Если я напишу: Код adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5 То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся??? Зачем Вы старшие биты отсекаете? Если Вы собрались писать Код return ADC; // Возвращает значение преобразования АЦП то, уж, запишите Код unsigned int read_adc(unsigned char adc_input) Измените также char на int и в описании переменной, которой присваивается измеренное значение
|
|
|
|
|
Apr 11 2011, 09:17
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(abitwise @ Apr 10 2011, 16:00)  Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!? Если я напишу: Код adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5 То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся??? Да, автоматически уберутся. Здесь работает стандартное правило языка C при конверсии типов. При присваивании двухбайтового значения int однобайтовому unsigned char старшая часть числа усекается. Аналогично можно было спросить, куда девается дробная часть после присвоения числа пи (3.14...) переменной типа int или unsigned char. В этом случае тоже произодйет конверсия типа числа, сопровождающаяся усечением до целого. Правда бывают компиляторы, которые в подобных случаях выдают предупреждение (Warning) "значащая часть числа потеряна", но его можно либо отменить, либо записать конверсию в явном виде: return (unsigned char)ADC; Сейчас у вас конверсия (усечение int до unsigned char) происходит при возврате значения из функции read_adc(). А если бы вы сделали эту функцию типа int (по совету Палыча), то тогда конверсия протекала бы по месту присваивания выдаваемого значения байтовой переменной, т.е. вот здесь: adc_data_l=read_adc(5); И если бы компиллятор выдавал здесь Warning, то лучше было бы выполнить конверсию явно: adc_data_l=(unsigned char)read_adc(5); Но это только тогда, когда Warning раздражает, а работать правильно будет и так.
|
|
|
|
|
Apr 11 2011, 09:19
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Нашёл решение данной проблемы. В даташите написано: Цитата Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. стр 218 Буду делать так: Код #define ADC_VREF_TYPE 0x20 // Выравнивание влеворî, AREF pin
unsigned char read_adc(unsigned char adc_input) // Считывание 8 СЗР // преобразования АЦП { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); delay_us(10); // Задержка для стабилизации входного напряжения АЦП ADCSRA|=0b11110111; // Начало АЦП while ((ADCSRA & 0x10)==0); // Ожидание завершения преобразования ADCSRA|=0x10; // Сброс флага прерывания return ADCH; // Возвращает значение 8СЗР }
|
|
|
|
|
Apr 11 2011, 09:37
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(abitwise @ Apr 11 2011, 13:19)  Код ADCSRA|=0b11110111; // Начало АЦП Уберите Bit 5 – ADATE: ADC Auto Trigger Enable, иначе запросто получите данные оцифровки предыдущего канала.
|
|
|
|
|
Apr 11 2011, 09:56
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Интересно. Я думал, что этот бит, совместно с комбинацией битов ADTS2:ADTS0 отвечают за режим преобразования. Так, в книге "Микроконтроллеры AVR семейства Mega. Руководство пользователя" А.В. Евстифеева написано:" Цитата ... Для выбора режима работы в этих моделях используется бит ADATE регистра ADCSRA и биты ADTS2:ADTS0 регистра SFIOR... ...Если бит ADATE сброшен в 0, АЦП работает в режиме одиночного преобразования. Если же бит ADATE установлен в 1, функционирование АЦП определяется содержимым битов ADTS2:ADTS0 согласно таблице... У меня АЦП должен работать в непрерывном режиме. Поэтому, я следумаю написанному в книге поставил бит ADATE в 1, а биты ADTS2:ADTS0 в 0, потому что такая конфигурация соответствует непрерывному режиму преобразования АЦП.
|
|
|
|
|
Apr 11 2011, 10:36
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Не забыл. Код #define ADC_VREF_TYPE 0x20 и ADMUX=adc_input | (ADC_VREF_TYPE & 0xff) Если я конечно правильно всё сделал_) То, что в скобках даёт 0010 0000. То есть бит ADLAR я установил в 1. Далее всё зависит от adc_input. Если adc_input = 4, то ADMUX=00100100, если adc_input=5, то ADMUX=00100101. Надеюсь, что я правильно понял ?!)))
|
|
|
|
|
Apr 11 2011, 11:36
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(abitwise @ Apr 11 2011, 14:36)  Надеюсь, что я правильно понял ? Правильно. А строчку Код ADCSRA|=0x10; // Сброс флага прерывания можно убрать, она лишняя - это делается и так двумя строками выше Цитата(Xenia @ Apr 11 2011, 14:28)  А то по умолчанию биты прижаты к правому краю, и в ADCH находится не младшая, а старшая часть числа. Уточню: Ксения говорит о том, что в регистре ADCH всегда находится старшая часть результата, но по умолчанию (ADLAR=0) - два старших разряда, а при ADLAR=1 в этом регистре находятся восемь старших разрядов результата.
|
|
|
|
|
Apr 11 2011, 12:09
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Спасибо за уточнения. Эту часть материала я усвоил. С учётом перечисленных замечаний, код получился такой Код /***************************************************** This program was produced by the CodeWizardAVR V1.25.5 Professional Automatic Program Generator © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.com
Project : Version : Date : 03.04.2011 Author : F4CG Company : F4CG Comments:
Chip type : ATmega16L Program type : Application Clock frequency : 8,00000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/
#include <mega16.h> #include <delay.h>
interrupt [TIM1_OVF] void timer1_ovf_isr(void) // Прерывание по переполнению Т/C1 { OCR1A=0x00; OCR1B=0x00; // TCNT1L=0x00; // PORTD=0b00110000; }
interrupt [TIM1_COMPA] void timer1_compa_isr(void) // Прерывание по совпадению события А { PORTD=0b00100000; }
interrupt [TIM1_COMPB] void timer1_compb_isr(void) // Прерывания по совпадению события Б { PORTD=0b00010000; }
#define ADC_VREF_TYPE 0x20 // Aref pin, выравнивание влево
unsigned int read_adc(unsigned char adc_input) // Считывание 8 СЗР // преобразования АЦП { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); delay_us(10); // Задержка для стабилизации входного напряжения АЦП ADCSRA|=0b11010111; // Начало АЦП, сброс флага прерывания while ((ADCSRA & 0x10)==0); // Ожидание завершения преобразования return ADCH; // Возвращение 8 СЗР }
void main(void) { int temp_range[9] = {299, 255, 217, 184, 156, 132, 112, 95, 81}; PORTA=0x30; // Инициализация порта А DDRA=0x00; // РА4, РА5 - входы с подключенным резистором
PORTB=0x00; // Инициализация порта Б DDRB=0x00;
PORTC=0x00; // Инициализация порта С DDRC=0x00;
PORTD=0x00; // Инициализация порта Д DDRD=0x30; // PD4, PD5 выходы с низким логическим уровнем
TCCR0=0x00; // Инициализация Т/C0 TCNT0=0x00; OCR0=0x00;
TCCR1A=0xA1; // Инициализация T/C1 TCCR1B=0x0B; // ICR1H=0x00; // Тактирование системное ICR1L=0x00; // Частота: 8000,000 kHz // Режим: Fast PWM top=00FFh // OC1A : не инвертирующий // OC1B : не инвертирующий ASSR=0x00; // Инициализация Т/C2 TCCR2=0x00; TCNT2=0x00; OCR2=0x00; MCUCR=0x00; MCUCSR=0x00;
TIMSK=0x1C; // Инициализация прерываний таймера счётчика
ACSR=0x80; // Аналоговый компаратор выключен SFIOR=0x00;
ADMUX=0b00000000; ADCSRA=0b00000000;
SPCR=0x40; // Инициализация SPI SPSR=0x01; #asm("sei") // Разрешение прерываний
for (;;) { unsigned int adc_data_l; TCNT1H=0x00; // Обнуление Т/С1 TCNT1L=0x00; OCR1AH=0x00; // Обнуление регистров сравнения OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00;
adc_data_l=0; // Обнуление переменной adc_data_l=read_adc(5); // Запись данных из АЦП с PA5 if(temp_range[0] <= adc_data_l) // Процедура сравнения значения АЦП с { // температурными диапазонами и OCR1A=0; // выдача ШИМ на вентилятор } else if(temp_range[1] <= adc_data_l) { OCR1A=0; } else if((temp_range[2] <= adc_data_l) && (adc_data_l < temp_range[1])) { OCR1A=128; } else if((temp_range[3] <= adc_data_l) && (adc_data_l < temp_range[2])) { OCR1A=149; } else if((temp_range[4] <= adc_data_l) && (adc_data_l < temp_range[3])) { OCR1A=170; } else if((temp_range[5] <= adc_data_l) && (adc_data_l < temp_range[4])) { OCR1A=191; } else if((temp_range[6] <= adc_data_l) && (adc_data_l < temp_range[5])) { OCR1A=213; } else if((temp_range[7] <= adc_data_l) && (adc_data_l < temp_range[6])) { OCR1A=234; } else if((temp_range[8] <= adc_data_l) && (adc_data_l < temp_range[7])) { OCR1A=255; } else if(adc_data_l < temp_range[8]) { OCR1A=255; } adc_data_l=read_adc(4); // Запись данных АЦП с PA4
if(temp_range[0] <= adc_data_l) // Процедура сравнения значения АЦП с { // температурными диапазонами и OCR1B=0; // выдача ШИМ на вентилятор } else if(temp_range[1] <= adc_data_l) { OCR1B=0; } else if((temp_range[2] <= adc_data_l) && (adc_data_l < temp_range[1])) { OCR1B=128; } else if((temp_range[3] <= adc_data_l) && (adc_data_l < temp_range[2])) { OCR1B=149; } else if((temp_range[4] <= adc_data_l) && (adc_data_l< temp_range[3])) { OCR1B=170; } else if((temp_range[5] <= adc_data_l) && (adc_data_l < temp_range[4])) { OCR1B=191; } else if((temp_range[6] <= adc_data_l) && (adc_data_l < temp_range[5])) { OCR1B=213; } else if((temp_range[7] <= adc_data_l) && (adc_data_l < temp_range[6])) { OCR1B=234; } else if((temp_range[8] <= adc_data_l) && (adc_data_l < temp_range[7])) { OCR1B=255; } else if(adc_data_l < temp_range[8]) { OCR1B=255; } }; } С типами данных у функции read_adc, массива temp_range и переменной adc_data_l ничего не напутал ? Всё верно ?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|