(实验10)单片机,STM32F4学习笔记,代码讲解【输入捕获实验】【正点原子】【原创】


其它文章链接,独家吐血整理

(实验3)单片机,STM32F4学习笔记,代码讲解【按键输入实验】【正点原子】【原创】
(实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】
(实验5)单片机,STM32F4学习笔记,代码讲解【外部中断实验】【正点原子】【原创】
(实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】
(实验8)单片机,STM32F4学习笔记,代码讲解【定时器实验】【正点原子】【原创】
(实验9)单片机,STM32F4学习笔记,代码讲解【PWM输出实验】【正点原子】【原创】
(实验10)单片机,STM32F4学习笔记,代码讲解【输入捕获实验】【正点原子】【原创】
(实验11)单片机,STM32F4学习笔记,代码讲解【电容触摸按键实验】【正点原子】【原创】
(实验12)单片机,STM32F4学习笔记,代码讲解【OLED显示实验】【正点原子】【原创】
(实验13)单片机,STM32F4学习笔记,代码讲解【TFTLCD彩屏显示实验】【正点原子】【原创】
(实验15)单片机,STM32F4学习笔记,代码讲解【RTC实时时钟实验】【正点原子】【原创】
(实验17)单片机,STM32F4学习笔记,代码讲解【待机唤醒实验】【正点原子】【原创】
(实验23)单片机,STM32F4学习笔记,代码讲解【DMA实验】【正点原子】【原创】
(实验25)单片机,STM32F4学习笔记,代码讲解【SPI实验】【正点原子】【原创】
(实验34)单片机,STM32F4学习笔记,代码讲解【FLASH模拟EEPROM实验】【正点原子】【原创】
(实验36)单片机,STM32F4学习笔记,代码讲解【外部SRAM实验】【正点原子】【原创】
(实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】
(实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】
(实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】
(实验46)单片机,STM32F4学习笔记,代码讲解【FPU测试实验】【正点原子】【原创】
(实验47)单片机,STM32F4学习笔记,代码讲解【DSP-FFT测试实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验-RTC时钟实验】【正点原子】【原创】
(实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】

实验现象

本实验利用TIM5_CH1来做输入捕获,我们将捕获PA0上的高电平脉宽,并将脉宽时间通过串口打印出来,大家可以通过按WK_UP按键,模拟输入高电平。同时,本实验将保留上一个实验的PWM输出,DS0还是会由暗–>亮的循环变化,大家可以通过杜邦线连接PA0和PF9,来观测PWM输出的高电平时间。

作者注:这里,DS0不是像前面那个,暗渐渐亮渐渐暗渐渐亮,而是暗渐渐亮瞬间暗再渐渐亮循环

主程序

extern u8  TIM5CH1_CAPTURE_STA;		//输入捕获状态		    				
extern u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值  

int main(void)
{ 
	long long temp=0;  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);  //初始化延时函数
	uart_init(115200);//初始化串口波特率为115200
	
 	TIM14_PWM_Init(500-1,84-1);       	//84M/84=1Mhz的计数频率计数到500,PWM频率为1M/500=2Khz     
 	TIM5_CH1_Cap_Init(0XFFFFFFFF,84-1); //以1Mhz的频率计数,记满一次0xFFFFFFFF是4294秒,这几乎不可能,太长了吧
   	while(1)
	{
 		delay_ms(10);
		TIM_SetCompare1(TIM14,TIM_GetCapture1(TIM14)+1); 
		if(TIM_GetCapture1(TIM14)==300)TIM_SetCompare1(TIM14,0);			 
 		if(TIM5CH1_CAPTURE_STA&0X80)        //成功捕获到了一次高电平 1000 0000
		{
			temp=TIM5CH1_CAPTURE_STA&0X3F; //0011 1111 最大是0x3F*4294秒,这特么也太长太长了吧,这上面没溢出一次,TIM5CH1_CAPTURE_STA低6位会加1一次
			temp*=0XFFFFFFFF;		 		         //溢出时间总和
			temp+=TIM5CH1_CAPTURE_VAL;		   //得到总的高电平时间
			printf("HIGH:%lld us\r\n",temp); //打印总的高点平时间
			TIM5CH1_CAPTURE_STA=0;			     //开启下一次捕获
		}
	}
}

定时器5输入捕获初始化程序

TIM_ICInitTypeDef  TIM5_ICInitStructure;

//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;


	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);  	//TIM5时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 	//使能PORTA时钟	

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0

	GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5


	TIM_TimeBaseStructure.TIM_Prescaler=psc;  //定时器分频
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseStructure.TIM_Period=arr;   //自动重装载值
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 

	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);


	//初始化TIM5输入捕获参数
	TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 	选择输入端 IC1映射到TI1上
	TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//上升沿捕获
	TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
	TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //配置输入分频,不分频 
	TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
	TIM_ICInit(TIM5, &TIM5_ICInitStructure);

	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断	

	TIM_Cmd(TIM5,ENABLE ); 	//使能定时器5


	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、
}

定时器5中断程序

//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)
//定时器5中断服务程序	 
void TIM5_IRQHandler(void)
{ 		 

	//if((TIM5CH1_CAPTURE_STA&0X80)==0)只判断第7位
	//if(TIM5CH1_CAPTURE_STA&0X40)只判断第6位
	//if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)只判断0-5位是否全为1
	//TIM5CH1_CAPTURE_STA|=0X80;第7位置为1,0-6位保持原样
	//TIM5CH1_CAPTURE_STA|=0X40;第6位置为1,0-5,7位保持原样
	//现在我所有都明白了,就是将一个8位变量间接当做寄存器使用,很巧妙,首先定时器5初始化时就默认设置好上升沿触发了
	//然后定时器5中断里面第一个if判断是定时器计数中断,第二个if判断是捕获器中断,先说第一个,当定时器计数溢出4294秒
	//此时若捕获到高电平说明还没遇到下降沿也就是还处于高电平,于是TIM5CH1_CAPTURE_STA++;每加一次代表4294秒
	//if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)只判断0-5位是否全为1,这一句代表高电平太长了这不可能但也加进去了4294*0x3F秒
	//然后第二个if中,发生捕获那么一定是上升沿捕获(初始化设置好的),那么此时进入else清空计数,设置下降沿,同时第6位置1
	//于是再进入捕获中断,判断第6位是否是1,如果是那么第7位置1,然后定时器计数中断再判断第17位是否为1,那么这就标记好了
	//就这么简单,哈哈哈
   
 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获	1000 0000
	{
		if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//溢出
		{	     
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}else TIM5CH1_CAPTURE_STA++;
			}	 
		}
		if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
		{	
			if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽
				TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取当前的捕获值.
				TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
			}else  								//还未开始,第一次捕获上升沿
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
				TIM_Cmd(TIM5,DISABLE ); 	//关闭定时器5
	 			TIM_SetCounter(TIM5,0);
	 			TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 设置为下降沿捕获
				TIM_Cmd(TIM5,ENABLE ); 	//使能定时器5
			}		    
		}			     	    					   
 	}
	TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}

