|
|
  |
Несколько прерываний, Как разрулить? |
|
|
|
Mar 30 2011, 12:12
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
Нужно ловить два сигнала от датчиков (для простоты прямоугольные). Первый сигнал нужно измерить его длительность. Для второго сигнала просто считать количество (при каждом импульсе инкремент некоей переменной). Решил повесить эти два сигнала на INT0 и INT1. Но как разрулить - не пойму. Если по INT0 начинать считать длительность, то для этого нужен ещё и таймер. Значит третье прерывание добавляется. А что будет, если придет прерывание INT1? В общем каша образовалась. Может проще сделать вообще без прерываний, тупо в цикле опрашивать порт и смотреть, появились импульсы или нет и реагировать, если они появились? Что посоветуете?
Сообщение отредактировал Ruffian - Mar 30 2011, 12:13
|
|
|
|
|
Mar 30 2011, 19:41
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
Цитата(AHTOXA @ Mar 30 2011, 16:40)  Для измерения длительности сигналов есть специально предназначенные модули захвата (input capture). Нашёл пример, перевел его с AVRStudio на mikroc. Работать отказывается. Весь вечер просидел с ним. Думаю, может ошибся когда переводил, взял оригинальный код и собрал в AVRStudio. Код #include <avr/io.h> #include <avr/interrupt.h> #include <math.h>
// Input: Square wave on ICP PIN // This program determines the pulse width of a square wave and represents that pulse width //in a certain form in port D
double overflow_counter, rising_edge, falling_edge, pulse_width; double TOP = 65535;
//This interrupt service routine calculates the pulse width of a square wave on the ICP pin //and displays that in a certain form on PORT D
ISR(TIMER1_CAPT_vect){ if (PORTA == 0xAA) PORTA = 0x55; else PORTA == 0xAA;
// If ICP pin is set, there was a rising edge else if its low there must have been a falling edge / if (bit_is_set(PINB,1)){ rising_edge = ICR1; TCCR1B &= ~(1<<ICES1); //Capture now on falling edge overflow_counter = 0; } else{ falling_edge = ICR1; TCCR1B |= (1<<ICES1);//Capture now on rising edge pulse_width =falling_edge - rising_edge + TOP*overflow_counter;
//Test to see if correct pulse width being calculated //if pulse width is greater than 35 than PD2 goes high otherwise PD3 IS HIGH if (pulse_width>35){ PORTD |= (1<<PD2); PORTD &= ~(1<<PD3); } else{ PORTD |= (1<<PD3); PORTD &= ~(1<<PD2); } } }
ISR(TIMER1_OVF_vect){ overflow_counter++; //increment counter when overflow occurs }
int main(void){
DDRB = 0;// ICP pin as input which is pin 0 on port B/
DDRD = 0XFF; // ALL PINS on port D are set as output.
DDRA = 0xFF; PORTA = 0xAA;
sei();//enable global interrupt
//setting up Timer control register 1
//TOP VALUE IS 0XFFFF; (NORMAL MODE) TCCR1A = 0; TCCR1B = 0;
//SETS PRESCALER ON 1 TCCR1B |= (1<<CS10); TCCR1B &= ~(1<<CS11) & ~(1<<CS12);
// Enable Input noise canceller and capture time on rising edge TCCR1B |= (1<<ICES1) | (1<<ICNC1);
TIMSK = 0; TIMSK |= (1<<TICIE1); //Enable Input Capture Interrupt TIMSK |= (1<<TOIE1); //Enable timer overflow interrupt
while(1){}
} Проект настроен на 8 МГц, Атмега16. В оригинале примера сигнал читался с PB0, хотя для Timer1 должен быть вход PB1. PB0 это для Timer0. Пробовал и так и так. В конечном счёте тупо взял и запараллелил оба входа, чтобы не гадать. Счётчик работает, прерывание TIMER1_OVF_vect срабатывает исправно, а прерывание TIMER1_CAPT_vect срабатывает только один раз, когда запускается main. И больше не вызывается. Независимо от состояния порта В. В чём прикол - не могу понять
|
|
|
|
|
Mar 30 2011, 20:12
|
Местный
  
Группа: Свой
Сообщений: 289
Регистрация: 6-12-05
Пользователь №: 11 864

|
Цитата ISR(TIMER1_CAPT_vect){ if (PORTA == 0xAA) PORTA = 0x55; else PORTA == 0xAA; Здесь наверное лишнее одно равно. Дмаю должно быть так: Цитата ISR(TIMER1_CAPT_vect){ if (PORTA == 0xAA) PORTA = 0x55; else PORTA = 0xAA;
|
|
|
|
|
Mar 30 2011, 20:54
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
Да, очепятка. Правда это ничего не меняет. Прерывание срабатывает только раз
|
|
|
|
|
Mar 31 2011, 04:03
|

Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 8-12-09
Пользователь №: 54 138

|
Цитата(Ruffian @ Mar 30 2011, 23:54)  Да, очепятка. Правда это ничего не меняет. Прерывание срабатывает только раз Важное уточнение требуется. С каким периодом и с какой скважностью у Вас импульсы идут? Чтоб захват сигнала работал корректно, нужно, чтоб частота захватываемых импульсов была как минимум в 2 раза меньше тактовой частоты AVR.
Сообщение отредактировал nk@ - Mar 31 2011, 04:04
|
|
|
|
|
Mar 31 2011, 08:05
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
Я конечно тупой, но не настолько  чтобы об этом не думать. Тактовая процика 8МГц. Измеряемые импульсы - меандр частотой около 10 КГц. Какая бы частота не была, прерывание должно срабатывать при перепадах на РВ0/РВ1. Если я правильно понял суть input capture.
|
|
|
|
|
Apr 1 2011, 19:49
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
К сожалению, не удается. Даже период. Сделал иначе: подаю сигнал на INT0 и его же через инвертор на INT1. В обработчике INT0 обнуляю таймер/счётчик, в обработчике INT1 останавливаю таймер, снимаю с него количество тиков, сохраняю их и перезапуск таймера. Правда используется два входа прерывания.
|
|
|
|
|
Apr 2 2011, 15:10
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Ruffian @ Apr 2 2011, 01:49)  К сожалению, не удается. Даже период. Странно, там же нет ничего сложного: Код static u16 long_time; u32 impulse_len;
void ic_init(void) { TCCR1A = 0; TCCR1B |= _BV(ICNC1) | _BV(CS10) | _BV(ICES1);; TIMSK |= _BV(TICIE1) | _BV(TOIE1); TIFR = _BV(ICF1) | _BV(TOV1); }
SIGNAL(SIG_OVERFLOW1) { long_time++; }
SIGNAL(SIG_INPUT_CAPTURE1) { static u32 prev_ticks = 0; u16 icr = ICR1; u32 ticks;
LoWord(ticks) = icr; HiWord(ticks) = long_time;
if ((ticks < prev_ticks) && HiWord(ticks)) HiWord(ticks)++;
impulse_len = ticks - prev_ticks; prev_ticks = ticks; }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 2 2011, 18:35
|

Частый гость
 
Группа: Участник
Сообщений: 78
Регистрация: 8-12-09
Пользователь №: 54 138

|
Цитата(AHTOXA @ Apr 2 2011, 18:10)  Странно, там же нет ничего сложного: Согласен, только нужно измерять длительность импульса, а не период. Правильнее будет так: CODE volatile uint16_t long_time; volatile uint32_t pulse_time; volatile uint32_t pause_time; volatile uint8_t flag = 0;
void ic_init(void) { TCCR1A = 0; TCCR1B |= (1<<ICNC1)|(1<<ICES1)|(1<<CS10); // здесь, возможно, нужно выбрать другой prescaler TIMSK |= (1<<TICIE1)|(1<<TOIE1); TIFR = (1<<ICF1)|(1<<TOV1); asm("sei"); }
SIGNAL(SIG_OVERFLOW1) { long_time++; if(long_time==0) { // overflow detected! Обработка переполнения (если нужно) } }
SIGNAL(SIG_INPUT_CAPTURE1) { uint16_t ticks;
TCNT1=0; ticks = ICR1; long_time = 0; if(TCCR1B & (1<<ICES1)) { //rising edge detected pause_time = long_time; pause_time = (pause_time<<16) | ticks; TCCR1B &= ~(1<<ICES1); // switch to detect falling edge } else { //falling edge detected pulse_time = long_time; pulse_time = (pulse_time<<16) | ticks; TCCR1B |= 1<<ICES1; // switch to detect rising edge } flag = 1; // new data arrived }
void main_loop( void ){
while(1) { if(flag) { // Здесь обрабатываем поступившие данные flag=0; } } }
Сообщение отредактировал nk@ - Apr 2 2011, 18:36
|
|
|
|
|
Apr 2 2011, 20:54
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 4-03-11
Пользователь №: 63 397

|
Дело не в том, как посчитать длительность или период. Проблема в том, что прерывание INPUT CAPTURE не происходит вообще. Если бы оно происходило и вызывалась функция обработки прерывания, я бы там уже разобрался бы, что и как подсчитать. У меня заряжены два прерывания: TIMER1_CAPT_vect и TIMER1_OVF_vect. По переполнению TIMER1_OVF_vect исправно срабатывает, а TIMER1_CAPT_vect не происходит. Прерывания настроены так: Код DDRB = 0;// ICP pin as input which is pin 0 on port B/ sei();//enable global interrupt
//setting up Timer control register 1
//TOP VALUE IS 0XFFFF; (NORMAL MODE) TCCR1A = 0; TCCR1B = 0; //SETS PRESCALER ON 1 TCCR1B |= (1<<CS10); TCCR1B &= ~(1<<CS11) & ~(1<<CS12); // Enable Input noise canceller and capture time on rising edge TCCR1B |= (1<<ICES1)| (1<<ICNC1); //| (1<<ICNC1)
TIMSK = 0; TIMSK |= (1<<TICIE1); //Enable Input Capture Interrupt TIMSK |= (1<<TOIE1); //Enable timer overflow interrupt TIFR = _BV(ICF1) | _BV(TOV1); может ещё какие флаги не установлены? В даташите вроде всё прочитал, больше никаких управляющих регистров не задействуется.
Сообщение отредактировал Ruffian - Apr 2 2011, 20:57
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|