MSP432自主开发笔记1:编码器测速_外部中断捕获法测速\测正反转

news2024/10/7 2:43:00

开发板芯片型号: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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/716229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的教务管理系统

基于ssm教务管理系统 一、项目背景介绍&#xff1a; 教务管理系统是一种基于信息技术的管理工具&#xff0c;可以用来管理学生、教师、课程、考试、教学资源等方面的信息&#xff0c;以实现高效、科学、规范的教务管理。随着信息技术的迅速发展&#xff0c;教务管理系统已经成为…

VM虚拟机端口映射接收CS弹反木马

VM虚拟机端口映射接收CS弹反木马 1. 前言1.1. 前期准备1.2. 整体思路 2. 整体操作流程2.1. 虚拟机配置2.2. WIFI路由器设置2.3. CS设置2.3.1. 创建本地监听器2.3.2. 创建生成木马监听器2.3.3. 创建反弹木马2.3.4. 查看效果 1. 前言 在日常的对客户的内网进行渗透的时候&#xf…

【广州华锐互动】VR地铁安全应急疏散模拟演练系统

VR地铁安全应急疏散模拟演练系统是一种利用虚拟现实技术模拟铁路安全事故的应用程序。该系统具有以下功能和内容&#xff1a; 多种场景和情境&#xff1a;用户可以选择不同的场景和情境进行模拟&#xff0c;例如列车脱轨、火灾、爆炸等。 操作控制器或手势识别技术&#xff1…

超细,RobotFramework自动化测试-测试套件使用详细(实战)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 自动化因为是基于…

Ubuntu 20.04 LTS 安装 nvidia 驱动 + cuda 11.8 从开始到放弃!

升级 sources.list # 默认注释了源码镜像以提高 apt update 速度&#xff0c;如有需要可自行取消注释 deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restri…

【赠书活动】同构:编程中的数学

写在前面 近年来随着人工智能、大规模分布式计算、多核CPU和异构计算等的发展&#xff0c;计算机中的各种编程技术在编程语言、软件架构、编译器、硬件体系结构、集成电路设计等方面都有着剧烈的变化。编程语言方面&#xff0c;越来越多的主流语言引入函数式编程的概念。软件架…

Zotero+百度网盘同步空间多电脑设置方法

Zotero百度网盘同步空间多电脑设置方法 之前一直用的Onedrive和Zotero来同步&#xff0c;原理差不多&#xff0c;但是百度网盘同步空间毕竟是国内的&#xff0c;&#xff08;开了会员&#xff09;速度快很多&#xff0c;记录一下多台电脑使用百度网盘同步空间来同步Zotero和相…

第六章.­ ­ Theory of Generalization

第六章. Theory of Generalization 上一章节我们主要探讨了M数值的大小对机器学习的影响。若M很大&#xff0c;我们就不能保证机器学习有很好的泛化能力&#xff0c;所以我们的问题就转换成验证M有限&#xff0c;最好是按照多项式成长&#xff0c;然后引入了成长函数mH(N)和二…

微服务一 实用篇 - 4.RabbitMQ

《微服务一 实用篇 - 4.RabbitMQ》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《微服务一 实用篇 - 4.RabbitMQ》 《微服务一 实用篇 - 4.RabbitMQ》1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯 1.2.技术对比 2.快速入门2.1.安装RabbitM…

viewsets.ViewSet 详解

目录 零、前提&#xff08;这一段可以忽略&#xff09; 一、地址 二、viewsets.ViewSet介绍 2.1 viewsets.ViewSet介绍 三、viewsets.ViewSet默认方法&#xff08;增删改查等方法&#xff09; 四、 生成路由 4.1 使用路由器注册 viewset&#xff0c;自动生成 URL 配置(推…

Git下载与安装(windows)

文章目录 Git 简介Git 下载Git 安装Git 环境变量配置 Git 简介 Git 是一种分布式版本控制系统&#xff0c;用于快速、高效地处理任何大小规模的项目。它是由 Linus Torvalds 在 2005 年开始开发的&#xff0c;Git 最初是为了管理 Linux 内核源代码而创建的。现在 Git 是一个广…

python脚本(Word转PDF格式小工具)

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QMessageBox from PyQt5.QtCore import Qt import sys import os from comtypes import client#文件转换脚本 class FileDropWidget(QWidget):def __init__(self):super().__init__()self.initUI()de…

IDEA+spring boot+mybatis+spring mvc+bootstrap+Mysql停车位管理系统源码

IDEAJavaSpring BootMyBatisshiroLayuiMysql停车位管理系统源码 一、系统介绍1.环境配置 二、系统展示1.登录2.注册3.个人信息4.修改密码5.我的订单6.我的留言7.查车位8.管理员登录9.公告列表10.车位列表11. 订单列表12. 积分排行13. 留言列表14.管理员列表15. 用户列表16.修改…

MySQL:整型类型的显示列宽

整型类型的显示列宽 1、概述2、显示宽度3、总结 1、概述 大家好&#xff0c;我是欧阳方超。 关于定义整型时括号中的数值&#xff0c;再补充一下。 2、显示宽度 定义整型类型&#xff0c;比如int(10)&#xff0c;这个括号中的值被称为展示宽度&#xff08;display width&…

Hive查询操作

Hive基本查询语法 基本使用规则 基本查询语句组成 select .. from ..join [tableName] on ..where ..group by ..having ..order by ..sort by ..limit .. union | union all ...执行顺序 第一步: FROM <left_table> 第二步: ON <join_condition> 第三步: <join…

python使用matplotlib库绘制数学函数

** 任务一&#xff1a;使用matplotlib绘制yx的曲线图 ** matplotlib是python的绘画库&#xff0c;它可以与NumPy一起使用&#xff0c;提供了一种轻量级的MatLab开源高效替代方案。它可以和图形工具包PyQt等工具 一起配合使用&#xff0c;能够完成日常科学计算中多种数学库图可…

RuoYi(分离版) 使用代码生成器添加子模块(idea版)

右键总文件夹&#xff0c;选择新模块添加新模块 新建的业务模块 新建的业务模块中添加若依通用模块工具 <dependencies><dependency><groupId>com.ruoyi</groupId><artifactId>ruoyi-common</artifactId></dependency></depen…

窨井水位监测的重要性

窨井是排水管网的检查井&#xff0c;能够直观准确的反映城市排水管网的运行状态&#xff0c;在城市排水系统中扮演着重要的角色。窨井水位监测是指对城市下水道或雨水收集系统中的窨井水位进行实时或定期的监测和测量。 窨井水位监测的重要性 预防溢流&#xff1a;窨井水位监测…

Nacos 无缝支持 confd 配置管理

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Android Studio实现内容丰富的安卓物业管理平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号102 1.开发环境 android stuido3.6 jak1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告…