|
|
  |
разделение источников в прерывании TIMERB1, какой то глюк с TBIV |
|
|
|
Oct 24 2006, 09:44
|
Частый гость
 
Группа: Свой
Сообщений: 105
Регистрация: 14-01-05
Из: Москва Зеленоград
Пользователь №: 1 962

|
есть 4 исмпульсных сигнала, частоту которых необходимо померить. Для этого хочу использовать режим захвата таймера B входы TB0-TB3 c TB0 все нормальнго , для него отдельное прервывание TIMERB0 а вот на 3 сигнала TB1-TB3 вектор один - TIMERB1 в мануале предлагается по регистру TBIV определять сточник прерывания даже есть примерчик на асме. Я пришу прогу на IAR C вот код прерывания: Код #pragma vector=TIMERB1_VECTOR __interrupt void Timer_B1 (void) { unsigned char tbiv = TBIV; // (1)
if(tbiv == 0x02) // (2) { delta1 = TBCCR1 - count1; count1 = TBCCR1; } if(tbiv == 0x04) { delta2 = TBCCR2 - count2; count2 = TBCCR2; } if(tbiv == 0x06) { delta3 = TBCCR3 - count3; count3 = TBCCR3; }
} однако ни одна ветка не не выполняется в режиме реального времени, хотя в отладке по шагам все работает если поставить точки останова в строках (1) и (2), и после остановки в (1) выполнить переход по шагам то tbiv получает парвильное значение и все работает если после остановки в (1) нажать F5 то программа остановится в (2) но tbiv будет =0, и ниодна ветка не сработает, хотя отлабчик упорно показывает что TBIV = 0x2. У меня мысль что TBIV сбрасывается еще до входа в прерывание , а при отладке по шагам TBIV вновь устанавливается от нового захвата (импульсы продолжают идти) Вообщем я уже порядочно запутался.
|
|
|
|
|
Oct 24 2006, 13:19
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37

