Новичок
Регистрация: 28.03.2011
Сообщений: 69
Репутация: 11
|
Всем доброго времени суток!
Помогите! Второй месяц бьюсь. Даже не знаю с чего начать, все уже перемешалось. Задача вроде бы проста. Нужно чтобы МК спал и по сторожевому таймеру пробуждался(переодичность 8 сек) , осматривался, выполнял действия(инкрементировал переменную) и ложился баиньки. Естественно все это нужно для экономии батарейки. За эти два месяца, перелопатил все что можно и не нужного. Перепробовал массу вариантов. И вот что у меня получилось. Отдельно алгоритм сна, работает. Отдельно алгоритм Ватчдога, работает. А вот объединить их у меня не получается. Получаю следующие "ошибки" при симуляции в Проеусе 7.10 SP0 (build 12355). 1) исполняется цикл Ватчдога один раз. После чего МК засыпает и его некому будить. 2) Исполняется цикл Ватчдога многократно, но почемуто вхождение в обработчик прерывания входит дважды, тем самым инкрементирует переменнцю дважды. Как им образом так делает я не понял, так как он у меня должен уснуть. Вот код (AtmelStudio 6) #define F_CPU 1000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/wdt.h> #include <avr/sleep.h> unsigned char count=0; unsigned char flag=0; //прерывание по таймеру WDT ISR(WDT_vect) { flag=1; wdt_reset(); } // инициализация Watchdog void WDT_init() { wdt_reset(); // сброс таймера WD WDTCSR=0x38; //0b00111000 предподготовка битов для изменения свойств функцилнирования а также предустановка делителя на 4 сек WDTCSR=0x60; //0b01100000 4s устанавливаем свойства функционирования , INT-On/INTmode(WDTON=1 unprogrammed) } void WDT_off(void) { /* Clear WDRF in MCUSR */ MCUSR &= ~(1<<WDRF); /* Write logical one to WDCE and WDE */ /* Keep old prescaler setting to prevent unintentional time-out */ WDTCSR |= (1<<WDCE) | (1<<WDE); /* Turn off WDT */ WDTCSR = 0x00; } int main(void) { cli(); // запретить прерывание PORTB=0;DDRB=255; PORTC=0;DDRC=255; PORTD=0;DDRD=255; WDT_init(); sei(); PORTD=255;PORTB=255; count=0; flag=0; while(1) { if (flag==1){flag=0;count++;} if (count==0) PORTC=0b00001111; if (count==1) PORTC=0b00000001; if (count==2) PORTC=0b00000011; if (count==3) PORTC=0b00000111; if (count==4) PORTC=0b00001111; if (count==5) {PORTC=0b00000000; count=0;} PORTD=255;_delay_ms(500);PORTD=0;_delay_ms(500); } }
__________________
Глаза боятся, мозг кипит, руки делают. |
||
Оценка
|
Специалист
|
Честно говоря, у меня вообще не получилось увидеть в симуляторе работу сторожевого таймера в режиме генерирования сигнала прерывания после истечения установленного периода времени (бит WDIE установлен, WDE сброшен), т.е. в обработчик прерывания не входит.
Если его на режим Interrupt and System Reset Mode (WDIE и WDE =1) или System Reset, то работает в симуляторах только системный сброс, но интервал не совпадает с заданным. Пробовал разные конфигурации. Код писал, правда, в 4 студии. Там же в симуляторе проверял и в Proteus 7.6 прогонял. В 4 студии (как и в протеусе) нет возможности посмотреть работу счетчика сторожевого таймера. А вы в 6 студии проверяли в симуляторе? Может там в симуляторе можно более подробно посмотреть работу встроенной периферии мк. Вообще я хотел проверить сразу в железе, но есть только mega128 и mega16, в которых сторожевой таймер не имеет функции генерирования прерывания (только системный сброс) по истечению установленного интервала времени. Буду сегодня еще играться с этой задачкой...
__________________
Уважаемые пассажиры, самолет ТУ-134 садится. У кого есть зарядка от ТУ-134, просьба пройти в кабину пилота.
Последний раз редактировалось Vadzz; 30.01.2014 в 10:27.
|
||
Оценка
|
Новичок
Регистрация: 28.03.2011
Сообщений: 69
Репутация: 11
|
Так как я уже пересмотрел и перичиал по десятому кругу все что касается этой Собаки (будь она не ладна уже ), сегодня с утра решил копать Протеус и АтмелСтудию.
И вот что нарыл: 1) В АтмелСтудии разобрался как работать во встроенном Simulator_е, посомотрел как мой Си код выглядит в асемблере, как меняются регистры, как отсчитывает микросекунды Watchdog и др. Прогнал в ассемлерном коде и на комманде SLEEP он у меня замер, причем WD продолжал тикать, и как только таймер переполнился, а он совпал с моими настойками, произошло прерывание. Т.е. получается что все работает. 2) Разобрался в Протеусе как дезасемблировать и стал прогонять код по шагово. Выясниласть что в Протеусе на комманде SLEEP ни каких остановок не происходило и сразу вызывалось прерывание. Теперь буду полигон в железе собирать и тестить , тестить, тестить. Вот мой тестовый код #define F_CPU 1000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <avr/wdt.h> #include <avr/sleep.h> #include <util/delay.h> void init_ports() { PORTB=0;DDRB=255;PORTC=0;DDRC=255;PORTD=0;DDRD=255 ; } ISR (WDT_vect) { PORTB ^= _BV(PINB4); // переключаем(инвертируем бит) светодиод //WDTCSR |= _BV(WDIE); // разрешаем прерывания по ватчдогу. Иначе будет резет. } int main() { // инициализация порта светодиода DDRB = _BV(PINB4); // на этом пине висит светодиод PORTB = _BV(PINB4); // зажгем его //инициализация ватчдога wdt_reset(); // сбрасываем //wdt_enable(WDTO_1S); // разрешаем ватчдог 1 сек MCUSR &= ~(1<<WDRF); /* Start the WDT Config change sequence. */ WDTCSR |= (1<<WDCE) | (1<<WDE); /* Configure the prescaler and the WDT for interrupt mode only*/ //WDTCSR = (1<<WDP0) | (1<<WDP3) | (1<<WDIE); // 8sec //WDTCSR = (1<<WDP2) | (1<<WDP1) | (1<<WDIE); // 4sec WDTCSR = (1<<WDP2) | (1<<WDP0) | (1<<WDIE); // 0.5sec //WDTCSR |= _BV(WDIE); // разрешаем прерывания по ватчдогу. Иначе будет резет. sei(); // разрешаем прерывания set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную while(1) { sleep_enable(); // разрешаем сон sleep_cpu(); // спать! sleep_disable(); } }
__________________
Глаза боятся, мозг кипит, руки делают. |
||
Оценка
|
Обратная связь РадиоЛоцман Вверх |