基于STM32F103ZET6红外遥控制步进电机

基于STM32F103ZET6红外遥控制步进电机# 基于STM32F103ZET6红外遥控制步进电机

希望在学习的过程中留下一点点记录,以便以后自己方便查找,特意再次留下记录。
第一次发博文写的不好请大家见谅,以后慢慢改正。
本设计选用以STM32F103ZET6单片机为核心得开发板作为主控系统,搭配步进电机驱动模块(驱动芯片为ULN2003A),步进电机、红外接收模块,遥控器以及LED灯指示模块作为整个设计得整体。通过遥控器对红外接收模块发出红外信号,红外接收器收到信号后在主控芯片中进行运算,将处理得到的数据通过主控芯片向步进电机驱动芯片发出指令,控制步进电机的运动。同时为防止在外部存在强干扰的情况下,红外控制失效,加上按键控制模块。同时通过按键可以对步进电机的位置进行微调,防止红外遥控的精度不高,导致步进电机的位置超出预定位置。
基于STM32F103ZET6红外遥控制步进电机_第1张图片
3、步进电机驱动模块
(1)ULN2003的概述
ULN2003是高耐压、大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成。一般采用DIP—16 或SOP—16 塑料封装。
(2)ULN2003的主要特点:
ULN2003 的每一对达林顿都串联一个2.7K 的基极电阻,在5V 的工作电压下它能与TTL 和CMOS 电路直接相连,可以直接处理原先需要标准逻辑缓冲器来处理的数据。
ULN2003 工作电压高,工作电流大,灌电流可达500mA,并且能够在关态时承受50V 的电压,输出还可以在高负载电流并行运行。
(3)ULN2003的作用
ULN2003是大电流驱动阵列,多用于单片机、智能仪表、PLC、数字量输出卡等控制电路中,可直接驱动继电器等负载。输入5VTTL电平,输出可达500mA/50V。
简单地说,ULN2003其实就是用来放大电流的,增加驱动能力。比如说单片机输出引脚一般输出就几mA,是无法驱动电机、继电器或者电磁阀的,像要让直流电机转需要500mA,而用ULN2003放大后,可以通过单片机的输出引脚直接控制这些设备。
(4)ULN2003内部原理图
基于STM32F103ZET6红外遥控制步进电机_第2张图片
(5)ULN2003的引脚功能
引脚1:CPU脉冲输入端,端口对应一个信号输出端;
引脚2:CPU脉冲输入端;
引脚3:CPU脉冲输入端;
引脚4:CPU脉冲输入端;
引脚5:CPU脉冲输入端;
引脚6:CPU脉冲输入端;
引脚7:CPU脉冲输入端;
引脚8:接地;
引脚9:该脚是内部7个续流二极管负极的公共端,各二极管的正极分别接各达林顿管的集电极。用于感性负载时, 该脚接负载电源正极,实现续流作用。如果该脚接地,实际上就是达林顿管的集电极对地接通;
引脚10:脉冲信号输出端,对应7脚信号输入端;
引脚11:脉冲信号输出端,对应6脚信号输入端;
引脚12:脉冲信号输出端,对应5脚信号输入端;
引脚13:脉冲信号输出端,对应4脚信号输入端;
引脚14:脉冲信号输出端,对应3脚信号输入端;
引脚15:脉冲信号输出端,对应2脚信号输入端;
引脚16:脉冲信号输出端,对应1脚信号输入端。

步进电机与uln2003A的接线
基于STM32F103ZET6红外遥控制步进电机_第3张图片

接线实物图

基于STM32F103ZET6红外遥控制步进电机_第4张图片

元件清单

