|
Вопросы по ATtiny461, как правильно работать с ADMUX? |
|
|
|
Oct 10 2007, 09:25
|

Профессионал
    
Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807

|
Устройство должно измерять три аналоговых сигнала: AS1, AS2, AS3. Таймер 1 переполняется каждые 32 мкс. К факту переполнения привязан ADC с общими настройками: Код
ADCSRA = BIN(10111101); // ADC 250kHz при Fbq=8MHz, включен
ADCSRB = BIN(00000110); Конечно, таймер 1 переполняется чаще, чем ADC успевает выполнить одно преобразование, но это пока представляется не важным. Обработчик прерывания по завершению преобразования выполнен так: Код // ADC Conversion Complete #pragma vector = ADC_vect __interrupt void ADC_COMPLITE(void) { unsigned int tmp = ADC; if(ADMUX == BIN(10010010)){AS1 = tmp;ADMUX = BIN(10000010);return;} if(ADMUX == BIN(10000010)){AS2 = tmp;ADMUX = BIN(10000011);return;} if(ADMUX == BIN(10000011)){AS3 = tmp;ADMUX = BIN(10010010);return;} } Казалось бы, все правильно: закончили одно преобразование, забрали результат, посмотрели от какого MUX оно произошло и записали в соотв глобалную переменную. Но не работает. Причина установлена, заключается в том, что ADMUX некорректно менять в данный момент в данном прерывании. Если читать только одну величину преобразования (не меняя ADMUX) ее значение получается правильным и устройство работает. В даташите по поводу работы с мультиплексором написано на стр.147-148: If Auto Triggering is used, the exact time of the triggering event can be indeterministic. Special
care must be taken when updating the ADMUX Register, in order to control which conversion
will be affected by the new settings.
If both ADATE and ADEN is written to one, an interrupt event can occur at any time. If the
ADMUX Register is changed in this period, the user cannot tell if the next conversion is based
on the old or the new settings. ADMUX can be safely updated in the following ways:
a. When ADATE or ADEN is cleared.
b. During conversion, minimum one ADC clock cycle after the trigger event.
c. After a conversion, before the Interrupt Flag used as trigger source is cleared.
When updating ADMUX in one of these conditions, the new settings will affect the next ADC conversion.
Использовать вариант (a) как-то не хочется, вкл/выкл ADC на такой частоте чреват переходными процессами... Хотелось бы все же менять ADMUX в прерывании по окончанию преобразования, но как это лучше сделать и можно ли понять пока не смог...
|
|
|
|
|
 |
Ответов
|
Oct 10 2007, 21:13
|

Профессионал
    
Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807

