基于STM32获取外部PWM信号的占空比和周期

思路:

    1、采用外部输入中断的方式获取PWM波形高低电平跳变(上升沿和下降沿),所以外部输入中断引脚配置为上升沿和下降沿中断有效;

    2、定时器定时时钟计数,可按照项目需求的精度确定定时器时钟大小,示例中精度选择为1us,所以定时器时钟设置为1us或者1Mhz。

    实现代码如下:(代码实现了简单的封装,调用简单,可以免费使用)

 pwm_input.h

 1 /************************************************************
 2 **   捕获PWM信号占空比
 3 **   编写:Awesome    QQ: 2281280195
 4 **   代码可以免费移植使用
 5 *************************************************************/
 6 
 7 #ifndef PWM_INPUT_H
 8 #define PWM_INPUT_H
 9 
10 #define us_to_ns(x)     ((x)*1000)
11 #define ns_to_us(x)     ((uint32_t)((x)/1000.0))
12 
13 typedef unsigned int uint32_t;
14 
15 typedef enum PWM_Status{
16     PWM_STATUS_NONE = 0,
17     PWM_STATUS_RAISE,    //出现上升沿,处于高电平期间
18     PWM_STATUS_FALLING,  //出现下降沿,处于低电平期间
19     PWM_STATUS_SUCCESS,
20 }PWM_Status;
21 
22 typedef enum io_status{
23     IO_STATUS_LOW,   //低电平
24     IO_STATUS_HIGH,  //高电平
25 }IO_STATUS;
26 
27 typedef struct _pwm{
28     volatile PWM_Status pwm_status;       //电平标志
29     volatile uint32_t timer_uint_ns;      //定时器计数器单位时间
30     volatile uint32_t timer_max_cnt;      //定时器计数寄存器最大定时值
31     volatile uint32_t rise_start_time;    //上升沿定时器CNT值
32     volatile uint32_t fall_start_time;    //下降沿定时器CNT值
33     volatile uint32_t rise_timer_count;   //高电平期间,定时器更新次数
34     volatile uint32_t fall_timer_count;   //低电平期间,定时器更新次数
35     volatile uint32_t pulse_tmp;          //中间值,用户不需要直接访问
36     volatile uint32_t period_tmp;         //中间值,用户不需要直接访问
37     volatile uint32_t pulse;              //占空比高电平时间,单位ns
38     volatile uint32_t period;             //周期,单位ns      
39     PWM_Status (*pwm_input_io_changed)(struct _pwm* pwm, IO_STATUS io_status, uint32_t current_time);  //IO电平变化调用函数
40     void (*pwm_input_timer_count)(struct _pwm* pwm);       //定时器更新调用
41     uint32_t (*get_pwm_input_pulse)(struct _pwm* pwm);     //获取高电平时间,ns
42     uint32_t (*get_pwm_input_period)(struct _pwm* pwm);    //获取周期 ns
43 }PWM;
44 
45 void pwm_input_init(PWM* pwm, uint32_t uint_ns, uint32_t max_cnt);     //初始化PWM对象
46 
47 PWM_Status pwm_input_io_changed(PWM* pwm, IO_STATUS io_status, uint32_t current_time);  //外部触发IO中断调用函数
48 
49 void pwm_input_timer_count(PWM* pwm);              //定时器中断调用该函数
50 
51 uint32_t get_pwm_input_pulse(struct _pwm* pwm);    //获取高电平时间,单位ns
52 
53 uint32_t get_pwm_input_period(struct _pwm* pwm);   //获取周期,单位ns
54 
55 #endif

pwm_input.c

 1 /************************************************************
 2 **   捕获PWM信号占空比
 3 **   编写:Awesome    QQ: 2281280195
 4 **   代码可以免费移植使用
 5 *************************************************************/
 6 
 7 #include "pwm_input.h"
 8 
 9 /* 初始化pwm对象,传入两个参数: 定时器单位时间,定时器最大计数值 */
