打印
[STM32F1]

单定时器多路输入捕获测量PWM的频率和占空比

[复制链接]
78|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
abotomson|  楼主 | 2024-4-14 20:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
对于定时器的单路捕获PWM的频率和脉冲,用cubemx配置:一个通道捕获上升沿,另一个通道捕获下降沿,Slave Mode 为Reset Mode .触发源为 TL1FP1 这可以很好地测量输入信号的周期和高电平时间,是使用定时器输入捕获的常用模式。(但仅限于定时器捕获单路PWM波)
在这种模式下:
1.上升沿到来时,触发中断,保存计数值到CCR1(假设通道1捕获上升沿的计数值),然后定时器的计数值清0(TIMx->CNT = 0)(这一点是关键)
2.下降沿到来时,保存计数值到CCR2(假设通道2捕获下降沿的计数值),定时器的计数值不会清0.
PWM一个周期下映射到定时器的计数值 = 上升沿的计数值.(CCRx)
PWM的频率 = 定时器的频率(1M) / (捕获上升沿的计数值 -0)
PWM的占空比 = (下降沿的计数值 / 上升沿的计数值)
配置(以通道1上升沿直接捕获,通道2下降沿间接捕获)
给出以上的实例代码
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){    static u16 t = 0;    static u16 d = 0;    if(htim->Instance == TIM2)    {        if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)        {            LEDDT[0]=1;            t = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;            freq = 1000000 / t;            duty = (float)d/t*100;        }        else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)        {              LEDDT[1]=2;            d =  HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;        }    }}多路捕获PWM的频率和占空比(状态机实现)
我的思路:
配置定时器的两个通道都为上升沿捕获,开启定时器对于通道的输入捕获中断。
状态图
需要注意定时器的计数值有可能会溢出,所以要记录下溢出次数(在定时器的溢出更新中断中记录)
PWM频率= 定时器频率/ 两个上升沿之间的计数值
定时器频率 = 系统时钟 /预分频系数 = 1M
两个上升沿之间的计数值 = 第一次上升沿的计数值 +( 溢出次数 x 重装载值)- 第二次上升沿的计数值
PWM占空比 = 有效计数值 / 两个上升沿的计数值
有效计数值(假设以高电平为有效电平) = 下降沿的计数值 + ( 溢出次数 x 重装载值)-上升沿的计数值
配置
设置定时器的两个通道(多通道)为上升沿捕获计数值,这意味着每次PWM波在上升沿都会进入中断,保留计数值到CCRx.
用cubemx配置的话,就是很简单的配置方式,系统时钟80m,预分配系数80-1, 定时器频率为1M,预装载为0xffff(65535)
给出示例代码
TIM3的通道1和通道2
数据类型:
typedef struct mypwm{    u32 firstrisingcnt;    u32 secondrisingcnt;    u32 fallingcnt;    u32 validcnt; //有效计数值对应于脉宽    float freq;    float duty;    u16 updatetimes;    u8 state;} pwms;
在溢出更新中断的回调函数中:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){  if(htim->Instance == TIM3)    {       mpwms[0].updatetimes++;       mpwms[1].updatetimes++;         //两路的更新计数值自加1,这里实际上可以用一个代替    }}
输入捕获的中断回调函数
void Inputcapturehandle(pwms * cpwm,u32 cnt,TIM_HandleTypeDef *htim,u32 ch){     u32 temp = 0;     switch(cpwm->state)    {           case 0:     //测量上升沿        {                  //开启下次为下降沿采样                __HAL_TIM_SET_CAPTUREPOLARITY(htim, ch, TIM_INPUTCHANNELPOLARITY_FALLING);                 //溢出计数值置为0                cpwm->updatetimes = 0;               //捕获第一次计数值                cpwm->firstrisingcnt =cnt;                //更新状态                cpwm->state = 1;                break;        }        case 1:    //测量下降沿        {            //开启下一次为上升沿采样         __HAL_TIM_SET_CAPTUREPOLARITY(htim, ch, TIM_INPUTCHANNELPOLARITY_RISING);           //捕获下降沿的计数值        cpwm->fallingcnt = cnt;         //计算有效计数值(考虑溢出)        cpwm->validcnt =  (cpwm->updatetimes * htim->Instance->ARR)+ cpwm->fallingcnt-cpwm->firstrisingcnt;           //溢出计数置为0        cpwm->updatetimes  =0;           //更新下一状态        cpwm->state = 2;                   break;            }        case 2:  //再次测量上升沿            {                //捕获第二次上升沿的计数值                cpwm->secondrisingcnt = cnt;                //计算两个上升沿之间的计数值(考虑溢出)                temp =  cpwm->secondrisingcnt + (cpwm->updatetimes * htim->Instance->ARR) - cpwm->firstrisingcnt;                //溢出计数值置为0                cpwm->updatetimes = 0;                //计算频率 = 定时器频率/一个PWM波的两个上升沿的计数值                cpwm->freq = 1e6/temp;                //计算占空比                cpwm->duty = cpwm->validcnt*1.0f / temp *100;                //更新状态                cpwm->state = 0;            }               break;      }}void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){     if(htim->Instance ==  TIM3)    {        if(htim->Channel ==  HAL_TIM_ACTIVE_CHANNEL_1)        {            //进入到自己的中断回调函数中执行            Inputcapturehandle(&mpwms[0],TIM3->CCR1,htim,TIM_CHANNEL_1);        }        else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)        {                 //进入到自己的中断回调函数中执行           Inputcapturehandle(&mpwms[1],TIM3->CCR2,htim,TIM_CHANNEL_2);        }    }}测试效果
通过电位器控制输出PWM波的频率和占空比:输出格式为 频率 -占空比


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

1313

帖子

1

粉丝