元件清单
名称 数量
LED灯 7个
芯片ULN2003A 1个
排针 50根
杜邦线 30根
单片机最小系统 1块
步进电机(28BYJ-48) 1个
红外接收器 CHQB接收器1个
红外遥控器 1个
程序下载器 1个
电阻(10k) 8个
单面线路板 1块
按键开关 4个
4、红外接收模块
(1)红外线简介
人的眼睛能看到的可见光按波长从长到短排列,依次为红、橙、黄、绿、青、蓝、紫。其中红光的波长范围为0.62~0.76μm;紫光的波长范围为0.38~0.46μm。比紫光波长还短的光叫紫外线,比红光波长还长的光叫红外线。红外线遥控就是利用波长为0.76~1.5μm之间的近红外线来传送控制信号的。
(2)红外遥控的原理
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。红外遥控通信系统一般由红外发射装置和红外接收设备两大部分组成。
(3)红外发射装置
红外发射装置,也就是通常我们说的红外遥控器是由键盘电路、红外编码电路、电源电路和红外发射电路组成。下图为本设计用到的红外发射遥控器:
基于STM32F103ZET6红外遥控制步进电机_第5张图片
红外接收设备是由红外接收电路、红外解码、电源和应用电路组成。成品红外接收头的封装大致有两种:一种采用铁皮屏蔽;一种是塑料封装。均有三只引脚,即电源正(VDD)、电源负(GND)和数据输出(VOUT)。如图
基于STM32F103ZET6红外遥控制步进电机_第6张图片
注:正对接收头的凸起处看,从左至右,管脚依次是1:VOUT,2:GND,3:VDD。
由于红外接收头在没有脉冲的时候为高电平,当收到脉冲的时候为低电平,所以可以通过外部中断的下降沿触发中断,在中断内通过计算高电平时间来判断接收到的数据是0还是1。
通常红外遥控为了提高抗干扰性能和降低电源消耗,红外遥控器常用载波的方式传送二进制编码,常用的载波频率为38kHz,这是由发射端所使用的455kHz晶振来决定的。在发射端要对晶振进行整数分频,分频系数一般取12,所以455kHz÷12≈37.9kHz≈38kHz。也有一些遥控系统采用36kHz、40 kHz、56 kHz等,一般由发射端晶振的振荡频率来决定。所以,通常的红外遥控器是将遥控信号(二进制脉冲码)调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去的。
二进制脉冲码的形式有多种,其中最为常用的是NECProtocol的PWM码(脉冲宽度调制)和 Philips RC-5 Protocol的PPM码(脉冲位置调制码,脉冲串之间的时间间隔来实现信号调制)。如果要开发红外接收设备,一定要知道红外遥控器的编码方式和载波频率,我们才可以选取一体化红外接收头和制定解码方案。我们配套的红外遥控器使用的是NEC协议,其特征如下:
1、 8 位地址和 8 位指令长度;
2、地址和命令 2 次传输(确保可靠性);
3、 PWM 脉冲位置调制,以发射红外载波的占空比代表“ 0”和“ 1”;
4、载波频率为 38Khz;
5、位时间为 1.125ms 或 2.25ms;
NEC 码的位定义
一个脉冲对应560us的连续载波,一个逻辑1传输需要 2.25ms(560us脉冲+1680us低电平),一个逻辑0的传输需要1.125ms(560us脉冲+560us低电平)。而红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑1应该是560us 低+1680us高,逻辑0应该是560us低+560us高。所以可以通过计算高电平时间判断接收到的数据是0还是1。
NEC码位定义时序图如图
基于STM32F103ZET6红外遥控制步进电机_第7张图片
NEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码。引导码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。数据格式如下:
在这里插入图片描述
NEC码还规定了连发码(由9ms低电平+2.5m高电平+0.56ms低电平+97.94ms高电平组成),如果在一帧数据发送完毕之后,红外遥控器按键仍然没有放开,则发射连发码,可以通过统计连发码的次数来标记按键按下的长短或次数。
(5)红外接收硬件电路
基于STM32F103ZET6红外遥控制步进电机_第8张图片

