你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

玩转STM32CubeMX | 输入捕获

[复制链接]
STMCU-管管 发布时间:2020-12-2 11:21
玩转STM32CubeMX | 输入捕获
1.输入捕获简介


输入捕获模式可以用来测量脉冲宽度或者测量频率,下图以测量脉宽为例来说明输入捕获的原理
11.png
假定定时器工作在向上计数模式,图中t1-t2的时间就是我们需要测量的低电平时间。测量方法为:首先设置定时器通道x为下降沿捕获,在t1时刻就会捕获到当前的CNT值,然后立即清零CNT,并设置通道x为上升沿捕获,到t2时刻又会发送捕获事件,得到此时的CNT值(记为CCRx2)。在t1-t2之间可能产生N次定时器溢出,因此需要对定时器溢出做处理,防止低电平太长导致数据不准确。
t1-t2之间计数的次数为:N * ARR + CCRx2,再乘以CNT计数周期即可得到低电平持续时间
12.png
2.硬件设计


本实验通过TIM5的通道1输入捕获功能捕获KEY_UP按键的高电平持续时间,并通过printf函数打印捕获到的高电平时间,用D1指示灯提示系统正常运行


指示灯D1
定时器TIM5
USART1串口
K_UP按键
13.png
3.软件设计


3.1 STM32CubeMX设置


➡️ RCC设置外接HSE,时钟设置为72M


➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平


➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位


➡️ 选择TIM5,设置定时器时钟源为内部时钟源、设置通道1为输入捕获模式(PA0自动被选中),NVIC设置中激活定时器中断,在GPIO设置里将PA0下拉保证没有信号输入的时候电平稳定
14.png
➡️ 预分频系数设置为72-1,向上计数,自动重装载值设为0xFFFF,则计时器时钟频率为1MHz,计时器周期为1us,定时器溢出周期为 65535 * 1 = 65535us
15.png
➡️输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码


3.2 MDK-ARM软件编程


➡️ 在tim.c文件中编写定时器更新中断处理回调函数
  1. /* TIM5CH1_CAP_STA 各数据位说明
  2. ** bit7   捕获完成标志
  3. ** bit6          捕获到高电平标志
  4. ** bit5~0 捕获高电平后定时器溢出的次数*/
  5. uint8_t TIM5CH1_CAP_STA = 0;
  6. uint16_t TIM5CH1_CAP_VAL;
  7. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
  8.   if((TIM5CH1_CAP_STA&0X80)==0){        //还未成功捕获
  9.     if(TIM5CH1_CAP_STA&0X40){        //已经捕获到高电平
  10.       if((TIM5CH1_CAP_STA&0X3F)==0X3F){ //高电平时间太长了
  11.         TIM5CH1_CAP_STA |= 0X80;//标记为完成一次捕获
  12.         TIM5CH1_CAP_VAL = 0XFFFF;//计数器值
  13.       }else
  14.         TIM5CH1_CAP_STA++;//溢出次数加1                        
  15.     }        
  16.   }
  17. }
复制代码
➡️ 在tim.c文件中编写输入捕获中断处理回调函数
  1. void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
  2.   if((TIM5CH1_CAP_STA & 0X80) == 0){        //还未成功捕获
  3.     if(TIM5CH1_CAP_STA & 0X40){        //捕获到上升沿后条件为真
  4.       TIM5CH1_CAP_STA |= 0X80;        //标记为完成一次高电平捕获
  5.       TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的计数器值
  6.       TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);//清除原来的设置               
  7.       TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//设置上升沿捕获
  8.     }else{
  9.       TIM5CH1_CAP_STA = 0;
  10.       TIM5CH1_CAP_VAL = 0;
  11.       TIM5CH1_CAP_STA |= 0X40;//标记捕获到上升沿
  12.       __HAL_TIM_DISABLE(&htim5);//关闭定时器
  13.       __HAL_TIM_SET_COUNTER(&htim5,0);//计数器值清零
  14.       TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);//清除原来的设置                                
  15.       TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//设置下降沿捕获
  16.       __HAL_TIM_ENABLE(&htim5);//使能定时器               
  17.     }        
  18.   }
  19. }        
复制代码
此处的TIM_RESET_CAPTUREPOLARITY() 函数有一处HAL库函数错误,会导致编译该函数报错,解决办法是找到该函数在 stm32f1xx_hal_tim.h 文件中的定义,删除多余的一个反括号 ‘)’
  1. stm32f1xx_hal_tim.h
  2. //修改前
  3. #define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  4.   (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :\
  5.    ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
  6.    ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
  7.    ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
  8. //修改后
  9. #define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
  10.   (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :\
  11.    ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
  12.    ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
  13.    ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
复制代码
➡️ 在main.c文件中编写高电平持续时间处理代码
  1. int main(void){
  2.   long long temp = 0;
  3.   HAL_Init();
  4.   SystemClock_Config();
  5.   MX_GPIO_Init();
  6.   MX_TIM5_Init();
  7.   MX_USART1_UART_Init();
  8.   /* USER CODE BEGIN 2 */
  9.   //一定要开启TIM5通道1的捕获中断
  10.   HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);
  11.   //一定要开启TIM5的更新中断        
  12.   __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);        
  13.   printf("This is TIM_CAP test...\n");
  14.   /* USER CODE END 2 */
  15.   while (1){
  16.     HAL_Delay(500);
  17.     if(TIM5CH1_CAP_STA & 0X80){        //完成一次高电平捕获
  18.       temp = TIM5CH1_CAP_STA & 0X3F;
  19.       temp *= 65536;                //溢出总时间
  20.       temp += TIM5CH1_CAP_VAL;        //总的高电平时间
  21.       printf("High level duration:%lld us\r\n",temp);
  22.       TIM5CH1_CAP_STA = 0;        //准备下一次捕获
  23.     }
  24.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
  25.   }
  26. }
复制代码
4.下载验证


编译无误后下载到开发板,可以看到D1指示灯每500ms闪烁一次,按下KEY_UP后,串口会打印出相应的高电平持续时间
16.png

收藏 评论1 发布时间:2020-12-2 11:21

举报

1个回答
网事悠悠 回答时间:2020-12-2 17:19:03
实用,感谢分享!
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版