开发板芯片型号:MSP432P401R
今日得以继续我的MSP432电赛速通之路!
进入此文章阶段,就预示着先人的开拓已经到了尽头,看着先人“一身转战三千里,一剑曾当百万师”,我们也该“门前学种先生柳”从而“步行夺得胡马骑”!先人的开拓从此文开始就稀绝了,往后的学习需要更多地自己开发摸索了~~
文章提供关键代码,测试视频效果。
目录
实践问题目标:
基本知识文章推荐:
1.串口接收上位机命令:
2.外部中断:
3.TB6612电机与编码器的知识:
4.通用定时器中断的配置:
实践问题解决步骤:
一、初始化通用定时器:
二、初始化串口1与串口命令接收处理函数编写:
三、外部中断函数的编写:
四、测瞬时速度函数的编写:
实验效果测试视频:
代码贴出:
实践问题目标:
学习总要有个目标,这里先介绍最终学习实现的目标:
1.上位机串口发送控制命令,控制电机加减速、正反转
上位机可以发送命令获取当前瞬时速度
(20ms内测得的速度)
2.单片机每3秒串口反馈一次数据数据包括以下内容:
1.测得总脉冲数
2.运行总路程
3.上次测得的瞬时速度
4.反馈当前状态是正转还是反转
3.测编码器脉冲用中断捕获的方式进行
4.初始化一个通用定时器1ms为周期
基本知识文章推荐:
本文需要用到一些基础知识,请大家确保自己了解这些知识再来学习:
我的编程都是从基础工程的基础上开始的,没有的自行下载:
https://download.csdn.net/download/qq_64257614/87781382?spm=1001.2014.3001.5503
1.串口接收上位机命令:
MSP432学习笔记10:串口接收字符串命令并执行任务_NULL指向我的博客-CSDN博客
2.外部中断:
MSP432学习笔记5——外部中断_NULL指向我的博客-CSDN博客
3.TB6612电机与编码器的知识:
【MSP432电机驱动学习—上篇】TB6612带稳压电机驱动模块、MG310电机、霍尔编码器_msp432驱动直流电机_NULL指向我的博客-CSDN博客
【MSP432电机驱动设计—下篇】霍尔编码器测车轮运行距离与M/T综合公式法测速概念_NULL指向我的博客-CSDN博客
4.通用定时器中断的配置:
MSP432学习笔记7:定时器A中断_NULL指向我的博客-CSDN博客
实践问题解决步骤:
一、初始化通用定时器:
单片机的运行离不开通用定时器,我们需要一个这样的计时分时模块,来给各项工作分配好中断运行的时间,此处初始化通用定时器有俩个作用:
1.为串口发送反馈数据做3S的时间计数
2.为采样编码器脉冲计算时间
3.为测速周期计算时间
代码:
首先找到头文件timA.h中的初始化定时器0的函数。我们直接用它来初始化,
因为都是周期是1ms,即频率为1000Hz,那么CCR0与CLKDIV分别如下设置:
#include "timA.h"
//宏定义通用定时器需要的参数
#define CCR0 999
#define CLK_DIV 48
然后正确调用函数即可:
二、初始化串口1与串口命令接收处理函数编写:
用的是串口1,所以找到#include "usart.h"文件,找到初始化串口的函数:
它在初始化中没有开启串口1的接收中断等,需要在函数最后几行加上:
MAP_UART_enableModule(EUSCI_A0_BASE); //开启串口模块
MAP_UART_enableInterrupt(EUSCI_A0_BASE,EUSCI_A_UART_RECEIVE_INTERRUPT);//开启串口中断
MAP_Interrupt_enableInterrupt(INT_EUSCIA0);
随后就是命令函数的编写了,首先把需要接收的合法命令罗列出来定义保存好:
uint32_t uart_cnt=0; //串口计时标志
uint16_t uart_flag=0; //串口发送标志
uint16_t Sta; //轮子正反转情况1正转0反转
uint32_t SPEED; //速度值存储
//定义串口程序需要用到的变量
char USART0_save[20]; //存字符串命令的数组
char USART0_xb=0; //帮助数组下标位移
char USART0_flag=0; //接收完成标志
//定义命令字符串,用于与接收进行比较 ,不可修改
const char str1_order[]="ADD\r\n\0"; //加占空比
const char str2_order[]="REDUCE\r\n\0"; //减占空比
const char str3_order[]="COROTATION\r\n\0"; //正转
const char str4_order[]="REVERSE\r\n\0"; //反转
const char str5_order[]="STOP\r\n\0"; //停转
const char str6_order[]="GETSPEED\r\n\0"; //获取当前瞬时速度
const char error_receive[]="ERROR!\r\n"; //错误命令
串口中断服务函数与命令处理函数:
//串口1中断处理函数:
void handle_uart(void)
{
if(USART0_flag==1)
{
printf("%s",USART0_save); //先重复接受到的字符串
USART0_flag=0; //再清理标志位
//先判断命令长度,再根据其判断是否为接受到的命令字符串,根据情况发送不同回应
if(USART0_xb==6)
{
if(strncmp(USART0_save,str1_order,6)==0) //接收到命令1,执行加速(加占空比)
{printf("PWM_DIVA=%d\r\n",PWM_DIVA);speedup_A();}
else
printf("%s",error_receive);
}
else if(USART0_xb==9)
{
if(strncmp(USART0_save,str2_order,9)==0) //接收到命令2,执行减速(减占空比)
{ printf("PWM_DIVA=%d\r\n",PWM_DIVA);speeddown_A();}
else
printf("%s",error_receive);
}
else if(USART0_xb==13) //接收到命令3,执行正转
{
if(strncmp(USART0_save,str3_order,13)==0)
{ printf("SET COROTATION\r\n");set_A(1);Sta=1;}
else
printf("%s",error_receive);
}
else if(USART0_xb==10)
{
if(strncmp(USART0_save,str4_order,10)==0) //接收到命令4,执行反转
{ printf("SET REVERSE\r\n");set_A(2);Sta=2;}
else
printf("%s",error_receive);
}
else if(USART0_xb==7)
{
if(strncmp(USART0_save,str5_order,7)==0) //接收到命令5,执行停转
{ printf("SET STOP\r\n");set_A(0);Sta=0;}
else
printf("%s",error_receive);
}
else if(USART0_xb==11)
{
if(strncmp(USART0_save,str6_order,11)==0) //接收到命令6,执行更新速度
{SPEED_flag=1;CAPTURE_LAST=CAPTURE;}
else
printf("%s",error_receive);
}
else
printf("%s",error_receive);
printf("\r\n");
memset(USART0_save,0,sizeof(USART0_save)); //处理完命令别忘了将数组清零,以便接收下个命令
USART0_xb=0; //重置数组下标
}
}
三、外部中断函数的编写:
外部中断函数的编写是这个计算速度程序的核心之一,另一个就是定时器,他们俩的中断服务函数必须写的逻辑对位,才能发挥正常的效果:
此处我选择将P4^0与P4^1设置为外部中断接收引脚,即他们接编码器的AB相输出
使用倍频(测编码器俩条线,上升沿触发)来减小M法测速在低速的误差
定义中断记录脉冲的一些参数等:
其中我们看到CAT_OUT_TIME这个变量,因为unsigned int 到65535之后会溢出,而编码器没有倍频时,一圈有13*20=260个脉冲,运行时间长了容易造成数据的溢出,所以需要另外的变量记录这个·溢出次数。
uint32_t CAT_OUT_TIME; //脉冲溢出次数,溢出一次就加一,记录有几个65530
uint32_t CAPTURE; //外部中断次数记录最大65530次脉冲,溢出后CAT_OUT_TIME会加一,CAPTURE归零
uint32_t CAPTURE_LAST; //上一次外部中断次数记录
uint32_t CAPTURE_NEW; //最新外部中断次数记录
uint32_t DISTANCE; //行驶总路程长度单位cm,最大65535cm
uint32_t SPEED; //速度值存储
初始化中断函数,初始化P4^0与P4^1为外部中断接收口(这么写是软件二倍频测速编码器):
//外部中断测上升沿个数:
void Interrupt_CAP_inint(void) //外部中断初始化
{
//1.配置GPIO输入
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4,GPIO_PIN2);
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4,GPIO_PIN3);
//2.清除中断标志位
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN2);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN3);
//3.配置触发方式 上升沿
GPIO_interruptEdgeSelect(GPIO_PORT_P4,GPIO_PIN2,GPIO_LOW_TO_HIGH_TRANSITION);
GPIO_interruptEdgeSelect(GPIO_PORT_P4,GPIO_PIN3,GPIO_LOW_TO_HIGH_TRANSITION);
//4.开启外部中断
GPIO_enableInterrupt(GPIO_PORT_P4,GPIO_PIN2);
GPIO_enableInterrupt(GPIO_PORT_P4,GPIO_PIN3);
//5.开启端口中断
Interrupt_enableInterrupt(INT_PORT4);
//6.开启总中断
Interrupt_enableMaster();
}
这里注自己写了外部中断初始化的函数,此工程原有的中断服务函数要删去(在timA.h):
否则是会重复定义报错的 ,这个中断服务函数最好是要写在主文件那的,此处先删去。
蓝色的是初始化TA0为通用计时器的函数,红色的就是它的中断服务函数
主函数中编写外部中断服务函数:
//编写GPIO ISR(外部中断中断服务函数)
void PORT4_IRQHandler(void)
{
uint16_t status;
status=GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
GPIO_clearInterruptFlag(GPIO_PORT_P4,status);
GPIO_clearInterruptFlag(GPIO_PORT_P4,status);
if(status & GPIO_PIN2)//对应P4^2中断
{CAPTURE++;}
if(status & GPIO_PIN3)//对应P4^3中断
{CAPTURE++;}
if(CAPTURE==65530) //快溢出就置0,CAT_OUT_TIME加一
{CAPTURE=0;CAT_OUT_TIME++;}
}
四、测瞬时速度函数的编写:
这个函数需要与以上三个板块结合起来运作了
首先贴出它的主体部分,整个函数最大的注意点就是注意溢出、注意数据的处理手法、以及标志位逻辑的正确:
//车轮编码器测速相关定义
#define WHEEL 15 //宏定义车轮周长 单位cm
#define SPEED_MES_CYCLE 20 //宏定义测速周期,单位ms
#define N_doubling_frequency 2 //宏定义倍频
//定义测速用变量
uint16_t SPEED_cnt=0; //测速计时标志
uint16_t SPEED_flag=0; //测速发送标志(0_无计时需求 1_开始计时 2_计时完成)
uint32_t CAT_OUT_TIME; //脉冲溢出次数,溢出一次就加一,记录有几个65530
uint32_t CAPTURE; //外部中断次数记录最大65530次脉冲,溢出后CAT_OUT_TIME会加一,CAPTURE归零
uint32_t CAPTURE_LAST; //上一次外部中断次数记录
uint32_t CAPTURE_NEW; //最新外部中断次数记录
uint32_t SPEED; //速度值存储,单位cm/s
uint32_t DISTANCE; //行驶总路程长度单位cm,最大65535cm
下段主体部分有段代码被注释掉了,因为我原先想要用这一个函数的调用就实现发送和接收定时器计数完成与否的标志,后来发现逻辑容易混乱出错,便修改了,大家先看代码,下面有介绍
void calculate_speed(void) //伪:计算瞬时速度
//(不是真的瞬时速度,但确实是特别小的一段时间的平均速度)
{
uint32_t CAPTURE_DET; //俩次捕获值的变化量
uint32_t LCM; //俩次捕获值的路程
/*
if(SPEED_flag==0) //先确认上次测速过程已结束,再置一标志开始测速
{SPEED_flag=1;CAPTURE_LAST=CAPTURE;}
发送开始计数标志的过程我决定放在命令需求响应上
*/
if(SPEED_flag==2) //当定时过程结束,进入获取最新捕获值
{
SPEED_flag=0; //重置标志
CAPTURE_NEW=CAPTURE; //获取第二次捕获值
//计算俩次捕获值的变化量:
//65530是溢出,而不是65536:
//因为我设置的CAPTURE计数到65530就软件置0了
if(CAPTURE_NEW>CAPTURE_LAST) //脉冲计数还未溢出时
{CAPTURE_DET=CAPTURE_NEW-CAPTURE_LAST;}
else if(CAPTURE_NEW<CAPTURE_LAST) //脉冲计数溢出了
{CAPTURE_DET=(65530-CAPTURE_LAST)+CAPTURE_NEW; }
//计算俩次捕获值之间的路程:
LCM=(CAPTURE_DET*WHEEL)*1000/(260*N_doubling_frequency);
//计算并更新瞬时速度:
//*1000使得时间单位变成秒,
//本来逻辑上是要SPEED_MES_CYCLE先除1000变成秒的,
//此处防止浮点型数据出现,做预乘处理:
SPEED=LCM/SPEED_MES_CYCLE;
}
}
这个程序要从标志位看起:即:
uint16_t SPEED_flag=0; //测速发送标志(0_无计时需求 1_开始计时 2_计时完成)
我在此讲解一下它如何被置0,被置1,被置2,大家就可以大概知道测速是什么进行原理了:
这个标志会在有计数需求的时候被置1:
比如我的实验中,是接收到上位机命令,他就会进行一次瞬时速度的测速,因此SPEED_flag会在串口接收到相应命令时置1:
我们会看到,计时开始的同时,还会在此保存一次当前的脉冲数CAPTURE,方便以后计算脉冲变化量
这个标志会在计数任务结束时被置2:
这时我们看到定时器中断服务函数,SPEED_flag==1时,定时器会为之持续计时,但当计数任务结束时,定时器会将其置2,标志计数任务结束,可以进行速度计算了:
这个标志会在测速函数计算速度时被重新置0:
这时我们看到测速函数,它接收到计时完成标志,就会第二次获取CAPTURE的值,然后进行计算,同时把标志位直接置0,等待下一次计算速度的过程开始:
实验效果测试视频:
编码器测速_外部中断捕获法测速\测正反转
代码贴出:
main.c
#include "main.h"
int main(void)
{
SysInit();
uart_init(115200);
delay_init();
TimA0_Int_Init(CCR0_COMMON,CLK_DIV_COMMON);//用宏定义初始化通用定时器,周期1ms
Interrupt_CAP_inint(); //外部中断初始化
inint_TB6612(); //初始化电机
printf("Hello,MSP432!\r\n");
MAP_Interrupt_enableMaster(); // 开启总中断
while (1)
{
handle_uart(); //处理串口接收
handle_printf_distance(); //每隔1S串口报告总路程
calculate_speed(); //伪:计算瞬时速度
}
}
//串口服务函数,串口1接收命令,存在数组中
void EUSCIA0_IRQHandler(void)
{
uint32_t status = UART_getEnabledInterruptStatus(EUSCI_A0_BASE);
if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) //接收中断
{
USART0_save[USART0_xb++]=MAP_UART_receiveData(EUSCI_A0_BASE);
if(USART0_xb== 20){USART0_xb=0; } //下标最大不超过20
if(USART0_save[USART0_xb-1]=='\0'){USART0_flag=1;} //命令以\0结尾
}
}
//串口1中断处理函数:
void handle_uart(void)
{
if(USART0_flag==1)
{
printf("%s",USART0_save); //先重复接受到的字符串
USART0_flag=0; //再清理标志位
//先判断命令长度,再根据其判断是否为接受到的命令字符串,根据情况发送不同回应
if(USART0_xb==6)
{
if(strncmp(USART0_save,str1_order,6)==0) //接收到命令1,执行加速(加占空比)
{printf("PWM_DIVA=%d\r\n",PWM_DIVA);speedup_A();}
else
printf("%s",error_receive);
}
else if(USART0_xb==9)
{
if(strncmp(USART0_save,str2_order,9)==0) //接收到命令2,执行减速(减占空比)
{ printf("PWM_DIVA=%d\r\n",PWM_DIVA);speeddown_A();}
else
printf("%s",error_receive);
}
else if(USART0_xb==13) //接收到命令3,执行正转
{
if(strncmp(USART0_save,str3_order,13)==0)
{ printf("SET COROTATION\r\n");set_A(1);Sta=1;}
else
printf("%s",error_receive);
}
else if(USART0_xb==10)
{
if(strncmp(USART0_save,str4_order,10)==0) //接收到命令4,执行反转
{ printf("SET REVERSE\r\n");set_A(2);Sta=2;}
else
printf("%s",error_receive);
}
else if(USART0_xb==7)
{
if(strncmp(USART0_save,str5_order,7)==0) //接收到命令5,执行停转
{ printf("SET STOP\r\n");set_A(0);Sta=0;}
else
printf("%s",error_receive);
}
else if(USART0_xb==11)
{
if(strncmp(USART0_save,str6_order,11)==0) //接收到命令6,执行更新速度
{SPEED_flag=1;CAPTURE_LAST=CAPTURE;}
else
printf("%s",error_receive);
}
else
printf("%s",error_receive);
printf("\r\n");
memset(USART0_save,0,sizeof(USART0_save)); //处理完命令别忘了将数组清零,以便接收下个命令
USART0_xb=0; //重置数组下标
}
}
void calculate_speed(void) //伪:计算瞬时速度
//(不是真的瞬时速度,但确实是特别小的一段时间的平均速度)
{
uint32_t CAPTURE_DET; //俩次捕获值的变化量
uint32_t LCM; //俩次捕获值的路程
/*
if(SPEED_flag==0) //先确认上次测速过程已结束,再置一标志开始测速
{SPEED_flag=1;CAPTURE_LAST=CAPTURE;}
发送开始计数标志的过程我决定放在命令需求响应上
*/
if(SPEED_flag==2) //当定时过程结束,进入获取最新捕获值
{
SPEED_flag=0; //重置标志
CAPTURE_NEW=CAPTURE; //获取第二次捕获值
//计算俩次捕获值的变化量:
//65530是溢出,而不是65536:
//因为我设置的CAPTURE计数到65530就软件置0了
if(CAPTURE_NEW>CAPTURE_LAST) //脉冲计数还未溢出时
{CAPTURE_DET=CAPTURE_NEW-CAPTURE_LAST;}
else if(CAPTURE_NEW<CAPTURE_LAST) //脉冲计数溢出了
{CAPTURE_DET=(65530-CAPTURE_LAST)+CAPTURE_NEW; }
//计算俩次捕获值之间的路程:
LCM=(CAPTURE_DET*WHEEL)*1000/(260*N_doubling_frequency);
//计算并更新瞬时速度:
//*1000使得时间单位变成秒,
//本来逻辑上是要SPEED_MES_CYCLE先除1000变成秒的,
//此处防止浮点型数据出现,做预乘处理:
SPEED=LCM/SPEED_MES_CYCLE;
}
}
//编写GPIO ISR(外部中断中断服务函数)
void PORT4_IRQHandler(void)
{
uint16_t status;
status=GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
GPIO_clearInterruptFlag(GPIO_PORT_P4,status);
GPIO_clearInterruptFlag(GPIO_PORT_P4,status);
if(status & GPIO_PIN2)//对应P4^2中断
{CAPTURE++;}
if(status & GPIO_PIN3)//对应P4^3中断
{CAPTURE++;}
if(CAPTURE==65530) //快溢出就置0,CAT_OUT_TIME加一
{CAPTURE=0;CAT_OUT_TIME++;}
}
//通用定时器中断中断服务函数,周期2ms
void TA0_0_IRQHandler(void)
{
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);
if(++uart_cnt==2000) //每2秒打印一次总运行路程
{uart_cnt=0;uart_flag=1;}
if(SPEED_flag==1) //有速度计数任务时计数
{if(++SPEED_cnt==SPEED_MES_CYCLE) //当时间计数到预定周期
{SPEED_cnt=0;SPEED_flag=2;} //标记测速计时任务结束
}
}
void distance_calculate(void) //总路程计算
{
uint32_t S1;//溢出脉冲部分路程
uint32_t S2;//未溢出脉冲部分路程
S1 = 65530*CAT_OUT_TIME*WHEEL/(260*N_doubling_frequency);
S2 = CAPTURE*WHEEL/(260*N_doubling_frequency);
DISTANCE=S1+S2;
}
void handle_printf_distance(void) //打印一些参数反馈
{
if(uart_flag==1)
{
uart_flag=0;
distance_calculate();
printf("CAT_OUT_TIME=%d\r\n",CAT_OUT_TIME); //脉冲捕获值溢出次数
printf("CAPTURE=%d\r\n",CAPTURE); //脉冲捕获值
printf("DISTANCE=%d\r\n",DISTANCE); //距离
printf("SPEED=%d\r\n",SPEED); //上次瞬时速度
//反馈正反转状态:
if(Sta==2) printf("REVERSE\r\n");
else if(Sta==1) printf("COROTATION\r\n");
else if(Sta==0) printf("STOP\r\n");
}
}
main.h
#ifndef _main_h_
#define _main_h_
#include "sysinit.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "tim32.h"
#include "TB6612.h"
#include "string.h"
#include "timA.h"
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
//宏定义 通用定时器需要的参数
#define CCR0_COMMON 999
#define CLK_DIV_COMMON 48
uint32_t uart_cnt=0; //串口计时标志
uint16_t uart_flag=0; //串口发送标志
uint16_t Sta; //轮子正反转情况 1正转 2反转 0是停
//定义串口程序需要用到的变量
char USART0_save[20]; //存字符串命令的数组
char USART0_xb=0; //帮助数组下标位移
char USART0_flag=0; //接收完成标志
//定义命令字符串,用于与接收进行比较 ,不可修改
const char str1_order[]="ADD\r\n\0"; //加占空比
const char str2_order[]="REDUCE\r\n\0"; //减占空比
const char str3_order[]="COROTATION\r\n\0"; //正转
const char str4_order[]="REVERSE\r\n\0"; //反转
const char str5_order[]="STOP\r\n\0"; //停转
const char str6_order[]="GETSPEED\r\n\0"; //获取当前瞬时速度
const char error_receive[]="ERROR!\r\n"; //错误命令
//车轮编码器测速相关定义
#define WHEEL 15 //宏定义车轮周长 单位cm
#define SPEED_MES_CYCLE 20 //宏定义测速周期,单位ms
#define N_doubling_frequency 2 //宏定义倍频
//定义测速用变量
uint16_t SPEED_cnt=0; //测速计时标志
uint16_t SPEED_flag=0; //测速发送标志
uint32_t CAT_OUT_TIME; //脉冲溢出次数,溢出一次就加一,记录有几个65530
uint32_t CAPTURE; //外部中断次数记录最大65530次脉冲,溢出后CAT_OUT_TIME会加一,CAPTURE归零
uint32_t CAPTURE_LAST; //上一次外部中断次数记录
uint32_t CAPTURE_NEW; //最新外部中断次数记录
uint32_t SPEED; //速度值存储,单位cm/s
uint32_t DISTANCE; //行驶总路程长度单位cm,最大65535cm
void handle_uart(void);
void handle_printf_distance(void); //打印一些参数
void calculate_speed(void); //计算瞬时速度
void distance_calculate(void); //总路程计算
#endif
TB6612.c
#include "TB6612.h"
uint16_t PWM_DIVA; //调整A电机占空比用
//初始化控制TB6612 的引脚,定时器,中断
void inint_TB6612(void)
{
//初始化AIN
MAP_GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN0);
MAP_GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN1);
//初始化定时器TA1 通道2
//1.配置GPIO复用
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P7,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION);
//2.配置结构体
Timer_A_PWMConfig TimA1_PWMConfig1; //定义一个名为 TimA1_PWMConfig的结构体
TimA1_PWMConfig1.clockSource=TIMER_A_CLOCKSOURCE_SMCLK; //时钟源
TimA1_PWMConfig1.clockSourceDivider=CLKDIV; //时钟分频 范围1~64
TimA1_PWMConfig1.timerPeriod=CCR0; //自动重载值
TimA1_PWMConfig1.compareRegister=TIMER_A_CAPTURECOMPARE_REGISTER_2;//通道2(与引脚相关联)
TimA1_PWMConfig1.compareOutputMode=TIMER_A_OUTPUTMODE_TOGGLE_SET; //输出模式
TimA1_PWMConfig1.dutyCycle=3; //此处可调占空比
//初始化定时器:
Timer_A_generatePWM(TIMER_A1_BASE,&TimA1_PWMConfig1);
AIN1=0;AIN2=0; //初始化不转
PWM_DIVA=CCR1_MIN;
}
//A电机加速
void speedup_A(void)
{
PWM_DIVA+=DIV_PWM;
if(PWM_DIVA>=99) {PWM_DIVA=CCR1_MAX;}
MAP_Timer_A_setCompareValue(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2,PWM_DIVA);
}
//A电机减速
void speeddown_A(void)
{
PWM_DIVA-=DIV_PWM;
if(PWM_DIVA<=3) {PWM_DIVA=CCR1_MIN;}
MAP_Timer_A_setCompareValue(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2,PWM_DIVA);
}
//设置A电机正反转 0停转 1正 2反
void set_A(uint16_t i)
{
switch(i)
{
case 0:AIN1=0;AIN2=0;break;
case 1:AIN1=1;AIN2=0;break;
case 2:AIN1=0;AIN2=1;break;
}
}
//外部中断测上升沿个数:
void Interrupt_CAP_inint(void) //外部中断初始化
{
//1.配置GPIO输入
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4,GPIO_PIN2);
MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4,GPIO_PIN3);
//2.清除中断标志位
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN2);
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN3);
//3.配置触发方式 上升沿
GPIO_interruptEdgeSelect(GPIO_PORT_P4,GPIO_PIN2,GPIO_LOW_TO_HIGH_TRANSITION);
GPIO_interruptEdgeSelect(GPIO_PORT_P4,GPIO_PIN3,GPIO_LOW_TO_HIGH_TRANSITION);
//4.开启外部中断
GPIO_enableInterrupt(GPIO_PORT_P4,GPIO_PIN2);
GPIO_enableInterrupt(GPIO_PORT_P4,GPIO_PIN3);
//5.开启端口中断
Interrupt_enableInterrupt(INT_PORT4);
//6.开启总中断
Interrupt_enableMaster();
}
TB6612.h
#ifndef _TB6612_h_
#define _TB6612_h_
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
//定义定时器中断需要的初始化变量
//定义调整占空比的变量 占空比 = PWM_DIVA/CCR0
//占空比越大电机转速也越大
#define CLKDIV 48 //时钟分频
#define CCR0 99 //时基(改变此项频率会变)
#define CCR1_MIN 3 //PWMA最小值
#define CCR1_MAX 99 //PWMA最大值
#define DIV_PWM 3 //PWMA加减分度值,改变此项能改变PWMA的加减分度
// 位带操作
//定义引脚名称,STBY引脚接5V或者3.3V皆可
#define AIN1 BITBAND_PERI(P4OUT,0)
#define AIN2 BITBAND_PERI(P4OUT,1)
#define PWMA BITBAND_PERI(P7OUT,6)
#define E1A BITBAND_PERI(P4OUT,0)
#define E1B BITBAND_PERI(P4OUT,1)
extern uint16_t PWM_DIVA; //改变占空比作用的变量
//函数声明:
void inint_TB6612(void);
void speedup_A(void); //加速
void speeddown_A(void); //减速
void set_A(uint16_t i); //设置正反转
void TA0_0_IRQHandle(void); //T0中断处理
void Interrupt_CAP_inint(void); //外部中断初始化
void calculate_speed(void);
#endif