• STM32-Project32:通用定时器输入捕获脉冲宽度实验;高级定时器捕获PWM的频率与占空比实验


    一 捕获脉冲宽度实验
    硬件设计
    根据开发板引脚使用情况,我们选用通用定时器 TIM5 CH1 ,就 PA0 这个 GPIO
    测量信号的脉宽。在开发板中 PA0 接的是一个按键,默认接 GND ,当按键按下的时候 IO
    口会被拉高,这个时候我们可以利用定时器的输入捕获功能来测量按键按下的这段高电平
    的时间。
    (1) 定时器用到的 GP IO 初始化
    (2) 定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化
    (3) 定时器输入捕获结构体 TIM_ICInitTypeDef 初始化
    (4) 编写中断服务函数,读取捕获值,计算出脉宽的时间
    1. #ifndef __GENERALTIME_H
    2. #define __GENERALTIME_H
    3. #include "stm32f10x.h"
    4. // 获取捕获寄存器值函数宏定义
    5. #define GENERAL_TIM_GetCapturex_FUN TIM_GetCapture1
    6. // 捕获信号极性函数宏定义
    7. #define GENERAL_TIM_OCxPolarityConfig_FUN TIM_OC1PolarityConfig
    8. // 测量的起始边沿
    9. #define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising
    10. // 测量的结束边沿
    11. #define GENERAL_TIM_END_ICPolarity TIM_ICPolarity_Falling
    12. // 定时器输入捕获用户自定义变量结构体声明
    13. typedef struct
    14. {
    15. uint8_t Capture_FinishFlag; // 捕获结束标志位
    16. uint8_t Capture_StartFlag; // 捕获开始标志位
    17. uint16_t Capture_CcrValue; // 捕获寄存器的值
    18. uint16_t Capture_Period; // 自动重装载寄存器更新标志
    19. }TIM_ICUserValueTypeDef;
    20. extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;
    21. void GENERAL_TIM_Init(void);
    22. #endif
    1. #include "generaltime.h"
    2. // 定时器输入捕获用户自定义变量结构体定义
    3. TIM_ICUserValueTypeDef TIM_ICUserValueStructure = {0,0,0,0};
    4. // 中断优先级配置
    5. static void GENERAL_TIM_NVIC_Config(void)
    6. {
    7. NVIC_InitTypeDef NVIC_InitStructure;
    8. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0
    9. NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn ; // 设置中断来源
    10. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 设置主优先级为 0
    11. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 设置抢占优先级为3
    12. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    13. NVIC_Init(&NVIC_InitStructure);
    14. }
    15. // 输入捕获通道 GPIO 初始化浮空输入
    16. static void GENERAL_TIM_GPIO_Config(void)
    17. {
    18. GPIO_InitTypeDef GPIO_InitStructure;
    19. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
    20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    21. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    22. GPIO_Init(GPIOA, &GPIO_InitStructure);
    23. }
    24. //配置定时器的5个结构体成员
    25. static void GENERAL_TIM_Mode_Config(void)
    26. {
    27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M
    28. //时基结构体初始化
    29. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    30. TIM_TimeBaseStructure.TIM_Period=0XFFFF; // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    31. TIM_TimeBaseStructure.TIM_Prescaler= (72-1); // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
    32. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分频因子 ,配置死区时间时需要用到,这里没用
    33. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,设置为向上计数
    34. TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管
    35. TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); // 初始化定时器
    36. //输入捕获结构体初始化
    37. TIM_ICInitTypeDef TIM_ICInitStructure;
    38. TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 配置输入捕获的通道,需要根据具体的GPIO来配置
    39. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 输入捕获信号的极性配置
    40. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 输入通道和捕获通道的映射关系,有直连和非直连两种
    41. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 输入的需要被捕获的信号的分频系数
    42. TIM_ICInitStructure.TIM_ICFilter = 0;// 输入的需要被捕获的信号的滤波系数
    43. TIM_ICInit(TIM5, &TIM_ICInitStructure); // 定时器输入捕获初始化
    44. TIM_ClearFlag(TIM5, TIM_FLAG_Update| TIM_IT_CC1); // 清除更新中断和捕获中断标志位
    45. TIM_ITConfig (TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE ); // 开启更新和捕获中断
    46. TIM_Cmd(TIM5, ENABLE);// 使能计数器
    47. }
    48. void GENERAL_TIM_Init(void)
    49. {
    50. GENERAL_TIM_GPIO_Config();
    51. GENERAL_TIM_NVIC_Config();
    52. GENERAL_TIM_Mode_Config();
    53. }
    在初始化时基结构体的周期和时钟分频因子这两个成员时,我们使用了两个宏
    GENERAL_TIM_PERIOD GENERAL_TIM_PSC GENERAL_TIM_PERIOD 配置的是
    ARR 寄存器的值,决定了计数器一个周期的计数时间,默认我们配置为 0XFFFF ,即最大。
    GENERAL_TIM_PSC 配置的是分频因子,默认配置为 72-1 ,则可以计算出计数器的计数
    周期为 (GENERAL_TIM_PSC+1)/72M = 1US 。所以输入捕获能捕获的最小的时间为 1us
    最长的时间为 1us*(0Xffff+1)=65536us=65.536ms ,当超过这个计数周期的时候,就会产生
    中断,然后在中断里面做额外的处理,需要记录好产生了多少次更新中断,最后把这个更
    新时间加入到脉宽的时间里面。
    GENERAL_TIM_Mode_Config() 函 数 中 , 我 们 配 置 输 入 捕 获 的 起 始 边 沿 为
    GENERAL_TIM_STRAT_ICPolarity ,这是一个宏,默认配置为上升沿。我们的按键默认是
    GND ,当按键按下的时候会被拉高,这个时候这个由低到高的上升沿会被捕获到,这是
    第一次捕获,此时我们把计数器清 0,开始计数,同时把捕获边沿改成下降沿捕获。当第
    二次进入中断服务函数的时候,说明捕获到下降沿,这个时候表示脉宽捕获完毕,我们读
    取捕获寄存器的值即可,然后我们就可以通过这个值算出脉宽的时间。最后把捕获编译配
    置为上升沿,为的是下一次捕获。如果脉宽的时间超过了计数器的最大计数时间,那么就
    会产生更新中断,我们需要做额外的处理,即产生了多少次更新中断记录下来,最后在算
    脉宽的时间的时候把这个更新的时间加进去即可。
    中断服务函数里面用到的捕获结束标志位、捕获开始标志位、捕获寄存器的值和自动
    重装载更新标志这几个成员是在一个结构体里面定义,具体声明见代码清单 32-12 。其中
    声明是在 bsp_GeneralTim.h 这个头文件中,定义和初始化则在 bsp_GeneralTim.c 文件。
    1. //捕获脉冲的核心代码
    2. void TIM5_IRQHandler(void)
    3. {
    4. // 当要被捕获的信号的周期大于定时器的最长定时时,定时器就会溢出,产生更新中断
    5. // 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去
    6. if ( TIM_GetITStatus (TIM5, TIM_IT_Update) != RESET )
    7. {
    8. TIM_ICUserValueStructure.Capture_Period ++;
    9. TIM_ClearITPendingBit(TIM5, TIM_FLAG_Update );
    10. }
    11. // 上升沿捕获中断
    12. if ( TIM_GetITStatus(TIM5,TIM_IT_CC1 ) != RESET)
    13. {
    14. // 第一次捕获
    15. if (TIM_ICUserValueStructure.Capture_StartFlag == 0 )
    16. {
    17. TIM_SetCounter (TIM5, 0);// 计数器清0
    18. TIM_ICUserValueStructure.Capture_Period = 0;// 自动重装载寄存器更新标志清0
    19. TIM_ICUserValueStructure.Capture_CcrValue = 0; // 存捕获比较寄存器的值的变量的值清0
    20. TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);// 当第一次捕获到上升沿之后,就把捕获边沿配置为下降沿
    21. TIM_ICUserValueStructure.Capture_StartFlag = 1; // 开始捕标志准置1
    22. }
    23. // 下降沿捕获中断
    24. else // 第二次捕获
    25. {
    26. // 获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值
    27. TIM_ICUserValueStructure.Capture_CcrValue = TIM_GetCapture1 (TIM5);
    28. // 当第二次捕获到下降沿之后,就把捕获边沿配置为上升沿,好开启新的一轮捕获
    29. TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
    30. TIM_ICUserValueStructure.Capture_StartFlag = 0;// 开始捕获标志清0
    31. TIM_ICUserValueStructure.Capture_FinishFlag = 1; // 捕获完成标志置1
    32. }
    33. TIM_ClearITPendingBit (TIM5,TIM_IT_CC1);
    34. }
    35. }
    1. #include "stm32f10x.h"
    2. #include "led.h"
    3. #include "key.h"
    4. #include "rcc.h"
    5. #include "exti.h"
    6. #include "systick.h"
    7. #include "usart.h"
    8. #include <stdio.h>
    9. #include "basetime.h"
    10. #include "advancetime.h"
    11. #include "generaltime.h"
    12. /*
    13. 通用定时器TIM5_CH1即PA0引脚测量脉冲,本身接wake_up按键,
    14. 按键按下接高电平,测量高电平脉冲时间,在串口上位机显示
    15. */
    16. int main(void)
    17. {
    18. uint32_t time;
    19. uint32_t TIM_PscCLK = 72000000 / ((72-1)+1); // TIM 计数器的驱动时钟
    20. USART_Config();//串口初始化
    21. GENERAL_TIM_Init();// 定时器初始化
    22. printf ( "\r\nSTM32 输入捕获实验\r\n" );
    23. printf ( "\r\n按下wake_up,测试按下的时间\r\n" );
    24. while (1){
    25. if(TIM_ICUserValueStructure.Capture_FinishFlag == 1)
    26. {
    27. // 计算高电平时间的计数器的值
    28. time = TIM_ICUserValueStructure.Capture_Period * (0XFFFF+1) +
    29. (TIM_ICUserValueStructure.Capture_CcrValue+1);
    30. // 打印高电平脉宽时间
    31. printf ( "\r\n测得高电平脉宽时间:%d.%d s\r\n",time/TIM_PscCLK,time%TIM_PscCLK );
    32. TIM_ICUserValueStructure.Capture_FinishFlag = 0;
    33. }
    34. }
    35. }

    二  高级定时器捕获PWM的周期与占空比

    在本节实验中,我们用通用定时器产 生一路 PWM 信号,然后用高级定时器的通道 1 或者通道 2 来捕获。
    硬件设计
    实验中用到两个引脚,一个是通用定时器 TIM3 的通道 1 ,即 PA6 ,用于输出 PWM
    号,另一个是高级控制定时器 TIM1 的通道 1 ,即 PA8 ,用于 PWM 输入捕获,实验中直接
    用一根杜邦线短接即可 PA6 PA8 即可,同时可用示波器监控 PA6 的波形,看看实验捕
    获的数据是否正确。
    编程要点
    (1) 通用定时器产生 PWM 配置
    (2) 高级定时器 PWM 输入配置
    (3) 编写中断服务程序,计算测量的频率和占空比,并打印出来比较
    编程的要点主要分成两部分,一个是通用定时器的 PWM 信号输出,另一个是 PWM
    信号输入捕获。
    通用定时器 PWM 输出
    1. #include "generaltime3.h"
    2. /**
    3. * @brief 通用定时器PWM输出用到的GPIO初始化
    4. * @param 无
    5. * @retval 无
    6. */
    7. static void GENERAL_TIM_GPIO_Config(void)
    8. {
    9. GPIO_InitTypeDef GPIO_InitStructure;
    10. // 输出比较通道1 GPIO 初始化
    11. RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);
    12. GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;
    13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    15. GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);
    16. }
    17. static void GENERAL_TIM_Mode_Config(void)
    18. {
    19. GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M
    20. //时基结构体初始化 配置周期,这里配置为100K
    21. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    22. TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    23. TIM_TimeBaseStructure.TIM_Prescaler= (72-1); // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
    24. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 时钟分频因子 ,配置死区时间时需要用到
    25. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,设置为向上计数
    26. TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管
    27. TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); // 初始化定时器
    28. //输出比较结构体初始化
    29. TIM_OCInitTypeDef TIM_OCInitStructure;
    30. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 配置为PWM模式1
    31. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 输出使能
    32. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置
    33. TIM_OCInitStructure.TIM_Pulse = 5;
    34. TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);// 初始化输出比较通道 1
    35. TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
    36. TIM_Cmd(GENERAL_TIM, ENABLE);// 使能计数器
    37. }
    38. void GENERAL_TIM3_Init(void)
    39. {
    40. GENERAL_TIM_GPIO_Config();
    41. GENERAL_TIM_Mode_Config();
    42. }
    高级定时器 PWM 输入捕获
    1. #ifndef __ADVANCETIME1_H
    2. #define __ADVANCETIME1_H
    3. #include "stm32f10x.h"
    4. #define ADVANCE_TIM TIM1
    5. #define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
    6. #define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
    7. // 输入捕获能捕获到的最小的频率为 72M/{ (ARR+1)*(PSC+1) }
    8. #define ADVANCE_TIM_PERIOD (1000-1)
    9. #define ADVANCE_TIM_PSC (72-1)
    10. // 中断相关宏定义
    11. #define ADVANCE_TIM_IRQ TIM1_CC_IRQn
    12. #define ADVANCE_TIM_IRQHandler TIM1_CC_IRQHandler
    13. // TIM1 输入捕获通道1
    14. #define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
    15. #define ADVANCE_TIM_CH1_PORT GPIOA
    16. #define ADVANCE_TIM_CH1_PIN GPIO_Pin_8
    17. #define ADVANCE_TIM_IC1PWM_CHANNEL TIM_Channel_1
    18. void ADVANCE_TIM1_Init(void);
    19. #endif
    在上面的宏定义里面,我们可以算出计数器的计数周期为 T=72M/(1000*72)=1MS ,这
    个是定时器在不溢出的情况下的最大计数周期,也就是说周期小于 1ms PWM 信号都可
    以被捕获到,转换成频率就是能捕获到的最小的频率为 1KHZ 。所以我们要根据捕获的
    PWM 信号来调节 ADVANCE_TIM_PERIOD ADVANCE_TIM_PSC 这两个宏。
    1. #include "advancetime1.h"
    2. static void ADVANCE_TIM_NVIC_Config(void)
    3. {
    4. NVIC_InitTypeDef NVIC_InitStructure;
    5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0
    6. NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; // 设置中断来源
    7. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级
    8. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 设置子优先级
    9. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    10. NVIC_Init(&NVIC_InitStructure);
    11. }
    12. static void ADVANCE_TIM_GPIO_Config(void)
    13. {
    14. GPIO_InitTypeDef GPIO_InitStructure;
    15. RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
    16. GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
    17. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    18. GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);
    19. }
    20. static void ADVANCE_TIM_Mode_Config(void)
    21. {
    22. ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE); //开启定时器时钟,即内部时钟CK_INT=72M
    23. //时基结构体初始化:用于测量频率那么你的时基就需要比信号高
    24. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    25. TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    26. TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
    27. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分频因子 ,配置死区时间时需要用到
    28. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 计数器计数模式,设置为向上计数
    29. TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管
    30. TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure); // 初始化定时器
    31. //输入捕获结构体初始化 使用PWM输入模式时,需要占用两个捕获寄存器,一个测周期,另外一个测占空比
    32. TIM_ICInitTypeDef TIM_ICInitStructure;
    33. TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 捕获通道IC1配置 ,选择捕获通道
    34. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 设置捕获的边沿
    35. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 设置捕获通道的信号来自于哪个输入通道,有直连和非直连两种
    36. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 1分频,即捕获信号的每个有效边沿(上升沿)捕获
    37. TIM_ICInitStructure.TIM_ICFilter = 0x0;// 不滤波
    38. TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);// 初始化PWM输入模式
    39. //直连与非直连区别仅仅是捕获寄存器1来捕获周期,2来捕获占空比。还是捕获寄存器2来捕获周期,1捕获占空比
    40. TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1);// 选择输入捕获的触发信号:即捕获信号周期
    41. // 选择从模式: 即复位模式。 因为PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
    42. TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
    43. TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);
    44. TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);// 使能捕获中断,这个中断针对的是主捕获通道(测量周期那个)
    45. TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);// 清除中断标志位
    46. TIM_Cmd(ADVANCE_TIM, ENABLE);// 使能高级控制定时器,计数器开始计数
    47. }
    48. void ADVANCE_TIM1_Init(void)
    49. {
    50. ADVANCE_TIM_GPIO_Config();
    51. ADVANCE_TIM_NVIC_Config();
    52. ADVANCE_TIM_Mode_Config();
    53. }

    ADVANCE_TIM_Mode_Config()函数中初始化了两个结构体,
    因为是 PWM 输入模式,只能使用通道 1 和通道 2 ,假如我们使用的是通道 1 ,即 TI1
    输入的 PWM 信号会被分成两路,分别是 TI1FP1 TI1FP2 ,两路都可以是触发信号。如
    果选择 TI1FP1 为触发信号,那么 IC1 捕获到的是 PWM 信号的周期, IC2 捕获到的是占空
    比 , 这 种 输 入 通 道 TI 和 捕获通道 IC 的映射 关系叫直连,输入捕获结构体的
    TIM_ICSelection 要配置为 TIM_ICSelection_DirectTI 。如果选择 TI1FP2 为触发信号,则
    IC2 捕获到的是周期, IC1 捕获到的是占空比,这种输入通道 TI 和捕获通道 IC 的映射关系
    叫非直连,输入捕获结构体的 TIM_ICSelection 要配置为 TIM_ICSelection_IndirectTI 。有关
    输入通道 TI 和捕获通道 IC 的具体映射关系见图 ,有直连和非直连两种。
    1. __IO uint16_t IC2Value = 0;
    2. __IO uint16_t IC1Value = 0;
    3. __IO float DutyCycle = 0;
    4. __IO float Frequency = 0;
    5. void ADVANCE_TIM_IRQHandler(void)
    6. {
    7. TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);/* 清除中断标志位 */
    8. /* 获取输入捕获值 */
    9. IC1Value = TIM_GetCapture1(ADVANCE_TIM);
    10. IC2Value = TIM_GetCapture2(ADVANCE_TIM);
    11. // 注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须加1
    12. if (IC1Value != 0)
    13. {
    14. DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);/* 占空比计算 */
    15. Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);/* 频率计算 */
    16. printf("占空比:%0.2f%% 频率:%0.2fHz\n",DutyCycle,Frequency);
    17. }
    18. else
    19. {
    20. DutyCycle = 0;
    21. Frequency = 0;
    22. }
    23. }
    当捕获到 PWM 信号的第一个上升沿时,产生中断,计数器被复位,锁存到捕获寄存
    IC1 IC2 的值都为 0 。当下降沿到来时, IC2 会捕获,对应的是占空比,但是会产生中
    断。当捕获到第二个下降沿时, IC1 会捕获,对应的是周期,而且会再次进入中断,这个
    时间就可以根据 IC1 IC2 的值计算出频率和占空比。有关 PWM 输入的时序见图 
    中断复位函数中,我们获取输入捕获寄存器 CCR1 CCR2 寄存器中的值,当 CCR1
    的值不为 0 时,说明有效捕获到了一个周期,然后计算出频率和占空比。在计算的时候
    CCR1 CCR2 的值都必须要加 1 ,因为计数器是从 0 开始计数的

     

    1. #include "stm32f10x.h"
    2. #include "led.h"
    3. #include "key.h"
    4. #include "rcc.h"
    5. #include "exti.h"
    6. #include "systick.h"
    7. #include "usart.h"
    8. #include
    9. #include "basetime.h"
    10. #include "advancetime.h"
    11. #include "generaltime.h"
    12. #include "advancetime1.h"
    13. #include "generaltime3.h"
    14. /*
    15. 采样率不能低于信号频率,不然采集不到,
    16. 把通用定时器3产生100Khz占空比50的pwmPA6引脚接到高级定时器1输入捕获引脚PA8
    17. */
    18. int main(void)
    19. {
    20. USART_Config();
    21. GENERAL_TIM3_Init();//基本的事情配置输出100Khz占空比50信号
    22. ADVANCE_TIM1_Init();/* 高级定时器初始化 ,用户捕获PWM信号*/
    23. while (1){
    24. }
    25. }

  • 相关阅读:
    Hive企业实战ORC表数据翻倍,颠覆你认知的Cluster by作用?
    s27.linux运维面试题分享
    计算机毕业设计之交互式大学英语学习平台
    Netty第三部
    华为数通方向HCIP-DataCom H12-831题库(单选题:41-60)
    idea工具中maven的Lifecycle功能讲解
    RTOS必备操作---临界区保护
    Videos Understanding Dataset
    最新720全景云系统/可生成小程序+带PC端+安装教程/价值800元的720云全景系统源码
    如何集成 Spring Boot实现 MyCat读写分离?
  • 原文地址:https://blog.csdn.net/qq_45871216/article/details/126571212