平衡小车代码部分全概括

STM32编码器与MPU6050自平衡小车实现
本篇博客详细介绍了如何使用STM32微控制器,结合编码器和MPU6050陀螺仪传感器,实现自平衡小车的控制。文章涵盖了硬件初始化、编码器读取、PWM控制、MPU6050数据读取及PID控制算法等内容。

注:本文代码全部来自于B站天下行走UP主,我只是加了很少的注释和自己的理解,他的这个视频我看了不下4、5遍,觉的讲的很好,点此转到B站 已征得本人同意!

初始化

编码器初始化(encoder.c)

编码器1——PA0/PA1—TIM2
编码器2——PB6/PB7—TIM4

void Encoder_TIM2_Init(void)
{
   
   
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//  第一步:开启时钟,因为所有GPIO都挂载在APB2上,先开APB2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //第五步:TIM2是通用定时器,挂载在APB1上。开启APB1
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//第二步:初始化GPIO--PA0、PA1 因为用的是编码器模式,是读取的并不是输出的,                          	                                             所以不用配置Speed,使用浮空输入模式
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1; // PA0、PA1
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);      //第四步:  编码器模式需要用到定时器 	TIM_TimeBaseStructInit()定 时器初始化函数
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;       //时钟分割 设置不分频TIM_CKD_DIV1
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;   //模式 向上计数
	TIM_TimeBaseInitStruct.TIM_Period=65535;                     //重装载值
	TIM_TimeBaseInitStruct.TIM_Prescaler=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	


	TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//编码器配置函数
	//函数有四个入口参数,定时器,编码器模式、极性
	TIM_ICStructInit(&TIM_ICInitStruct);//第三步:初始化输入捕获(编码器模式相关函数)
	TIM_ICInitStruct.TIM_ICFilter=10;    //滤波器 经验值     只配置这一个函数就可以 
	TIM_ICInit(TIM2,&TIM_ICInitStruct);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);    // 清楚中断标志位,溢出更新
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);// 配置溢出更新中断标志
	TIM_SetCounter(TIM2,0);//    清零定时器计数值
	
	TIM_Cmd(TIM2,ENABLE);//开启定时器
}

编码器2——PB6/PB7—TIM4 代码和上面一样,改一下引脚和定时器就可以了

编码器初始化完成,下面写编码器的读取函数

先采集,再清零。那么采集到的数值就是速度

int Read_Speed(int TIMx)  //传入定时器X,读取TIM x的值
{
   
   
	int value_1;
	switch(TIMx)
	{
   
   
		case 2:value_1=(short)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);break;//IF是定时器2,1.采集编码器的计数值并保存。2.将定时器的计数值清零。	(如果是定时器2,就读取定时器2的计数值,保存到value_1;再把定时器2清零)
		case 4:value_1=(short)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4,0);break;  //TIM_GetCounter()返回的是short类型,所以要强转一下,否则可能会出现一些小错误
		default:value_1=0;
	}
	return value_1;
}

中断寻址函数

void TIM2_IRQHandler(void)
{
   
   
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=0) //中断标志位不等于0,说明已经进入中断了,需要清除一下
	{
   
   
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
	
void TIM4_IRQHandler(void)
{
   
   
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=0)
	{
   
   
		TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
	}
}

PWM(pwm.c)

PWM1——PA8
PWM2——PA11

void PWM_Init_TIM1(u16 Psc,u16 Per)   //传入两个参数,调控PWM
{
   
   
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct; 
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);//开启时钟
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//初始化GPIO--PA8、PA11为复用推挽输出 
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//初始化定时器。
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=Per;
	TIM_TimeBaseInitStruct.TIM_Prescaler=Psc;
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
	
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//初始化输出比较函数  模式 PWM1模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;         //极性  高
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;     //状态 
	TIM_OCInitStruct.TIM_Pulse=0;
	TIM_OC1Init(TIM1,&TIM_OCInitStruct);    //通道1
	TIM_OC4Init(TIM1,&TIM_OCInitStruct);    //通道4
	
	TIM_CtrlPWMOutputs(TIM1,ENABLE);//高级定时器专属--MOE主输出使能    一定要开!
	
	TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);/*【3】*///ENABLE//OC1预装载寄存器使能
	TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);//ENABLE//OC4预装载寄存器使能
	TIM_ARRPreloadConfig(TIM1,ENABLE);//TIM1在ARR上预装载寄存器使能
	
	TIM_Cmd(TIM1,ENABLE);//开定时器。
}

EXTI MPU6050中断引脚——PB5

void MPU6050_EXTI_Init(void)
{
EXTI_InitTypeDef EXTI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//开启时钟   复用时钟	

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;/**【1】//配置为上拉输入,因为mpu6050产生中断是有一个下降沿的
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//PB5配置为上拉输入
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);	

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);//  中断映射到GPIO

EXTI_InitStruct.EXTI_Line=EXTI_Line5;    //中断线
EXTI_InitStruct.EXTI_LineCmd=ENABLE;  //使能
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;  //模式  中断触发
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;  //
EXTI_Init(&EXTI_InitStruct);

}

电机初始化(moter.c)

电机1——PB12/PB13
电机2——PB14/PB15



/*电机初始化函数*/
void Motor_Init(void)
{
   
   
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值