基于stm32f103rbt6 实现输入捕获实验

本文详细介绍了STM32中定时器的输入捕获和输出比较功能,包括配置步骤、代码实现和中断处理。通过实例展示了如何利用定时器通道进行输入捕获和输出比较,解释了占空比计算、中断优先级设置以及寄存器映射等关键概念。同时,文中还探讨了可能遇到的问题和解决方案,强调了初始化赋值和计算频率的重要性。
摘要由CSDN通过智能技术生成

输入捕获

在这里插入图片描述

这个时序图为什么 我要这么圈呢  因为输入捕获 并不是一个 io 就可以实现的 
它用分割线 分成了两半。 而它必须 要有两个 io 才可以 一端输出 之后 
 一端捕获数据 这样才叫输入捕获的过程

定时器只要有io有对应的 定时器通道  我们就可以设置为输入捕获 或者输出比较
这样我们用起来就很方便。

输出比较回顾

@接上一篇的输出比较 我们简单回顾一下其中的知识点

占空比 就是 一个周期内高电平持续的时间和周期时间的比值 即 高电平时间:一周期时间  
ARR可以改变占空比的比值。

代码设计

1)PA1 作为 输出比较 的io PA7 作为 输入捕获的 IO
在这里插入图片描述
在这里插入图片描述

灵活运用定时器通道  并且定时器都是独立存在的 不用考虑他们冲突的问题 

3)代码

GPIOA7.c

  	GPIO_InitTypeDef GPIO_Initstruct;
   	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	
	GPIO_Initstruct.GPIO_Pin=GPIO_Pin_7;
	GPIO_Initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Initstruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&GPIO_Initstruct);
配置为输入  选择 浮空输入就行 

NVIC.c

    NVIC_InitTypeDef NVIC_Initstruct;
	NVIC_Initstruct.NVIC_IRQChannel	=TIM3_IRQn;
	NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority =	0;
	NVIC_Initstruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_Initstruct.NVIC_IRQChannelCmd	= ENABLE;
	   NVIC_Init(&NVIC_Initstruct);
因为要计算捕获数据  所以要不断产生溢出 时间 产生溢出时间 就要配置中断   配置中断 必要 
中断优先级 

TIM3.c

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitstruct;
  	TIM_TimeBaseInitstruct.TIM_Period=65535;
	TIM_TimeBaseInitstruct.TIM_Prescaler=0;
	TIM_TimeBaseInitstruct.TIM_CounterMode	=TIM_CounterMode_Up;
	TIM_TimeBaseInitstruct.TIM_ClockDivision  =TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitstruct);
定时器配置  这里的ARR 必须为最大 预分频只要取到合适的 起到倍频就行了 即要大于1  
因为我们的分频只要不为 0 得到(0+1) 那么他可以 倍频 在定时器二我会说取 65535的原因 
你们可以先记下来 等会在回头看看 

TIM3Capture.c

	TIM_ICInitTypeDef TIM_ICInitstruct;
   TIM_ICInitstruct.TIM_ICSelection	=TIM_ICSelection_DirectTI; //寄存器映射到 外设 
   TIM_ICInitstruct.TIM_ICPrescaler	=TIM_ICPSC_DIV1;//预分频系数为 1
   TIM_ICInitstruct.TIM_ICPolarity =TIM_ICPolarity_Rising;//高电平 
   TIM_ICInitstruct.TIM_Channel =TIM_Channel_2;
   TIM_ICInitstruct.TIM_ICFilter =0X00;//一周期更新一次  
   TIM_ICInit(TIM3,&TIM_ICInitstruct);
   TIM_PWMIConfig(TIM3,&TIM_ICInitstruct);//配置为输入模式 (重点 )

其中要点

寄存器映射 :寄存器是特殊的存储器 ,给寄存器地址命名的过程就是 寄存器映射
简单的说 它存放的就是ARR的值  

PWM IN.C(重点看 )

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	GPIOA7_IN();//1 初始化io
	NVICstruct();// 2	中断
	TIM_DeInit(TIM3);	   //复位 
	TIM3_BaseInit();//4	 //定时器 配置
	TIM3_CaptureInit();//5   //输入配置
	TIM_SelectInputTrigger(TIM3,TIM_TS_TI2FP2);//输入触发源  通道二
	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//捕获 上升沿	配置为复位模式 
	TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE);
	TIM_Cmd(TIM3,ENABLE);

输入捕获 为复位模式 (重要)
在这里插入图片描述

输入捕获的全过程

捕获的是占空比  占空比就是高电平 
输入的基本流程 1 io ----2 中断 -----3 复位 (在检查一次中断有无出错)----4 定时
---5转为输入模式-----选择输入触发源 -------设置捕获上升沿-----更新中断源-----使能定时器

