【STM32】可变焦、聚焦摄像头驱动电路与驱动程序——两相四线步进电机驱动


注: 本文仅用于学习交流分享,[若有不妥之处,请指正,感谢]
关键词:【两相四线步进电机】【可变焦、聚焦摄像头】 最后面有 程序 与 测试原理图PCB 分享

用到的工具有:

    Keil 5 编译器 Altium Designer

实现的小功能有: ①可驱动ZOOM步进电机实现 变焦 ②可驱动FOCUS步进电机实现 聚焦

总体介绍

1.步进电机简介 2.基础硬件驱动设计 3.单片机控制程序设计 4.效果展示

1.步进电机简介

1)什么是步进电机

    步进电机是将电脉冲信号转变为角位移或线位移的开环控制电机。 脉冲数越多,电机转动的角度越大。 脉冲的频率越高,电机转速越快,但不能超过最高频率,否则电机的力矩迅速减小,电机不转。

2)为何需要驱动电路

    单片机的IO口是数字口,本身的驱动能力非常小(一般为10-25mA左右),所以需要电机驱动芯片来驱动电机。驱动芯片的作用就是把单片机的小电流的控制信号转成逻辑上相同的大电流的驱动源。这就是所谓的弱电控制强电。

3)步进电机的几个概念

    电机转动一圈的脉冲数=(步进电机)一圈的脉冲数 =细分数x每转脉冲数x减速比

①细分数:步进电机的细分技术实质上是一种电子阻尼技术,其主要目的是减弱或消除步进电机的低频振动,提高电机的运转精度只是细分技术的一个附带功能。比如对于步进角为1.8°的两相混合式步进电机,如果细分驱动器的细分数设置为4,那么电机的运转分辨率为每个脉冲0.45°,电机的精度能否达到或接近0.45°,还取决于细分驱动器的细分电流控制精度等其它因素。不同厂家的细分驱动器精度可能差别很大;细分数越大精度越难控制。

②步距角:也就是每转脉冲数。

③减数比:即减速装置的传动比,是传动比的一种,是指减速机构中瞬时输入速度与输出速度的比值,用符号“i”表示减速比的意思:比如减速比1/64,:如果步进电机输出1N.m的转矩的话,通过减速箱转换后的输出力矩64N.m,当然转速降低为原转速的1/64

2.变焦摄像头参数与结构介绍

1)本款变焦摄像头结构

    该款实验的变焦摄像头为“创威视讯”的 电动变焦镜头 变焦范围为:2.8-12mm 其镜头有两个 两相四线步进电机 : 一个为 FOCUS MOTOR:为控制聚焦 一个为 ZOOM MOTOR:为控制变焦 变焦镜头内部结构 两相步进电机内部结构

2)其节拍表

3)其对应线序表

4)镜头实物图

图1 镜头 图2 镜头 图3 镜头

3.基础硬件测试驱动

电路硬件: [MCU] STM32F103RCT6系统板[Mini stm32] [稳压电源]【AMS1117-3.3】5.0V稳压3.3V [驱动电路] L293D驱动电路

1)整体原理图

2)PCB电路

3)3D_PCB

4.STM32控制驱动程序设计

1)端口定义与函数声明

motor.h:

#ifndef __MOTOR_H
#define __MOTOR_H 
#include "sys.h"  

typedef enum {
          
   FALSE = 0, TRUE = !FALSE} bool;

#define ZOOM_MOTOR  0   //定义变焦步进电机ID
#define FOCUS_MOTOR 1

/*定义 变焦摄像头 引脚信息*/
#define ZOOM_STEP_PORT GPIOB   //步进电机的控制端口为A端口  
#define ZOOM_A1 GPIO_Pin_8     //PA8对应步进电机的A相   ZOOM  A+
#define ZOOM_A0 GPIO_Pin_9     //PA9对应步进电机的B相   ZOOM  A-
#define ZOOM_B1 GPIO_Pin_10    //PA10对应步进电机的C相  ZOOM  B+
#define ZOOM_B0 GPIO_Pin_11    //PA11对应步进电机的D相  ZOOM  B-


/*定义 聚焦摄像头 引脚信息*/
#define FOCUS_STEP_PORT GPIOB //步进电机的控制端口为A端口  
#define FOCUS_A1 GPIO_Pin_12	// FOCUS  A+
#define FOCUS_A0 GPIO_Pin_13	// FOCUS  A-
#define FOCUS_B1 GPIO_Pin_14	// FOCUS  B+
#define FOCUS_B0 GPIO_Pin_15	// FOCUS  B-

