(实验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不是像前面那个,暗渐渐亮渐渐暗渐渐亮,而是暗渐渐亮瞬间暗再渐渐亮循环

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值