OUTput.c

 void TIM2_PwmOutPut(unsigned int peroid,unsigned int TIM2Plshu)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitstruct;
	TIM_OCInitTypeDef  TIM_OCInitstruct;
 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
		
	TIM_TimeBaseInitstruct.TIM_Period=peroid;//ARR  设置为变量 
	TIM_TimeBaseInitstruct.TIM_Prescaler=0; //不分频
	TIM_TimeBaseInitstruct.TIM_CounterMode	=TIM_CounterMode_Up;
	TIM_TimeBaseInitstruct.TIM_ClockDivision  =TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitstruct);  
	TIM_PrescalerConfig(TIM2,35,TIM_PSCReloadMode_Immediate);	(重点)
	//设置定时器的arr 在定时器工作时 的值为 35 
	//这样就可以算出他在工作时的频率了 
	36/(35+1)*(0+1)=1M  	
	TIM_OCInitstruct.TIM_OCMode	 =TIM_OCMode_PWM2;
	TIM_OCInitstruct.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitstruct.TIM_OCPolarity =TIM_OCPolarity_Low;
	TIM_OCInitstruct.TIM_Pulse=TIM2Plshu;	
	TIM_OC2Init(TIM2,&TIM_OCInitstruct);
    TIM_CtrlPWMOutputs(TIM2,ENABLE);	(重点)配置为输出模式 	
	TIM_Cmd(TIM2,ENABLE);
}

注意输出模式的函数名字

注意输出模式的函数 TIM_CtrlPWMOutputs(TIM2,ENABLE);	 

解答 TIM3遗漏的问题

TIM3 为什么 设为 65535
/*******************************
根据上面算出了 TIM2的频率(往下看 )
//设置定时器的arr 在定时器工作时 的值为 35 
	//这样就可以算出他在工作时的频率了 
	36/(35+1)*(0+1)=1M  	
	**************************/
	通过TIM2的计算得出 最大频率为1m 对应的计数值也应该是最大了
	那么在TIM3身上 设定的 65535 得到的频率也应该是 1M 那么就是 捕获速度设为最大了
	提高效率

中断函数

 void TIM3_IRQHandler(void)
 {
   	 TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);//清除标志位 
	  GPOA7_CCR2=TIM3->CCR2;
	  if(GPOA7_CCR2!=0){  	
		Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2;
		PWM_HZ=SystemCoreClock/GPOA7_CCR2;    
	  }else {
    	Workhanlder=0;
		PWM_HZ=0; 
	  } 
 }

在这里插入图片描述

 GPOA7_CCR2=TIM3->CCR2; 计算周期占空比
  Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2;
  (TIM3->CCR1*100) 相当于一个100倍的长度 100不是固定的 这里只是为一个合适的取值 
  为了给输出比较的初始化取值方便  继续往下看。
  这样就得出了 设定的高电平的周期长度 注意是高电平信号周期长度  最后除以 CCR2
  得到的是 占空比的工作周期次数

注意字母写法

TIMX->CCRX:寄存器的写法: 指的是 比较值  比较值用于确定占空比

main.c

 #include "stm32f10x.h"
#include "funcofig.h"
#include "tim.h" 
#include "lcd.h" 
#include "systick.h"
#include "key.h" 

#define PWM_x(X,B) (B+1)*X/100   //X为占空比 
extern  unsigned  int PWM_HZ;
extern  unsigned  int Workhanlder;
unsigned char x1=10,y1=1;
unsigned char  keyflag=2;
unsigned char  keyreturns;
unsigned char  show_lcd=2;
unsigned char  key_pwm;

char PWM_IN_buff[128];
char PWM_OUT_buff[128];
char CCR2_IN_buff[128];
char CCR2_OUT_buff[128];


void ALLInit(void) 
{
  	SysTickInit(); //1ms中断一次
 
	STM3210B_LCD_Init();
	 key_init();//按键
	PWM_INConfig();//输入模式配置(重要)
    GPIOA1_OUT();//输出函数调用
    LCD_Clear(White); //清屏为白色 
	LCD_SetBackColor(Red);
	LCD_SetTextColor(Black);	//字体为 蓝色 
	show_lcd=2; 
	lcd_xianshi();
    TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);//往下看 有你想知道的答案 
}