10 void pwm_input_init(PWM* pwm, uint32_t uint_ns, uint32_t max_cnt){
11     if((void*)0==pwm) return;
12     pwm->pwm_status = PWM_STATUS_NONE;
13     pwm->timer_uint_ns = uint_ns;
14     pwm->timer_max_cnt = max_cnt;
15     pwm->fall_start_time = 0;
16     pwm->fall_timer_count = 0;
17     pwm->pulse_tmp = 0;
18     pwm->period_tmp = 0;
19     pwm->period = 0;
20     pwm->pulse = 0;
21     pwm->rise_timer_count = 0;
22     pwm->rise_start_time = 0;
23     pwm->pwm_input_io_changed = pwm_input_io_changed;
24     pwm->pwm_input_timer_count = pwm_input_timer_count;
25     pwm->get_pwm_input_pulse = get_pwm_input_pulse;
26     pwm->get_pwm_input_period = get_pwm_input_period;
27 }
28 
29 /* IO输入上升沿中断或者下降沿中断,一个周期包括一个上升沿,一个下降沿,
30 ** 在接下来的上升沿触发时计算PWM周期
31 */
32 PWM_Status pwm_input_io_changed(PWM* pwm, IO_STATUS io_status, uint32_t current_time){
33     if((void*)0==pwm) return PWM_STATUS_NONE;
34     if(IO_STATUS_HIGH==io_status){ 
35             if(pwm->pwm_status==PWM_STATUS_NONE){  //第一个为上升沿
36                 pwm->pwm_status = PWM_STATUS_RAISE;  //上升沿开始
37                 //记录第一个周期上升开始时间
38                 pwm->rise_timer_count = 0;
39                 pwm->rise_start_time = current_time;
40             }else if(pwm->pwm_status==PWM_STATUS_FALLING){  //已经采集到下降沿,整个周期采集完成
41                 //计算周期
42                 if(pwm->fall_timer_count==0) pwm->period_tmp=pwm->pulse_tmp+(current_time-pwm->fall_start_time);
43                 else pwm->period = pwm->pulse_tmp + (pwm->fall_timer_count-1)*pwm->timer_max_cnt +(pwm->timer_max_cnt-pwm->fall_start_time) + current_time;
44                 
45                 pwm->rise_timer_count = 0;
46                 pwm->rise_start_time = current_time;
47                 pwm->pwm_status = PWM_STATUS_RAISE;
48                 
49                 pwm->period = pwm->period_tmp*pwm->timer_uint_ns;
50                 pwm->pulse = pwm->pulse_tmp*pwm->timer_uint_ns;
51                                         
52                 return PWM_STATUS_SUCCESS;   //成功计算一个PWM周期
53                 
54             }
55         }else {
56             if(pwm->pwm_status==PWM_STATUS_RAISE){ //已经采集到上升沿,在进入下降沿中断的时候计算占空比时间
57 
58                 pwm->fall_start_time = current_time;
59                 if( pwm->rise_timer_count==0 ) pwm->pulse_tmp = current_time - pwm->rise_start_time;
60                 else pwm->pulse_tmp = current_time + (pwm->rise_timer_count-1)*pwm->timer_max_cnt + (pwm->timer_max_cnt-pwm->rise_start_time);
61                 
62                 pwm->fall_timer_count = 0;
63                 pwm->pwm_status = PWM_STATUS_FALLING;
64                 
65             }
66         }
67         return pwm->pwm_status;
68 }
69 
70 /* 定时器更新调用 */
71 void pwm_input_timer_count(PWM* pwm){
72     if((void*)0==pwm) return;
73     if(pwm->pwm_status==PWM_STATUS_NONE){
74             pwm->rise_timer_count = 0;
75             pwm->fall_timer_count = 0;
76         }else if(pwm->pwm_status==PWM_STATUS_RAISE){
77             ++pwm->rise_timer_count;
78         }else if(pwm->pwm_status==PWM_STATUS_FALLING){
79             ++pwm->fall_timer_count;
80         }
81 }
82 
83 /* 获取高电平时间,单位ns */
84 uint32_t get_pwm_input_pulse(struct _pwm* pwm){
85     if((void*)0==pwm) return 0;
86     
87     return pwm->pulse;
88 }  
89 
90 /* 获取周期,单位ns */
91 uint32_t get_pwm_input_period(struct _pwm* pwm){
92     if((void*)0==pwm) return 0;
93     
94     return pwm->period;
95 }    

主代码调用

 1 /* 简单调用实例 */
 2 
 3 uint32_t pulse, period; //定义PWM占空比时间、周期结果变量,单位采用us
 4 
 5 PWM current_pwm;
 6 
 7 //初始化PWM对象,定时器单位时间为1us,最大定时值为0x10000
 8 pwm_input_init(&current_pwm, us_to_ns(1), 0x10000); 
 9 
10 //外部IO中断覆盖调用,基于cubeMX开发
11 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
12 {
13     IO_STATUS flag = IO_STATUS_LOW;
14     uint32_t curr_cnt = htim3.Instance->CNT; //在此使用定时器三,回去计数值16     
17     if(GPIO_Pin==GPIO_PIN_6){
18         if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)==GPIO_PIN_SET){ //高电平,上升沿
19             flag = IO_STATUS_HIGH;   
20         }else flag = IO_STATUS_LOW;  //低电平,下降沿
21         if( PWM_STATUS_SUCCESS==current_pwm.pwm_input_io_changed(&current_pwm, flag, curr_cnt) ){ //判断是否完整获取过一个周期
22             pulse = ns_to_us(current_pwm.pulse);   //获取占空比时间,单位us
23             period = ns_to_us(current_pwm.period); //获取周期,单位us29         }
30     }
31 }
32 
33 //定时器中断调用覆盖,基于cubeMX开发
34 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
35 {
36     if(htim==&htim3){  //使用定时器三
37         current_pwm.pwm_input_timer_count(&current_pwm);  //更新定时器计数值
38     }
39 }

获取输入PWM信号的占空比程序采用了面向对象的封装方法,可以使得程序调用简单。

猜你喜欢

转载自www.cnblogs.com/BlogsOfLei/p/12637663.html
今日推荐