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

|
Доброго времени суток. Поскольку я не профессиональный программист и до этого момента с микроконтроллерами общался постольку поскольку, то обращаюсь к знающим и опытным людям с просьбой помочь разобраться с поставленной передо мной задачей. Исходные данные: Есть - мк Atmega16L-16AI (TQFP) - два вентилятора Jamicon (JF0825B1H), Evercool (EC6010H12B) - два дачитка температуры типа NTC Задача: необходимо считывать информацию с датчиков и выдавать на вентиляторы напряжения, соответствующие температурным диапазонам. Так как я в этом деле новичок, то разбил задачу на три. 1) Научиться выдавать ШИМ на вентиляторы. С этим я худо бедно разобрался! Вот код Код 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>
// Timer 1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { OCR1A=0x00; OCR1B=0x00; TCNT1L=0x00; PORTD=0b00110000; }
//Timer 1 output compare A interrupt service routine interrupt [TIM1_COMPA] void timer1_compa_isr(void) { PORTD=0b00110000;
}
// Timer 1 output compare B interrupt service routine interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{ PORTD=0b00110000; }
void main(void) {
// Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTA=0x00; DDRA=0x00;
// Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTB=0x00; DDRB=0x00;
// Port C initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0x00; DDRC=0x00;
// Port D initialization // Func7=In Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=0 State4=0 State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x30;
// Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x00; TCNT0=0x00; OCR0=0x00;
// Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 8192,000 kHz // Mode: Fast PWM top=00FFh // OC1A output: Non-Inv. // OC1B output: Non-Inv. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: On // Input Capture Interrupt: Off // Compare A Match Interrupt: On // Compare B Match Interrupt: On TCCR1A=0xA1; TCCR1B=0x09; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00;
// Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00;
// External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x1C;
// Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00;
// ADC initialization // ADC Clock frequency: 64,000 kHz // ADC Voltage Reference: AREF pin // ADC Auto Trigger Source: Timer1 Overflow // Only the 8 most significant bits of // the AD conversion result are used //ADMUX=0b00000000; //ADCSRA=0xF7; //SFIOR&=0x1F; //SFIOR|=0xC0; SPCR=0x40; SPSR=0x01;
#asm("sei")
while (1) { OCR1B=100; OCR1A=100; }; } По части теории вопросов у меня пока что нет. Перед решением этой задачи были проведены расчёты и получены соответствующие значения регистров сравнения таймера/счётчика1, соответствующих температурным диапазонам. Также согласно формуле из даташита на атмегу получено число ADC. Вот эти значения (приведу только один диапазон в целях экономии времени): температура, С измерительное напряжение, В ADC OCR1A OCR1B 25 1.196 299 0 0 26 1.159 290 0 0 27 1.123 281 0 0 28 1.087 272 0 0 29 1.053 263 0 0 30 1.020 255 0 0 и т. д. Со второй задачей справиться не получается. Заключается она в том, чтобы научиться работать с АЦП. А именно как правильно считывать информацию из АЦП, где и какие прерывание нужны в данной задаче? То есть я хочу понять структуру кода на Си, которая позволяет это делать и как такую структуру писать. Дело в том, что я пользуюсь CodeVisionAvr, который генерит код, если использовать Wizard. Это на мой взгляд удобно, но только в том, случае если есть полное понимание сгенеренного кода. У меня такого понимания нету. Я пытался самостоятельно решить эту проблему и протестировать полученный результат в Протеус, как в решении первой задачи, но ничего не вышло Вот код (всё тоже самое только с добавлением сгенеренного кода для АЦП): Код
1- #define ADC_VREF_TYPE 0x04 2- // Read the 8 low significant bits 3- // of the AD conversion result 4- unsigned char read_adc(unsigned char adc_input) 5- { 6- ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); 7- Delay needed for the stabilization of the ADC input voltage 8- delay_us(10); 9- // Start the AD conversion 10- ADCSRA=0b11100110; 11- // Wait for the AD conversion to complete 12- while ((ADCSRA & 0x40)==0); 13- ADCSRA|=0x10; 14- return ADCL; 15- }
16- // ADC interrupt service routine 17- interrupt [ADC_INT] void adc_isr(void) 18- { 19- unsigned char adc_data_l; 20- // Read the 8 low significant bits 21- // of the AD conversion result 22- adc_data_l = ADCL;
23- if(adc_data_l==0xFF) 24- { 25- OCR1A = 255 - adc_data_l; 26- OCR1B = 255 - adc_data_l; 27- } 28- else 29- { 30- OCR1A = adc_data_l; 31- OCR1B = adc_data_l; 32- }; 33- } Хотелось бы узнать от опытных людей, для чего необходимо и что означают 1 и 6 строчки кода, а также 12 и 13. Далее хотелось бы понять правильно ли я сделал, что в процедуре прерывания АЦП написал последовательность действий по присвоению значений регистрам сравнения ? 3) Третья задача пока вообще не рассматриволась. Заключается она в передаче данных из АЦП в процедуру сравнения полученного из АЦП числа. У меня процедура сравнения выглядит следующим образом: Код int range[9]={299, 255, 217, 184, 132, 112, 95, 81};
if (range[0] <= adc_data_l) { OCR1AL=0; OCR1BL=0; }; if (range[1] <= adc_data_l) { OCR1AL=0; OCR1BL=0; }; if (range[2] <= adc_data_l < range[1]) { OCR1AL=128; OCR1BL=85; }; if (range[3] <= adc_data_l< range[2]) { OCR1AL=149; OCR1BL=96; }; if (range[4] <= adc_data_l < range[3]) { OCR1AL=170; OCR1BL=106; }; if (range[5] <= adc_data_l < range[4]) { OCR1AL=191; OCR1BL=138; }; if (range[6] <= adc_data_l < range[5]) { OCR1AL=213; OCR1BL=149; }; if (range[7] <= adc_data_l < range[6]) { OCR1AL=234; OCR1BL=170; }; if (range[8] <= adc_data_l < range[7]) { OCR1AL=255; OCR1BL=255; }; Массив из значений регистров сравнения ввёл для удобства. Хотя может быть оно и сомнительное. В какой части кода необходимо писать эту процедуру ? В бесконечном цикле while(1){}? Или в прерываниях? Поскольку переменная adc_data_l объявлена внутри функции, то использовать её как глобальную переменную нельзя. Как решается эта проблема?. То есть, допустим я прочитал АЦП и записал число в эту переменную, что нужно сделать чтобы можно было пользоваться этой переменной в процедуре сравнения? Заранее благодарю за помощь! Если на форуме или в интернете уже есть идентичные темы, в которых предложены решения данных проблем, то прошу поделиться ссылкой. Я обыскался в инете на эту тему, но не нашёл ничего, чтобы мне объяснило или подсказало как решать и что делать. Надеюсь на вашу помощь!
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 14)
|
Apr 7 2011, 07:06
|

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

