ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

使用stm32制作双脉冲发生器

2021-05-25 21:30:25  阅读:217  来源: 互联网

标签:NVIC 脉冲 发生器 stm32 TIM InitStructure ADC GPIO EXTI


使用stm32制作双脉冲发生器

在工作中由于需要对电机驱动电路进行双脉冲测试,以检测电机驱动电路的性能,之前用过555定时器做过一板,但结果不是很理想,后面不甘心就利用业余时间重新做一板双脉冲测试板,不得不说软件的灵活性还是要远远大于硬件的,PCB见下图一,没有使用的I/O口均引出备用。图一  软件主要实现以下功能:
1、每按一次增大按钮,脉冲2以延长10us;
2、每按一次减小按钮,脉冲2以减小10us;
3、按输出按钮,输出两个脉冲;
4、根据AD采样值,定时器TIM2对应的PA0、PA1、PA2、PA3共四个通道输出固定频率,不同占空比的PWM波。
由于网上的参考代码较多,使用库函数编写,程序较为简单,主要驱动代码有:

#include "pwm.h"       //PWM驱动
#include "adc.h"       //ADC驱动
#include "key.h"       //按键驱动
#include "oled.h"      //OLED屏驱动
#include "bmp.h"       //图像驱动
#include "exti.h"      //外部中断驱动程序

PWM驱动程序如下:

/**********************
函数名称:P_OUT_Init

功   能:脉冲PA、PB输出初始化

参   数:无

 返回值:无

作   者:lkjx
*********************/	
void P_OUT_Init()
{

 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PBD端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;				 //PB5  PB6 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		       //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		       //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					            //根据设定参数初始化GPIOB
 GPIO_ResetBits(GPIOB,GPIO_Pin_5|GPIO_Pin_6);						    //PB5  PB6 输出低
	}

/**********************
函数名称:TIM2_PWM_Init

功   能:定时器2通道1、2、3、4的PWM模块输出初始化

参   数:arr--------自动重装值
         psc--------时钟预分频数

 返回值:无

作   者:lkjx
*********************/
void TIM2_PWM_Init(u16 arr,u16 psc)
{  
	 GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);     // 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);   //使能GPIO外设时钟使能
	                                                                     	
  //设置该引脚为复用输出功能,输出TIM2 CH1\CH2\CH3\CH4\的GPIO_A0、GPIO_PA1、GPIO_PA2、GPIO_PA3的PWM脉冲波形
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 |GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 ; //TIM_CH1  TIM_CH2  TIM_CH3  TIM_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//初始化TIM2
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 20K
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM2  Channel1的PWM输出模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	//TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	
	//初始化TIM2  Channel2的PWM输出模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	//TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	
	//初始化TIM2  Channel3的PWM输出模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	//TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	
	//初始化TIM2  Channel4的PWM输出模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	//TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC4Init(TIM2, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	

  //  TIM_CtrlPWMOutputs(TIM2,ENABLE);	//MOE 主输出使能	
	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  //TIM2 CH1预装载使能	
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //TIM2 CH2预装载使能	
  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);  //TIM2 CH3预装载使能	
  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);  //TIM2 CH4预装载使能	
	
//	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CH1预装载使能	 
//	TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIMx在ARR上的预装载寄存器
   TIM_Cmd(TIM2, ENABLE);  //使能TIM2
  
}

ADC驱动程序如下:

/**********************
函数名称:Adc_Init

功   能:ADC1模块初始化

参   数:无

 返回值:无

作   者:lkjx
*********************/
void  Adc_Init(void)
{ 	
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1	, ENABLE );	  //使能ADC1通道时钟
 
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

	//PB0 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_Init(GPIOB, &GPIO_InitStructure);	

	ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
 
//	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能

}				  



/**********************
函数名称:Get_Adc

功   能:获得ADC采样值

参   数:ch------采样通道

 返回值:ADC_GetConversionValue(ADC1),ADC采样转换值

作   者:lkjx
*********************/
u16 Get_Adc(u8 ch)   
{
  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道,采样时间为239.5周期	  			    
  
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}



/**********************
函数名称:Get_Adc_Average

功   能:对ADC进行多次采样,求取平均值

参   数:ch--------采样通道
        times------采样次数

 返回值:temp_val/times,采样平均值

作   者:lkjx
*********************/
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
} 	 


按键驱动程序如下:

