完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
由于功能添加且板子已经定型的原因,在原来没有定时器输入捕获的引脚上添加频率检测,便使用了STM32的外部中断与定时器的配合来做简单测量。
一、步骤: 1、初始化引脚的外部中断,我这里用了PA11和PA12两个引脚,void EXTI_PA11_PA12_Config(void),需要注意的是频率检测只使用上升沿触发即可,如果测量占空比,则采用双边沿检测; 2、初始化两个定时器,TIM4和TIM6, GENERAL_TIM4_Mode_Config(); BASIC_TIM6_Mode_Config(); 这里需要注意的是: (1)定时器的最小采样时间是根据时钟的分频系数相关的,比如时钟现在是72000000HZ,定时器分频系数是72-1,则分频后的定时器时钟为1000000HZ(即1us); (2)最大采样间隔(即超过这个时间还没有采样到一个脉冲)是跟定时器的中断间隔相关的,定时器产生溢出中断后计数值CNT会自动清0,定时器的中断间隔由分频系数Prescaler和自动重装载寄存器Period决定,分频系数前面已经确定,那最大采样间隔只需要考虑自动重装载寄存器Period的设置,比如频分析系数72-1,自动重装寄存器值10000-1,则 中断间隔=72000000/72/10000=100HZ,即最大采样间隔10ms,如果10ms内没有检测到一个脉冲,则这么设定间隔是不合理的,必须想办法牺牲最小的采样时间1us(扩大分频系数)或者扩大自动重装寄存器值(16位,<65535)来增加定时器中断间隔,也可以编写自己的应用函数来计算溢出的定时时间。 3.编写外部中断函数void EXTI15_10_IRQHandler(void); 来一次脉冲上升沿则会触发一次外部中断,定时器的时钟一直运行着,CNT计数值++,计算两次的CNT差值然后根据定时器时钟即可算出频率; 4.编写定时器中断函数,这部分主要是应用,根据项目的要求,在没有接收到脉冲后1s需要清零计数值,这里清零的地方正好放在定时器中断中处理。 仿真: 信号发生器: 二、代码: TimeInput.c /** ****************************************************************************** * @file TimeInput.c * @author davidysw * @version V1.0 * @date 2019-12-xx * @brief 定时器输入捕获 * @brief ****************************************************************************** **/ #include "TimeInput.h" float FrequencyPA11; //输入脉冲的频率HZ float FrequencyPA12; //输入脉冲的频率HZ uint16_t PA11_Counter1=0; uint16_t PA12_Counter1=0; uint16_t ClearPA11Count=0;//用来计数,2s内不在有脉冲进入则清零 测速值 uint16_t ClearPA12Count=0;//用来计数,2s内不在有脉冲进入则清零 测速值 /*************************************************** //中断优先级配置 *****************************************************/ static void GENERAL_TIM4_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM4_IRQ ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /*************************************************** //定时器配置 *****************************************************/ static void GENERAL_TIM4_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; GENERAL_TIM4_NVIC_Config(); // 开启定时器时钟,即内部时钟CK_INT=72M GENERAL_TIM4_APBxClock_FUN(GENERAL_TIM4_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM4_Period; // 时钟预分频数 TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM4_Prescaler; // 时钟分频因子 ,没用到不用管 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM4, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(GENERAL_TIM4, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(GENERAL_TIM4,TIM_IT_Update,ENABLE); // 使能计数器 TIM_Cmd(GENERAL_TIM4, ENABLE); } /*************************************************** //中断优先级配置 *****************************************************/ static void BASIC_TIM6_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM6_IRQ ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /*************************************************** //定时器配置 *****************************************************/ static void BASIC_TIM6_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; BASIC_TIM6_NVIC_Config(); // 开启定时器时钟,即内部时钟CK_INT=72M BASIC_TIM6_APBxClock_FUN(BASIC_TIM6_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 TIM_TimeBaseStructure.TIM_Period = BASIC_TIM6_Period; // 时钟预分频数为 TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM6_Prescaler; // 时钟分频因子 ,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置 //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定时器 TIM_TimeBaseInit(BASIC_TIM6, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(BASIC_TIM6, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(BASIC_TIM6,TIM_IT_Update,ENABLE); // 使能计数器 TIM_Cmd(BASIC_TIM6, ENABLE); } /*************************************************** //引脚输入初始化 *****************************************************/ void GPIO_NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 配置NVIC为优先级组1 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); /* 配置中断源:PA11、PA12 */ NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; /* 配置抢占优先级 */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 配置子优先级 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 使能中断通道 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /** * @brief 配置 IO为EXTI中断口,并设置中断优先级 * @param 无 * @retval 无 */ void EXTI_PA11_PA12_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; /*开启GPIO口的时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); /* 配置 NVIC 中断*/ GPIO_NVIC_Configuration(); /*--------------------------配置-----------------------------*/ /* 选择按键用到的GPIO */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; /* 配置为浮空输入 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 选择EXTI的信号源 */ GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource11); EXTI_InitStructure.EXTI_Line = EXTI_Line11; /* EXTI为中断模式 */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* 上升沿中断 */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; /* 使能中断 */ EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /*--------------------------配置-----------------------------*/ /* 选择按键用到的GPIO */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; /* 配置为浮空输入 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 选择EXTI的信号源 */ GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource12); EXTI_InitStructure.EXTI_Line = EXTI_Line12; /* EXTI为中断模式 */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* 下降沿中断 */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; /* 使能中断 */ EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } /*************************************************** //定时器初始化,定时10us *****************************************************/ void TIME_INPUT_Init(void) { GENERAL_TIM4_Mode_Config(); BASIC_TIM6_Mode_Config(); EXTI_PA11_PA12_Config(); } /*************************************************** //PA11、PA12外部中断,上升沿检测,计数脉冲精度1us,与定时器分频有关,最大脉冲间隔与定时器计数值有关,10000即10ms *****************************************************/ void EXTI15_10_IRQHandler(void) { //确保是否产生了EXTI Line中断 if(EXTI_GetITStatus(EXTI_Line11) != RESET) { FrequencyPA11=1000000/(TIM4->CNT-PA11_Counter1); TIM4->CNT=0; PA11_Counter1=TIM4->CNT; ClearPA11Count=0; EXTI_ClearITPendingBit(EXTI_Line11); //清除中断标志位 } if(EXTI_GetITStatus(EXTI_Line12) != RESET) { FrequencyPA12=1000000/(TIM6->CNT-PA12_Counter1); TIM6->CNT=0; PA12_Counter1=TIM6->CNT; ClearPA12Count=0; EXTI_ClearITPendingBit(EXTI_Line12);//清除中断标志位 } } /*************************************************** //定时器中断 *****************************************************/ void TIM4_IRQHandler (void) { if ( TIM_GetITStatus( GENERAL_TIM4, TIM_IT_Update) != RESET ) { ClearPA11Count++; if(ClearPA11Count>100)//1s { ClearPA11Count=0; PA11_Counter1=0; FrequencyPA11=0; } TIM_ClearITPendingBit(GENERAL_TIM4 , TIM_FLAG_Update); } } void TIM6_IRQHandler (void) { if ( TIM_GetITStatus( BASIC_TIM6, TIM_IT_Update) != RESET ) { ClearPA12Count++; if(ClearPA12Count>100) //1s { ClearPA12Count=0; PA12_Counter1=0; FrequencyPA12=0; } TIM_ClearITPendingBit(BASIC_TIM6 , TIM_FLAG_Update); } } TimeInput.h #ifndef _TIMEINPUT_H #define _TIMEINPUT_H #include "stm32f10x.h" #define GENERAL_TIM4 TIM4 #define GENERAL_TIM4_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM4_CLK RCC_APB1Periph_TIM4 #define GENERAL_TIM4_Period (10000-1) #define GENERAL_TIM4_Prescaler 72-1 #define GENERAL_TIM4_IRQ TIM4_IRQn #define GENERAL_TIM4_IRQHandler TIM4_IRQHandler #define BASIC_TIM6 TIM6 #define BASIC_TIM6_APBxClock_FUN RCC_APB1PeriphClockCmd #define BASIC_TIM6_CLK RCC_APB1Periph_TIM6 #define BASIC_TIM6_Period 10000-1 #define BASIC_TIM6_Prescaler 71 #define BASIC_TIM6_IRQ TIM6_IRQn #define BASIC_TIM6_IRQHandler TIM6_IRQHandler extern void TIME_INPUT_Init(void); #endif |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1606 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1538 浏览 1 评论
969 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
681 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1584 浏览 2 评论
1861浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
643浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
528浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
503浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-20 09:18 , Processed in 0.560875 second(s), Total 48, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号