|
Цитата(abitwise @ Apr 7 2011, 10:26)  Хотелось бы узнать от опытных людей, для чего необходимо и что означают 1 и 6 строчки кода, а также 12 и 13. Строка 1: определяет константу для задания опорного напряжения (в Вашем случае - AVCC with external capacitor at AREF pin) Строка 6: коммутирует на АЦП один из входов (номер входа определяется значением adc_input) и опорное напряжение Строка 12: ожидание окончания преобразования (измерения) Строка 13: сброс флага прерывания Цитата(abitwise @ Apr 7 2011, 10:26)  Далее хотелось бы понять правильно ли я сделал, что в процедуре прерывания АЦП написал последовательность действий по присвоению значений регистрам сравнения ? Непонятно: зачем используете процедуру прерывания, раз в функции измерения (read_adc) дожидаетесь готовности, кроме того функция измерения возвращает код АЦП (регистр ADCL)... Если Ваша программа только и должна делать, что измерять температуру и по её значению менять параметры ШИМ, то эти действия можно поместить в бесконечный цикл.
|
|
|
|
|
Apr 7 2011, 09:19
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Спасибо за ответ. Если я вас правильно понял, то процедура прерывания не нужна, и достаточно функции read_adc, чтобы прочитать данные из АЦП? В даташите сказано, что регистры ADCL и ADCH можно только читать. Следовательно, чтобы работать с полученным числом надо создать переменную, так ? Где и как её объявить, чтобы я мог пользоваться ей в процедуре сравнения? Не очень понял Цитата Строка 1: определяет константу для задания опорного напряжения (в Вашем случае - AVCC with external capacitor at AREF pin) Строка 6: коммутирует на АЦП один из входов (номер входа определяется значением adc_input) и опорное напряжение То есть вот здесь Код 6- ... (ADC_VREF_TYPE & 0xff) мы получаем число 0000 0100; вот здесь Код adc_input | (ADC_VREF_TYPE & 0xff); происходит побитовая логическая операция ИЛИ. И потом получившийся результат записывается в ADMUX? И это число зависит от значения adc_input?
|
|
|
|
|
Apr 7 2011, 09:50
|

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