/**********************
函数名称:KEY_Scan

功   能:按键处理函数,对按键进行扫描
         此函数有响应优先级,KEY_ADD>KEY_DEC>KEY_OUT!!

参   数:mode------0,不支持连续按;
         mode------1,支持连续按;

 返回值:0,没有任何按键按下
         KEY_ADD,KEY_ADD_PRES按下
         KEY_DEC,KEY_DEC_PRES按下
         KEY_OUT,KEY_OUT_PRES按下 

作   者:lkjx
*********************/	
u8 KEY_Scan(u8 mode)
{	 
	static u8 key_up=1;//按键按松开标志
	if(mode)key_up=1;  //支持连按		  
	if(key_up&&(KEY_ADD==0||KEY_DEC==0||KEY_OUT==0))
	{
		delay_ms(10);//去抖动 
		key_up=0;
		if(KEY_ADD==0)return KEY_ADD_PRES;
		else if(KEY_DEC==0)return KEY_DEC_PRES;
		else if(KEY_OUT==0)return KEY_OUT_PRES; 
	}
	else if(KEY_ADD==1&&KEY_DEC==1&&KEY_OUT==1)
		key_up=1; 	     
	return 0;// 无按键按下
}

exti外部中断驱动程序:

/**********************
函数名称:EXTIX_Init

功   能:外部中断初始化

参   数:无

 返回值:无

作   者:lkjx
*********************/

void EXTIX_Init(void)
{
 
 	  EXTI_InitTypeDef EXTI_InitStructure;
 	  NVIC_InitTypeDef NVIC_InitStructure;

  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟

	  KEY_Init();//初始化按键对应io模式

    //GPIOA.15 中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line15;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

    //GPIOB.3	  中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource3);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line3;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

    //GPIOB.4  中断线以及中断初始化配置
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource4);

   	EXTI_InitStructure.EXTI_Line=EXTI_Line4;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


 
  	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;			//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
		
		NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;					//子优先级1
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 
 
 
   	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;			//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级1  0x00的优先级最高
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 
 
}

 /**********************
函数名称:EXTI3_IRQHandler

功   能:外部中断处理程序

参   数:无

 返回值:无

作   者:lkjx
*********************/

void EXTI3_IRQHandler(void)
{
  delay_ms(5);    //消抖
	if(KEY_DEC==0)   //由1改为0
	{	  
	   m=m-10;
		if(m<0) m=0;
	} 		
	EXTI_ClearITPendingBit(EXTI_Line3);  //清除EXTI3线路挂起位
}


 /**********************
函数名称:EXTI4_IRQHandler

功   能:外部中断处理程序

参   数:无

 返回值:无

作   者:lkjx
*********************/
 void EXTI4_IRQHandler(void)
{			
	delay_ms(5);   //消抖			
				  PA_M_OUT=0;			
        PB_M_OUT=0;
        delay_us(100);
			  PA_M_OUT=1;			
        PB_M_OUT=1;
        delay_us(30);	  //第1次脉冲时间		
        PA_DQ_OUT=0;			
        PB_DQ_OUT=0;
        delay_us(100);  //第1次脉冲与第2次脉冲之间的间隔时间				
				PA_M_OUT=1;			
        PB_M_OUT=1;
			  delay_us(m);	  //第2次脉冲时间		
	      PA_DQ_OUT=0;			
        PB_DQ_OUT=0;	
 	 EXTI_ClearITPendingBit(EXTI_Line4);    //清除LINE4上的中断标志位  
}




 /**********************
函数名称:EXTI15_10_IRQHandler

功   能:外部中断处理程序

参   数:无

 返回值:无

作   者:lkjx
*********************/

void EXTI15_10_IRQHandler(void)
{
	
  delay_ms(5);    //消抖		
  if(KEY_ADD==0)	
		{
		m=m+10;
	}
	 EXTI_ClearITPendingBit(EXTI_Line15);  //清除LINE15线路挂起位
}

以上为代码的驱动程序,其中OLED驱动代码太长,这里就不列举了,上述代码主要来自于网络,主要实现功能如下图2。
在这里插入图片描述
后续想将该OLED屏做成菜单栏形式,不仅可以设置脉冲1,也能够设置脉冲2,但最近一直忙于学习TI的电机矢量控制相关程序,以后有时间再进行升级。

标签:NVIC,脉冲,发生器,stm32,TIM,InitStructure,ADC,GPIO,EXTI
来源: https://blog.csdn.net/hurryuptowang/article/details/117264328

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有