概述
1. 前言
基于《【众拳STM8 40 讲】PWM 输入捕获原理与实验(频率)》我们已经了解了利用 STM8 库函数 如何捕获和计算 PWM 的频率,但是确没有介绍占空比的捕获方法。
基于《【思修STM8 39 讲】PWM 输入捕获之占空比测量(寄存器版)》我们了解了 PWM 捕获的详细流程步骤,但是其并非利用 STM8库函数 实现,同时也没有利用中断实现采集。
基于《【STM8】PWM 捕获实战:占空比和频率(TIM1)》我们了解了利用PWM输入模式和复位触发模式采集 PWM,但是并非所有定时器都具有复位触发模式
下面我们介绍利用 STM8库函数 和 中断 的方式来实现利用 TIM2 捕获 PWM 占空比和频率。
2. 实现代码
PWM 采集规定是:CH1 上升捕获,CH2 下降沿捕获
不同于 TIM1 的复位触发模式,TIM2 不具备复位触发模式,所以编码方式上还是有些不同
// tim2.c
u16 GV_Tim2PwmiFreq = 0; //【系统使用】定时器捕获的 PWM 频率
double GV_Tim2PwmiDuty = 0.0; //【系统使用】定时器捕获的 PWM 正占空比
/**
* TIM2 PWM 输入初始化
*/
void TIM2_PWMI_Init()
{
// 重置初始化
TIM2_DeInit();
// 初始化 TIME1 时基单元
// 16预分频,向上计数,每 1s/1M = 1us 计数器值加 1(累加 1000 次需要 1 毫秒)
// 参数说明:预分配值,自动重装载值(计数器值到 65536 后重新装载)
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 65536-1);
// PWM的通道1配置
//
// 参数说明:
// 1. TIM2 通道1
// 2. 极性:上升沿捕获
// 3. 输入脚:TIM2_ICSELECTION_DIRECTTI 表示直接将 T1 信号经过 TI1FP1 发送给 IC1 模块进行处理
// 4. 预分频:意思是控制在多少个输入周期做一次捕获;【经过实际测试,复位触发模式下该值无效,都是按照1分频执行】
// 1M 系统时钟,捕获 20Hz PWM 一个周期需要计数 50000 次(1M/20=50000),TIM2 最大计数有65536,可以捕获
// 1M 系统时钟,捕获 15Hz PWM 一个周期需要计数 66666 次(1M/15=66666),TIM2 最大计数有65536,无法捕获
// 5. 滤波频率:经历几个周期相同的跳变则波形稳定。如果频率捕获偶发值不对,那么可以启用 0x02(4个事件)
TIM2_PWMIConfig(TIM2_CHANNEL_1, TIM2_ICPOLARITY_RISING, TIM2_ICSELECTION_DIRECTTI, TIM2_ICPSC_DIV1, 0x00);
// PWM的通道2配置
//【经过实际测试,通道2 可以不用配置,也可以配置,但是如果配置那么参数必须要填写正确:TIM2_ICPOLARITY_FALLING,TIM2_ICSELECTION_INDIRECTTI】
//【至于为什么不用配置系统仍旧能正常运行,猜想可能是 STM8库函数 内部自动做了一些处理】
//
// 参数说明:
// 1. TIM2 通道2
// 2. 极性:下降沿捕获
// 3. TIM2_ICSELECTION_INDIRECTTI 表示直接将 T1 信号经过 TI1FP2 发送给 IC2 模块进行处理
// 4. 预分频:意思是控制在多少个输入周期做一次捕获;【经过实际测试,复位触发模式下该值无效,都是按照1分频执行】
// 5. 滤波频率:经历几个周期相同的跳变则波形稳定。如果频率捕获偶发值不对,那么可以启用 0x02(4个事件)
//TIM2_PWMIConfig(TIM2_CHANNEL_2, TIM2_ICPOLARITY_FALLING, TIM2_ICSELECTION_INDIRECTTI, TIM2_ICPSC_DIV1, 0x00);
// 输入捕获/比较输出使能
//【经过实际测试,以下使能代码可以注释掉,但是为了安心还是加上去】
TIM2_CCxCmd(TIM2_CHANNEL_1, ENABLE);
TIM2_CCxCmd(TIM2_CHANNEL_2, ENABLE);
}
/**
* 开始 PWM 捕获
*/
void TIM2_PWMI_Start()
{
// 清空俘获中断标志
TIM2_ClearITPendingBit(TIM2_IT_CC1);
TIM2_ClearFlag(TIM2_FLAG_CC1);
// 启用中断函数:俘获比较通道CH1中断
TIM2_ITConfig(TIM2_IT_CC1, ENABLE);
// 开定时器
//【经过实际测试,定时器就算未开启,上面的 TIM2_IT_CC1 中断仍正常进入,但是获取的计数器值不确定】
TIM2_Cmd(ENABLE);
}
/**
* 终止 PWM 捕获
* 利用 TIM2_Cmd(DISABLE) 关闭输出,注意其他函数可能受影响,例如:TIM2_PWMI_Init
*/
void TIM2_PWMI_Stop()
{
// 关闭中断函数:俘获比较通道CH1中断
TIM2_ITConfig(TIM2_IT_CC1, DISABLE);
// 关闭定时器
TIM2_Cmd(DISABLE);
}
/**
* 获取 TIM2 CH1 捕获的 PWM 频率
*
* @return integer 频率
*/
u16 TIM2_PWMI_GetFreq()
{
return GV_Tim2PwmiFreq;
}
/**
* 获取 TIM2 CH1 捕获的 PWM 正占空比
*
* @return double 占空比
*/
double TIM2_PWMI_GetDuty()
{
return GV_Tim2PwmiDuty;
}
// stm8s_it.c
INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 12)
{
// 初始化定时器输入捕获值
// 分别对应一个PWM周期的第一个上升沿,第一个下降沿,第二个上升沿
static u16 icValueA, icValueB, icValueC;
// 获取定时器输入捕获值
if( icValueA == 0 ){
icValueA = TIM2_GetCapture1();
}else{
icValueB = TIM2_GetCapture2();
icValueC = TIM2_GetCapture1();
// 处理定时器捕获值溢出情况
if( icValueC < icValueA ) icValueC = icValueC-icValueA+65535;
else icValueC = icValueC - icValueA;
if( icValueB < icValueA ) icValueB = icValueB-icValueA+65535;
else icValueB = icValueB - icValueA;
// 计算频率和周期
// 这里的 1000000 是基于初始化函数中的系统时钟设置(16预分频 = 1000000)
// 这里的 100.0 小数点表示将表达式 icValueB*100.0/icValueC 的过程和结果以浮点数来进行
GV_Tim2PwmiFreq = 1000000/icValueC;
GV_Tim2PwmiDuty = icValueB*100.0/icValueC;
// 重置定时器输入捕获值
icValueA = icValueB = icValueC = 0;
}
// 清除中断标志位
TIM2_ClearITPendingBit(TIM2_IT_CC1);
TIM2_ClearFlag(TIM2_FLAG_CC1);
}
注意:建议使用 TIM2 就启用一个功能:输入捕获或者输出比较
主要考虑到不同通道输出/捕获时都同时设置 TIM2_TimeBaseInit 函数,会相互干扰,为了减少程序复杂度所以建议使用 TIM2 就启用一个功能
最后
以上就是高高小蝴蝶为你收集整理的【STM8】PWM 捕获实战:占空比和频率(TIM2)的全部内容,希望文章能够帮你解决【STM8】PWM 捕获实战:占空比和频率(TIM2)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复