|
Цитата(abitwise @ Apr 7 2011, 13:19)  Если я вас правильно понял, то процедура прерывания не нужна, и достаточно функции read_adc, чтобы прочитать данные из АЦП? В процедуре прерывания в Вашем случае не вижу необходимости. Цитата(abitwise @ Apr 7 2011, 13:19)  В даташите сказано, что регистры ADCL и ADCH можно только читать. Следовательно, чтобы работать с полученным числом надо создать переменную, так ? Где и как её объявить, чтобы я мог пользоваться ей в процедуре сравнения? Примерно, как-то так: Код for(;;) // бесконечный цикл в main { unsigned char adc_data_l; adc_data_l = read_adc(_код_канала_первого_датчика_); // ......... в этом месте анализ значения adc_data_l и выставляем параметры ШИМ первого вентилятора (не написанная часть 3 Вашей программы).... adc_data_l = read_adc(_код_канала_второго_датчика_); // ......... в этом месте анализ значения adc_data_l и выставляем параметры ШИМ второго вентилятора.... } Цитата(abitwise @ Apr 7 2011, 13:19)  Не очень понял... Подозреваю, что должно быть Код #define ADC_VREF_TYPE 0x40 Еще хочу обратить внимание на то, что использованная Вами функция read_adc возвращает только младшие 8 бит результата преобразования (измерения) АЦП, а в намётках третьей части Вашей программы для сравнения используются целые числа, бОльшие чем 255. Наверное, нужно внести изменения: Код unsigned int read_adc(unsigned char adc_input) { .............. return ADC; } и, тогда Код for(;;) // бесконечный цикл в main { unsigned int adc_data; adc_data = read_adc(_код_канала_первого_датчика_); // ......... adc_data = read_adc(_код_канала_второго_датчика_); // ......... }
|
|
|
|
|
Apr 7 2011, 10:51
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
С каждым вашим ответом, ситуация в голове проясняется всё больше.) Спасибо! Цитата Подозреваю, что должно быть Код #define ADC_VREF_TYPE 0x40 Схема питается от внешнего источника опорного напряжения, сигналы с датчиков поступает на входы ADC4 ADC5, выравнивание вправо, соответственно биты Ref1=0; Ref0=0. Бит ADLAR=0.
Сообщение отредактировал abitwise - Apr 7 2011, 10:52
|
|
|
|
|
Apr 7 2011, 14:42
|

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

