MSP430 Генерация пачки импульсов при помощи таймера А

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Цикл while, в данном конкретном случае, не нужен, если только МК не будет делать еще что-то.
Следовало-бы проиниацилизировать переменные pauseCnt и pulseCnt их соответствующими значениями из дефайном в начале кода в функции настройки таймера.
Реклама
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Вот полностью весь код:

#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?
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Не понял зачем его вообще включать для данного приложения? В коде прерывание происходит каждый раз по достижении счетчиком таймера его максимального значения. Вопрос первоначально был как обойтись одним таймером. Чего хотите добиться сейчас, задействовав второй таймер?
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Вообще задача в том, чтобы отправлять с таймера А пачку импульсов и принимать пришедший сигнал на таймер В.

Решила постепенно разбираться.
Сейчас мне не понятно, почему в прерывании не выполняются условия.
Также есть вопрос, как добавить в данный код работу таймера В.

Есть еще вопрос почему код по захвату у меня не заходит в прерывание:
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();
}

Да и почему-то записывает не в те регистры флаг прерывания.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

почему код по захвату у меня не заходит в прерывание
Потому что таймер стоит и не считает. Запишите значение МС_1 в TBCTL. Кроме того, TBCL0=0 дефолтно и для запуска таймера там должно быть ненулевое значение. Ну и ещё этот таймер, согласно конфигурации тактируется от ACLK. Чему равна эта частота (из кода определить это невозможно)?

Остальные вопросы я не понял. Что значит "принимать пришедший сигнал на таймер В"? И какие условия должны выполняться в прерывании (сейчас там никаких условий не проверяется)?

Напишите нормально что надо сделать, я не телепат. Если это студенческая методичка, лучше выложите её сюда полностью. Кроме того, какие имеете средства отладки (FET debugger? Лог. анализатор? Среда разработки?). Если у Вас демо-плата с MSP430, что за плата.
Реклама
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Задача в том, чтобы отправлять пачку импульсов с таймера А на ультразвуковой датчик, излучать, а затем принимать усиленный отраженный сигнал на вход таймера В.

Прерывания таймера В должны происходить тогда, когда на вход его поступает отраженный сигнал. Нужно выводить время с начала запуска таймера В и захвата сигнала. Также останавливать таймер и запускать заново после расчета времени.

Вообще я тактирую от SMCLK (TBSELL_2) ибо когда пыталась от ACLK таймер В не считал.

Среда разработки - code composer studio.
Демо платы нет, есть схема с микроконтроллером msp430f149. Средство отладки - FET debugger.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

В прошлый раз я был не прав с советами. Теперь задачу понял. Вот рабочий код использования Таймера для захвата. Он измеряет длительность нажатия кнопки, подсоединённой между 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
}	
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Большое спасибо за листинг!

В данном примере
#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)?
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Не нужно там никакого условия. Вход в обработчик прерывания произойдёт как только совершится захват.
Кстати, я вспомнил, что у меня есть 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, стабилизированным часовым кристаллом. Код проверен в железе и работоспособность его гарантируется.
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

А не могли бы Вы объяснить, почему при выполнении кода пошагово, все застревает в прерывании Таймера А? Что-то я забыла добавить?

#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
}
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Нужно раскомментить строку где сбрасывается флаг прерывания ТаймераА в его обработчике, если синтакс позволяет. Как написано сделано неправильно. Попробуйте так: TACTL &= ~TAIFG;
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Исправила, но все равно зациклился в обработчике(
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Я не пишу под 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 будет всегда принимать разные значения, что и подтверждается на практике.
Спойлер

Код: Выделить всё

#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
}	
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Большое спасибо за вашу помощь!!)

Сегодня я смогла добраться до осциллографа и посмотреть что происходит.
Пачки излучаются, но нужна все-таки больше пауза. Я пыталась поменять в #define PAUSE_CNT 10 // pause duration значение на 2000, но мах задержка 7.5 мсек. Как можно увеличить до секунды?

Насчет таймера В, в ccs нельзя написать TB0CCTL0_bit.CCIFG = 0; поэтому пишу TBCCTL0 &= ~CCIFG;. Пока разбираюсь что в схеме не так и почему не происходит захвата и зажигания светодиода в этом случае.
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Насколько я понимаю, на вход Таймера А поступает частота 720 кгц, так что если он досчитает до 18, то это будет соответствовать периоду ультразвука 40 кгц. Этот таймер 16-битный, и максимальное значение туда можно отправить PAUSE_CNT=65535, что будет соответствовать задержке в 65535/720 = 91 миллисек. Если нужна большая задержка, то можно задействовать 32-битный счётчик прерываний в программе обработчика Таймера А или прескейлер 1:8 на входе таймера. Однако, он у Вас может быть уже задействован для получения частоты в 720 кгц на счетном входе. Поэтому я и спрашивал выше как Вы получили частоту 720 кгц на этом входе. Напишите в деталях систему и настройки тактирования МК и таймера.

А нужна-ли Вам такая большая задержка в 1 сек? Я полагаю целью проекта является построение ультразвукового локатора. Если принять скорость звука в воздухе 333 м/с (если правильно со школы помню), то максимальная дальность Вашего устройства с секундной паузой будет около 150м. Однако, мне не представляется реальным получить радиус действия более где-то 10м. Или причина в секундной задержке - экономия токопотребления? Проясните этот момент. Может заодно схемкой устройства поделитесь, можно через ЛС.
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Скорее всего это частота осциллятора DCO, так как я в коде не подключаю внешний кварц.
Да, вы правы, это схема локатора, который должен измерять расстояние до 3-х метров.
3 метра это около 0,018 сек. Сейчас я могу добиться только измерения расстояния до 0.5 метров.
Так как используется диффузионный режим работы ультразвукового датчика, то лучше иметь большую паузу таймера а, для того, чтобы пластины в датчике могли успокоиться и без проблем переключиться на нужный режим.
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Хорошо, пусть будет 1 сек. А с чем связано ограничение в 0.5м сейчас? Я не увидел новых вопросов в последнем сообщении. Полагаю, проблемы с программированием таймеров решены (?)

Кстати, что в проекте фиксировано кроме устройства дальномера? Я имею в виду МК и датчик. Этот уж слишком древний. А насчёт датчика - если устроит дальность до 2м с погрешностью около 3%, посмотрите на датчики другого типа VL6180X.
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

0,5 метров не связано ни с чем. Просто максимальное время паузы можно сделать - 7 мсек, а это как раз 0,5 м.
Пыталась с помощью delay(); попробовать сделать задержку, но не выходит сделать больше паузу чем 7 мсек. Вопрос мой тот же, как реализовать паузу в 1 сек? Что такое прескейлер, а также что такое 32-битный счётчик прерывания и есть ли у вас пример его использования?
Друг Кота
Аватара пользователя
Сообщения: 3784
Зарегистрирован: Ср дек 24, 2008 09:58:58

Сообщение Ser60 »

Я всё-таки не понял какие проблемы с получением задержки в 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мсек.
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт апр 06, 2017 16:59:44

Сообщение Terminator_2017 »

Большущее спасибо Вам, 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 В, то есть по логике он должен переходить в прерывание.
Ответить

Вернуться в «Разные вопросы по МК»