MSP430G2553 PWM控制速度,并自我检测和简单调节速度
2022-09-23 来源:csdn
MSP430G2553 测量小车速度,并简单调速
需要了解MSP430系列的GPIO,TIMERA,UART相关的知识
涉及内容:PWM输出配置,TIMER A 的捕捉/比较寄存器的输入捕捉配置,串口通信的配置,系统时钟的配置
STEP 1 测量小车速度的方法
公式:v = s/t;
s,就是轮子周长;t就是中断周期
PREPARE 1 小车橡胶轮子
参数:
周长:C=2*pi*R=pi*D=20.41975cm;总共20个洞。
1.0209875cm/洞
每穿过一个洞,产生一个中断,得到计算的周期T
v = s/t
PREPARE 2 测速模块
未被遮挡,指示灯亮,输出高电平
被遮挡,指示灯灭,输出低电平
STEP 2 MSP430 输入捕捉中断计算速度
开发板:MSP430G2ET(MSP430G2553)
设计思路
使用定时器A的计数器1的CCR2作为输入捕捉的功能。
TACCR0寄存器的值,就是UP MODE 的峰值
总时间 = (时间戳时间间隔)* TACCR0周期 + 中断捕捉时间间隔
速度 = S / 总时间
代码部分
1. 输入捕捉配置
TA1CTL,
TA1CCTL
P2SEL,
总中断使能打开
void TA1_CCR2_PIN1_5()
{
/*设置定时间隔*/
// TA1CCR0 = 49999;//50ms
/*开启TAIFG中断*/
TA1CTL |= TAIE;
/*TA1,CCR2用于捕捉功能*/
TA1CCTL2 |= CAP;
/*上升沿捕捉*/
TA1CCTL2 |= CM0;
/*P2.5作为捕捉输入(CCI2B)*/
TA1CCTL2 |= CCIS0;
P2SEL |= BIT5;
/*允许捕捉比较中断*/
TA1CCTL2 |= CCIE;
__bis_SR_register(GIE);
}
2. PWM波输出配置
P2SEL(Px端口第二功能),
P2DIR(端口输出方向),
TA1CTL(定时器A控制寄存器),
TA1CCTL1(CCR1控制寄存器),
TA1CCR0(UP MODE的周期),
TA1CCR1(PWM输出)
void TA11_P21_PWM_OUT(void)
{
P2SEL |= BIT1;
P2DIR |= BIT1;//P2.1设为输出TA1.1
TA1CTL |= TASSEL_2 + MC_1; //选SMCLK,UP MODE
TA1CCTL1 = OUTMOD_7;
TA1CCR0 = 2000;
TA1CCR1 = PWM; //占空比:TACCR1/TACCR0
}
3. 中断服务函数
捕捉/比较1,捕捉/比较2,定时器中断溢出共用一个中断向量
#pragma vector = TIMER1_A1_VECTOR
__interrupt void Time_Tick(void)
{
static uint8_t cnt = 0;
__bis_SR_register(GIE);//允许中断嵌套
switch(TA1IV)
{
case 0x02://捕捉比较中断1
break;
case 0x04://捕捉比较中断2
if(cnt == 0)
{
capvalue_1 = TA1CCR2;//保存第一次捕捉值
timestamp_1 = timestamp;//保存第一次时间戳
cnt ++;
}
else
{
capvalue_2 = TA1CCR2;//保存第二次捕捉值
timestamp_2 = timestamp;//保存第二次时间戳
cnt = 0;
totaltime = (timestamp_2 - timestamp_1) * 2000 + capvalue_2 - capvalue_1;//计算总时间
}
break;
case 0x0A://溢出中断
timestamp ++;
break;
default:
break;
}
}
总代码及演示效果
#include #include 'stdint.h' #include //#define PWM 170 // max for RCCX UNDER 2000 uint32_t timestamp = 0;//时间戳 uint16_t capvalue_1 = 0;//第一次捕捉值 uint16_t capvalue_2 = 0;//第二次捕捉值 uint32_t timestamp_1 = 0;//第一次时间戳 uint32_t timestamp_2 = 0;//第二次时间戳 uint32_t totaltime = 0; float freq = 0; #define P1_IE_ON P1IE |= BIT3 #define P1_IE_OFF P1IE &=~ BIT3 int num = 0; int temp = 0; unsigned int i,j; /* * @FN: void GPIO_INIT() * @PAR: NONE * @RETURN:NONE * @BRIEF:配置三个 TCRT5000 模块 */ //void GPIO_INIT() //{ // P1DIR &=~(BIT3+BIT4+BIT5); // P1REN |= (BIT3+BIT4+BIT5); // P1OUT &=~(BIT3+BIT4+BIT5); //} /* * @FN: void InitSystemClock(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置系统时钟1MHZ */ void InitSystemClock(void) { WDTCTL = WDTPW | WDTHOLD; /*配置DCO为1MHz*/ DCOCTL = CALDCO_1MHZ; BCSCTL1 = CALBC1_1MHZ; /*配置SMCLK的时钟源为DCO*/ BCSCTL2 &= ~SELS; /*SMCLK的分频系数置为1*/ BCSCTL2 &= ~(DIVS0 | DIVS1); } /* * @FN: void TA11_P21_PWM_OUT(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置定时器A1,产生PWM波 * 输出引脚 P21 * 周期T=TA1CCR0S * 占空比TA1CCR1/TA1CCR0(2000), * 修改值:TACCR1 */ void TA11_P21_PWM_OUT(void) { P2SEL |= BIT1; P2DIR |= BIT1;//P2.1设为输出TA1.1 TA1CTL |= TASSEL_2 + MC_1; //选SMCLK,UP MODE TA1CCTL1 = OUTMOD_7; TA1CCR0 = 2000; TA1CCR1 = 1000; //占空比:TACCR1/TACCR0 } /* * @FN: void TA01_P12_PWM_OUT(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置定时器A0产生PWM波 * 输出引脚P12 */ void TA01_P12_PWM_OUT() { P1SEL |= BIT2; P1DIR |= BIT2; TA0CTL |= TASSEL_2 + MC_1; TA0CCTL1 = OUTMOD_7; TA0CCR0 = 2000; TA0CCR1 = 100; //Capture/Compare ACTION } //void CCR3_CAL_TIME() //{ // TA0CTL |= //} void speed_test() { TA0CCR1 = 50; __delay_cycles(500000); TA0CCR1 = 1000; __delay_cycles(500000); TA0CCR1 = 1200; __delay_cycles(500000); } /* * @fn: void InitUART(void) * @brief: 初始化串口,包括波特率,数据位,停止位,校验位 * @para: none * @comment:初始化串口 */ void InitUART(void) { /*复位USCI_Ax*/ UCA0CTL1 |= UCSWRST; /*选择USCI_Ax为UART模式*/ UCA0CTL0 &= ~UCSYNC; /*配置UART时钟源为SMCLK*/ UCA0CTL1 |= UCSSEL1; /*配置波特率为9600@1MHz*/ UCA0BR0 = 104; UCA0BR1 = 0; UCA0MCTL = 1 <<1; /*使能端口复用*/ P1SEL |= BIT1 + BIT2; P1SEL2 |= BIT1 + BIT2; /*清除复位位,使能UART*/ UCA0CTL1 &= ~UCSWRST; } /* * @fn: void UARTSendString(uint8_t *pbuff, uint8_t num) * @brief: 通过串口发送字符串 * @para: pbuff :指向要发送字符串的指针 * num :要发送的字符串的个数 * @comment:通过串口发送字符串 */ void UARTSendString(unsigned char *pbuff, unsigned char num) { unsigned char cnt = 0; for(cnt = 0; cnt < num; cnt++) { while(UCA0STAT & UCBUSY); UCA0TXBUF = *(pbuff + cnt); } } void TA1_CCR2_PIN1_5() { /*设置定时间隔*/ // TA1CCR0 = 49999;//50ms /*开启TAIFG中断*/ TA1CTL |= TAIE; /*TA1,CCR2用于捕捉功能*/ TA1CCTL2 |= CAP; /*上升沿捕捉*/ TA1CCTL2 |= CM0; /*P2.5作为捕捉输入(CCI2B)*/ TA1CCTL2 |= CCIS0; P2SEL |= BIT5; /*允许捕捉比较中断*/ TA1CCTL2 |= CCIE; __bis_SR_register(GIE); } uint32_t GET_V_FOR_WHEEL(uint32_t time) { uint32_t v = 0; v = 1020987.5 / time; return v; } void PrintV(uint32_t num) { uint8_t buff[8] = {0,0,0,0,0,0,0,' '}; uint8_t cnt = 0; for(cnt = 0;cnt < 7;cnt ++) { buff[6 - cnt] = (uint8_t)(num % 10 + '0'); num /= 10; } UARTSendString(buff,8); UARTSendString('cm/s',4); } void main(void) { InitSystemClock(); TA1_CCR2_PIN1_5(); InitUART(); // Interrupt_GPIO_Init(); TA01_P12_PWM_OUT(); TA11_P21_PWM_OUT(); while(1) { temp++; if(temp > 20) { UARTSendString('当前小车速度为:',16); PrintV(GET_V_FOR_WHEEL(totaltime)); temp = 0; } if(GET_V_FOR_WHEEL(totaltime) < 88) { TA1CCR1 += 4; } if(GET_V_FOR_WHEEL(totaltime) > 100 ) { TA1CCR1-= 4; } __delay_cycles(20000); // totaltime = 0; } } #pragma vector = TIMER1_A1_VECTOR __interrupt void Time_Tick(void) { static uint8_t cnt = 0; __bis_SR_register(GIE);//允许中断嵌套 switch(TA1IV) { case 0x02://捕捉比较中断1 break; case 0x04://捕捉比较中断2 if(cnt == 0) { capvalue_1 = TA1CCR2;//保存第一次捕捉值 timestamp_1 = timestamp;//保存第一次时间戳 cnt ++; } else { capvalue_2 = TA1CCR2;//保存第二次捕捉值 timestamp_2 = timestamp;//保存第二次时间戳 cnt = 0; totaltime = (timestamp_2 - timestamp_1) * 2000 + capvalue_2 - capvalue_1;//计算总时间 } break; case 0x0A://溢出中断 timestamp ++; break; default: break; } } STEP 3 简单调速 if(GET_V_FOR_WHEEL(totaltime) < 80) { TA1CCR1 += 2; } if(GET_V_FOR_WHEEL(totaltime) > 85 ) { TA1CCR1-= 2; } 附录 整体代码(环境:CCS) 演示说明 硬件环境 软件环境测试 初始时,PWM占比75%,速度初始为128cm/s,后经过简单的自我反馈(伪PID)原理,进行自我速度调节,大致稳定在88~100cm/s之间,下一步朝着真PID算法的方向前进! 以下,附上全部代码,型号MSP430G2553, #if 1 #include #include 'stdint.h' #include //#define PWM 170 // max for RCCX UNDER 2000 uint32_t timestamp = 0;//时间戳 uint16_t capvalue_1 = 0;//第一次捕捉值 uint16_t capvalue_2 = 0;//第二次捕捉值 uint32_t timestamp_1 = 0;//第一次时间戳 uint32_t timestamp_2 = 0;//第二次时间戳 uint32_t totaltime = 0; float freq = 0; #define P1_IE_ON P1IE |= BIT3 #define P1_IE_OFF P1IE &=~ BIT3 int num = 0; int left = 0; int right = 0; int temp = 0; unsigned int i,j; /* * @FN: void GPIO_INIT() * @PAR: NONE * @RETURN:NONE * @BRIEF:配置三个 TCRT5000 模块 */ void GPIO_INIT() { P1DIR &=~(BIT3+BIT4+BIT5); P1REN |= (BIT3+BIT4+BIT5); P1OUT &=~(BIT3+BIT4+BIT5); } /* * @FN: void InitSystemClock(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置系统时钟1MHZ */ void InitSystemClock(void) { WDTCTL = WDTPW | WDTHOLD; /*配置DCO为1MHz*/ DCOCTL = CALDCO_1MHZ; BCSCTL1 = CALBC1_1MHZ; /*配置SMCLK的时钟源为DCO*/ BCSCTL2 &= ~SELS; /*SMCLK的分频系数置为1*/ BCSCTL2 &= ~(DIVS0 | DIVS1); } /* * @FN: void TA11_P21_PWM_OUT(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置定时器A1,产生PWM波 * 输出引脚 P21 * 周期T=TA1CCR0S * 占空比TA1CCR1/TA1CCR0(2000), * 修改值:TACCR1 */ void TA11_P21_PWM_OUT(void) { P2SEL |= BIT1; P2DIR |= BIT1;//P2.1设为输出TA1.1 TA1CTL |= TASSEL_2 + MC_1; //选SMCLK,UP MODE TA1CCTL1 = OUTMOD_7; TA1CCR0 = 2000; TA1CCR1 = 1000; //占空比:TACCR1/TACCR0 } /* * @FN: void TA01_P12_PWM_OUT(void) * @PAR: NONE * @RETURN:NONE * @BRIEF: 配置定时器A0产生PWM波 * 输出引脚P12 */ void TA01_P12_PWM_OUT() { P1SEL |= BIT2; P1DIR |= BIT2; TA0CTL |= TASSEL_2 + MC_1; TA0CCTL1 = OUTMOD_7; TA0CCR0 = 2000; TA0CCR1 = 100; //Capture/Compare ACTION } //void CCR3_CAL_TIME() //{ // TA0CTL |= //} void speed_test() { TA0CCR1 = 50; __delay_cycles(500000); TA0CCR1 = 1000; __delay_cycles(500000); TA0CCR1 = 1200; __delay_cycles(500000); } /* * @fn: void InitUART(void) * @brief: 初始化串口,包括波特率,数据位,停止位,校验位 * @para: none * @comment:初始化串口 */ void InitUART(void) { /*复位USCI_Ax*/ UCA0CTL1 |= UCSWRST; /*选择USCI_Ax为UART模式*/ UCA0CTL0 &= ~UCSYNC; /*配置UART时钟源为SMCLK*/ UCA0CTL1 |= UCSSEL1; /*配置波特率为9600@1MHz*/ UCA0BR0 = 104; UCA0BR1 = 0; UCA0MCTL = 1 <<1; /*使能端口复用*/ P1SEL |= BIT1 + BIT2; P1SEL2 |= BIT1 + BIT2; /*清除复位位,使能UART*/ UCA0CTL1 &= ~UCSWRST; } /* * @fn: void UARTSendString(uint8_t *pbuff, uint8_t num) * @brief: 通过串口发送字符串 * @para: pbuff :指向要发送字符串的指针 * num :要发送的字符串的个数 * @comment:通过串口发送字符串 */ void UARTSendString(unsigned char *pbuff, unsigned char num) { unsigned char cnt = 0; for(cnt = 0; cnt < num; cnt++) { while(UCA0STAT & UCBUSY); UCA0TXBUF = *(pbuff + cnt); } } void TA1_CCR2_PIN1_5() { /*设置定时间隔*/ // TA1CCR0 = 49999;//50ms /*开启TAIFG中断*/ TA1CTL |= TAIE; /*TA1,CCR2用于捕捉功能*/ TA1CCTL2 |= CAP; /*上升沿捕捉*/ TA1CCTL2 |= CM0; /*P2.5作为捕捉输入(CCI2B)*/ TA1CCTL2 |= CCIS0; P2SEL |= BIT5; /*允许捕捉比较中断*/ TA1CCTL2 |= CCIE; __bis_SR_register(GIE); } uint32_t GET_V_FOR_WHEEL(uint32_t time) { uint32_t v = 0; v = 1020987.5 / time; return v; } void PrintV(uint32_t num) { uint8_t buff[8] = {0,0,0,0,0,0,0,' '}; uint8_t cnt = 0; for(cnt = 0;cnt < 7;cnt ++) { buff[6 - cnt] = (uint8_t)(num % 10 + '0'); num /= 10; } UARTSendString(buff,8); UARTSendString('cm/s',4); } void main(void) { InitSystemClock(); TA1_CCR2_PIN1_5(); InitUART(); // Interrupt_GPIO_Init(); TA01_P12_PWM_OUT(); TA11_P21_PWM_OUT(); while(1) { temp++; if(temp > 20) { UARTSendString('当前小车速度为:',16); PrintV(GET_V_FOR_WHEEL(totaltime)); temp = 0; } if(GET_V_FOR_WHEEL(totaltime) < 80) { TA1CCR1 += 2; } if(GET_V_FOR_WHEEL(totaltime) > 85 ) { TA1CCR1-= 2; } __delay_cycles(20000); // totaltime = 0; } } #pragma vector = TIMER1_A1_VECTOR __interrupt void Time_Tick(void) { static uint8_t cnt = 0; __bis_SR_register(GIE);//允许中断嵌套 switch(TA1IV) { case 0x02://捕捉比较中断1 break; case 0x04://捕捉比较中断2 if(cnt == 0) { capvalue_1 = TA1CCR2;//保存第一次捕捉值 timestamp_1 = timestamp;//保存第一次时间戳 cnt ++; } else { capvalue_2 = TA1CCR2;//保存第二次捕捉值 timestamp_2 = timestamp;//保存第二次时间戳 cnt = 0; totaltime = (timestamp_2 - timestamp_1) * 2000 + capvalue_2 - capvalue_1;//计算总时间 } break; case 0x0A://溢出中断 timestamp ++; break; default: break; } }
- msp430g2553+pcf8574+dht11+lcd1602
- 基于MSP430G2553的模拟风扇控制系统
- 利用MSP430G2553测量信号幅度
- 利用MSP430G2553测量信号频率(频率计)
- 基于MSP430G2553和MATLAB Appdesigner的心电信号复现和心率显示
- MSP430G2553 频率、占空比、脉冲宽度测量
- MSP430G2553 移植 Contiki RTOS 实时操作系统
- 【MSP430G2553】图形化开发笔记(1) 配置环境
- 【MSP430G2553】图形化开发笔记(2) 系统时钟和低功耗模式
- 基于GD32驱动BLDC电机(1)定时器和PWM