精华内容
下载资源
问答
  • 单片机连接ULN2003驱动步进电机的应用
  • 在由单片机结合ULN2003组成单片机驱动系统的程序设计过程中,根据不同的转动幅度调用不同的驱动程序,最终实现了高精度的控制转动角度。
  • STM32F103单片机使用ULN2003驱动步进电机

    千次阅读 多人点赞 2020-12-24 11:29:01
    最近整理东西,突然发现以前买的一个步进电机模块,以前使用5V单片机驱动的。突然想试试能不能用STM32F103单片机的3.3V直接驱动ULN2003这个芯片。 试了一下ULN2003可以用3.3V电压直接驱动。下面分享下电机驱动的...

          最近整理东西,突然发现以前买的一个步进电机模块,以前使用5V单片机驱动的。突然想试试能不能用STM32F103单片机的3.3V直接驱动ULN2003这个芯片。

    试了一下ULN2003可以用3.3V电压直接驱动。下面分享下电机驱动的过程。

    先看看实物图

    单片机使用的是STM32F103C8T6最小系统。电机和驱动板是网上买的整套模块。

    驱动板的原理图如下

            步进电机使用的是5线4相直流减速步进电机   直径:28mm  电压:5V  步进角度:5.625 x 1/64  减速比:1/64

           步距角:5.625 / 64 = 0.087度 (也就是说理论上,你给一个脉冲,电机外部轴转动0.087度)也就是说一个脉冲内部转子转5.625度,但是由于减速64倍,所以外部轴只转了0.087度那么外部轴要转一圈的话,需要360/0.087=4096个脉冲。采用4相8拍驱动的话,8个脉冲是一个周期,那么就需要4096/8=512个周期,外部轴刚好转一圈。

        电机的驱动一般分为3种方法

        一.  1相励磁法:每一瞬间只有一个线圈相通,其它休息。

              (优点)简单,耗电低,精确性良好。

             (缺点)力矩小,振动大,每次励磁信号走的角度都是标称角度。  1相励磁法  A->B->C->D

       二、 2相励磁法:每一瞬间有两个线圈导通。

             (优点)力矩大,震动小。

             (缺点)每励磁信号走的角度都是标称角度。2相励磁法  AB->BC->CD->DA

       三、 1-2相励磁法:1相和2相交替导通。

               (优点)精度较高,运转平滑,每送一个励磁信号转动1/2标称角度,称为半步驱动。(前两种称为4相4拍,这一种称为4相8拍)

                1-2相励磁法  A-->AB-->B->BC->C-->CD->D-->DA

    下面就用代码来实现这三种方式

           ULN2003这个小驱动板上IN1、IN2、IN3、IN4四个插针和单片机的 IO口直接用杜邦线连接,为了方便控制,首先定义好要使用的 IO口。就直接在LED的工程上修改。

           首先新建一个bsp_motor.h的头文件,在头文件里面进行端口声明。

    #define LA    PBout(6) 			//A 相
    #define LB    PBout(7) 			//B 相
    #define LC    PBout(8) 			//C 相
    #define LD    PBout(9) 			//D 相
    
    /* 定义电机连接的GPIO端口, 用户只需要修改下面的代码即可改变控制电机的引脚 */
    #define LA_GPIO_PORT    	GPIOB		                /* GPIO端口 */
    #define LA_GPIO_CLK 	    RCC_APB2Periph_GPIOB		/* GPIO端口时钟 */
    #define LA_GPIO_PIN			GPIO_Pin_6
    
    #define LB_GPIO_PORT    	GPIOB
    #define LB_GPIO_CLK 	    RCC_APB2Periph_GPIOB
    #define LB_GPIO_PIN		    GPIO_Pin_7
    
    #define LC_GPIO_PORT    	GPIOB
    #define LC_GPIO_CLK 	    RCC_APB2Periph_GPIOB
    #define LC_GPIO_PIN		    GPIO_Pin_8
    
    #define LD_GPIO_PORT    	GPIOB
    #define LD_GPIO_CLK 	    RCC_APB2Periph_GPIOB
    #define LD_GPIO_PIN		    GPIO_Pin_9
    

           这里使用PB口的6、7、8、9四个端口来控制,端口使用了位带定义的方法,这样用程序控制起来更方便。关于位带定义可以自己查阅相关资料。端口和时钟都使用了宏定义重新命名。这样以后需要更改IO口的时候,只需要在头文件中更改,不需要更改程序中的代码,方便程序移植。  

          下面开始编写驱动代码,首先使用1相励磁法,也就是使4个IO口轮流为高电平,可以直接使用位带操作,依次给LA、LB、LC、LD给高电平。但是这样写的话每一种驱动方式都要写一个驱动函数,为了使操作起来更方便,将这4个口的值组成一个字节,并存在数组中,通过下标轮流调用数组中的数就行。这里将LA作为字节得最低位bit0,将LD作为字节第3位bit3。

           这样电机导通相序为  D-C-B-A时,定义数组中的值为

    u8 phasecw[4] = {0x08, 0x04, 0x02, 0x01};

           电机导通相序为   A-B-C-D 是,数组中的值为

    u8 phaseccw[4] = {0x01, 0x02, 0x04, 0x08};

    下面新建bsp_motor.c文件,并在里面编写一个函数来调用这个数组就行了

    void MotorCW( void )
    {
        u8 i;
        u8 temp = 0;
        for( i = 0; i < 4; i++ )
        {
            temp = phasecw[i];
    
            LD = ( temp >> 3 ) & 0x01;							//取bit4的值
            LC = ( temp >> 2 ) & 0x01;
            LB = ( temp >> 1 ) & 0x01;
            LA = ( temp >> 0 ) & 0x01;							//取bit0的值
            delay_ms( 2 ); 										
        }
    }

            通过一个for循环,依次读取数组中的值,然后根据A、B、C、D四相的位置,去读取对应位的值,直接赋值给 IO口。这样电机驱动的函数就写好了,在主程序中直接调用这个函数就可以控制电机转动了。

           如果要改成 2相励磁法驱动的话,直接替换数组中的数据就行。

    u8 phasecw[4] = {0x0c, 0x06, 0x03,0x09};   //正转 电机导通相序  DC-CB-BA-AD
    u8 phaseccw[4] = {0x03, 0x06, 0x0c, 0x09}; //反转 电机导通相序  AB-BC-CD-DA

           如果要改成 1-2相励磁法,依然是直接修改数组中的值就行。

    u8 phasecw[8] = {0x08, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09}; //正转 电机导通相序  D-DC-C-CB-B-BA-A-AD
    u8 phaseccw[8] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x89}; //反转 电机导通相序  A-AB-B-BC-C-CD-D-DA
    

          通过 1-2相励磁法控制的话,每次需要发送8个脉冲,也就是4相8拍,这样一个周期需要发送8个数组,要在for循环中将循环数量改为8。

    void MotorCW( void )
    {
        u8 i;
        u8 temp = 0;
        for( i = 0; i < 8; i++ )
        {
            temp = phasecw[i];
            LD = ( temp >> 3 ) & 0x01;							//取bit4的值
            LC = ( temp >> 2 ) & 0x01;
            LB = ( temp >> 1 ) & 0x01;
            LA = ( temp >> 0 ) & 0x01;							//取bit0的值
            delay_ms( 2 ); 										
        }
    }

    然后在主程序中直接调用这个函数就可以让电机转起来了。

    int main( void )
    {
      
        NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
       
        Motor_GPIO_Config();
        while ( 1 )
        {      
          MotorCW();   
        }
    }

    这样看来驱动电机是很简单的用keil模拟的仿真波形

    1相励磁法  D-C-B-A

    2相励磁法 DC-CB-BA-AD

    1-2相励磁法 D-DC-C-CB-B-BA-A-AD

    波形和理论相符,说明驱动是正确的。

    到这里应该就结束了,但是又手贱的给主程序加了个LED闪灯的程序,这一加出事了。

    int main( void )
    {
        u16 cnt = 0;
        NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
        LED_GPIO_Config();
        Motor_GPIO_Config();
        while ( 1 )
        {
            LED1_TOGGLE;
            MotorCW();
    	    delay_ms(20);
        }
    }

    主程序中加了一个20ms的延时,同时让LED灯翻转。程序烧进去之后,发现电机不转了。这是怎么回事?赶紧看看仿真波形。

           这一看发现了问题,A项的波形怎么高电平突然变长了?

    u8 phasecw[4] = {0x08, 0x04, 0x02, 0x01};

            数组中依次给的值是8、4、2、1,也就是D、C、B、A相依次为高电平,其他三相高电平只持续了2ms,但是A相的电平持续了20多ms,这是什么原因?仔细分析程序执行流程后发现了问题所在。在for循环中依次给4个相赋值,A相位最后一个赋值,当给A项赋值时,其他3项为低电平,A项为高电平,然后程序退出for循环,回到主程序中,此时又执行了20ms的延时,这时A项的电平还是最后一次赋值的高电平。将这20ms延时去掉后,电机正常运转,波形也正常了。也就是说就是这个延时影响了电机的转动。

           那么主程序中就不能用延时了吗?LED闪烁功能都实现不了了吗?还能让一个电机驱动程序把单片机霸占了不成?这当然是不行了,一定要将这个问题的根源找到,既然是最后一次给A项赋值后,A项高电平没有复位,那么就手动让A项复位。强制让A项的电平归零。

        在增加一个复位的函数

    void MotorStop( void )
    {
        LA = 0;
        LB = 0;
        LC = 0;
        LD = 0;
    }

          这个函数强制的将四相复位,然后在电机驱动的时候,每次执行完一个周期,就强制让这4项复位。

    void MotorCW( void )
    {
        u8 i;
        u8 temp = 0;
        for( i = 0; i < 4; i++ )
        {
            temp = phasecw[i];
    
            LD = ( temp >> 3 ) & 0x01;							//取bit4的值
            LC = ( temp >> 2 ) & 0x01;
            LB = ( temp >> 1 ) & 0x01;
            LA = ( temp >> 0 ) & 0x01;							//取bit0的值
            delay_ms( 2 ); 													
        }
        MotorStop(); //一个周期转动结束后需要复位所有相,否则最后一项如果被设置为高电平后会持续维持高电平。
    }

         增加复位功能后,主程序中依然加上20ms延时,继续仿真查看波形。

            这下波形正常了,下载程序后电机也缓慢转动起来了,LED灯也开始闪烁了。说明刚开始驱动时只想到了相位的逻辑,但是没有考虑到相位复位的问题,考虑问题还是不全面。

           下来在主程序中加上电机正反转功能,让电机正转一圈,然后又反转一圈。

    int main( void )
    {
        u16 cnt = 0;
        NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
        LED_GPIO_Config();
    
        Motor_GPIO_Config();
        while ( 1 )
        {
            cnt++;
    
            if( cnt <= 512 )							//采用4相8拍,512个周期刚好是一圈
                MotorCW();								//正转
            else if( cnt <= 1024 )
                MotorCCW();								//反转
            else
            {
                cnt = 0;
                LED1_TOGGLE;
                delay_ms( 500 );
            }
        }
    }

           这里采用4相8拍驱动,8个脉冲是一个周期,那么就需要4096/8=512个周期,外部轴刚好转一圈。计数器小于512时正转,计时器在512和1024之间时反转。然后LED灯翻转一次,在延时500ms。 这里还要注意一个问题,在电机驱动函数中,每个脉冲的延时时间经过实际测试不能小于2ms,延时太小的时候,电机抖动严重,但是不会转动。延时越大,电机转动越慢。

         到此电机驱动程序已经完美运行了。

          完整工程下载地址 STM32F103单片机+ULN2003驱动直流电机

    展开全文
  • 基于单片机ULN2003步进电机控制系统(汇编及C语言程序各一个) 51单片机
  • ULN2003A驱动步进电机仿真 1、步进电机及ULN2003介绍 步进电机是无刷直流电机,它能以固定的步距角旋转。步进电机一般采用200步完成360度旋转,即每一步旋转1.8度。可以通过适当的指令将步进电机旋转到任何特定的...

    ULN2003A驱动步进电机仿真

    1、步进电机及ULN2003介绍

    步进电机是无刷直流电机,它能以固定的步距角旋转。步进电机一般采用200步完成360度旋转,即每一步旋转1.8度。可以通过适当的指令将步进电机旋转到任何特定的角度。因此步进电机被广泛应用于旋转运动设备,如机械人、自动控制、机械手臂等。

    步进电机一般分为为两种类型:

    • 单极步进电机:一般有五或六根导线,其中四根导线是四个固定子线圈的一端(A、B、C、D),四个线圈的另一端连接在一起,代表第五根导线,即为公共端。单极步进电机使用广泛。
    • 双极步进电机:只有四根导线从两组线圈中接出,没有共用导线。

    单机电机如下图所示:

    在这里插入图片描述

    步进电机由定子和转子组成,定子代表四个电磁线圈,转子代表旋转的永磁体。当线圈通电产生磁场时,导致转子旋转。通电线圈应该以一个特定的顺序来进行旋转,因此单极步进电机的工作方式分为如下方式:

    • 细分驱动方式:在这种模式下,四组线圈一个接一个通电,转矩小,功耗低。

    展开全文
  • ULN2003驱动步进电机.pdf这个挺不错的
  • 当使用STM32控制ULN2003驱动步进电机28BYJ-48时,步进电机转速变化缓慢,想要得到合适的控制速度,需要不断的调试,不断的更改代码,编辑、编译、下载到STM32中,不断的重复下载造成开发速度慢同时对单片机也是一种...

    传送门:STM32控制ULN2003驱动步进电机28BYJ-48最基础版

    使用串口调试步进电机28BYJ-48获得需要转速

    当使用STM32控制ULN2003驱动步进电机28BYJ-48时,步进电机转速变化缓慢,想要得到合适的控制速度,需要不断的调试,不断的更改代码,编辑、编译、下载到STM32中,不断的重复下载造成开发速度慢同时对单片机也是一种损耗,废话不多说直接上代码。

    • 定义struct.h进行宏定义,如下:
    #define STRUCT(type)    typedef struct _tag_##type      type;\
    struct _tag_##type
    

    电机部分代码改进

    • 在step_motor.h中定义类型,使用对象可以使数据组织起来使用更加方面,如下:
    /* 类型定义 ------------------------------------------ */
    STRUCT(StepMotor_t)
    {
        /* 
         *state: bit0  0 表示电机处于非运行态;     1 表示运行态
         *       bit1  0 表示电机正转       1 反转   
         */
        uint8_t state;
        /* 每步时间片 */
        uint16_t step_slice;
        /* 总步数 */
        u32 step_num; 
        void (*run)(StepMotor_t *motor);
    };
    
    • 在step_motor.c中定义电机运行函数,如下:
    /**
     * @name: Step_Motor_Run
     * @description: step motor run.
     * @param {StepMotor_t} *motor
     * @return {*}
     */
    void Step_Motor_Run(StepMotor_t *motor)
    {
        /* 判断正反转 */
        if(!(motor->state & 0x02))
        {
            printf("motor ready run cw... , period is %d .\r\n", motor->step_slice);
            Step_Motor_CW(motor);
        }
        else
        {
            printf("motor ready run ccw... , period is %d .\r\n", motor->step_slice);
            Step_Motor_CCW(motor);
        }
        motor->state &= ~0x01; 
    }
    
    
    • 同时进行运行正反转的函数定义:
    /**
     * @name: Step_Motor_CW
     * @description: 电机正转函数
     * @param {uint32_t} nms
     * @return {*}
     */
    static void Step_Motor_CW(StepMotor_t *motor)
    {
        volatile uint8_t i;
        uint32_t j, pieces; /* pieces 表示8个位一组的脉冲一共多少组 */
        uint8_t temp = 0;
        
        pieces = motor->step_num / 8;
        for(j = 0; j < pieces; j++)
            for(i = 0; i < 8; i++)
            {
                temp = steps[i];
                LA = (uint8_t)((temp&PLA) >> 0);
                LB = (uint8_t)((temp&PLB) >> 1);
                LC = (uint8_t)((temp&PLC) >> 2);
                LD = (uint8_t)((temp&PLD) >> 3);
                
                delay_us(motor->step_slice);
            }
        Step_Motor_Stop(&StepMotor);
    }
    

    串口部分代码改进

    • 在usart.h中进行宏配置,可以方便的开关USART接收中断,配置如下:
    /* 串口1接收配置使能,使用串口进行调试 */
    #define USART1_RCV_EN      1
    
    • 在usart.c中进行USART初始化,在初始化中开启接收中断,并对中断进行配置
    void Usart1_Init(unsigned int baud)
    {
    	GPIO_InitTypeDef gpio_initstruct;
    	USART_InitTypeDef usart_initstruct;
    	NVIC_InitTypeDef nvic_initstruct;
    	/* 时钟使能 */
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    	/* gpio口配置 */
    	//PA9	TXD
    	gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
    	gpio_initstruct.GPIO_Pin = GPIO_Pin_9;
    	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpio_initstruct);
    	
    	//PA10	RXD
    	gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	gpio_initstruct.GPIO_Pin = GPIO_Pin_10;
    	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpio_initstruct);
    	
    	/* 串口配置 */
    	usart_initstruct.USART_BaudRate = baud; /* 波特率设置 */
    	usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
    	usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
    	usart_initstruct.USART_Parity = USART_Parity_No;									//无校验
    	usart_initstruct.USART_StopBits = USART_StopBits_1;								//1位停止位
    	usart_initstruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
    	USART_Init(USART1, &usart_initstruct);
    	
    	USART_Cmd(USART1, ENABLE);														//使能串口
    	/* 接收中断使能 */
    	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									//使能接收中断
    	/* 接收中断配置 */
    	nvic_initstruct.NVIC_IRQChannel = USART1_IRQn;
    	nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
    	nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
    	nvic_initstruct.NVIC_IRQChannelSubPriority = 2;
    	NVIC_Init(&nvic_initstruct);
    }
    
    • 设置一个结构类型,用来处理数据和USART接收中的状态
    /* 类型定义 ------------------------------------------------- */
    STRUCT(RcvDta_t)
    {
        uint8_t rcv_dta[13];/* 接收数据 */
        uint8_t worked_dta[13];/* 处理数据 */
        /* state:   bit0 ~ bit6 记录data数量
         *          bit7 : 0 表示接收状态
         *                 1 表示处理状态         
         */
        uint8_t state;
        void (*func)(RcvDta_t *rcv_ptr);
    };
    
    • 定义结构体数据
    /* 变量定义 ---------------------------------------------- */
    #if USART1_RCV_EN
    RcvDta_t RcvMsg;
    #endif
    
    • 串口中断函数,在串口中接收并判断是不是接收完成
    void USART1_IRQHandler(void)
    {
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
    	{
    #if USART1_RCV_EN
    		uint8_t ch = USART_ReceiveData(USART1);
    		/* 结束条件判断,在发送数据的时候需要在末尾加上回车 */
    		if(ch == '\n')
    			RcvMsg.state |= 0x80;
    
    		if(!(RcvMsg.state & 0x80))
    		{
    			if((RcvMsg.state & 0x7f) < sizeof(RcvMsg.rcv_dta) - 1)
    			{
    				
    				RcvMsg.rcv_dta[RcvMsg.state++] = ch;
    			}
    		}
    #endif
    		USART_ClearFlag(USART1, USART_FLAG_RXNE);
    	}
    }
    
    • 定义app.c和app.h,并在app.c中定义串口接收处理函数
    #if USART1_RCV_EN
    /**
     * @name: Dubug_MsgHandler
     * @description: 处理串口接收数据,将接收数据处理为电机的数据
     * @param {RcvDta_t} *rcv_ptr 串口数据结构体指针
     * @param {StepMotor_t} *motor 电机结构体指针
     * @return {*}
     */
    void Dubug_MsgHandler(RcvDta_t *rcv_ptr, StepMotor_t *motor)
    {
    	char *ret = NULL;
    	char *is_space = NULL;
        int speed;
    
        /* 将内容复制到worked_dta, rcv_dta将清空下次接收 */
    	strncpy((char *)rcv_ptr->worked_dta, (char *)rcv_ptr->rcv_dta, 11);
    	// printf("usart rcv: %s state: %#x\r\n", rcv_ptr->worked_dta, rcv_ptr->state);
    
        /* 指令处理 ------------------------------------ */
        /* 电机运转 --------- */
    	ret = strstr((char *)rcv_ptr->worked_dta, "run");
    	if(ret != NULL)
    	{
            motor->state |= 0x01;
            motor->state &= ~(1<<1);
            ret = NULL;
    	}
    
        /* 电机正转 --------- */
    	ret = strstr((char *)rcv_ptr->worked_dta, "run_cw");
    	if(ret != NULL)
    	{
            motor->state |= 0x01;
            motor->state &= ~(1<<1);
            ret = NULL;
    	}
    
        /* 电机反转 --------- */
    	ret = strstr((char *)rcv_ptr->worked_dta, "run_ccw");
    	if(ret != NULL)
    	{
            motor->state |= 0x01;
            motor->state |= (1<<1);
            ret = NULL;
    	}
    
        /* 电机速度设置 --------- */
        ret = strstr((char *)rcv_ptr->worked_dta, "speed");
        if(ret)
        {
            ret += strlen("speed");
            ret++;
            is_space = strchr(ret, ' ');
            if(is_space) ret++;
            speed = atoi(ret);
            motor->step_slice = speed;
    
            ret = NULL;
        }
    
    	memset(rcv_ptr->rcv_dta, 0, sizeof(rcv_ptr->rcv_dta));
    	rcv_ptr->state &= 0x00;
    }
    #endif
    

    处理函数只进行了简单处理,需要复杂功能都可以在此函数中进行处理。

    • 在main.c中调用
    int main(void)
    {
    	uint32_t t = 0;
    
    	initSysTick();
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	Usart1_Init(115200);
    	LED1_Init();
    	Step_Motor_Init();
    
    	for(;;)
    	{
    		/* 串口接收是否接受到 */
    		if(RcvMsg.state & 0x80)
    		{
    			Dubug_MsgHandler(&RcvMsg, &StepMotor);
    			delay_ms(1);
    		}
    		
    		/* 是否启动电机 */
    		if(StepMotor.state & 0x01)
    		{
    			StepMotor.run(&StepMotor);	
    		}
    		
    		if(t % 100 < 50)
    			LED1_Open();
    		else
    			LED1_Close();
    
    		if(t > 1000)
    			t = 0;
    
    		t++;
    		delay_ms(10);
    	}
    }
    

    调试结果

    • 使用串口调试助手进行调试
      在这里插入图片描述

    调试结果图

    以上的调试过程中,需要注意每次输入的时候使用回车,不然程序会卡住或者下调指令执行错误,有稍微的不方便之处,可以使用定时器中断进行程序改进,各有优略。


    以上代码传送门: 串口调试步进电机,再也不用担心调试重复下载啦


    喜欢请点个赞哦,谢谢!欢迎指正

    展开全文
  • 源代码+仿真+电路图
  • STM32+ULN2003驱动步进电机

    万次阅读 多人点赞 2014-05-12 00:06:01
    选用的步进电机的型号为28BYJ-48(或MP28GA,5V,转速比1/64),驱动电路选用uln2003芯片的驱动板,其控制时序图如下: 四相八拍:A->AB->B ->BC ->C ->CD ->D ->DA 其A、B、C、D指的是uln2003芯片驱动板的1N1...

    选用的步进电机的型号为28BYJ-48(或MP28GA5V,转速比1/64),驱动电路选用uln2003芯片的驱动板,其控制时序图如下:

    四相八拍:A->AB->B ->BC ->C ->CD ->D ->DA

    ABCD指的是uln2003芯片驱动板的1N11N21N31N4,波形在上表示有输入信号。

    此外至少需要4根杜邦线,还需提供一个5V的直流电源,接线方式如下:

    PE0IN1
        PE1IN2 
        PE2IN3
        PE3IN4 
        5V电源(一个是地,一个是正)。

    1. /***************************************************************************//**
    2.  * @file : stm32_pio.h
    3.  * @brief : STM32F1xx CoX PIO Peripheral Interface
    4.  * @version : V1.0
    5.  * @date : 28 Feb. 2011
    6.  * @author : CooCox
    7. *******************************************************************************/
    8. #ifndef __STM_PIO_H
    9. #define __STM_PIO_H

    10. #include "cox_pio.h"

    11. /***************************************************************************//**
    12.  * Define STM32F1xx CoX PIO Peripheral Interface
    13. *******************************************************************************/
    14. extern COX_PIO_PI pi_pio;

    15. #endif
    1. /***************************************************************************//**
    2.  * @file : stm32_pio.c
    3.  * @brief : STM32F1xx CoX PIO Peripheral Interface
    4.  * @version : V1.0
    5.  * @date : 28 Feb. 2011
    6.  * @author : CooCox
    7.  ******************************************************************************/
    8. #include "stm32_pio.h"
    9. #include "stm32f10x.h"


    10. /***************************************************************************//**
    11.  * @brief Get pointer to GPIO peripheral due to GPIO port
    12.  * @param[in] portNum : Port Number value, should be in range from 0 to 6.
    13.  * @return Pointer to GPIO peripheral
    14. *******************************************************************************/
    15. static GPIO_TypeDef* STM32_GetGPIO(uint8_t port)
    16. {
    17.     GPIO_TypeDef *pGPIO = COX_NULL;

    18.     switch(port)
    19.     {
    20.         case 0: pGPIO = GPIOA; break;
    21.         case 1: pGPIO = GPIOB; break;
    22.         case 2: pGPIO = GPIOC; break;
    23.         case 3: pGPIO = GPIOD; break;
    24.         case 4: pGPIO = GPIOE; break;
    25.         case 5: pGPIO = GPIOF; break;
    26.         case 6: pGPIO = GPIOG; break;
    27.         default: break;
    28.     }

    29.     return pGPIO;
    30. }


    31. /***************************************************************************//**
    32.  * @brief Initializes the PIO peripheral
    33.  * @param[in] pio : The specified peripheral
    34.  * @return Result, may be :
    35.  * -COX_ERROR : Error occurred, parameter is not supported
    36.  * -COX_SUCCESS : Previous argument of the specified option
    37. *******************************************************************************/
    38. static COX_Status STM32_PIO_Init (COX_PIO_Dev pio)
    39. {

    40.     GPIO_TypeDef* pGPIO = COX_NULL;
    41.     uint8_t port, pin;

    42.     port = (pio >> 8) & 0xFF;
    43.     pin = (pio >> 0) & 0xFF;

    44.     pGPIO = STM32_GetGPIO(port);

    45.     if(port >|| port<|| pin<|| pin > 15)
    46.         return COX_ERROR;

    47.     /* Enable GPIO and AFIO clocks */
    48.     switch(port)
    49.     {
    50.         case 0: RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN); break;
    51.         case 1: RCC->APB2ENR |= (RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN); break;
    52.         case 2: RCC->APB2ENR |= (RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN); break;
    53.         case 3: RCC->APB2ENR |= (RCC_APB2ENR_IOPDEN | RCC_APB2ENR_AFIOEN); break;
    54.         case 4: RCC->APB2ENR |= (RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN); break;
    55.         default: break;
    56.     }
    57.   return COX_SUCCESS;
    58. }


    59. /***************************************************************************//**
    60.  * @brief Set direction (Input or Output)
    61.  * @param[in] pio : The specified PIO peripheral
    62.  * @param[in] dir : Direction, should be
    63.  * -0: Input
    64.  * -1: Output
    65.  * @return Result, may be :
    66.  * -COX_ERROR : Error occurred, parameter is not supported
    67.  * -COX_SUCCESS : Previous argument of the specified option
    68. *******************************************************************************/
    69. static COX_Status STM32_PIO_SetDir(COX_PIO_Dev pio, uint8_t dir)
    70. {

    71.     GPIO_TypeDef* pGPIO = COX_NULL;
    72.     uint8_t port, pin;

    73.     port = (pio >> 8) & 0xFF;
    74.     pin = (pio >> 0) & 0xFF;

    75.     pGPIO = STM32_GetGPIO(port);

    76.     /* Direction is input:GPIO_Mode_IN_FLOATING */
    77.     if(dir == 0){
    78.         if(pin>7)
    79.         {
    80.             /* Configure the eight high port pins */
    81.             pin = pin-8;
    82.             /* MODE[1:0]=00 */
    83.             pGPIO -> CRH &= ~(0x3 << (pin*4));
    84.             /* CNF[1:0] =01 */
    85.             pGPIO -> CRH &= ~(0x8 << (pin*4));
    86.             pGPIO -> CRH |= (0x4 <<(pin*4));
    87.         }

    88.         else
    89.         {
    90.             /* Configure the eight low port pins */
    91.             pGPIO -> CRL &= ~(0x3 << (pin*4));
    92.             pGPIO -> CRL &= ~(0x8 << (pin*4));
    93.             pGPIO -> CRL |= (0x4 << (pin*4));
    94.         }
    95.     }

    96.     /* Direction is output:GPIO_Mode_Out_PP */
    97.     else {
    98.         if(pin>7)
    99.         {
    100.             pin = pin-8;
    101.             /* MODE[1:0]=11 */
    102.             pGPIO -> CRH |= (0x3 <<(pin*4));
    103.             /* CNF[1:0] =00 */
    104.              pGPIO -> CRH &= ~(0xc <<(pin*4));
    105.         }
    106.         else
    107.         {
    108.             pGPIO -> CRL |= (0x3 << (pin*4));
    109.             pGPIO -> CRL &= ~(0xc<<(pin*4));
    110.         }
    111.     }
    112.     return COX_SUCCESS;
    113. }


    114. /******************************<span s

    uln2003 驱动 继电器及步进电机

    由于单片机的驱动能力较弱,使用继电器、步进电机等外设时,一般需要外接5v 12v电源驱动,使用uln2003即可使用小电压控制大电压的通断。
     
    uln2003
     
    uln2003的内部是一组达林顿管,你可以理解为放大倍数很高的三极管,你用到的控制极就是其基极,所以,它有0.7V电压就可以工作了。但一般在使用时,还是要保证提供2V以上,不然可能不会很可靠。
     
        原理图                                                     应用电路
    uln2003.png  QQ截图20120618193218.png
     
    单片机的I/O口直接和ULN2003连,ULN2003有16个脚共7路驱动.
    ULN2003的8脚接5V电源地,9脚接+5V或12V电源,因为ULN2003里面有续流二极管从9脚引出.
     
    假如你用P1.0驱动一个电机,那么P1.0接ULN2003的1脚,ULN2003的16脚接电机线圈的一端,电机线圈的另一端接+5V电源.P1.0为高电平,电机就转,P1.0为低电平,电机就停.ULN2003驱动电流500MA.
     
    这个器件用起来很简单,它是一个不能输出高电平的反相器,就是说你输入高电平的时候,输出低电平,你输入低电平的时候它就成高阻态(就是电阻很大,可以看成短路,这时如果你加上拉电阻的话输出就会拉成高电平)。
     
    一般他的用法就当成电子开关用,就是你输入高电平的时候它相应的端口会输出低电平,而且这个低电平能吸收的电流达500mA。所以一般就是电机或者其他用电器的一段接ULN2003 的输出口(像接了一个开关然后再接到低)。还有一段接高电平或者电源。使用的时候就把相应的端口置高电平就会打开开关,让电机形成对地的回路,从而让电机运行;如果相应的端口为低电平,输出为高阻态,就像断开了对地的开关,从而不形成回路让电机关闭。
     
    继电器
     
    QQ截图20120618205011.jpg(继电器型号: hjr-4120-*v   *为线圈控制电压)
     
    一般继电器的外壳有标注,如果没有,自己用万用表测一下也很简单:
     
    1、找出线圈引脚。
        用万用表测各引脚间的电阻,阻值在数百至1K欧姆左右的两个脚是线圈引脚。注意有些继电器的线圈分正负极,反接虽然不至于损坏,但不动作。
     
    2、找出常开、常闭点。
        用万用表测除线圈之外的四个引脚,导通的两个引脚是常闭关 系,给线圈加上5V(继电器线圈有效电压)直流电,使继电器动作,它们应断开;如果没有断开,则内部是短接关系。
        给线圈加上5V(继电器线圈有效电压)直流电,使继电器动作,此时再用万用表测,如果有原来不通的两个引脚导通了,则它们是常开关系。
     
        既与常开点有关系,又与常闭点有关系的引脚,就是公共端。

     
    步进电机
     
    相关特性:
    1、 步进电机必须加驱动才可以运转, 驱动信号必须为脉冲信号,没有脉冲的时候,
    步进电机静止, 如果加入适当的脉冲信号, 就会以一定的角度(称为步角)转动。转
    动的速度和脉冲的频率成正比。
    2、28BYJ48 5V 驱动的4 相5 线的步进电机,而且是减速步进电机,减速比为1:64,步进角为5.625/64 度。
    如果需要转动1 圈,那么需要360/5.625*64=4096 个脉冲信号。
    3、 步进电机具有瞬间启动和急速停止的优越特性。
    4、 改变脉冲的顺序, 可以方便的改变转动的方向。
     
    因此,目前打印机,绘图仪,机器人,等等设备都以步进电机为动力核心。
     
    每一个脉冲信号对应步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态的改变完成一个循环时,转子转过一个齿距。四相步进电机可以在不同的通电方式下运行,常见的通电方式有单(单相绕组通电)四拍(A-B-C-D-A。。。),双(双相绕组通电)四拍(AB-BC-CD-DA-AB-。。。),八拍(A-AB-B-BC-C-CD-D-DA-A。。。)。
     
    采用四拍方式驱动:
    QQ截图20120618210127.png
    将单片机IO(如P1)接到uln2003输入端,将步进电机的信号线对应接到uln2003的输出口,根据上表可以单片机IO口的8个驱动脉冲信号为:
    uchar code Step_1[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}; //逆时钟旋转相序表
    uchar code Step_2[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08}; //正时钟旋转相序表
     
    uln2003驱动继电器  步进电机原理图:
     
    QQ截图20120618212527.png


    28byj48步进电机工作时序图和stm32+uln2003驱动代码  

    2013-04-30 11:30:41|  分类: 单片机 |  标签:stm32  28byj48  步进电机  |举报|字号 订阅

    28byj48步进电机工作时序图和stm32+uln2003驱动代码 - Avocado - Gekkos Glory
      void init_stepmotor_GPIO(void)
    {
    //打开时钟
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //GPIO设置
          GPIO_InitTypeDef GPIO_InitStructure;   
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;   
          GPIO_Init(GPIOA,&GPIO_InitStructure);  
    }

    void motor_cw(uint32_t circle,uint32_t delay)//circle循环数 delay控制转速
    {
      uint32_t i,j;
      j=2000;
      for(i=0;i<=circle;i++)
      {
       GPIO_Write(GPIOA, 8);
       motor_delay(j);
       GPIO_Write(GPIOA, 12);
       motor_delay(j);
       GPIO_Write(GPIOA, 4);
       motor_delay(j);
       GPIO_Write(GPIOA, 6);
       motor_delay(j);
       GPIO_Write(GPIOA, 2);
       motor_delay(j);
       GPIO_Write(GPIOA, 3);
       motor_delay(j);
       GPIO_Write(GPIOA, 1);
       motor_delay(j);
       GPIO_Write(GPIOA, 9);
       motor_delay(j);
       motor_delay(delay);//这个控制转速
      }
    }

    void motor_ccw(uint32_t circle,uint32_t delay)
    {
      uint32_t i,j;
      j=2000;
      for(i=0;i<=circle;i++)
      {
       GPIO_Write(GPIOA, 9);
       motor_delay(j);
       GPIO_Write(GPIOA, 1);
       motor_delay(j);
       GPIO_Write(GPIOA, 3);
       motor_delay(j);
       GPIO_Write(GPIOA, 2);
       motor_delay(j);
       GPIO_Write(GPIOA, 6);
       motor_delay(j);
       GPIO_Write(GPIOA, 4);
       motor_delay(j);
       GPIO_Write(GPIOA, 12);
       motor_delay(j);
       GPIO_Write(GPIOA, 8);
       motor_delay(j);
       motor_delay(delay);//这个控制转速
      }
    }

    void motor_delay(uint32_t delay)
    {
      uint32_t i;
      for(i=1;i<delay;i++)
        {
        asm("nop");
        } 
    }


    28BYJ48型步进电机的控制方法  

    2011-03-13 23:02:00|  分类: 单片机技术|举报|字号 订阅

      前不久弄到一只28BYJ48型步进电机,没有资料,从网上查找,搜到一些资料,但按照网上介绍的程序实验,都没有成功。后来根据资料的原理部分,试着自己编写了一段程序,经过多次实验调试,终于成功了。

      哈哈,收获不小!!!

      步进电机是一种将电脉冲转化为角位移的执行设备。通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(即步进角)。我们可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时我们可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。

      28BYJ48型步进电机是四相八拍电机,电压为DC5V~DC12V。当对步进电机按一定顺序施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号使得步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度。当通电状态的改变完成一个循环时,转子转过一个齿距。四相步进电机可以在不同的通电方式下运行,常见的通电方式有单(单相绕组通电)四拍(A-B-C-D-A……),双(双相绕组通电)四拍(AB-BC-CD-DA-AB……),四相八拍(A-AB-B-BC-C-CD-D-DA-A……)。本例是使用四相八拍驱动方式实现的。

      下面是我写的C语言控制程序实现28BYJ48型步进电机正转五圈然后倒转五圈的效果:

    //********************************************************************************
    //*  标题:  步进电机正反转演示程序                                               *
    //*  文件:  步进电机正反转演示.C                                                 *
    //*  日期:  2011-3-13                                                            *
    //*  环境:  使用自制单片机最小系统板测试通过                                     *
    //********************************************************************************
    //*  描述:  28BYJ-48步进电机正反转控制                                           *
    //*  电机使用端口:P1.0、P1.1、P1.2、P1.3                                        *
    //*  单双八拍工作方式:A-AB-B-BC-C-CD-D-DA                                       *
    //********************************************************************************

    #include <reg51.h>
    #include <intrins.h>

    //**********************正向旋转相序表*****************************
    unsigned char code FFW[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09};

    //**********************反向旋转相序表***************************** 

    unsigned char code REV[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08};

    //***********************延时子程序******************************** 

    void delay(unsigned int t)
    {                          
       unsigned int k;
       while(t--)
       {
         for(k=0; k<125; k++)
         {}
       }
    }

     

    //**********************步进电机正转****************************** 

    void  motor_ffw(unsigned int n)
     {
       unsigned char i;
       unsigned int  j;
       for (j=0; j<8*64*n; j++)
        {
          for (i=0; i<8; i++)
            {
              P1 = FFW[i];
             delay(1);
             }
        }
     }

     

    //*********************步进电机反转******************************** 

    void  motor_rev(unsigned int n)
    {
        unsigned char i;
      unsigned int  j;
      for (j=0; j<8*64*n; j++)
          {
            for (i=0; i<8; i++)
            {
              P1 = REV[i];
              delay(1);
            }
          }
     }

     

    //*************************主程序*********************************
    main()
     {  
       while(1)                    
        { 
           motor_ffw(5);          //电机正转5圈
           delay(1000);
           motor_rev(5);          //电机反转5圈
           delay(1000);

        }
     }



    展开全文
  • STM32控制ULN2003驱动步进电机28BYJ-48

    千次阅读 2021-04-27 16:23:59
    传送门:一文搞懂步进电机特性、原理及驱动器设计 28BYJ-48步进电机 28BYJ-48永磁式减速单极性步进电机 28:步进电机的有效最大外径是28毫米 B:表示是步进电机 Y:表示是永磁式 J:表示是减速型(减速比1:64) 48...
  • 基于51单片机+ULN2003控制步进电机S曲线加减速

    千次阅读 多人点赞 2021-05-16 21:34:54
    可以用来驱动四线五相步进电机,例如常用的28BYJ和35BYJ系列,也可以用来驱动有抽头的HB42步进电机,单相电流可以到500mA,本文以28BYJ48为例进行介绍。 2.28BYJ48简介 ①完整实物图如下 ②拆去盖板是上层的4级...
  • 如何用STM32单片机通过ULN2003驱动步进电机28BYJ-48 单片机:STM32F103ZET6 步进电机:28BYJ-48 驱动电路:ULN2003芯片的驱动板 引脚连接如下: IN1:PC3 IN2:PC2 IN3:PC0 IN4:PC13 OUT1:步进电机4 OUT2:步进...
  • AT89C51驱动ULN2003控制步进电机proteus仿真源文件 (含C程序源码),包含proteus工程源文件,单片机C语言程序。proteus8.6可正常打开,仿真。
  • ULN2003步进电机驱动模块,原理图,相关资料,测试程序
  • 在之前的驱动步进电机的基础上引入了按键的功能,可以通过按键实现电机的正转、反转和停止。 硬件连接如下: 单片机:STM32F103ZET6 步进电机:28BYJ-48 驱动电路:ULN2003芯片的驱动板 引脚连接如下: IN1:PC3 IN...
  • ULN2003驱动步进电机代码以及接线
  • 传送门:STM32控制ULN2003驱动步进电机28BYJ-48最基础方法 上节代码应该是能搜到的控制ULN2003驱动步进28BYJ-48最通用的方法了,但是上节代码的执行会导致整个系统进行阻塞。如果电机运转10圈可能导致41s的阻塞时间...
  • 51单片机ULN2003驱动~5线4相5V步进电机~程序

    千次阅读 多人点赞 2021-05-23 12:38:57
    硬件选择:某宝上有卖,一块驱动板加一个5V小步进电机大概是10块钱,这种套装一般用来做摄像头转动等等,因为电机驱动板较小,力量小,易发热。 一共3种程序,减速、加速、正反转,需要哪种自己选择。 ********...
  • 例说51单片机(C语言版)(第3版)源程序及professional仿真电路-L298、ULN2003驱动2相可调速步进电机实验
  • 基于stm32F103的ULN2003步进电机驱动硬件准备一、本次使用的硬件二、使用步骤1.引入库2.读入数据总结(一)硬件(二)代码(二)想法 硬件准备 一、本次使用的硬件 开发板:stm32f103c8t6核心板 电机:ULN2003 步进...
  • 下面介绍一种驱动步进电机的驱动器ULN2003A,它是一种新型的七路高耐压、大电流达林顿晶体管驱动IC,在继电器驱动、显示驱动、电磁阀驱动、伺服电机以及步进电机驱动电路当中都会用到,ULN2003常见的封装有
  • 单片机IO驱动能力不够,因此使用ULN2003驱动。 采用4相8拍驱动方式,步进电机在proteus里是motor-stepper,接法:中间引出接电源,其他脚顺时针或逆时针接即可。
  • 用stm32驱动步进电机(一) ——使用ULN2003芯片

    万次阅读 多人点赞 2019-07-28 20:22:02
    概述 随着嵌入式系统的发展,步进电机的使用开始激增,只要涉及到把物体从一个地方...首先从最简单的入手,用ULN2003芯片,来驱动这种淘宝单片机套件中经常见到(但其实并没有什么用处)的5V四相五线步进电机。 长这...
  • 电机驱动板采用的是ULN2003 步进电机采用的是28BYJ4 (5V 4相5线步进电机) 三、驱动代码 3.1 motor.c #include "motor.h" //步进电机正反转数组1 u16 PositiveSequence[4] ={0x0200,0x0100,0x0080,0x...
  • 51单片机步进电机驱动ULN2003

    千次阅读 多人点赞 2019-02-26 22:55:34
    在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”,它的旋转是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 387
精华内容 154
关键字:

单片机uln2003驱动步进电机