5、 LED模块
LED模块主要是为了显示当前转速的挡位状态,根据LED指示灯表示的二进制数就可以看出当前工作在那个速度状态。
原理图如下:
基于STM32F103ZET6红外遥控制步进电机_第9张图片

通过将所有的LED灯阳极相连,通过ULN2003A芯片的输出引脚来指示当前步进电机的运动情况。

程序编写

函数功能:红外端口初始化函数,时钟端口及外部中断使能函数

void Hwjs_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/* 开启GPIO时钟及管脚复用时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO,ENABLE);
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//红外接收
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Init(GPIOG,&GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource15); //选择GPIO管脚用作外部中断线路
	EXTI_ClearITPendingBit(EXTI_Line15);
	
	/* 设置外部中断的模式 */ 
	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); 

	/*设置NVIC的参数 */
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;   //打开全局中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 	 //响应优先级为1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //打开使能
	NVIC_Init(&NVIC_InitStructure);
}

红外接收函数

u8 HW_jssj()
{
	u8 t=0;
	while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)//¸高电平
	{
		t++;
		delay_us(20);
		if(t>=250) return t;//超时溢出
	}
	return t;
}

红外接收中断函数


void EXTI15_10_IRQHandler(void)	  //红外遥控外部中断
{
	u8 Tim=0,Ok=0,Data,Num=0;

   while(1)
   {
	   	if(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)
		{
			 Tim=HW_jssj();//获得此次高电平时间

			 if(Tim>=250) break;//不是有用的信号

			 if(Tim>=200 && Tim<250)
			 {
			 	Ok=1;//收到起始信号
			 }
			 else if(Tim>=60 && Tim<90)
			 {
			 	Data=1;//收到数据1
			 }
			 else if(Tim>=10 && Tim<50)
			 {
			 	Data=0;//收到数据0
			 }
			 if(Ok==1)
			 {
			 	hw_jsm<<=1;
				hw_jsm+=Data;
				if(Num>=32)
				{
					hw_jsbz=1;
				  	break;
				}
			 }
			 Num++;
		}
   }
   EXTI_ClearITPendingBit(EXTI_Line15);	
}

红外编码接收函数
32 hwjskz(u32 jieshouma)
{
	u32 temp;
	if(jieshouma==0x00FF6897)//0
	{
		temp=0x00FF6897;	
		stepmotor_init();
	}
	else if(jieshouma==0x00ff30cf)//1
	{
		temp=0x00ff30cf;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff7a85)//3
	{
		temp=0x00ff7a85;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff10ef)//4
	{
		temp=0x00ff10ef;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff18e7)//2
	{
		temp=0x00ff18e7;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff38c7)//5
	{
		temp=0x00ff38c7;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff5AA5)//6
	{
		temp=0x00ff5AA5;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff42bd)//7
	{
		temp=0x00ff42bd;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff4ab5)//8
	{
		temp=0x00ff4ab5;
		stepmotor_init();
	}
	else if(jieshouma==0x00ff52ad)//9
	{
		temp=0x00ff52ad;
		stepmotor_init();
	}
	return temp;
}

外部中断控制步进电机转动

基于STM32F103ZET6红外遥控制步进电机_第10张图片

//中断初始化函数
void My_EXTI_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	EXTI_InitTypeDef  EXTI_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2;//  选择GPIO管脚作为外部中断线路
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);// 选择GPIO管脚作为外部中断线路
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);// 选择GPIO管脚作为外部中断线路
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);// 选择GPIO管脚作为外部中断线路
·
	//EXTI0 NVIC配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
	
	//EXTI2 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//EXTI2中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
	//EXTI3 NVIC 配置	
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//EXTI3抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			// IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
	//EXTI4 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//EXTI4抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			// IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	EXTI_InitStructure.EXTI_Line=EXTI_Line2|EXTI_Line3|EXTI_Line4; 
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
}

