STM32两轮自平衡小车(学习记录)——编码器

本文介绍了如何使用STM32的TIM2和TIM4进行编码器计数,包括不同计数模式配置、信号处理以及中断处理。详细讲解了正反转判断方法和编码器速度读取技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编码器正反转

在这里插入图片描述

正转的时候信号线A先输出信号,信号线B后输出 A相超前B相90度 证明是正转

反转的时候信号线B先输出信号,信号线A后输出 B相超前A相90度 证明是反转

STM32编码器模式

在这里插入图片描述
三种模式
1.仅在TL1计数(A相)
2.仅在TL2计数(B相)
3.在TL1和TL2都计数(A相和B相都计数)

计数

在这里插入图片描述
一个脉冲信号周期完成4次跳变。
1时刻:TI2为低电平,TI1上升沿跳变,计数器向上/向下计数;
2时刻:TI1为高电平,TI2上升沿跳变,计数器仍然向上/向下计数;
3时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上/向下计数;
4时刻:TI1为低电平,TI2下降沿跳变,计数器仍然向上/向下计数。

接线方式

在这里插入图片描述

编码器代码

/**********
初始化TIM2 编码器1
**********/
void Encoder_TIM2_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);						
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;							//初始化PA0|PA1
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_Init(GPIOA,&GPIO_InitStruct);

	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);								//初始化TIM2
	TIM_TimeBaseInitStruct.TIM_ClockDivision = 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);		//清零TIM2计数值
	
	TIM_Cmd(TIM2,ENABLE);			//使能
}

/**********
初始化TIM4 编码器2
**********/
void Encoder_TIM4_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;									//初始化PB6|PB7
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_Init(GPIOB,&GPIO_InitStruct);

	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);										//初始化TIM4
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 65535;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
	
	TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);

	TIM_ICStructInit(&TIM_ICInitStruct);
	TIM_ICInitStruct.TIM_ICFilter = 10;
	TIM_ICInit(TIM4,&TIM_ICInitStruct);
	
	TIM_ClearFlag(TIM4,TIM_FLAG_Update);
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
	
	TIM_SetCounter(TIM4,0);
	
	TIM_Cmd(TIM4,ENABLE);
}


/***************
编码器速度读取函数
入口参数:TIMx定时器
***************/
int Read_Speed(int TIMx)
{
	int value_1;
	switch(TIMx)
	{
		case 2:value_1 = (short)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);break;	//TIM2:采集TIM2编码器计数值并保存;TIM2清零;break。
		case 4:value_1 = (short)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4,0);break;	//TIM4:同上
		default:value_1 = 0;
	}
	return value_1;
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=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);
	}
}

### 使用STM32 HAL库实现平衡小车的自主学习 #### 1. 平衡小车概述 平衡小车是一种基于倒立摆原理设计的小型机器人系统,其核心目标是通过实时控制算法使两轮小车保持直立状态并能按照指令移动。该系统的硬件部分通常包括电机驱动模块、陀螺仪/加速度计传感器以及主控芯片(如STM32微控制器),而软件则涉及PID控制或其他高级控制算法的设计与实现。 为了实现这一目标,可以利用STM32的HAL库来简化底层外设配置过程,从而专注于控制系统逻辑的开发[^3]。 --- #### 2. 系统架构分析 平衡小车的核心组件及其功能如下: - **主控单元 (MCU)** STM32系列微控制器作为主控单元负责数据采集、处理及输出PWM信号给电机驱动器。 - **姿态检测模块** 姿态检测一般采用MPU6050等六轴IMU传感器获取角度信息。这些数据经过滤波后用于计算当前车身倾斜角。 - **电机驱动电路** 驱动直流无刷电机或者步进马达完成前进、后退动作调整重心位置维持稳定状态。 - **电源管理系统** 提供稳定的电压供应保障整个电子设备正常运行。 上述各部件之间相互协作共同构成了完整的闭环反馈控制系统结构图。 --- #### 3. 软件设计方案 以下是基于STM32 HAL库构建平衡小车的主要步骤说明: ##### (1)初始化项目环境 借助ST官方提供的工具链——STM32CubeMX生成初始工程框架文件夹,并导入Keil MDK环境中进一步完善编码工作流程[^1]。 ```c // 初始化GPIO口和定时器资源 __HAL_RCC_GPIOA_CLK_ENABLE(); // 开启端口时钟 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, DutyCycle); // 设置占空比参数 ``` ##### (2)读取惯性测量单元的数据 调用I2C接口访问外部连接好的MEMS器件读回原始加速分量值再经由卡尔曼估计方法消除噪声干扰得到精确倾角数值。 ```c float GetAngle(void){ uint8_t Buf[6]; float AccX,AccY,GyroZ; HAL_I2C_Mem_Read(&hi2c1,(uint16_t)(MPU_ADDR<<1),ACCEL_XOUT_H_REG,I2C_MEMADD_SIZE_8BIT,Buf,sizeof(Buf),10); AccX = ((int16_t)((Buf[0]<<8)|Buf[1]))*ACC_SENSITIVITY; AccY = ((int16_t)((Buf[2]<<8)|Buf[3]))*ACC_SENSITIVITY; GyroZ= ((int16_t)((Buf[4]<<8)|Buf[5]))*GYRO_SENSITIVITY; return atan2(-AccX , AccY)*RAD_TO_DEG + KALMAN_FILTER(GyroZ*dt); } ``` ##### (3)编写比例积分微分调节程序 针对不同阶段需求分别设定合适的KP,Ki,Kd系数组合形式达到最优性能表现效果。 ```c void PID_Calculate(float Target,float Current){ Error = Target - Current ; ITerm += Ki *Error ; if(ITerm > MAX_OUTPUT) ITerm=MAX_OUTPUT; else if(ITerm < MIN_OUTPUT ) ITerm=MIN_OUTPUT ; DTerm = KP*(Error-last_Error)+Ki*ITerm+KD*(Error-last_Error)/dt; last_Error=Error; } ``` ##### (4)发送脉宽调制命令至动力源 最终依据运算得出的结果改变相应通道上的高低电平持续时间长短进而影响实际矩大小方向变化情况达成动态均衡目的。 ```c if(Duty>MaxDuty){Duty=MaxDuty;} else if(Duty<MinDuty){Duty=MinDuty;} __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,Duty); ``` --- #### 4. 学习建议 对于初学者而言,可以从以下几个方面入手逐步深入掌握相关技能知识点: - 掌握基本嵌入式编程概念和技术手段; - 练习操作各类常见外围设备驱动技巧; - 研究经典自动控制理论模型应用实例解析文档资料[^2]; ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值