Oleg_IT 0 5 января, 2015 Опубликовано 5 января, 2015 (изменено) · Жалоба Есть такой код #include <stdint.h> #include <avr/io.h> #include <avr/interrupt.h> //#include "PortDefine.h" #include "avrlibdefs.h" #include "avrlibtypes.h" //#define USE_INT0 union { uint16_t ADC_Data; uint8_t ADC_Bute[2]; } Data; #ifdef USE_INT0 ISR (INT0_vect) { ADCSRA |= (1 << ADSC); } #endif // USE_INT0 ISR (ADC_vect) { PORTD |= 1; Data.ADC_Data = (unsigned short)inb(ADCL) | (unsigned short)(inb(ADCH) << 8); PORTD &=~ 1; } int main( void ) { // ADC ADMUX |= (1 << REFS0) | (1 << MUX0) | (1 << MUX2); // ADC5, AVCC ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIE); ADCSRB |= (1 << ADTS1); DDRC = 0; PORTC = 0; #ifdef USE_INT0 EICRA |= (1 << ISC01) | (1 << ISC00); EIMSK |= (1 << INT0); #endif // USE_INT0 DDRD = 0x03; PORTD = 4; sei(); ADCSRA |= (1 << ADSC); while (1) { PORTD ^= 2; } return 0; } По идеи он должен запускать оцифровку по внешнему сигналу, но этого не происходит. Если я открываю строку //#define USE_INT0 всё работает правильно, но при этом теряется время. Строку инициализации EICRA убирал из под ифа, не помогает. Может я чего в инициализации упускаю. Изменено 8 января, 2015 пользователем IgorKossak [codebox] для длинного кода, [code] - для короткого!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Я обычно запускаю АЦП от сигнала таймера, но и для внешнего прерывания должно быть аналогично. 1. Настраиваю АЦП, там мои макросы, но надеюсь будет понятно adc_enable (); adc_mode_trigger (); adc_set_source (ADC_SOURCE_TC0_CMPA); adc_set_prescaler (ADC_PRESCALE_DIV64); // or 128 ?? adc_set_reference (ADC_REFERENCE_AVCC); adc_left_adjusted (); // ADLAR = 1 // adc_right_adjusted(); // ADLAR = 0 adc_int_enable (); adc_set_channel (0x00); // начальный канал 2. настраиваю таймер timer0_init (TIMER0_MODE_CTC, T0_TICK *TIME_1MS); // for ADC 3. пишу обрабртчик таймера, если не нужен - то делаем его пустой ISR(TIMER0_COMPA_vect) { timer0_tick += T0_TICK; } 4. пишу обработчик АЦП, например так ISR(ADC_vect) { rms.val = ADCH; adc_flag = 1; } Соответственно с внешним прерыванием аналогично: 1. прерывание ExtINT0 должно быть настроено и включено, иначе откуда будет подаваться сигнал на АЦП? 2. для избежания косяков, необходимо написать обработчик ExtINT0, пусть даже и пустой 3. в этом обработчике НЕ НАДО напускать АЦП, иначе это будет ПЕРЕЗАПУСК, запуск АЦП делает логика МК, которая подключает старт АЦП от внешнего прерывания. А вот само прерывание должно обрабатывать аппаратная логика этого прерывания 4. что за, извиняюсь, гуанокод? ADMUX |= (1 << REFS0) | (1 << MUX0) | (1 << MUX2); // ADC5, AVCC ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIE); ADCSRB |= (1 << ADTS1); Вы же однократно и один раз в начале програмы инициализируете АЦП, зачем там "|=" ? уберите их ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2); // ADC5, AVCC ADCSRA = (1 << ADEN) | (1 << ADATE) | (1 << ADIE); ADCSRB = (1 << ADTS1); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Oleg_IT 0 16 января, 2015 Опубликовано 16 января, 2015 · Жалоба Так как Вы описали инициализацию работает, но выигрыш во времени не впечатлил, Atmega48, 10МГц, с запуском АЦП в обработчике внешнего прерывания от начала входного импульса на INT0 до начала прерывания АЦП 66,8 мкс, а тоже время с автоматическим запуском составляет 46,4 мкс. По поводу |= или =. В данном случае это эквивалентно, т.к. регистры по умолчанию равны 0. Но |= всё таки правильнее, это нужно, что бы не повреждать те биты которые нужны для других целей. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 16 января, 2015 Опубликовано 16 января, 2015 · Жалоба Но |= всё таки правильнее, это нужно, что бы не повреждать те биты которые нужны для других целей.В данном случае вы инициализируете. И вам нужно не "не повредить" их, а вам нужно, чтобы в них были нули. Поэтому именно здесь правильнее "=". Кроме того, это даст более короткий код. но выигрыш во времени не впечатлилКакой выигрыш? АЦП запускается или сразу (аппаратно) или с задержкой (вручную в обработчике). Остальное время уходит на преобразование. Максимальная тактовая для АЦП (для получения 10 бит) - 1 МГц, вы можете затактировать АЦП частотой 10 МГц / 16 = 625 КГц, преобразование занимает 13.5 тактов, т.е. 21.6 мкС - это максимум, что можно выжать для вашего кварца и 10 бит. 40 мкС должно занимать первое преобразование после переключения канала. В вашем коде я не вижу смены канала, значит уже второе преобразование должно закончиться через 21.6 мкС. Но это только при условии, что вы настроите тактирование. В вашем коде я не вижу настройки предделителя АЦП, значит оно работает на 5 МГц и если при этом вы наблюдаете время преобразования 44 мкС, то я могу только предположить, что ваш процессор вместо 10 МГц работает от внутреннего RC-генератора деленного на 8, т.е. на 1 МГц. Хотя и тогда должно получиться около 27 мкС. В общем показывайте последний код, телепатировать не хочется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 19 января, 2015 Опубликовано 19 января, 2015 (изменено) · Жалоба Сергей, а где Вы нашли Максимальная тактовая для АЦП (для получения 10 бит) - 1 МГц ? Я знаю только By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate. Да, согласен, Oleg_IT нужно выставить предделитель для АЦП для лучшей точности измерения. Совсем выпустил это из виду. Упс, нашел, таблица 28-7. частота АЦП от 50 до 1000 кГц. Изменено 19 января, 2015 пользователем alexeyv Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться