MSP430 Генерация пачки импульсов при помощи таймера А
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Цикл while, в данном конкретном случае, не нужен, если только МК не будет делать еще что-то.
Следовало-бы проиниацилизировать переменные pauseCnt и pulseCnt их соответствующими значениями из дефайном в начале кода в функции настройки таймера.
Следовало-бы проиниацилизировать переменные pauseCnt и pulseCnt их соответствующими значениями из дефайном в начале кода в функции настройки таймера.
- Реклама
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Вот полностью весь код:
#include "msp430f149.h"
#define PULSE_CNT 5 // # of pulses in a burst
#define PAUSE_CNT 10 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
char pulseCnt, pauseCnt;
void wait( volatile int i ){
while ( i-- > 0 );
}
void Ports_config()
{
P1SEL = BIT6; // assign P1.2 to TimerA
P1DIR = BIT6;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1DIR &= ~BIT0;
}
void flash() {
P1OUT = 0x01;
wait((int)5000);
P1OUT &= ~0x01;
wait((int)10000);
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 10;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
}
#pragma vector=TIMER0_A1_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
(TACTL & TAIFG)==0;
// TA0CTL_bit.TAIFG = 0; // clear TimerA interrupt
if (timerMode)
{
if (!(--pauseCnt)) // pause is over is complete
{
pauseCnt = PAUSE_CNT; // restore pause counter
timerMode = 0; // switch to the other mode
TACCTL1 = OUTMOD_7; // toggle mode
}
}
else
{
if (!(--pulseCnt)) // burst is complete
{
pulseCnt = PULSE_CNT; // restore pulse counter
timerMode = 1; // switch to the other mode
TACCTL1 = OUTMOD_5; // reset mode
}
}
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
//Clock_config(); // set 8 MHz MSCK, 2 MHz SMCLK
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
__enable_interrupt(); // enable interrupts globally
__low_power_mode_0(); // wait for char receive
while(1)
{
__no_operation();
}
}
А если во время паузы необходимо включать таймер B в режиме захвата, необходимо в прерывании добавить или в main?
#include "msp430f149.h"
#define PULSE_CNT 5 // # of pulses in a burst
#define PAUSE_CNT 10 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
char pulseCnt, pauseCnt;
void wait( volatile int i ){
while ( i-- > 0 );
}
void Ports_config()
{
P1SEL = BIT6; // assign P1.2 to TimerA
P1DIR = BIT6;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1DIR &= ~BIT0;
}
void flash() {
P1OUT = 0x01;
wait((int)5000);
P1OUT &= ~0x01;
wait((int)10000);
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 10;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
}
#pragma vector=TIMER0_A1_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
(TACTL & TAIFG)==0;
// TA0CTL_bit.TAIFG = 0; // clear TimerA interrupt
if (timerMode)
{
if (!(--pauseCnt)) // pause is over is complete
{
pauseCnt = PAUSE_CNT; // restore pause counter
timerMode = 0; // switch to the other mode
TACCTL1 = OUTMOD_7; // toggle mode
}
}
else
{
if (!(--pulseCnt)) // burst is complete
{
pulseCnt = PULSE_CNT; // restore pulse counter
timerMode = 1; // switch to the other mode
TACCTL1 = OUTMOD_5; // reset mode
}
}
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
//Clock_config(); // set 8 MHz MSCK, 2 MHz SMCLK
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
__enable_interrupt(); // enable interrupts globally
__low_power_mode_0(); // wait for char receive
while(1)
{
__no_operation();
}
}
А если во время паузы необходимо включать таймер B в режиме захвата, необходимо в прерывании добавить или в main?
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Не понял зачем его вообще включать для данного приложения? В коде прерывание происходит каждый раз по достижении счетчиком таймера его максимального значения. Вопрос первоначально был как обойтись одним таймером. Чего хотите добиться сейчас, задействовав второй таймер?
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Вообще задача в том, чтобы отправлять с таймера А пачку импульсов и принимать пришедший сигнал на таймер В.
Решила постепенно разбираться.
Сейчас мне не понятно, почему в прерывании не выполняются условия.
Также есть вопрос, как добавить в данный код работу таймера В.
Есть еще вопрос почему код по захвату у меня не заходит в прерывание:
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P4DIR &= ~BIT0;
P4SEL |= BIT0;
timerB_init();
__bis_SR_register(LPM0_bits + GIE); // LPM0 + Enable global ints
}
void timerB_init()
{
TBCCTL0=CM_1+SCS+CCIS_1+CAP+CCIE;
TBCTL=MC_2+TBSSEL_2;
}
#pragma vector = TIMERB0_VECTOR
__interrupt void TIMERB0_VECTOR_ISR (void)
{
__no_operation();
}
Да и почему-то записывает не в те регистры флаг прерывания.
Решила постепенно разбираться.
Сейчас мне не понятно, почему в прерывании не выполняются условия.
Также есть вопрос, как добавить в данный код работу таймера В.
Есть еще вопрос почему код по захвату у меня не заходит в прерывание:
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P4DIR &= ~BIT0;
P4SEL |= BIT0;
timerB_init();
__bis_SR_register(LPM0_bits + GIE); // LPM0 + Enable global ints
}
void timerB_init()
{
TBCCTL0=CM_1+SCS+CCIS_1+CAP+CCIE;
TBCTL=MC_2+TBSSEL_2;
}
#pragma vector = TIMERB0_VECTOR
__interrupt void TIMERB0_VECTOR_ISR (void)
{
__no_operation();
}
Да и почему-то записывает не в те регистры флаг прерывания.
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Потому что таймер стоит и не считает. Запишите значение МС_1 в TBCTL. Кроме того, TBCL0=0 дефолтно и для запуска таймера там должно быть ненулевое значение. Ну и ещё этот таймер, согласно конфигурации тактируется от ACLK. Чему равна эта частота (из кода определить это невозможно)?почему код по захвату у меня не заходит в прерывание
Остальные вопросы я не понял. Что значит "принимать пришедший сигнал на таймер В"? И какие условия должны выполняться в прерывании (сейчас там никаких условий не проверяется)?
Напишите нормально что надо сделать, я не телепат. Если это студенческая методичка, лучше выложите её сюда полностью. Кроме того, какие имеете средства отладки (FET debugger? Лог. анализатор? Среда разработки?). Если у Вас демо-плата с MSP430, что за плата.
- Реклама
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Задача в том, чтобы отправлять пачку импульсов с таймера А на ультразвуковой датчик, излучать, а затем принимать усиленный отраженный сигнал на вход таймера В.
Прерывания таймера В должны происходить тогда, когда на вход его поступает отраженный сигнал. Нужно выводить время с начала запуска таймера В и захвата сигнала. Также останавливать таймер и запускать заново после расчета времени.
Вообще я тактирую от SMCLK (TBSELL_2) ибо когда пыталась от ACLK таймер В не считал.
Среда разработки - code composer studio.
Демо платы нет, есть схема с микроконтроллером msp430f149. Средство отладки - FET debugger.
Прерывания таймера В должны происходить тогда, когда на вход его поступает отраженный сигнал. Нужно выводить время с начала запуска таймера В и захвата сигнала. Также останавливать таймер и запускать заново после расчета времени.
Вообще я тактирую от SMCLK (TBSELL_2) ибо когда пыталась от ACLK таймер В не считал.
Среда разработки - code composer studio.
Демо платы нет, есть схема с микроконтроллером msp430f149. Средство отладки - FET debugger.
Re: MSP430 Генерация пачки импульсов при помощи таймера А
В прошлый раз я был не прав с советами. Теперь задачу понял. Вот рабочий код использования Таймера для захвата. Он измеряет длительность нажатия кнопки, подсоединённой между P1.1 и землёй. Для этого в P1.1 задействован внутренний подтягивающий резистор. Только что протестил его на макетке при тактировании таймера от ACLK. Код работает с Таймером А, т.к. в моём МК G2553 нет Таймера B, однако работа с последним полностью аналогична. В принципе, код работы с таймером у Вас был правильный. Следует только сбрасывать флаг прерывания в ISR.
Спойлер
Код: Выделить всё
#include "io430.h"
void Clock_config(); // function prototypes
void Ports_config();
void TimerA_config();
unsigned int lastCapture;
unsigned int duration; // button press duration
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
Clock_config(); // set 8 MHz MSCK, 2 MHz SMCLK
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module capture
__enable_interrupt(); // enable interrupts globally
while(1)
{
__low_power_mode_0(); // wait for capture
__no_operation();
__no_operation(); // set breakpoint here to examine duration
}
}
void Clock_config() // configure basic clock module
{
DCOCTL = CALDCO_8MHZ; // set 8 MHz MCLK
BCSCTL1 = CALBC1_8MHZ;
BCSCTL2 = DIVS_1;
BCSCTL3 = LFXT1S1; // select VLO as ACLK
}
void Ports_config()
{
P1SEL = P1; // assign P1.1 to TimerA input
P1DIR &= ~P1; // and configure it for capture
P1REN = P1; // enable pull-up resistor
P1OUT = P1;
}
void TimerA_config()
{
TA0CCTL0 = CM_3 | SCS | CAP | CCIE;
TA0CTL = TASSEL_1 + MC_2 + TACLR;
}
#pragma vector=TIMER0_A0_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
if (P1IN & P1) // button is released
{
duration = TACCR0 - lastCapture;
__low_power_mode_off_on_exit();
}
lastCapture = TACCR0;
TA0CCTL0_bit.CCIFG = 0; // clear TimerA capture
} -
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Большое спасибо за листинг!
В данном примере
#pragma vector=TIMER0_A0_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
if (P1IN & P1) // button is released
{
duration = TACCR0 - lastCapture;
__low_power_mode_off_on_exit();
}
lastCapture = TACCR0;
TA0CCTL0_bit.CCIFG = 0; // clear TimerA capture
}
есть условие if (P1IN & P1) , а если не использовать кнопку, то условие должно быть: что если CAP ==1? или просто if(CCIFG)?
В данном примере
#pragma vector=TIMER0_A0_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
if (P1IN & P1) // button is released
{
duration = TACCR0 - lastCapture;
__low_power_mode_off_on_exit();
}
lastCapture = TACCR0;
TA0CCTL0_bit.CCIFG = 0; // clear TimerA capture
}
есть условие if (P1IN & P1) , а если не использовать кнопку, то условие должно быть: что если CAP ==1? или просто if(CCIFG)?
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Не нужно там никакого условия. Вход в обработчик прерывания произойдёт как только совершится захват.
Кстати, я вспомнил, что у меня есть MSP430FR5730 с Таймером B и адаптировал код для IAR под него.
В схеме помимо МК есть кнопка между выводом P2.1 и землёй. Таймер Б изначально остановлен и программа ожидает прерывания по спаду уровня на P2.1, которое происходит по нажатии на кнопку. Как произойдёт нажатие, пин P2.1 переконфигурируется на работу с модулем захвата канала 0 Таймера Б и сам таймер запускается в режим захвата по нарастающему уровню сигнала на P2.1, который образуется по отпускании кнопки. Как только захват произойдёт, таймер останавливается, кнопка переконфигугируется на GPIO и весь процесс повторяется. В этом примере Таймер Б тактируется от кварцевого генератора XT1 на порте J, стабилизированным часовым кристаллом. Код проверен в железе и работоспособность его гарантируется.
Кстати, я вспомнил, что у меня есть MSP430FR5730 с Таймером B и адаптировал код для IAR под него.
Спойлер
Код: Выделить всё
#include "io430.h"
void Clock_config(); // function prototypes
void Ports_config();
void TimerB_config();
unsigned int lastCapture;
unsigned int duration; // button press duration
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
REFCTL0_L |= REFTCOFF; // disable temp sensor
Ports_config(); // set up ports for GPIO
Clock_config(); // set 8 MHz MSCK, 1 MHz SMCLK
TimerB_config(); // configure TimerB module capture
__enable_interrupt(); // enable interrupts globally
while(1)
{
__low_power_mode_0(); // wait for capture
__no_operation();
__no_operation(); // set breakpoint here to examine duration
}
}
void Clock_config() // configure clock system
{
CSCTL0_H = CSKEY_H; // unlock the clock interface
CSCTL4_L = XT1DRIVE1; // crystal drive level
while (SFRIFG1_L & OFIFG) // wait for 32KHz oscillator to start
{
CSCTL5_L &= ~XT1OFFG; // clear XT1 fault flag
SFRIFG1_L &= ~OFIFG; // clear oscillator fault flag
}
CSCTL3 = DIVS_3; // set 8 MHz MCLK, SMCLK
}
void Ports_config()
{
P2DIR_bit.P2DIR1 = 0; // assign P2.1 to TimerB input
P2REN_bit.P2REN1 = 1; // enable pull-up resistor on P2.1
P2OUT_bit.P2OUT1 = 1;
P2IES_bit.P2IES1 = 1; // enable button falling edge interrupt
P2IE_bit.P2IE1 = 1; // enable button interrupt
P2IFG_bit.P2IFG1 = 0; // clear interrupt flag
PJSEL0_L = PJSEL0_4 | PJSEL0_5; // config Xtal pins for X1OSC
}
void TimerB_config()
{
TB0CCTL0 = CM_1 | SCS | CAP | CCIE;
}
#pragma vector=PORT2_VECTOR // PORT2 handler
__interrupt void PORT2_ISR(void)
{
if (P2IFG & PAIFG1) // button interrupt?
{
TB0CTL = TASSEL_1 + MC_2 + TBCLR; // start capture
lastCapture = 0;
P2IE_bit.P2IE1 = 0; // disable button interrupt
P2SEL1_bit.P2SEL1_1 = 1; // reassign button for TimerB
P2SEL0_bit.P2SEL0_1 = 1;
P2IFG_bit.P2IFG1 = 0; // clear interrupt flag
}
}
#pragma vector=TIMER0_B0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
P2SEL1_bit.P2SEL1_1 = 0; // reassign button to GPIO
P2SEL0_bit.P2SEL0_1 = 0;
P2IE_bit.P2IE1 = 1; // enable button interrupt
P2IFG_bit.P2IFG1 = 0; // clear button interrupt flag
TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
TB0CCTL0_bit.CCIFG = 0; // clear TimerB capture flag
__low_power_mode_off_on_exit(); // wake up CPU on exit
} В схеме помимо МК есть кнопка между выводом P2.1 и землёй. Таймер Б изначально остановлен и программа ожидает прерывания по спаду уровня на P2.1, которое происходит по нажатии на кнопку. Как произойдёт нажатие, пин P2.1 переконфигурируется на работу с модулем захвата канала 0 Таймера Б и сам таймер запускается в режим захвата по нарастающему уровню сигнала на P2.1, который образуется по отпускании кнопки. Как только захват произойдёт, таймер останавливается, кнопка переконфигугируется на GPIO и весь процесс повторяется. В этом примере Таймер Б тактируется от кварцевого генератора XT1 на порте J, стабилизированным часовым кристаллом. Код проверен в железе и работоспособность его гарантируется.
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
А не могли бы Вы объяснить, почему при выполнении кода пошагово, все застревает в прерывании Таймера А? Что-то я забыла добавить?
#include "msp430f149.h"
#define PULSE_CNT 5 // # of pulses in a burst
#define PAUSE_CNT 10 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
char pulseCnt, pauseCnt;
unsigned int lastCapture;
unsigned int duration;
void Ports_config()
{
P1SEL = BIT6; // assign P1.2 to TimerA
P1DIR = BIT6;
P4SEL = BIT0; //timer B
P4DIR &= ~BIT0;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1DIR &= ~BIT0;
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 7;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
}
void TimerB_config()
{
TB0CCTL0 = CM_3 | SCS | CAP | CCIE;
TB0CTL = TBSSEL_1 + MC_2 + TBCLR;
}
//————————Timer A interrupt——————
#pragma vector=TIMER0_A1_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
(TACTL & TAIFG) == 0;
// TA0CTL_bit.TAIFG = 0; // clear TimerA interrupt
if (timerMode)
{
if (!(--pauseCnt)) // pause is over is complete
{
pauseCnt = PAUSE_CNT; // restore pause counter
timerMode = 0; // switch to the other mode
TACCTL1 = OUTMOD_7; // toggle mode
}
}
else
{
if (!(--pulseCnt)) // burst is complete
{
pulseCnt = PULSE_CNT; // restore pulse counter
timerMode = 1; // switch to the other mode
TACCTL1 = OUTMOD_5; // reset mode
}
}
}
//————————Timer B interrupt——————
#pragma vector=TIMERB0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
if(TBR < 300)
P1OUT &= ~BIT0;
lastCapture = 0;
TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
__low_power_mode_off_on_exit(); // wake up CPU on exit
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
TimerB_config();
__enable_interrupt(); // enable interrupts globally
__low_power_mode_0(); // wait for char receive
}
#include "msp430f149.h"
#define PULSE_CNT 5 // # of pulses in a burst
#define PAUSE_CNT 10 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
char pulseCnt, pauseCnt;
unsigned int lastCapture;
unsigned int duration;
void Ports_config()
{
P1SEL = BIT6; // assign P1.2 to TimerA
P1DIR = BIT6;
P4SEL = BIT0; //timer B
P4DIR &= ~BIT0;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1DIR &= ~BIT0;
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 7;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
}
void TimerB_config()
{
TB0CCTL0 = CM_3 | SCS | CAP | CCIE;
TB0CTL = TBSSEL_1 + MC_2 + TBCLR;
}
//————————Timer A interrupt——————
#pragma vector=TIMER0_A1_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
(TACTL & TAIFG) == 0;
// TA0CTL_bit.TAIFG = 0; // clear TimerA interrupt
if (timerMode)
{
if (!(--pauseCnt)) // pause is over is complete
{
pauseCnt = PAUSE_CNT; // restore pause counter
timerMode = 0; // switch to the other mode
TACCTL1 = OUTMOD_7; // toggle mode
}
}
else
{
if (!(--pulseCnt)) // burst is complete
{
pulseCnt = PULSE_CNT; // restore pulse counter
timerMode = 1; // switch to the other mode
TACCTL1 = OUTMOD_5; // reset mode
}
}
}
//————————Timer B interrupt——————
#pragma vector=TIMERB0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
if(TBR < 300)
P1OUT &= ~BIT0;
lastCapture = 0;
TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
__low_power_mode_off_on_exit(); // wake up CPU on exit
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
TimerB_config();
__enable_interrupt(); // enable interrupts globally
__low_power_mode_0(); // wait for char receive
}
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Нужно раскомментить строку где сбрасывается флаг прерывания ТаймераА в его обработчике, если синтакс позволяет. Как написано сделано неправильно. Попробуйте так: TACTL &= ~TAIFG;
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Исправила, но все равно зациклился в обработчике(
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Я не пишу под CCS и не знаю его синтаксиса. Нужно добиться сброса флага прерывания в отладчике. При пошаговой отладке в пока находитесь в прерывании после сброса флага может сгенерироваться новое и тогда отладка зациклится. Лучше отладчиком пошагово в прерывание не заходить. Вообще, зачем пошагово отлаживаете? Убирайте здесь длинные листинги под спойлер и пользуйтесь тагом "код". Там хоть какое-то форматирование текста есть.
Добавлено позже:
Для гарантированного сброса флага таймера А, независимо от того как в CCS определена константа TAIFG, напишите:
TACTL &= 0xFFFE;
Причина невыхода из прерывания Таймера А ещё и в том, что при выходе из прерывания состояние процессора восстанавливается таким, которым оно было до входа. А поскольку в main() процессор помещается в сон, то и пробуждаться по выходу из обработчика он не будет.
Посмотрев Ваш код подробнее не обнаружил там сброса флага Таймера Б - тогда код и там циклится будет, принимая во внимание, что приоритет таймера Б выше, чем А. В моём коде выше для этого была строчка:
TB0CCTL0_bit.CCIFG = 0;
Кроме того, если в конце обработчика таймера Б стоит
__low_power_mode_off_on_exit();
то куда будет выход по пробуждении, если в main() нет цикла?
Я модифицировал свой код, следуя Вашему. У меня он выходит в main() там где указано установить breakpoint. Для этого я подсоединил выход PWM (у меня Р1.0) к входу захвата Таймера Б (Р2.1). Только смысла я в нём не вижу. Захват будет& происходить по первому фронту импульса PWM и переменная duration будет всегда принимать разные значения, что и подтверждается на практике.
Добавлено позже:
Для гарантированного сброса флага таймера А, независимо от того как в CCS определена константа TAIFG, напишите:
TACTL &= 0xFFFE;
Причина невыхода из прерывания Таймера А ещё и в том, что при выходе из прерывания состояние процессора восстанавливается таким, которым оно было до входа. А поскольку в main() процессор помещается в сон, то и пробуждаться по выходу из обработчика он не будет.
Посмотрев Ваш код подробнее не обнаружил там сброса флага Таймера Б - тогда код и там циклится будет, принимая во внимание, что приоритет таймера Б выше, чем А. В моём коде выше для этого была строчка:
TB0CCTL0_bit.CCIFG = 0;
Кроме того, если в конце обработчика таймера Б стоит
__low_power_mode_off_on_exit();
то куда будет выход по пробуждении, если в main() нет цикла?
Я модифицировал свой код, следуя Вашему. У меня он выходит в main() там где указано установить breakpoint. Для этого я подсоединил выход PWM (у меня Р1.0) к входу захвата Таймера Б (Р2.1). Только смысла я в нём не вижу. Захват будет& происходить по первому фронту импульса PWM и переменная duration будет всегда принимать разные значения, что и подтверждается на практике.
Спойлер
Код: Выделить всё
#include "io430.h"
#define PULSE_CNT 5 // # of pulses in a burst
#define PAUSE_CNT 10 // pause duration
void Clock_config(); // function prototypes
void Ports_config();
void TimerA_config();
void TimerB_config();
unsigned int lastCapture;
unsigned int duration; // button press duration
char timerMode; // 0: burst, 1:pause
char pulseCnt, pauseCnt;
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
REFCTL0_L |= REFTCOFF; // disable temp sensor
Ports_config(); // set up ports for GPIO
Clock_config(); // set 8 MHz MSCK, 1 MHz SMCLK
TimerA_config(); // configure TimerA module for PWM
TimerB_config(); // configure TimerB module capture
while(1)
{
__low_power_mode_0(); // wait for capture
__no_operation();
__no_operation(); // set breakpoint here to examine duration
}
}
void Clock_config() // configure clock system
{
CSCTL0_H = CSKEY_H; // unlock the clock interface
CSCTL4_L = XT1DRIVE1; // crystal drive level
while (SFRIFG1_L & OFIFG) // wait for 32KHz oscillator to start
{
CSCTL5_L &= ~XT1OFFG; // clear XT1 fault flag
SFRIFG1_L &= ~OFIFG; // clear oscillator fault flag
}
CSCTL3 = DIVS_3; // set 8 MHz MCLK/1MHz SMCLK
}
void Ports_config()
{
P1SEL1_bit.P1SEL1_0 = 0; // assign P1.0 to TimerA0.1
P1SEL0_bit.P1SEL0_0 = 1;
P1DIR_bit.P1DIR0 = 1;
P2SEL1_bit.P2SEL1_1 = 1; // assign button for TimerB input
P2SEL0_bit.P2SEL0_1 = 1;
// P2DIR_bit.P2DIR1 = 0; // assign P2.1 to GPIO
// P2REN_bit.P2REN1 = 1; // enable pull-up resistor on P2.1
// P2OUT_bit.P2OUT1 = 1;
// P2IES_bit.P2IES1 = 1; // enable button falling edge interrupt
// P2IE_bit.P2IE1 = 1; // enable button interrupt
// P2IFG_bit.P2IFG1 = 0; // clear interrupt flag
PJSEL0_L = PJSEL0_4 | PJSEL0_5; // config Xtal pins for X1OSC
}
void TimerA_config()
{
TA0CCR0 = 18; // timer period
TA0CCR1 = 10; // PWM duty
TA0CCTL1 = OUTMOD_7; // toggle output
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE; // start timer
timerMode = 0;
pauseCnt = PAUSE_CNT;
pulseCnt = PULSE_CNT;
}
void TimerB_config()
{
TB0CCTL0 = CM_1 | SCS | CAP | CCIE;
TB0CTL = TASSEL_1 + MC_2 + TBCLR; // start capture
lastCapture = 0;
}
#pragma vector=PORT2_VECTOR // PORT2 handler
__interrupt void PORT2_ISR(void)
{
if (P2IFG & PAIFG1) // button interrupt?
{
TB0CTL = TASSEL_1 + MC_2 + TBCLR; // start capture
lastCapture = 0;
P2IE_bit.P2IE1 = 0; // disable button interrupt
P2SEL1_bit.P2SEL1_1 = 1; // reassign button for TimerB
P2SEL0_bit.P2SEL0_1 = 1;
P2IFG_bit.P2IFG1 = 0; // clear interrupt flag
}
}
#pragma vector=TIMER0_A1_VECTOR // TimerA handler
__interrupt void TimerA_ISR(void)
{
TA0CTL_bit.TAIFG = 0; // clear TimerA interrupt
if (timerMode)
{
if (!(--pauseCnt)) // pause is over is complete
{
pauseCnt = PAUSE_CNT; // restore pause counter
timerMode = 0; // switch to the other mode
TA0CCTL1 = OUTMOD_7; // toggle mode
}
}
else
{
if (!(--pulseCnt)) // burst is complete
{
pulseCnt = PULSE_CNT; // restore pulse counter
timerMode = 1; // switch to the other mode
TA0CCTL1 = OUTMOD_5; // reset mode
}
}
}
#pragma vector=TIMER0_B0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
// P2SEL1_bit.P2SEL1_1 = 0; // reassign button to GPIO
// P2SEL0_bit.P2SEL0_1 = 0;
// P2IE_bit.P2IE1 = 1; // enable button interrupt
// P2IFG_bit.P2IFG1 = 0; // clear button interrupt flag
// TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
TB0CCTL0_bit.CCIFG = 0; // clear TimerB capture flag
__low_power_mode_off_on_exit(); // wake up CPU on exit
} -
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Большое спасибо за вашу помощь!!)
Сегодня я смогла добраться до осциллографа и посмотреть что происходит.
Пачки излучаются, но нужна все-таки больше пауза. Я пыталась поменять в #define PAUSE_CNT 10 // pause duration значение на 2000, но мах задержка 7.5 мсек. Как можно увеличить до секунды?
Насчет таймера В, в ccs нельзя написать TB0CCTL0_bit.CCIFG = 0; поэтому пишу TBCCTL0 &= ~CCIFG;. Пока разбираюсь что в схеме не так и почему не происходит захвата и зажигания светодиода в этом случае.
Сегодня я смогла добраться до осциллографа и посмотреть что происходит.
Пачки излучаются, но нужна все-таки больше пауза. Я пыталась поменять в #define PAUSE_CNT 10 // pause duration значение на 2000, но мах задержка 7.5 мсек. Как можно увеличить до секунды?
Насчет таймера В, в ccs нельзя написать TB0CCTL0_bit.CCIFG = 0; поэтому пишу TBCCTL0 &= ~CCIFG;. Пока разбираюсь что в схеме не так и почему не происходит захвата и зажигания светодиода в этом случае.
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Насколько я понимаю, на вход Таймера А поступает частота 720 кгц, так что если он досчитает до 18, то это будет соответствовать периоду ультразвука 40 кгц. Этот таймер 16-битный, и максимальное значение туда можно отправить PAUSE_CNT=65535, что будет соответствовать задержке в 65535/720 = 91 миллисек. Если нужна большая задержка, то можно задействовать 32-битный счётчик прерываний в программе обработчика Таймера А или прескейлер 1:8 на входе таймера. Однако, он у Вас может быть уже задействован для получения частоты в 720 кгц на счетном входе. Поэтому я и спрашивал выше как Вы получили частоту 720 кгц на этом входе. Напишите в деталях систему и настройки тактирования МК и таймера.
А нужна-ли Вам такая большая задержка в 1 сек? Я полагаю целью проекта является построение ультразвукового локатора. Если принять скорость звука в воздухе 333 м/с (если правильно со школы помню), то максимальная дальность Вашего устройства с секундной паузой будет около 150м. Однако, мне не представляется реальным получить радиус действия более где-то 10м. Или причина в секундной задержке - экономия токопотребления? Проясните этот момент. Может заодно схемкой устройства поделитесь, можно через ЛС.
А нужна-ли Вам такая большая задержка в 1 сек? Я полагаю целью проекта является построение ультразвукового локатора. Если принять скорость звука в воздухе 333 м/с (если правильно со школы помню), то максимальная дальность Вашего устройства с секундной паузой будет около 150м. Однако, мне не представляется реальным получить радиус действия более где-то 10м. Или причина в секундной задержке - экономия токопотребления? Проясните этот момент. Может заодно схемкой устройства поделитесь, можно через ЛС.
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Скорее всего это частота осциллятора DCO, так как я в коде не подключаю внешний кварц.
Да, вы правы, это схема локатора, который должен измерять расстояние до 3-х метров.
3 метра это около 0,018 сек. Сейчас я могу добиться только измерения расстояния до 0.5 метров.
Так как используется диффузионный режим работы ультразвукового датчика, то лучше иметь большую паузу таймера а, для того, чтобы пластины в датчике могли успокоиться и без проблем переключиться на нужный режим.
Да, вы правы, это схема локатора, который должен измерять расстояние до 3-х метров.
3 метра это около 0,018 сек. Сейчас я могу добиться только измерения расстояния до 0.5 метров.
Так как используется диффузионный режим работы ультразвукового датчика, то лучше иметь большую паузу таймера а, для того, чтобы пластины в датчике могли успокоиться и без проблем переключиться на нужный режим.
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Хорошо, пусть будет 1 сек. А с чем связано ограничение в 0.5м сейчас? Я не увидел новых вопросов в последнем сообщении. Полагаю, проблемы с программированием таймеров решены (?)
Кстати, что в проекте фиксировано кроме устройства дальномера? Я имею в виду МК и датчик. Этот уж слишком древний. А насчёт датчика - если устроит дальность до 2м с погрешностью около 3%, посмотрите на датчики другого типа VL6180X.
Кстати, что в проекте фиксировано кроме устройства дальномера? Я имею в виду МК и датчик. Этот уж слишком древний. А насчёт датчика - если устроит дальность до 2м с погрешностью около 3%, посмотрите на датчики другого типа VL6180X.
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
0,5 метров не связано ни с чем. Просто максимальное время паузы можно сделать - 7 мсек, а это как раз 0,5 м.
Пыталась с помощью delay(); попробовать сделать задержку, но не выходит сделать больше паузу чем 7 мсек. Вопрос мой тот же, как реализовать паузу в 1 сек? Что такое прескейлер, а также что такое 32-битный счётчик прерывания и есть ли у вас пример его использования?
Пыталась с помощью delay(); попробовать сделать задержку, но не выходит сделать больше паузу чем 7 мсек. Вопрос мой тот же, как реализовать паузу в 1 сек? Что такое прескейлер, а также что такое 32-битный счётчик прерывания и есть ли у вас пример его использования?
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Я всё-таки не понял какие проблемы с получением задержки в 1 сек между пачками. Вы писали что использовали PAUSE_CNT = 2000. Почему не 40000? Период обнуления таймера для генерации частоты ШИМ 40 кгц - 1/40 мсек. Т.е. для получения 1 сек нужно сосчитать 40000 прерываний в обработчике. Попробуйте это сначала, только объявите переменную pauseCnt как unsigned int. У меня всё работает. Это брутальное решение, т.к. процессор будет часто пробуждаться лишь для увеличения счётчика, но зато быстро реализуемое.
Правильнее было-бы уменьшить частоту на входе счётчика таймера, задействовав его прескайлер, т.е. делитель входной частоты в максимальным делением 1:8 на время паузы. Тогда можно будет считать лишь до 5000. А если ещё увеличить период обнуления до 50000 в режиме подсчёта паузы, то можно будет считать до 11. А применив прескайлер 1:8 и установив период таймера 45000, можно будет считать лишь до 2. Короче, вариантов масса. Прочитать про прескайлер (input divider) можно в ДШ. Он управляется битами IDx в регистре TACTL.
Кстати о птичках: когда Вы писали про 2000, я полагаю, что не изменили тип переменной pauseCnt с char на unsigned int. При этом в переменную типа char нельзя будет записать что-то более 255, и если записываете туда 2000 (0х790 hex), то компилятор обрубит её до младшего байта (0х90). При этом максимальная зaдержка пачек действительно будет 256/40 = 6.4мсек.
Правильнее было-бы уменьшить частоту на входе счётчика таймера, задействовав его прескайлер, т.е. делитель входной частоты в максимальным делением 1:8 на время паузы. Тогда можно будет считать лишь до 5000. А если ещё увеличить период обнуления до 50000 в режиме подсчёта паузы, то можно будет считать до 11. А применив прескайлер 1:8 и установив период таймера 45000, можно будет считать лишь до 2. Короче, вариантов масса. Прочитать про прескайлер (input divider) можно в ДШ. Он управляется битами IDx в регистре TACTL.
Кстати о птичках: когда Вы писали про 2000, я полагаю, что не изменили тип переменной pauseCnt с char на unsigned int. При этом в переменную типа char нельзя будет записать что-то более 255, и если записываете туда 2000 (0х790 hex), то компилятор обрубит её до младшего байта (0х90). При этом максимальная зaдержка пачек действительно будет 256/40 = 6.4мсек.
-
Terminator_2017
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Чт апр 06, 2017 16:59:44
Re: MSP430 Генерация пачки импульсов при помощи таймера А
Большущее спасибо Вам, Ser60!
Я поменяла тип и получилось сделать паузу в 250 мсек.
Но скорее всего не работает режим захвата.
Пытаюсь проверить что происходит заход в прерывание таймера Б - пытаюсь зажечь диод.
Но безуспешно:
#include "msp430f149.h"
#define PULSE_CNT 4 // # of pulses in a burst
#define PAUSE_CNT 10000 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
unsigned int pulseCnt, pauseCnt;
unsigned int lastCapture;
unsigned int duration;
void Ports_config()
{
P1SEL = BIT6; // assign P1.6 to TimerA
P1DIR = BIT6;
P4SEL = BIT0; // timer B
P4DIR &= ~BIT0;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1OUT = 0x01;
//P1SEL &= ~BIT0;
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 10;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
pauseCnt = PAUSE_CNT;
pulseCnt = PULSE_CNT;
}
void TimerB_config()
{
TB0CCTL0 = CM_3 | SCS | CAP | CCIE;
TB0CTL = TBSSEL_1 + MC_2 + TBCLR;
lastCapture = 0;
}
//————————Timer B interrupt——————
#pragma vector=TIMERB0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
//if(TB0CCR0 < 0x12C)
P1OUT ^= BIT1;
lastCapture = 0;
TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
//TBCTL &= ~ TBIFG;
TB0CCTL0 &= ~CCIFG;
//CCIFG = 0; // clear TimerB capture flag
__low_power_mode_off_on_exit(); // wake up CPU on exit
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
TimerB_config();
while(1)
{
__low_power_mode_0(); // wait for capture
__no_operation();
__no_operation(); // set breakpoint here to examine duration
}
}
В чем может быть проблема? На вход таймера В приходит уровень - 3 В, то есть по логике он должен переходить в прерывание.
Я поменяла тип и получилось сделать паузу в 250 мсек.
Но скорее всего не работает режим захвата.
Пытаюсь проверить что происходит заход в прерывание таймера Б - пытаюсь зажечь диод.
Но безуспешно:
#include "msp430f149.h"
#define PULSE_CNT 4 // # of pulses in a burst
#define PAUSE_CNT 10000 // pause duration
void Ports_config();
void TimerA_config();
char timerMode; // 0: burst, 1:pause
unsigned int pulseCnt, pauseCnt;
unsigned int lastCapture;
unsigned int duration;
void Ports_config()
{
P1SEL = BIT6; // assign P1.6 to TimerA
P1DIR = BIT6;
P4SEL = BIT0; // timer B
P4DIR &= ~BIT0;
P1DIR |= BIT0;
P1SEL|=BIT0;
P1OUT = 0x01;
//P1SEL &= ~BIT0;
}
void TimerA_config()
{
TA0CCR0 = 18;
TA0CCR1 = 10;
TA0CCTL1 = OUTMOD_7;
TA0CTL = TASSEL_2 + MC_1 + TACLR + TAIE;
timerMode = 0;
pauseCnt = PAUSE_CNT;
pulseCnt = PULSE_CNT;
}
void TimerB_config()
{
TB0CCTL0 = CM_3 | SCS | CAP | CCIE;
TB0CTL = TBSSEL_1 + MC_2 + TBCLR;
lastCapture = 0;
}
//————————Timer B interrupt——————
#pragma vector=TIMERB0_VECTOR // TimerB handler
__interrupt void TimerB_ISR(void)
{
//if(TB0CCR0 < 0x12C)
P1OUT ^= BIT1;
lastCapture = 0;
TB0CTL = 0; // stop capture
duration = TB0CCR0 - lastCapture;
lastCapture = TB0CCR0;
//TBCTL &= ~ TBIFG;
TB0CCTL0 &= ~CCIFG;
//CCIFG = 0; // clear TimerB capture flag
__low_power_mode_off_on_exit(); // wake up CPU on exit
}
int main()
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
Ports_config(); // set up ports for GPIO
TimerA_config(); // configure TimerA module for 40 KHz
TimerB_config();
while(1)
{
__low_power_mode_0(); // wait for capture
__no_operation();
__no_operation(); // set breakpoint here to examine duration
}
}
В чем может быть проблема? На вход таймера В приходит уровень - 3 В, то есть по логике он должен переходить в прерывание.


