注:本文代码全部来自于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
STM32编码器与MPU6050自平衡小车实现

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

被折叠的 条评论
为什么被折叠?