|
А почему Вы не использовали swith, интересно. Вот мой код из изделия, все работает прекрасно. Тут, правда, измеряется 1 сигнал, но не в этом проблема, в другом изделии измеряется несколько. В третьем 2 последовательных порта на таймереА в дуплексе молотят, правда со скорость 19200. Код #define QUANTUM_B ID_0 // Входной делитель для таймера В (квант таймера В)
#if ( QUANTUM_B == ID_0 ) // == 1 (2/3 us) #define MAGIC_tax 180000000L // Постоянная для перевода измереного в квантах периода в об/мин #define MAX_tax_h 0x0132 // приблизительно 9 об/мин = 13.3 секунд период #define tax_h_0300 0x0009 // приблизительно 300 об/мин #define tax_h_0700 0x0004 // приблизительно 700 об/мин #elif ( QUANTUM_B == ID_1 ) // == 2 (4/3 us) #define MAGIC_tax 90000000L // Постоянная для перевода измереного в квантах периода в об/мин #define MAX_tax_h 0x0099 // приблизительно 9 об/мин = 13.3 секунд период #define tax_h_0300 0x0005 // приблизительно 300 об/мин #define tax_h_0700 0x0002 // приблизительно 700 об/мин #elif ( QUANTUM_B == ID_2 ) // == 4 (8/3 us) #define MAGIC_tax 45000000L // Постоянная для перевода измереного в квантах периода в об/мин #define MAX_tax_h 0x004d // приблизительно 9 об/мин = 13.3 секунд период #define tax_h_0300 0x0002 // приблизительно 300 об/мин #define tax_h_0700 0x0001 // приблизительно 700 об/мин #endif //QUANTUM_B
#define tax_T_MAX ULONG_MAX
void tax_ini( void ) { tax_T = tax_T_MAX; tax_h = MAX_tax_h; P4SEL = BINARY( 01000000 ); // Capture6 P4DIR = BINARY( 00111111 ); P4OUT = BINARY( 00000000 );
// Capture6 по фронту, входной сигнал CCI6A, Синхронный, Режим захвата, прерывание TBCCTL6 = CM_1 + CCIS_0 + SCS + CAP + CCIE; // Настроим таймер B TBCTL = TBSSEL_2 // тактирование от SMCLK = 1.5 МГц + QUANTUM_B // входной делитель + MC_2 // Непрерывный режим: таймер считает вверх к 0ffffh + TBIE; // прерывание }
#pragma vector=TIMERB1_VECTOR __interrupt void TIMERB1_isr( void ) // 12 * 2 - 0xfff8 Timer B 1-7 { unsigned long t; static unsigned short c6zero; // "нулевое" состояние таймера ("вес тары") для Capture6
switch ( __even_in_range( TBIV, 0x0e )) { // + Compare1 - case 0x02: break; // - Compare1 -
// + Capture/Compare2 - case 0x04: break; // - Capture/Compare2 -
// + Capture/Compare3 - case 0x06: break; // - Capture/Compare3 -
// + Capture/Compare4 - case 0x08: break; // - Capture/Compare4 -
// + Capture/Compare5 - case 0x0a: break; // - Capture/Compare5 -
// + Capture6 - измерение периода вращения case 0x0c: t = tax_h * 0x10000L + TBCCR6; t -= c6zero; // вычтем "нулевое" состояние таймера ("вес тары") c6zero = TBCCR6; // сохраним "нулевое" состояние таймера ("вес тары") if ( tax_h > tax_h_0300 ) tax_T = t; else if ( tax_h > tax_h_0700 ) tax_T = ( tax_T + t ) / 2; // Вращается быстро, немного усредним else tax_T = ( 3 * tax_T + t ) / 4; // Вращается совсем быстро, усредним сильнее tax_h = 0; // сбросим старшее слово break; // - Capture6 - измерение периода вращения
// + переполнение таймера, считаем старшее слово case 0x0e: // переполнение таймера, считаем старшее слово if ( tax_h < MAX_tax_h ) // ограничиваем минимальные обороты tax_h++; else tax_T = tax_T_MAX; // минимальные обороты достигнуты break; // - переполнение таймера, считаем старшее слово } }
--------------------
Если зайца бить, его можно и спички научить зажигать Сколько дурака не бей - умнее не будет. Зато опытнее
|
|
|
|
|
Oct 25 2006, 06:23
|
Частый гость
 
Группа: Свой
Сообщений: 105
Регистрация: 14-01-05
Из: Москва Зеленоград
Пользователь №: 1 962

|
как я понял вся разница в использовании или нет функции __even_in_range насчет switch или if? у меня раньше и был switch, надо будет к ней вернуться единственно что ни как не вкурю что за __even_in_range и что она делает референсгуайд и нелп читал , не помогает Цитата(CompilerReferenceGuide) The interrupt vector register contains information about the interrupt source, and the interrupt service routine normally uses a switch statement to find out which interrupt source issued the interrupt. To help the compiler generate optimal code for the switch statement, the intrinsic function __even_in_range must be used. The following example defines a Timer A interrupt routine: Код #pragma vector=TIMERA1_VECTOR __interrupt void Timer_A1_ISR(void) { switch (__even_in_range(TAIV, 10)) { case 2: P1POUT ˆ= 0x04; break; case 4: P1POUT ˆ= 0x02; break; case 10: P1POUT ˆ= 0x01; break; } } The intrinsic function __even_in_range requires two parameters, the interrupt vector register and the last value in the allowed range. The effect of the intrinsic function is that the generated code can only handle even values within the given range, which is exactly what is required in this case as the interrupt vector register for Timer A can only be 0, 2, 4, 6, 8, or 10. If the __even_in_range intrinsic function is used in a case where an odd value, or a value outside the given range could occur, the program will fail.
|
|
|
|
|
Oct 25 2006, 06:45
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(-=Space=- @ Oct 24 2006, 15:44)  однако ни одна ветка не не выполняется в режиме реального времени, хотя в отладке по шагам все работает если поставить точки останова в строках (1) и (2), и после остановки в (1) выполнить переход по шагам то tbiv получает парвильное значение и все работает если после остановки в (1) нажать F5 то программа остановится в (2) но tbiv будет =0, и ниодна ветка не сработает, хотя отлабчик упорно показывает что TBIV = 0x2.
У меня мысль что TBIV сбрасывается еще до входа в прерывание , а при отладке по шагам TBIV вновь устанавливается от нового захвата (импульсы продолжают идти) Вообщем я уже порядочно запутался. Цитата из Компэловской книги "Семейство микроконтроллеров MSP430x1xx. Руководство пользователя." Код Генератор вектора прерывания TBIV Флаг TBIFG и флаги TBCCRx CCIFG (кроме TBCCR0 CCIFG) распределены по при- оритетам и объединены в источник одного вектора прерывания. Регистр вектора пре- рывания TBIV используется для определения, какой флаг запросил прерывание. Разрешенное прерывание с наивысшим приоритетом (кроме TBCCR0 CCIFG) генерирует число в регистре TBIV (см. описание регистра). Можно оце- нить это число или добавить его к программному счетчику для автоматическо- го входа в соответствующую процедуру программы. Запрещенные прерывания таймера В не воздействуют на значение TBIV. Любой тип доступа: чтение или запись регистра TBIV автоматически сбра- сывает флаг наивысшего ожидающего прерывания. Если установлен другой флаг прерывания, будет немедленно сгенерировано другое прерывание после обработки изначального прерывания. К примеру, если флаги TBCCR1 и TBCCR2 CCIFG установлены, когда процедура обработки прерывания обращается к ре- гистру TBIV, флаг TBCCR1 CCIFG автоматически сбрасывается. После выпол- нения команды процедуры обработки прерывания RETI, флаг TBCCR2 CCIFG генерирует другое прерывание. Во-первых, проверьте разрешены ли у вас идивидуальные прерывания от регистров capture - бит CCIE в регистрах TBCCTLx. Во-вторых, для того чтобы обслужить все флаги в одном прерывании нужно прочитать TBIV столько раз сколько имеется источников прерываний в данном модуле (6+1). У вас же насколько я вижу TBIV читается один раз. Поэтому обрабатываться за одно прерывание может только один источник прерываний модуля TimerB. И для обработки трех установленных флагов (в вашем случае) прерывание должно быть вызвано последовательно три раза.
|
|
|
|
|
Oct 25 2006, 07:51
|
Частый гость
 
Группа: Свой
Сообщений: 105
Регистрация: 14-01-05
Из: Москва Зеленоград
Пользователь №: 1 962

|
попробовал с функцией __even_in_range вообщем она влияет на компиляциию и в асме видно что код становится короче девайса пока нет, проверить в железе не могу, но в Симуляции НЕ работает!!! прерывание вызывается, но ни в один из cаse не заходит в симуляторе TBIV упорно хранит 0, хотя прерывания вызывал пачками давайте выложу проект полностью
|
|
|
|
|
Oct 25 2006, 20:58
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Shread @ Oct 26 2006, 01:42)  Цитата(-=Space=- @ Oct 25 2006, 11:51)  попробовал с функцией __even_in_range вообщем она влияет на компиляциию и в асме видно что код становится короче девайса пока нет, проверить в железе не могу, но в Симуляции НЕ работает!!!
прерывание вызывается, но ни в один из cаse не заходит в симуляторе TBIV упорно хранит 0, хотя прерывания вызывал пачками
давайте выложу проект полностью
Симулятор периферию не симулит, в том числе таймеры. Точнее будет сказать не полностью симулирует. В C-CPY есть оконо Forced Interrupt Window, где можно симулировать прерывания, выбрав нужное и кликнув по кнопке Trigger. В поле Description этого окна указаны пары: маска прерывания и флаг прерывания. Например, у вектора TIMERB1_VECTOR можно вызвать прерывания с маской TBCCTLx.CCIE и флагом TBCCTLx.CCIFG (где x - номер соответствующего регистра capture/compare). Но если, остановив дебаггер, последовательно симулировать вызов нескольких разных прерываний с вектором TIMERB1_VECTOR, а потом немного пошагать, то видно что симулятор вполне правильно установил флаги соответствующих прерываний в регистрах TBCCTLx. И сбрасываются они по одному при каждом вызове прерывания с вектором TIMERB1_VECTOR в соответствии с их приоритетами. А вот TBIV при этом действительно не изменяется и если нужно проверить логику выполнения ветвлений по TBIV, то его значение следует выставлять в симуляторе ручками.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|