|
Цитата(abitwise @ Apr 7 2011, 14:51)  биты Ref1=0; Ref0=0 Тогда Код #define ADC_VREF_TYPE 0 Собственно - эта константа и содержит эти два бита Цитата(abitwise @ Apr 7 2011, 14:51)  сигналы с датчиков поступает на входы ADC4 ADC5 Параметр функции read_adc следует задавать 4 и 5 соответственно. При разработке Вами части 3 программы, вероятно, следует предусмотреть гистерезис. Иначе, при температуре близкой к границе участка возможны "интересные" эффекты при управлении вентиляторами.
|
|
|
|
|
Apr 7 2011, 17:37
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Ясно! Уже учёл. Спасибо! Вот код, который получился с учётом перечисленных выше поправок и подсказок, посмотрите, может быть найдёте ошибки (скорей всего_) ): Код /***************************************************** 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) // Прерывание Т/С1 по переполнению { OCR1A=0x00; OCR1B=0x00; // TCNT1L=0x00; // PORTD=0b00110000; }
interrupt [TIM1_COMPA] void timer1_compa_isr(void) // Прерывание Т/С1 по совпадению события А { PORTD=0b00100000; }
interrupt [TIM1_COMPB] void timer1_compb_isr(void) // Прерывание Т/С1 по совпадению события Б { PORTD=0b00010000; }
#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 ADCL; // Возвращает значение 8 МЗР }
void main(void) { int temp_range[9] = {299, 255, 217, 184, 156, 132, 112, 95, 81}; PORTA=0x30; // Инициализация порта А; DDRA=0x00; // PA4, РА5 - вход с подтянутым резистором
PORTB=0x00; // Инициализация порта Б DDRB=0x00;
PORTC=0x00; // Инициализация порта С DDRC=0x00;
PORTD=0x00; // Инициализация портп Д; DDRD=0x30; // PD4, PD5 выходы с низким логическим уровнем;
TCCR0=0x00; // Инициализация Т/С0 TCNT0=0x00; OCR0=0x00;
TCCR1A=0xA1; // Инициализация T/C1 TCCR1B=0x0B; // Инициализация T/C1 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; // Частота тактирования 125,000 kHz // Источник питания: AREF pin // Используются только 8 МЗР
SPCR=0x40; // Инициализация интерфейса SPI SPSR=0x01; #asm("sei") // Рарешение прерываний
for (;;) // Бесконечный цикл { unsigned char adc_data_l; TCNT1H=0x00; // обнуление таймера счётчика на всякий случай 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; // выдача ШИМ на вентилятор }; if(temp_range[1] <= adc_data_l) { OCR1A=0; }; if(temp_range[2] <= adc_data_l < temp_range[1]) { OCR1A=128; }; if(temp_range[3] <= adc_data_l < temp_range[2]) { OCR1A=149; }; if(temp_range[4] <= adc_data_l < temp_range[3]) { OCR1A=170; }; if(temp_range[5] <= adc_data_l < temp_range[4]) { OCR1A=191; }; if(temp_range[6] <= adc_data_l < temp_range[5]) { OCR1A=213; }; if(temp_range[7] <= adc_data_l < temp_range[6]) { OCR1A=234; }; if(temp_range[8] <= adc_data_l < temp_range[7]) { OCR1A=255; }; adc_data_l=read_adc(4); // Запись данных из АЦП с ноги PA4
if(temp_range[0] <= adc_data_l) // Процедура сравнения полученного значения АЦП { // с температурными диапазонами и OCR1B=0; // выдача ШИМ на вентилятор }; if(temp_range[1] <= adc_data_l) { OCR1B=0; }; if(temp_range[2] <= adc_data_l < temp_range[1]) { OCR1B=128; }; if(temp_range[3] <= adc_data_l < temp_range[2]) { OCR1B=149; }; if(temp_range[4] <= adc_data_l < temp_range[3]) { OCR1B=170; }; if(temp_range[5] <= adc_data_l < temp_range[4]) { OCR1B=191; }; if(temp_range[6] <= adc_data_l < temp_range[5]) { OCR1B=213; }; if(temp_range[7] <= adc_data_l < temp_range[6]) { OCR1B=234; }; if(temp_range[8] <= adc_data_l < temp_range[7]) { OCR1B=255; }; }; } По поводу 10 бит АЦП. Дело в том, что это программа являет собой решение в первом приближении, поэтому высокая точноть преобразования пока не нужна. Поэтому я пользуюсь только данными регистра ADCL. С гистерезисом обязательно подумаю.
|
|
|
|
|
Apr 8 2011, 04:04
|

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

|
Проверку на попадание в диапазон Вы записали в виде Код if(A <= X < B) Такая запись не даст ожидаемый Вами результат. Следует исправить на такой вид Код if((A <= X) && (X < B))
|
|
|
|
|
Apr 8 2011, 09:01
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Можете предложить другой вариант решения ? Цепочка if-в была выбрана по совету моего товарища, который сослался на то, что циклы типа while, for и др. могут подзагрузить процессор.
|
|
|
|
|
Apr 8 2011, 09:34
|

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

|
Цитата(abitwise @ Apr 8 2011, 13:01)  Цепочка if-в была выбрана по совету моего товарища, который сослался на то, что циклы типа while, for и др. могут подзагрузить процессор. Если Вы описали все функции Вашего устройства, то, собственно, загрузка то и не велика, как не напиши программу... Цикл, возможно, будет выполняться несколько медленнее, но не для того кода, что привели Вы: в Вашем случае будет произведена проверка на попадание в каждый диапазон, когда (надеюсь, что это Вам понятно) значение переменной adc_data_l может лежать внутри только одного диапазона. В случае цепочки if, это решается так Код 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])) ................... и т.д. В случае использования цикла - применяют оператор break, для того, чтобы не перебирать ненужные диапазоны, раз уж нашли подходящий диапазон. Кстати, проверку в if в виде двух условий (типа А<=X<B), можно заменить на одно условие, беря в расчет то, что границы диапазонов расположены в массиве по убыванию (т.е. второе условие было проверено предыдущим оператором if) Код 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) { OCR1A=128; } else if(temp_range[3] <= adc_data_l) ................... и т.д. При этом видно, что этот кусок программы хорошо "ложится" под цикл
|
|
|
|
|
Apr 8 2011, 11:42
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Спасибо. Уже обратил) Буду пробовать прошивать... По результатам обязательно отпишусь! Благодарю за советы и помощь!
|
|
|
|
|
Apr 9 2011, 18:36
|
Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056

|
Прошил атмегу. Но программа по заданному алгоритму не работает! После подачи питания происходит включение вентилиторов на полную. На ножках PD4, PD5 никакого ШИМ-а нету, есть напряжение 12 В. Видимо просто выдаётся логическая еденица и всё. Есть подозрения, что АЦП вообще не включается и ничего не преобразовывает. К сожалению контрольных точек на плате для того, чтобы осцилографом посмотреть, что на ногах PA4, PA5, нету. Как вы думаете, в чём может быть дело??? Может быть дело в том, что я в программе неправильно или не в том месте инициализировал регистры ADCSRA и ADMUX ? Насколько я понимаю, в теле бесконечного цикла for(;;) когда я записываю значение АЦП в переменную adc_data_l Код adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5 должна вызываться функция read_adc() со значением параметра 5, и в ходе вызова должна произойти инициализация регистров ADCSRA и ADMUX. Может быть я зря вот здесь: Код ADMUX=0b00000000; // Инициализация АЦП ADCSRA=0b00000000; // Частота тактирования 125,000 kHz // Источник питания: AREF pin // Используются только 8 МЗР установил все биты в ноль ?
|
|
|
|
|
Apr 9 2011, 20:29
|

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

|
Цитата(abitwise @ Apr 7 2011, 21:37)  По поводу 10 бит АЦП. Дело в том, что это программа являет собой решение в первом приближении, поэтому высокая точноть преобразования пока не нужна. Поэтому я пользуюсь только данными регистра ADCL. Мне кажется, что даже в том случае, если вам достаточно данных младшего регистра ADCL, старший регистр ADCH вы читать тоже обязаны, если хотите, чтобы данные обновлялись. Цитирую пункт 25.8.3.2 даташита: Цитата When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH. Да и не сложное это дело, прочесть обе части регистра - читайте регистр ADC целиком, без указания H или L, и тогда компилятор прочтет оба байта. А присваивать полученное значение можете и однобайтной переменной - тогда старший байт обрежется.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|