代码讲解

//输入捕获实验很简单=测量高电平脉冲的持续时间=据此可计算脉冲宽度或者测量频率(私以为不就是频率计嘛)
//原理很简单,就是先将定时器设置成向上捕获状态,当高电平来临时,触发后得到当前CNT值=定时器计数值,然后再清0
//于是此时定时立即设置成向下捕获模式,当下降沿来临时说明高电平持续时间结束了,于是得到当前CNT计数值
//可是向上与向下之间肯定会有N次计数溢出,这没事,所以总CNT计数值=CCRx2(向下捕获的CNT)+N*ARR(溢出计数值)
//于是下面就好做了,利用定时器计数频率,计数这些个数字得到的时间即可

//除了TIM6和TIM7,其它定时器都有输入捕获功能,这个程序代码呢,就是使用TIM5来进行输入捕获前面的TIM14输出的PWM波
//哈哈,活学活用

//在定时器输入捕获时,上升沿或者下降沿触发捕获时,还可以设置触发中断/DMA等
//输入/比较模式寄存器中,TIMx_CCMR1和TIMx_CCMR2两个寄存器,前者输入捕获通道12,后者是34
//这和前面PWM输出实验中所说,也是两个寄存器,一个控制12路·,一个控制34路类似,在这里TIM5用TIMx_CCMR1低8位0-7
//进行输入捕获通道1,这低8位中,四位用来设置滤波器,2位设置预分频,2位设置通道方向
//此程序中,TIM5通道1中,预分频设置00=一次边沿触发一次捕获,滤波器设置0000=不滤波(提高响应速度),CC1设置01=IC1映射到TI1上
//作者说,IC1与TI1不明白的,可看中文参考手册,淦,CC1设置01=IC1=对应于TIMx_CH1

//输入捕获的自动重装载值和计数频率=前面说过的定时器设置方式=一样的

//这一块的具体思路,我大概明白了,程序没有百分百弄明白,就是把这个TIM5CH1_CAPTURE_STA,8位数据=一个字节间接当做寄存器使用了
//这和那个串口打印一摸一样的道理,总之就是很精彩,8位最高位用来表示成功捕获到一次表示,6位用来做设置下降沿捕获标志位
//而剩下的6位全部用来存储溢出的次数,你想想本来溢出一次就是4294秒,没溢出一次这六位数据加1,所以足够了

:这里,DS0不是像前面那个,暗渐渐亮渐渐暗渐渐亮,而是暗渐渐亮瞬间暗再渐渐亮循环

#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值