Прерывания по таймеру
- Войдите на сайт для отправки комментариев
Всем привет. Суть в следующем - нужно 3-5 раз в секунду считывать состояние портов ввода вывода в предназначенные для этого переменные и затем выводить их состояние на экран. Все это уже реализовано но без прерываний. Имеем плату расширения портов ввода вывода и LCD шилд. Все это подключено по I2C. Решил сделать считывание портов по прерыванию таймера. Использовать решил библиотеку http://robocraft.ru/blog/arduino/614.html. Так же поключены библиотеки <MCP23xxx.h> <LiquidCrystal_MCP23x17.h>
void scanIOport()
{
portI = mcp23_in.digitalRead16();
portO = mcp23_out.digitalRead16();
}Так вот суть проблемы в том что контроллер виснет сразу после запуска. Висяк вызван именно методом .digitalRead16(); Если вместо считывания присваивать переменным рандомные значения то все работает как часы. И дело похоже не в частоте опроса портов, так как ни 1 раз в 2 секунды ни 2 раза в секунду опрашивания не происходит. Имеем просто светящийся оранжевый экран. Программа не выполняет ни единой строчки из цикла loop(); пробовал и без использования библиотеки TimerOne - аналогично. пожоже конфликт с I2C?
MarioM, о том как , и в какое прерывание вы это засовывате -нужно самому догадываться?
Написал же что использую библиотеку TimerOne ( ссылку дал)
вот как инициализируется объект в этой библиотеке
void TimerOne::initialize(long microseconds) { TCCR1A = 0; // clear control register A TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer setPeriod(microseconds); } void TimerOne::setPeriod(long microseconds) // AR modified for atomic access { long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum oldSREG = SREG; cli(); // Disable interrupts for 16 bit register access ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode SREG = oldSREG; TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock }вот в какое прерывание засунута моя функция :
ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt { Timer1.isrCallback(); }вот как происходит привязывание
void TimerOne::attachInterrupt(void (*isr)(), long microseconds) { if(microseconds > 0) setPeriod(microseconds); isrCallback = isr; // register the user's callback with the real ISR TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit // might be running with interrupts disabled (eg inside an ISR), so don't touch the global state // sei(); resume(); }а если в кратце то пробовал и c TIMER1 и TIMER2 без использования библиотеки TimerOne. но с прерываниями я еще на Вы и подумал, что делаю что-то не так, поэтому и подключил библиотеку TimerOne, но результат аналогичный. Вообще позволяет ли Ардуина работать с I2C по прерыванию?
MarioM, могу только высказать предположение. Где-то видимо используется прерывание, а запуск некоего кода, использующего прерывания из-под другого прерывания по-умолчанию запрещён. Попробуйте разрешить, может прокатит. Лучше пробывать без timerOne . Опция используется так: ISR(XXX_vect, ISR_NOBLOCK)
MarioM, могу наврать, но по-моему функция по указателю не так вызывается.
Как правильно - не помню, спишите откуда-нибудь. Я сам всегда списываю. :)
-----
Upd: Вот так попробуйте:
Для примера, PORTC5 переключается раз в секунду а PORTC4 раз в max_tick секунд.
#define TOGGLE(x,y) (x ^= (1<<y)) #define max_tick 5 unsigned char tick=0; unsigned char flags=0; #define sec1 0 #define Nsec 1 void timer1_init(void) { TCCR1A = 0x00; TCCR1B = 0x04; TCCR1C = 0x00; TCNT1H = 0x0B; TCNT1L = 0xDC; TIMSK1 = 0x01; } //======================================================================= ISR(TIMER1_OVF_vect) { //TIMER1 has overflowed TCNT1H = 0x0B; //reload counter high value TCNT1L = 0xDC; //reload counter low value bitSet(flags, sec1); tick++; if(tick >= max_tick) { tick = 0; bitSet(flags, Nsec); } } //======================================================================= void setup(){ timer1_init(); DDRC = 0x30; } void loop(){ if(bitRead(flags, sec1)){ bitClear(flags, sec1); // выполняется раз в секунду TOGGLE(PORTC, 5); } else if(bitRead(flags, Nsec)){ bitClear(flags, Nsec); // выполняется раз в max_tick секунд TOGGLE(PORTC, 4); } }dimax, спасибо заработало но не без глюков. Буду дальше копать.