void STEP_Init(void);                      //步进电机引脚初始化

void SetMotor(unsigned char Motor_ID,unsigned char InputData);    //根据传送的数据Inputdata设置脉冲引脚输出

void MotorNCircle(unsigned char Motor_ID,int n,bool position);    //n为步进电机转动的圈数,position为正转或者反转

void MotorNAngle(unsigned char Motor_ID,int n,bool position);    //n为步进电机转动的角度为n*120,position为正转或者反转
#endif

2)步进电机驱动函数

#include "motor.h"
#include "delay.h"

//unsigned char F_Rotation[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09} ;  //单双8拍反转表 五线四相步进电机表
//unsigned char B_Rotation[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08} ;  //单双8拍正转表

unsigned char F_Rotation[4]={
          
   0x09,0x0A,0x06,0x05} ;  //4拍正转表  Forward
unsigned char R_Rotation[4]={
          
   0x05,0x06,0x0A,0x09} ;  //4拍反转表  Reverse


/******************************************************************************
* Name: 	 STEP_Init
*
* Desc: 	 初始化两个两相四线步进电机引脚
* Param:   无
* Return:  无
* Note:    本函数为 变焦、聚焦控制的步进电机引脚初始化
* Author:  Dwfish
* -------------------------------------
* Log: 	 2018/12/27, Create this function by Dwfish
 ******************************************************************************/
void STEP_Init()
{
          
   
 
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PA,PD端口时钟
	GPIO_InitStructure.GPIO_Pin = ZOOM_A1|ZOOM_A0|ZOOM_B1|
	ZOOM_B0|FOCUS_A1|FOCUS_A0|FOCUS_B1|FOCUS_B0;           //初始化两个两相四线步进电机引脚
	
	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_8);		//输出低
	GPIO_ResetBits(GPIOB,GPIO_Pin_9);		
	GPIO_ResetBits(GPIOB,GPIO_Pin_10);		
	GPIO_ResetBits(GPIOB,GPIO_Pin_11);
	
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);		
	GPIO_ResetBits(GPIOB,GPIO_Pin_13);		
	GPIO_ResetBits(GPIOB,GPIO_Pin_14);		
	GPIO_ResetBits(GPIOB,GPIO_Pin_15);	
}

/******************************************************************************
* Name: 	 SetMotor
*
* Desc: 	 使步进电机转动
* Param:   电机编号:Motor_ID[0为变焦、1为聚焦]     传入:InputData选择相位使能
* Return:  无
* Note:    根据自己定义的节拍表输出相应脉冲
* Author:  Dwfish
* -------------------------------------
* Log: 	 2018/12/27, Create this function by Dwfish
 ******************************************************************************/
void SetMotor(unsigned char Motor_ID,unsigned char InputData)    //根据传送的数据Inputdata设置PB12-PB15引脚输出
{
          
   
    if(InputData & 0x08){
          
   
				switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_SetBits(ZOOM_STEP_PORT, ZOOM_A1 );	break;
					case FOCUS_MOTOR : GPIO_SetBits(FOCUS_STEP_PORT, FOCUS_A1 );break;
				}					
    }
    else {
          
   
		  	switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_ResetBits(ZOOM_STEP_PORT, ZOOM_A1 );	break;
					case FOCUS_MOTOR : GPIO_ResetBits(FOCUS_STEP_PORT, FOCUS_A1 );break;
				}	
    }
	 
    if(InputData & 0x04){
          
   
				switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_SetBits(ZOOM_STEP_PORT, ZOOM_A0 );	break;
					case FOCUS_MOTOR : GPIO_SetBits(FOCUS_STEP_PORT, FOCUS_A0 );break;
				}	  
    }
   else{
          
   
		  	switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_ResetBits(ZOOM_STEP_PORT, ZOOM_A0 );	break;
					case FOCUS_MOTOR : GPIO_ResetBits(FOCUS_STEP_PORT, FOCUS_A0 );break;
				}	
    }
		
    if(InputData & 0x02){
          
   
				switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_SetBits(ZOOM_STEP_PORT, ZOOM_B1 );	break;
					case FOCUS_MOTOR : GPIO_SetBits(FOCUS_STEP_PORT, FOCUS_B1 );break;
				}	   
    }
    else{
          
   
		  	switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_ResetBits(ZOOM_STEP_PORT, ZOOM_B1 );	break;
					case FOCUS_MOTOR : GPIO_ResetBits(FOCUS_STEP_PORT, FOCUS_B1 );break;
				}	
    }
    if(InputData & 0x01){
          
   
				switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_SetBits(ZOOM_STEP_PORT, ZOOM_B0 );	break;
					case FOCUS_MOTOR : GPIO_SetBits(FOCUS_STEP_PORT, FOCUS_B0 );break;
				}	  
    }
    else{
          
   
				switch(Motor_ID){
          
   
					case ZOOM_MOTOR : GPIO_ResetBits(ZOOM_STEP_PORT, ZOOM_B0 );	break;
					case FOCUS_MOTOR : GPIO_ResetBits(FOCUS_STEP_PORT, FOCUS_B0 );break;
				}	
    }
}

