STM32CubeMX系列 | 输入捕获

发布时间:2023-03-21  

1. 输入捕获简介

输入捕获模式可以用来测量脉冲宽度或者测量频率,下图以测量脉宽为例来说明输入捕获的原理

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

2. 硬件设计

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

  • D1指示灯

  • K_UP按键

  • USART1串口

  • TIM5

3. 软件设计

3.1 STM32CubeMX设置

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

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

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

  • 选择TIM5,设置定时器时钟源为内部时钟源、设置通道1为输入捕获模式(PA0自动被选中),NVIC设置中激活定时器中断,在GPIO设置里将PA0下拉保证没有信号输入的时候电平稳定

  • 预分频系数设置为72-1,向上计数,自动重装载值设为0xFFFF,则计时器时钟频率为1MHz,计时器周期为1us,定时器溢出周期为 65535 * 1 = 65535us

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

3.2 MDK-ARM编程

  • 在tim.c文件中编写定时器更新中断处理回调函数

/* TIM5CH1_CAP_STA 各数据位说明

** bit7   捕获完成标志

** bit6   捕获到高电平标志

** bit5~0 捕获高电平后定时器溢出的次数*/

uint8_t TIM5CH1_CAP_STA = 0;

uint16_t TIM5CH1_CAP_VAL;


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){

    if((TIM5CH1_CAP_STA & 0X80) == 0){  //还未成功捕获

        if(TIM5CH1_CAP_STA & 0X40){     //已经捕获到高电平

            if((TIM5CH1_CAP_STA & 0X3F) == 0X3F){   //高电平时间太长了

                TIM5CH1_CAP_STA |= 0X80;            //标记为完成一次捕获

                TIM5CH1_CAP_VAL = 0XFFFF;           //计数器值

            }

            else

                TIM5CH1_CAP_STA++;      //溢出次数加1            

        }   

    }

}

在tim.c文件中编写输入捕获中断处理回调函数

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){

    if((TIM5CH1_CAP_STA & 0X80) == 0){  //还未成功捕获

        if(TIM5CH1_CAP_STA & 0X40){     //捕获到上升沿后条件为真

            TIM5CH1_CAP_STA |= 0X80;    //标记为完成一次高电平捕获

            TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);  //获取当前的计数器值

            TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);    //清除原来的设置       

            TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);    //设置上升沿捕获

        }

        else{

            TIM5CH1_CAP_STA = 0;

            TIM5CH1_CAP_VAL = 0;

            TIM5CH1_CAP_STA |= 0X40;    //标记捕获到上升沿

            __HAL_TIM_DISABLE(&htim5);  //关闭定时器

            __HAL_TIM_SET_COUNTER(&htim5,0);    //计数器值清零

            TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);    //清除原来的设置               

            TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);   //设置下降沿捕获

            __HAL_TIM_ENABLE(&htim5);   //使能定时器     

        }   

    }

}

此处的TIM_RESET_CAPTUREPOLARITY() 函数有一处HAL库函数错误,会导致编译该函数报错,解决办法是找到该函数在 stm32f1xx_hal_tim.h 文件中的定义,删除多余的一个反括号 ‘)’

stm32f1xx_hal_tim.h

//修改前

#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__)

  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :

   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :

   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))

//修改后

#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__)

  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :

   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :

   ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))

在main.c文件中编写高电平持续时间处理代码

int main(void){

  long long temp = 0;

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  MX_TIM5_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);    //一定要开启TIM5通道1的捕获中断

  __HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);    //一定要开启TIM5的更新中断

  printf("This is TIM_CAP test...n");

  /* USER CODE END 2 */

  while (1){

    HAL_Delay(500);

    if(TIM5CH1_CAP_STA & 0X80){     //完成一次高电平捕获

        temp = TIM5CH1_CAP_STA & 0X3F;

        temp *= 65536;              //溢出总时间

        temp += TIM5CH1_CAP_VAL;    //总的高电平时间

        printf("High level duration:%lld usrn",temp);

        TIM5CH1_CAP_STA = 0;        //准备下一次捕获

    }

    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

  }

}

4. 下载验证

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


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>