遇到问题的时候,自己研究一段时间后仍不能解决,就要及早提问,少钻牛角尖
————小白
相比软件模拟PWM
而言,软件捕获PWM
则十分不稳定,因为需要大量的计算过程,这些过程消耗的时间可能会拖延处理捕获点的到达,导致出现捕获点丢失的情况,除非能够保证数据运算在两个捕获点间隔内完成,否则结果常常是错误的。还是那句话,能用硬件就不用软件,所以慎用软件捕获PWM
01 - 软件捕获PWM思路
软件捕获PWM
的方法有多种,但是无论哪一种,基本思想都是提取高电平和低电平的时间进行计算,小白使用最简单的一种,一个定时器和一个可以边沿触发的外部中断,整体思路图如下:
下面是具体步骤:
- 初始化外部中断
En
为边沿触发,初始化相应端口Pn
- 选定一个定时器
Tn
作计数器 - 第一次外部中断,记录端口当前电平
flag
,开启定时器Tn
,定时器内进行计数,包含溢出 - 第二次外部中断,记录计数值
S1
,Tn
继续跑 - 第三次外部中断,再次记录计数值
S2
,一次捕获完成,置标志位Kn
,重置Tn
和相关变量 - 主进程监听
Kn
,标志位完成后对flag
、S1
和S2
进行处理 - 回到步骤3
当然,这些理想状态,即我们假设每一个捕获点都能被CPU处理,但实际并不是,如果PWM
源的周期频率未知,那么这样做的结果几乎是错误的,如果能够知道PWM
源的一些信息比如是ms级别还是us级别、周期范围等等,就比较好处理
02 - 核心源码
作为例子,选用SINO的SH79M1612B(8051)
进行具体配置
定时器1
#define Fsys_Mhz 12.0
#define timer1_start() TCON |= 0x40
#define timer1_stop() TCON &= ~0x40
#define set_timer1_ms(x) TL1 = ((uint16)((MAX_16BIT-(x)*1000*Fsys_Mhz)))&0x00ff; \
TH1 = (((uint16)((MAX_16BIT-(x)*1000*Fsys_Mhz)))&0xff00)>>8;}
#define set_timer1_value(x) TL1 <