//
void lcd_xianshi(void)
{
   if(show_lcd==2)
   {
   	  LCD_SetBackColor(White);//背景为白色 
	  LCD_SetTextColor(Blue); 	//字体为 蓝色 
	
	sprintf((unsigned char *)PWM_OUT_buff,"PWM_OUT2:%dKHZ              ",y1);
	LCD_DisplayStringLine(Line3,PWM_OUT_buff);
	
	sprintf((unsigned char *)PWM_IN_buff,"PWM_IN2:%dHZ                 ",PWM_HZ/2);
	LCD_DisplayStringLine(Line4,PWM_IN_buff);
	
	sprintf((unsigned char *)CCR2_OUT_buff,"CCR2_OUT:%d                 ",x1);
	LCD_DisplayStringLine(Line5,CCR2_OUT_buff);
	
	sprintf((unsigned char *)CCR2_IN_buff,"CCR2_IN:%d                  ",Workhanlder);
	LCD_DisplayStringLine(Line6,CCR2_IN_buff);
    LCD_DisplayChar(Line5,319-16*12,'%');
	LCD_DisplayChar(Line6,319-16*12,'%');
 
//       
   } 
}
 void PWM_Capture_OUT(void) 
 {
	  key_pwm=key_Scan();//按键函数 
      switch(key_pwm){

	  	 case 'B': 	 
		   Delay_Ms(100);	 
		  if(show_lcd==2){//事件2  (为复位事件)
			show_lcd=2; //标记事件2
		   lcd_xianshi();
		 		 if(x1==100){ //加到100%
		    x1=10;  //加到100% 就回到10%
		 }	 else
		 {
		   x1+=10;//每次加 10%
		 }
		  if(y1==7)    TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
		  else     TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
		 
		 }break;
		 case 'C':
		Delay_Ms(100);	 //消抖
		  
		 if(show_lcd==2){//事件2
			show_lcd=2; //标记事件2
		  lcd_xianshi();	 
				 if(y1==10){ //加10khz
		    y1=0; //回到0khz
		 }	 
		 	     else
		 {
		 
		   y1+=1;//每次加1khz
		 
		 }
		  if(y1==7)    TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
		  else     TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
		 
		 }
		 break;
		              
		 
	    
	  }
 
    
 }	

***核心部分

#define PWM_x(X,B) (B+1)*X/100   //X为占空比 
B相当于是占空比的次数  简单理解就行了 

根据这段代码反推出初始化的赋值

在这里插入图片描述

下面的多看几次 (工程最核心部分)

 unsigned char x1=10,y1=1;
 TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
 我们这里的两千并不是随意写的 根据 #define PWM_x(X,B) (B+1)*X/100  对应
 TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);  结合中断函数来看
 Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2; 因为这里乘了100 原本为1m的计算频率现在就为
10 000 00/100 =10000了 又因为占空比为 ( #define PWM_x(X,B) (B+1)*X/100 )
这样对应了初始化函数部分形参  得到占空比为(0+1*10/100=10%  //X为占空比  
所以 计算频率又为 10000 *10%=1000 hz 因为是输出 比较 和输入捕获  所以要乘2 
所以初始化频率为2000HZ
   

可能出现的问题

  if(y1==7)    TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
		  else     TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
	286可以根据情况来改 286相当于是某个时间点定时器固定的值 
   如果还是出错 可以把y1的值 改为 11	  
知识点比较多   大家要稳住 

key.c

#include "stm32f10x.h"
#include "key.h"

void key_init(void) 
{

	GPIO_InitTypeDef GPIO_Initstruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_Initstruct.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;
	GPIO_Initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Initstruct.GPIO_Mode =GPIO_Mode_IPU;
	GPIO_Init(GPIOB,&GPIO_Initstruct);

   	GPIO_Initstruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
	GPIO_Init(GPIOA,&GPIO_Initstruct);

}
unsigned char key_Scan(void) 
{
   static unsigned char key_res=0;
   switch(key_res){
   
    case 0:if((A0==GPIO_RESET)||(A8==GPIO_RESET)||(B1==GPIO_RESET)||(B2==GPIO_RESET)){
				key_res=1;
	}break;
   	  case 1:if((A0==GPIO_RESET)||(A8==GPIO_RESET)||(B1==GPIO_RESET)||(B2==GPIO_RESET)){
				key_res=2;
				if(A0==GPIO_RESET) {return 'A';}
				if(A8==GPIO_RESET) {return 'B';}
			 	if(B1==GPIO_RESET) {return 'C';}
				if(B2==GPIO_RESET) {return 'D';}

	}break;
   
     case 2:if((A0!=GPIO_RESET)&&(A8!=GPIO_RESET)&&(B1!=GPIO_RESET)&&(B2!=GPIO_RESET)){
	 		   	key_res=0;
	 
	 }break;
   
    
   }
   return 88;

}

main.c

#include "stm32f10x.h"
#include "systick.h"
#include "lcd.h"
#include "tim.h" 
#include "key.h"
#include "funcofig.h"

int main(void)			  
{   

 	ALLInit(); ///用到的所有初始化  	             
 
	while(1)
	{
	      PWM_Capture_OUT();//捕获占空比  
     
  }


 }


 
提及的要点多看几次  很重要 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#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;//开启下一次捕获 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值