完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
实验目的
STM32的通用定时器和高级定时器拥有输入捕获功能,本章我们将利用TIM3的CH3通道产生PWM输出波形连接到TIM5的CH2输入捕捉通道,测量PWM输出波形频率。数据手册请参看第14章中的相关内容 实验简介 输入捕获模式可以用来测量脉冲宽度和频率。所谓的捕获,就是检测定时器的TIMx_CHx输入捕获引脚,检测到信号跳变时,将当前的定时器的计数值(TIMx_CNT)保存到捕获寄存器(TIMx_CCRx),完成一次捕获,当使能捕获中断时,会产生中断。 本实验是利用捕获功能来测量脉冲频率,脉冲由PWM模块产生,那我们是怎么样测量的呢?原理是这样的:连续捕获2次上升沿/下降沿信号跳变,分别记录下2次的定时器计数值,这2个计数值的差值就是脉冲宽度,且计数器的计数频率我们是知道的,这样我们就可以计算出周期和频率。 电路设计 本实验,是将上一章产生的PWM波形,通过跳帽连接到TIM5的CH2(PA1)进行捕捉,USB转串口打印频率信息 有关寄存器 因为使用的是TIM5_CH2通道 APB1 外设时钟使能寄存器(RCC_APB1ENR) APB2 外设时钟使能寄存器(RCC_APB2ENR) TIM1 和TIM8 捕获/比较模式寄存器 1(TIMx_CCMR1) 这里配置为10 IC2映射到TI1上 注意: 这里主要靠介绍,我们使用的是2 这里是1 TIM1 和TIM8 捕获/比较使能寄存器(TIMx_CCER) **TIM1 和TIM8 DMA/中断使能寄存器(TIMx_DIER) ** 寄存器代码 test.c #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "timer.h" #include "key.h" extern u8 TIM5CH2_CAPTURE_STA; //输入捕获状态 extern u8 TIM5CH2_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp = 0; Stm32_Clock_Init(9); uart_init(72,115200); delay_init(72); LED_Init(); TIM3_PWM_Init(899,0); //不分频 ,PWM频率为72000/(899+1)=80Khz TIM5_Cap_Init(0xffff,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); LED3_PWM_VAL++; if(LED3_PWM_VAL ==300) LED3_PWM_VAL=0; if(TIM5CH2_CAPTURE_STA & 0x80) //成功捕获道了一次高电平 { temp = TIM5CH2_CAPTURE_STA & 0x3f; //一般情况下定时器不会溢出,前六位做溢出时间 temp *= 65536; //1次 65536 temp += TIM5CH2_CAPTURE_VAL; //得到高电平时间时间 printf("HIGH: %d usrn",temp); //打印高电平 TIM5CH2_CAPTURE_STA = 0; //开启下次捕获 } } } timer.h #ifndef __TIMER_H #define __TIMER_H #include "sys.h" #define LED3_PWM_VAL TIM3->CCR3 void TIM3_Int_Init(u16 arr,u16 psc); void TIM3_PWM_Init(u16 arr,u16 psc); void TIM5_Cap_Init(u16 arr,u16 psc); #endif timer.c #include "timer.h" #include "led.h" //捕捉前的前章有,不再赘述 void TIM3_IRQHandler(void) { if(TIM3->SR & 0x0001) { LED2 = !LED2; } TIM3->SR &= ~(1<<0); } void TIM3_Int_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1<<1; TIM3->ARR = arr; TIM3->PSC = psc; TIM3->DIER |= 1<<0; TIM3->CR1 |= 0x01; MY_NVIC_Init(1,3,TIM3_IRQn,2);×é 2 } void TIM3_PWM_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1<<1; RCC->APB2ENR |= 1<<3; GPIOB->CRL &= 0xFFFFFFF0; GPIOB->CRL |= 0x0000000B; RCC->APB2ENR |= 1<<0; AFIO->MAPR &= 0xFFFFF3FF; AFIO->MAPR |= 1<<11; TIM3->ARR = arr; TIM3->PSC = psc; TIM3->CCMR2 |= 7<<4; TIM3->CCMR2 |= 1<<3; TIM3->CCER |= 1<<8; TIM3->CR1 = 0x0080; TIM3->CR1 |= 0x01; } void TIM5_Cap_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1<<3; //TIM5使能 RCC->APB2ENR |= 1<<2; //GPIOA 也就是PORTA时钟使能 //因为使用的是PB1 GPIOA->CRL &= 0xFFFFFF0F; GPIOA->CRL |= 0x00000080; //PA1 引脚 下拉/上拉输入模式 GPIOA->ODR |= 0<<1; //先让PA1为低电平,然后上升沿捕捉 TIM5->ARR = arr; //设定计时器自动重装值 TIM5->PSC = psc; //预分频器 TIM5->CCMR1 |= 1<<9; //CC2S = 10 TIM5->CCMR1 |= 0<<12; //IC2F = 0000 ,配置输入滤波器,不滤波 TIM5->CCMR1 |= 0<<10; //配置输入分频,不分频 TIM5->CCER |= 0<<5; //CC2P = 0 上升沿捕捉 TIM5->CCER |= 1<<4; //允许捕捉计数器值到捕获寄存器中 TIM5->DIER |= 1<<2; //允许2捕获中断 TIM5->DIER |= 1<<0; //允许更新中断 TIM5->CR1 |=0x01; //使能定时器 MY_NVIC_Init(2,0,TIM5_IRQn,2); } u8 TIM5CH2_CAPTURE_STA = 0; //输入捕获状态 u16 TIM5CH2_CAPTURE_VAL ; //输入捕获值 void TIM5_IRQHandler(void) { u16 tsr; tsr = TIM5->SR; //状态寄存器 if((TIM5CH2_CAPTURE_STA&0x80) == 0) //还未捕捉成功 { if(tsr&0x01) //溢出 { if(TIM5CH2_CAPTURE_STA&0x40) //已经捕获到了高电平 { if((TIM5CH2_CAPTURE_STA&0x3F) == 0x3F) //高电平太长了 { TIM5CH2_CAPTURE_STA |= 0x80; //标志成功捕获了一次 TIM5CH2_CAPTURE_VAL = 0xFFFF; } else TIM5CH2_CAPTURE_STA++; } } if(tsr&0x04) //捕获2发生捕获事件 { if(TIM5CH2_CAPTURE_STA&0x40) //捕获到一个下降沿 { TIM5CH2_CAPTURE_STA|=0x80; //标记成功捕获到一次高电平脉宽 TIM5CH2_CAPTURE_VAL = TIM5->CCR1; //读取当前的捕获值 TIM5->CCER &= ~(1<<5); } else { TIM5CH2_CAPTURE_STA = 0; //清空 TIM5CH2_CAPTURE_VAL = 0; // TIM5CH2_CAPTURE_STA |= 0x40; //标记捕捉上升沿 TIM5->CNT = 0; //计数器清零 TIM5->CCER |= 1<<5; //CC1p = 1 设置为下降沿捕捉 } } } TIM5->SR = 0; //清除中断标志位 } HAL库代码 main.c #include "MyIncludes.h" uint32_t uwIC2Value1 = 0; //第一次捕捉值 uint32_t uwIC2Value2 = 0; //第二次捕捉值 uint32_t uwDiffCapture = 0; //两次捕捉差值 uint16_t uhCaptureIndex = 0; //捕捉索引 uint32_t uwFrequency = 0; //捕捉到的波形频率 uint8_t Cap_Over = 0; void Cap_Process(void) { if(TimCapHandle.Channel == HAL_TIM_ACTIVE_CHANNEL_2) //如果有源通道 为2 // TIM5 的 CH2 输入捕捉通道 { if(uhCaptureIndex == 0) //第一次捕捉 { uwIC2Value1 = HAL_TIM_ReadCapturedValue(&TimCapHandle,TIM_CHANNEL_2); //第一次捕捉值 uhCaptureIndex = 1; } else if(uhCaptureIndex == 1) //第二次捕捉 { uwIC2Value2 = HAL_TIM_ReadCapturedValue(&TimCapHandle,TIM_CHANNEL_2); //第二次捕捉值 if(uwIC2Value2 > uwIC2Value1) { uwDiffCapture = (uwIC2Value2 - uwIC2Value1); } else if(uwIC2Value2 < uwIC2Value1) { uwDiffCapture = ((0xffff - uwIC2Value1) + uwIC2Value2) + 1; //如果第二次小于第一次说明已经计满一次 } uwFrequency = HAL_RCC_GetPCLK1Freq()/uwDiffCapture; uhCaptureIndex = 0; //捕捉到的波形频率=定时器PCK频率/2次捕捉的差值 Cap_Over = 1; //捕捉完成 } } } char buff[50]; int main(void) { u8 dir = 0; u16 duty = 50; u32 Set_Freq = 10000; //设置频率 System_Init(); SysTick_Init(NULL); USART1_Init(115200,NULL,NULL); PWM_Init(Set_Freq,duty); // 默认10kHz //PWM初始化(频率,占空比) Tim5_CapInit(FREQ_COUNTER,Cap_Process); //Tim5输入捕捉初始化(计数器频率,函数) while(1) { if(Cap_Over == 1) //显示捕获结果 { Cap_Over = 0; sprintf(buff,"Cap Freq: %dHzzrn",uwFrequency); printf(buff); //打印信息 if(dir == 0) //递增 { if(Set_Freq < 20000) Set_Freq+=100; else dir = 1; } else if(dir == 1) { if(Set_Freq > 10000) Set_Freq -= 100; else dir = 0; } PWM_Init(Set_Freq,duty); delay_ms(500); } } } InCap.h #ifndef __INCAP_H_ #define __INCAP_H_ #include "stm32f1xx.h" #include "stm32_types.h" #include "stm32f1xx_hal.h" #define FREQ_COUNTER 1000000 //定义计数频率,要和初始化中一致 typedef struct { void (*T5_CapISR)(void); //定时器5中断中运行的函数 }_TIMERCAP_ISR; extern TIM_HandleTypeDef TimCapHandle; void Tim5_CapInit(u32 Cnt_Freq,void(*ISR)(void)); //TImER5输入捕捉初始化 #endif InCap.c #include "InCap.h" TIM_HandleTypeDef TimCapHandle; //TIM基本句柄结构变量声明 TIM_IC_InitTypeDef sICConfig; //TIM输入捕获配置结构变量声明 _TIMERCAP_ISR TIM5_CAP_ISR; void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) //HAL_TIM_IC_Init中调用 { GPIO_InitTypeDef GPIO_InitStruct; //GPIO基本配置结构 __HAL_RCC_TIM5_CLK_ENABLE(); //使能TIM5时钟 __GPIOA_CLK_ENABLE(); //TIM5_CH2管脚PA1 //使能GPIOA时钟 //配置输入捕捉管脚 GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT; //交替功能输入模式 GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_InitStruct); //配置NVIC中断 HAL_NVIC_SetPriority(TIM5_IRQn,0,1); //设置中断 HAL_NVIC_EnableIRQ(TIM5_IRQn); //设置中断源 } void Tim5_CapInit(u32 Cnt_Freq,void (*ISR)(void)) //TIMER5输入捕捉初始化 { TIM5_CAP_ISR.T5_CapISR = ISR; //回调函数 TimCapHandle.Instance = TIM5; //设置定时器 TimCapHandle.Init.Period = 0xffffffff; //自动重装值,这里设为最大 TimCapHandle.Init.Prescaler = 0; //设置1us的计数频率 TimCapHandle.Init.ClockDivision = 0; //时钟不分频,来自RCC TimCapHandle.Init.CounterMode = TIM_COUNTERMODE_UP; // 递增计数 TimCapHandle.Init.RepetitionCounter = 0; //指定重复计数器值。 HAL_TIM_IC_Init(&TimCapHandle); //定时器输入捕获初始化 sICConfig.ICPolarity = TIM_ICPOLARITY_RISING; //上升沿捕获 sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI; //管脚为捕获输入,映射到TI2 sICConfig.ICPrescaler = TIM_ICPSC_DIV1; //输入捕获预分频,为 0 禁止预分频 sICConfig.ICFilter =0x00; //输入捕获滤波器,这是一个递减计数器,这里不滤波 HAL_TIM_IC_ConfigChannel(&TimCapHandle,&sICConfig,TIM_CHANNEL_2); //定时器捕获配置通道 HAL_TIM_IC_Start_IT(&TimCapHandle,TIM_CHANNEL_2); //启动输入捕捉 } void TIM5_IRQHandler(void) //TIMER5中断服务函数 { HAL_TIM_IRQHandler(&TimCapHandle); } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) //用户回调函数,在HAL_TIM_IRQHandler中调用 { if(TIM5_CAP_ISR.T5_CapISR != NULL) TIM5_CAP_ISR.T5_CapISR(); } 实验现象 注意:要将P8 跳帽连接。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1115 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1140 浏览 1 评论
572 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
428 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1026 浏览 2 评论
1614浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
281浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
291浏览 3评论
276浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
253浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-20 16:27 , Processed in 0.975309 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号