/******************************************************************************
* Name: 	 MotorNCircle
*
* Desc: 	 电机转动 N 圈
* Param:   电机编号:Motor_ID     转动n圈     正反:position【0正1反】
* Return:  无
* Note:    无
* Author:  Dwfish
* -------------------------------------
* Log: 	 2018/12/27, Create this function by Dwfish
 ******************************************************************************/
void MotorNCircle(unsigned char Motor_ID,int n,bool position)
{
          
   
   int i=0;
   int j=0;
   int k=0;
   for(j=0;j<n;j++)
   {
          
   
      for(i=0;i<64*4;i++){
          
   
          for(k=0;k<4;k++){
          
   
              if(TRUE == position)
                 SetMotor(Motor_ID,R_Rotation[k]);  
             else
                 SetMotor(Motor_ID,F_Rotation[k]);  
             	delay_us(1000);       
          }
      }
    }
}

/******************************************************************************
* Name: 	 MotorNAngle
*
* Desc: 	 电机转动 N °
* Param:   电机编号:Motor_ID     转动n°     正反:position【0正1反】
* Return:  无
* Note:    第二个for循环中i所对应的i<1中"1"参数,需要根据自己实际步进电机调整
* Author:  Dwfish
* -------------------------------------
* Log: 	 2018/12/27, Create this function by Dwfish
 ******************************************************************************/

void MotorNAngle(unsigned char Motor_ID,int n,bool position) //n为步进电机转动的角度为n*120,position为正转或者反转
{
          
   
   int i=0;
   int j=0;
   int k=0;
   for(j=0;j<n;j++)
   {
          
   
      for(i=0;i<1;i++)     
      {
          
   
          for(k=0;k<4;k++)   
          {
          
   
              if(TRUE == position)
                 SetMotor(Motor_ID,R_Rotation[k]);  
              else
                 SetMotor(Motor_ID,F_Rotation[k]);  
             	delay_us(1000);       
          }
      }
    }
}

3)按键简单调用转动步进电机【正反转】

#include "include.h"
#include "my_font.h"
#include "motor.h"

u8 key_value = 0;
u32 count = 0;
	
int main(void)
{
          
    
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
  Perpheral_Init();      //外部初始化
	POINT_COLOR=RED;//设置字体为红色
	LCD_ShowString(20,30,200,24,24, "Count: ");
	POINT_COLOR=BLUE;

	TIM_Cmd(TIM1, ENABLE); //使能TIMx外设
	TIM_Cmd(TIM3, ENABLE); //使能TIMx外设

	STEP_Init();
	while (1)
    {
          
             
			key_value = KEY_Scan(1);
			if(key_value == 1)
			{
          
   
				count++;
				LCD_ShowxNum(150,30,count,6,24,0);
				MotorNAngle(ZOOM_MOTOR,1,FALSE);//正转
				
			}
			else if(key_value == 2)
			{
          
   
				count++;
				LCD_ShowxNum(90,30,count,3,24,0);
				MotorNAngle(ZOOM_MOTOR,1,TRUE);
				
			}
			else if(key_value == 3)
			{
          
   
				count++;
				LCD_ShowxNum(90,100,count,3,24,0);
				MotorNAngle(FOCUS_MOTOR,1,FALSE);	
			}
	 }							    
}

5.效果展示

DESIGN

1)调试图连接图

图1 变焦前 图2 变焦后

变焦 前 拍摄:

变焦 后 拍摄:

附【Download】: 程序+测试硬件(原理图+PCB):

Dwfish 淹死的鱼 2018.12.29
经验分享 程序员 微信小程序 职场和发展