/*******************************************************************************
* 函数名称         : EXTI0_IRQHandler
* 函数功能		   : 外部中断0函数
* 输    入          :无Þ
* 输    出          :无
注意:按键按下以后电机停转需要控制按键断开
*******************************************************************************/
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0)==1)
	{
		delay_ms(10);
		if(K_UP==1)//一个键连续按下则会执行该函数
		{
			step_four();
		}	
		
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}

/*******************************************************************************
* 函数名称         : EXTI3_IRQHandler
* 函数功能		   : 外部中断3函数
* 输    入          :无Þ
* 输    出          :无
注意:按键按下以后电机停转需要控制按键断开
*******************************************************************************/
void EXTI3_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line3)==1)
	{
		delay_ms(10);
		if(K_DOWN==0)
		{	
			step_two();
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line3);
}

/*******************************************************************************
* 函数名称         : EXTI2_IRQHandler
* 函数功能		   : 外部中断2函数
* 输    入          :无Þ
* 输    出          :无
注意:按键按下以后电机停转需要控制按键断开
*******************************************************************************/
void EXTI2_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line2)==1)
	{
		delay_ms(10);
		if(K_LEFT==0)
		{
			step_one();
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line2);
}

/*******************************************************************************
* 函数名称         : EXTI4_IRQHandler
* 函数功能		   : 外部中断4函数
* 输    入          :无Þ
* 输    出          :无
注意:按键按下以后电机停转需要控制按键断开
*******************************************************************************/
void EXTI4_IRQHandler(void)
{
	
	if(EXTI_GetITStatus(EXTI_Line4)==1)
	{
		
		delay_ms(10);
		if(K_RIGHT==0)
		{
			step_three();
			
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line4);
}

void step_one(void)
{
			
		
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_0);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_1);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_2);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_3);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_0);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_1);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_2);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_3);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_0);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_1);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_2);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_3);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_0);
			delay_ms(10);
			GPIO_ResetBits(MOTOR_PORT,GPIO_Pin_1);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_2);
			delay_ms(10);
			GPIO_SetBits(MOTOR_PORT,GPIO_Pin_3);
			delay_ms(10);
}
注:其他的电机驱动函数类似上述一档转速的代码,通过内部滴答定时器定时,防止给定脉冲频率过高而导致电机停转。

主函数代码
int main()
{
	//对各个寄存器进行初始化
	//各个外设进行初始化
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //ÖжÏÓÅÏȼ¶·Ö×é ·Ö2×é
	LED_Init();
	USART1_Init(9600);
	Hwjs_Init();
	stepmotor_init();
	//进入循环,等待红外接收中断,通过switch-case语句来缩短代码执行的时间。
	while(1)
	{
		u32 temp;
		switch (hwjskz(hw_jsm))
		{
			case one://一档转速
							led1=1;
							led2=0;
							led3=0;
							step_one();
							break;
			case two://二档转速
							led1=0;
							led2=1;
							led3=0;
							step_two();
							break;
			case stop://停止
							led1=0;
							led2=0;
							led3=0;
							motor_stop();
							break;
			case three://三档转速
							led1=1;
							led2=1;
							led3=0;
							step_three();
							break;
			case four://四档转速
							led1=0;
							led2=0;
							led3=1;
							step_four();
							break;
			case oneback://一档转速反转
							led1=1;
							led2=0;
							led3=1;
							motor_oneback();
							break;
			case twoback://二档转速反转
							led1=0;
							led2=1;
							led3=1;
							motor_twoback();
							break;
			case threeback://三档转速反转
							led1=1;
							led2=1;
							led3=1;
							motor_threeback();
							break;
			case fourback://四档转速反转
							led1=0;
							led2=0;
							led3=0;
							step_fourback();
							break;
			case qidong://等待接收启动信号
							qidong();
							break;
		}
	}
}


你可能感兴趣的:(单片机,芯片,嵌入式)