我们使用的是STM32F103C8T6进行编程和实现。
一.配置一下PWM输出
1.PWM设置
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);启动PWM
使用的是TIM1的ch1通道,也就是PA8端口,cubemx会自动帮我们配置好。预分频为72,自从重装值1000,采用向上计数模式,占空比为500,那么我们实测的话应该会产生一个占空比500的PWM波形,我们连接到逻辑分析仪,观测波形
2.波形观察
然后逻辑分析仪查看结果。
可以看到确实产生了一个占空比50的PWM波形。
3.动态改变占空比
因为单纯的占空比设置肯定不能满足我们对于平衡车的要求。所一我们测试一下动态改变占空比,再主循环接入一下代码
HAL_Delay(10);
a += 300;
if(a > 900){
a = 100;
}
//通过这个宏改变占空比
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, a);
我们发现还是可以改变占空比的。
二 使用定时器编码器接口对电机进行测速
先找到逻辑分析仪对应的软件,之后我们来配置定时器编码器接口,使用的是TIM3的ch1和ch2
之后就是不分频然后启动预加载值。之后把定时器设置为编码器模式。之后生成文件用于试验测速是否可行,记得勾选生成.c和.h文件。
使用cubemx配置完成之后,我们就可以观测波形了。
先来了解一下函数
硬件中断发生:定时器溢出。
固定入口:CPU跳到固定地址TIM3_IRQHandler这是谁都不能改的)。
HAL库接管:TIM3_IRQHandler里直接调用了HAL_TIM_IRQHandler(&htim3)。这个HAL函数会做所有标准杂活:检查是哪种中断、清除中断标志等。
关键一步:当HAL_TIM_IRQHandler判断出这次是“更新中断”(即溢出)后,它就会去寻找并调用一个名为HAL_TIM_PeriodElapsedCallbac函数。
你的舞台:HAL_TIM_PeriodElapsedCallback就是留给你的“插槽”。HAL库提供了一个默认的空函数,但如果你自己写了一个,程序就会执行你的版本。你在这个函数里写if(htim->Instance == TIM3)和记录溢出方向的代码,这才是你的定制化处理逻辑。
所以,“回调”的意思是:HAL库的通用处理函数“回过头来调用”你提供的函数。这样,你无需关心复杂的中断标志位清除等底层细节,只需关注核心业务逻辑
TIM_HandleTypeDef *htim这个函数里面的参数是什么意思
之后我们可以用串口看一下是否会溢出。使用我们的串口发送函数。
接下来我们据需要进行溢出判断也就是速度,看看到底是正向溢出还是反向溢出
假设定时器是16位,最大值65535
编码器计数:... 65533, 65534, 65535, 0, 1, 2, ...
如果没有溢出记录,我们会以为从65535到2是转少了
实际上:65535 → 溢出 → 0 → 1 → 2 = 实际增加了4
// 全局变量
int32_t overflow_count = 0; // 溢出次数,正数表示正转溢出,负数表示反转溢出
uint32_t last_counter = 0; // 上一次读取的计数值
之后我们需要启动定时器2定一个基准时间用来给编码器测速。
第一步先要配置好管脚和串口,然后启动我们得定时器3配置为编码器模式。
第一步先要配置好管脚和串口,然后启动我们得定时器3配置为编码器模式。
这样子就可以实现编码器测速以及中断溢出检测了
我们可以看到CNT得值以及溢出后得中断。接下来我们规定速度。因为我们规定的是达到30之后产生溢出,我们先用编码器测试,之后对接到测速。
- TIM3的CNT值 = 脉冲数
- TIM2的溢出周期 = 时间间隔
- TIM3的CNT寄存器只有16位(最大值65535)
- 当电机转得很快时,CNT可能会溢出多次
- n 记录的是完整的65535循环次数
第一步:读取当前CNT值
第二步:计算总脉冲数
- n = 溢出次数
- n * 10= 溢出部分的总脉冲数
- x = 当前未溢出的脉冲数
- 总脉冲数= 溢出部分 + 当前部分
- 当反向旋转时,n是负数(如-1、-2...)
- 10-x:因为反向旋转时,CNT从10开始递减
- - (n + 1) * 10:计算溢出的负脉冲数
第三步:计算转速并输出
- n>=0?1:-1:输出旋转方向(1正向,-1反向)
- total*1.0/0.1:计算脉冲频率(脉冲数/秒)
- total:100ms内的脉冲数
- total*1.0/0.1:换算成1秒内的脉冲数
第四步:复位
- 从9开始:9(表示刚开始)
- 到8:走了1步
- 到7:走了2步
- ...
- 到0:走了9步
- n = -1:已经发生了1次溢出(刚开始第一个循环)
- n = -2:已经发生了2次溢出(完成第一个循环 + 刚开始第二个循环)
- n = -3:已经发生了3次溢出(完成两个循环 + 刚开始第三个循环)
- 硬件标志位:UIF(更新中断标志)在CNT从ARR→0(正向)或从0→ARR(反向)时置位
- 对称性:硬件设计要保持正反向的对称性
- 中断触发:无论是正向还是反向,当CNT"翻越"边界时都触发中断
- n 记录的是溢出事件次数(负数)
- n+1 得到的是负数,如:-1→0, -2→-1, -3→-2
- -(n+1) 才是完整循环数:0, 1, 2...
- -(n+1*10 就是完整循环的脉冲数
- 楼梯编号:0(地面), 1, 2, ..., 9(楼顶)
- 正向:从0开始向上爬,到9再回到0(循环结束)
- 反向:从0开始向下?不对,0是地面,没法向下!
- 实际上:先瞬移到楼顶(9),然后向下爬
- 每次从地面瞬移到楼顶时,记一次"溢出"
- 从楼顶爬回地面时,完成一个循环,但没有"溢出"事件