|
Привожу полный код. Оказывается, в прерывании от ADC важна последовательность измерения сигналов. Один из трех измеренных измеряется неверно. Теперь это AS3. Код // мультиплексор ADC #define AS1set BIN(10000011)// для сигнала AS1 #define AS2set BIN(10010010)// для сигнала AS2-AS1 #define AS3set BIN(10000010)// для сигнала AS3 /********************************************************************************/ unsigned int AS3value,AS2value,AS1value; unsigned int __eeprom A; /********************************************************************************/ __C_task void main (void) { SETUP(SWUP,OUT0);SETUP(SWBAT,OUT0);SETUP(SWPWR,OUT0); SETUP(AS1GND,OUT0);SETUP(AS2GND,OUT0);SETUP(AS4GND,OUT0);// подключить делители // общие настройки компаратора CLRBIT(ACSRA,ACIE); ACSRA = BIN(01010000); // компаратор с AIN+ = BANDGAP_REF включен ACSRB = BIN(00000100); //SETBIT(ACSRA,ACIE); // общие настройки ADC ADMUX = AS2set; // опора компаратора и ADC = 1.1 вольт ADCSRA = BIN(10011101); // ADC 250kHz при Fbq=8MHz,включен,прерывание по оконч. ADCSRB = BIN(00000000); DIDR0 = BIN(11111111);// отключить входные буферы ADC(нет вх цифровых сигналов) DIDR1 = BIN(11110000); Tmr1Ini(); __enable_interrupt(); SETBIT(ADCSRA,ADSC);// начать первое преобразование Tmr1Start; Work: { unsigned int tmp; __disable_interrupt(); tmp = AS3value;// !!!!!!!!!!!!!значение AS3 наблюдаем неверное!!!!!!!!!!!! __enable_interrupt(); A = tmp; } goto Work; } /********************************************************************************/ // Timer/Counter1 Overflow #pragma vector = TIM1_OVF_vect __interrupt void TIM1_OVF(void) { unsigned char tmp2; tmp2 = AS3value;// !!!!!!!!!!!!!значение AS3 наблюдаем неверное!!!!!!!!!!!! TC1H = ((tmp2 >> 8) & 0x0003); OCR1D = (tmp2 & 0x00FF);// загрузка величины сравнения для след. цикла }
// ADC Conversion Complete #pragma vector = ADC_vect __interrupt void ADC_COMPLITE(void) { SETBIT(ADCSRA,ADSC);// начать преобразование по текущему ADMUX switch(ADMUX){// установить следующий ADMUX case AS1set: ADMUX = AS2set;AS1value = ADC;break; case AS2set: ADMUX = AS3set;AS2value = ADC;break; case AS3set: ADMUX = AS1set;AS3value = ADC;break; } } /********************************************************************************/ // ини таймера1 для stepDown и stepUp регуляторов void Tmr1Ini(void){ Tmr1Stop; CLRBIT(PRR,PRTIM1); // включить модуль таймера 1 SETBIT(PLLCSR,LSM); // PLL = 32MHz SETBIT(PLLCSR,PLLE);Delay(200*us);do{}while(!CHKBIT(PLLCSR,PLOCK));// запуск PLL SETBIT(PLLCSR,PCKE); // разрешить тактирование таймера от PLL TCCR1A = BIN(00110001); TCCR1B = BIN(01000000);do{}while(CHKBIT(TCCR1B,PSR1));// сброс прескалера TCCR1C = BIN(00111101); TCCR1D = BIN(00000000); TCCR1E = BIN(00000000); DT1 = 0x00; Reg10write(TCNT1reg,0x000); Reg10write(OCR1Areg,0x3FF); Reg10write(OCR1Breg,0x3FF); Reg10write(OCR1Creg,0x3FF); Reg10write(OCR1Dreg,0x3FF); SETBIT(TIFR,TOV1); SETBIT(TIMSK,TOIE1); } /********************************************************************************/
|
|
|
|
|
Oct 11 2007, 08:35
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ivainc1789 @ Oct 11 2007, 01:13)  Код // ADC Conversion Complete #pragma vector = ADC_vect __interrupt void ADC_COMPLITE(void) { SETBIT(ADCSRA,ADSC);// начать преобразование по текущему ADMUX switch(ADMUX){// установить следующий ADMUX case AS1set: ADMUX = AS2set;AS1value = ADC;break; case AS2set: ADMUX = AS3set;AS2value = ADC;break; case AS3set: ADMUX = AS1set;AS3value = ADC;break; } } Проблема в том что Вы сначала запускаете преобразование SETBIT(ADCSRA,ADSC); и тут же меняете номер канала ADMUX = .... SETBIT(ADCSRA,ADSC); НЕ запускает преобразование немедленно, реально новое преобразование запустится только когда начнется очередной такт ADC клока. Попробуйте так: Код // ADC Conversion Complete #pragma vector = ADC_vect __interrupt void ADC_COMPLITE(void) {
switch(ADMUX){// установить следующий ADMUX case AS1set: ADMUX = AS2set;AS1value = ADC;break; case AS2set: ADMUX = AS3set;AS2value = ADC;break; case AS3set: ADMUX = AS1set;AS3value = ADC;break; } SETBIT(ADCSRA,ADSC); // запускаем новый канал }
|
|
|
|
Сообщений в этой теме
ivainc1789 Вопросы по ATtiny461 Oct 10 2007, 09:25 Qwertty Цитата(ivainc1789 @ Oct 10 2007, 13:25) .... Oct 10 2007, 10:23 ivainc1789 Цитата(Qwertty @ Oct 10 2007, 14:23) Може... Oct 10 2007, 11:11  Qwertty Если ADC работает в режиме одиночного преобразоани... Oct 10 2007, 14:04   ivainc1789 Цитата(Qwertty @ Oct 10 2007, 18:04) Если... Oct 10 2007, 15:49 ivainc1789 И, наконец, окончательно установлено: в ATtiny461 ... Oct 10 2007, 17:25 singlskv Цитата(ivainc1789 @ Oct 10 2007, 21:25) И... Oct 10 2007, 18:20  ivainc1789 Цитата(singlskv @ Oct 10 2007, 22:20) Пок... Oct 10 2007, 18:58   singlskv Цитата(ivainc1789 @ Oct 10 2007, 22:58) В... Oct 10 2007, 19:53 ArtemKAD Цитатаa. When ADATE or ADEN is cleared.
b. During ... Oct 10 2007, 19:37 ArtemKAD ЦитатаЧто я не так делаю, что у меня и без этого п... Oct 10 2007, 20:16  ivainc1789 Цитата(singlskv @ Oct 11 2007, 12:35) реа... Oct 11 2007, 20:51 smk ЦитатаВопрос по сути: как правильно менять настрой... Oct 11 2007, 06:12 ivainc1789 Оказывается, стоило просто открыть даташит на како... Oct 12 2007, 17:01 ArtemKAD Да, кстати, еще одна "особенность" связа... Oct 17 2007, 16:38 ivainc1789 Цитата(ArtemKAD @ Oct 17 2007, 20:38) Да,... Oct 17 2007, 22:49
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|