⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main_ok.c

📁 这是我做的一个步进电机测试程序,程序实现了单4步,双4步,8步步进电机驱动,并可改变旋转方向,改变每步时长,是比较完善的步进电机驱动.
💻 C
字号:

//步进电机驱动测试程序,用于测试步进电机每相最短时间和最长时间,单位毫秒
//硬件环境:Atmel 89C2051 晶振频率 7.3728MHz
//硬件系统描述:   步进电机采用TOSHIBA 的 ULN2803A驱动,
//                步进电机 1  -- 电源
//                         2  -- 1相 -- ULN2803 14脚 -- 5脚    -- 2051 19脚 P1.7
//                         3  -- 2相 -- ULN2803 13脚 -- 6脚    -- 2051 18脚 P1.6
//                         4  -- 3相 -- ULN2803 12脚 -- 7脚    -- 2051 17脚 P1.5
//                         5  -- 4相 -- ULN2803 11脚 -- 8脚    -- 2051 16脚 P1.4
//                按键:   2051 6脚 P3.2 INT0 --  增加步长 UP_KEY
//                         2051 7脚 P3.3 INT1 --  减小步长 DOWN_KEY
//                         2051 9脚 P3.5      --  改变电机旋转方向 DIR_KEY

//设计描述: 定时器0产生驱动电机的脉冲,宽度可以通过2个按键以SETP_LEN为步长改变,电机旋转方向可按DIR_KEY来切换.
//          步进电机分8拍,每相高电平占3拍,低电平占5拍;
//          步进电机8个状态依次为(P1.7 -- P1.4): 0101(0x50) --> 0001(0x10) --> 1001(0x90) --> 1000(0x80) --> 1010(0xa0) --> 0010(0x20) --> 0110(0x60) --> 0100(0x40)
//          以上8个状态应取反,取反后依次为:      1010(0xa0) --> 1110(0xe0) --> 0110(0x60) --> 0111(0x70) --> 0101(0x50) --> 1101(0xd0) --> 1001(0x90) --> 1011(0xb0)
//                                               1001(0x90) --> 1000(0x80) --> 1100(0xc0) --> 0100(0x40) --> 0110(0x60) --> 0010(0x20) --> 0011(0x30) --> 0001(0x10)

//测试结论:每拍时长最低3ms,低于3ms电机无法旋转.

#include <reg52.h>          //包括一个52标准内核的头文件

#define STEP_LEN    1       //步进电机驱动脉冲改变步长
#define MIN_STEP    3       //最小拍长
#define STEP_NUM    8       //拍数
#define TIMER_TIME  1       //定时器中断时间,取值范围为1,10,100ms

#define uchar unsigned char //定义一下方便使用
#define uint  unsigned int
#define ulong unsigned long
#define MOTOR_PORT     P1

sbit Phase1 = P1^7;       //步进电机1相
sbit Phase2 = P1^6;       //步进电机2相
sbit Phase3 = P1^5;       //步进电机3相
sbit Phase4 = P1^4;       //步进电机4相
sbit DirKey = P3^5;       //旋转方向控制键
sbit KeyUp  = P3^2;       //拍长加一个步长STEP_LEN
sbit KeyDown= P3^3;       //拍长减一个步长STEP_LEN

uchar CurrStatus = 0;   //步进电机当前状态,共8个,0 -- 7
//uchar MotorStatus[8] = {0x50,0x10,0x90,0x80,0xa0,0x20,0x60,0x40};   //八个状态值
//uchar MotorStatus[8] = {0xa0,0xe0,0x60,0x70,0x50,0xd0,0x90,0xb0};   //八个状态取反值
uchar MotorStatus[8] = {0x90,0x80,0xc0,0x40,0x60,0x20,0x30,0x10};
//uchar MotorStatus[4] = {0x90,0xc0,0x60,0x30};                       //4拍,未测试 
uchar phase_width = MIN_STEP;//每拍脉冲宽度
uchar dir = 1;               //电机旋转方向 1 -- 逆时针  0 -- 顺时针
unsigned int LedCount;       //led亮灭计数,保证led亮灭的时间大于500ms.

sbit LED    = P1^2;       //定时器指示LED

uchar TimerCount = 0;     //定时溢出计数器
void Delay(unsigned int utime);

void main(void)          // 主程序
{
    MOTOR_PORT = 0xff;   //初始状态,关闭所有驱动口线
    //Timer0采用模式1,即16位计数器,时钟模式,10ms中断一次
    TMOD = 0x01;

#if TIMER_TIME == 1
    //1ms
    TH0 = 0xFD;
    TL0 = 0x99;
    LedCount = 500;
#endif
#if TIMER_TIME == 10
    //10ms
    TH0 = 0xE8;
    TL0 = 0x0;
    LedCount = 50;
#endif
#if TIMER_TIME == 100
    //100ms
    TH0 = 0x10;
    TL0 = 0x0;
    LedCount = 5;
#endif

    EA = 1;          //开中断
    ET0 = 1;         //T/C0中断开放
    TR0 = 1;         //T/C0启动定时
    EX0 = 0;         //外部中断0关闭
    EX1 = 0;         //外部中断1关闭

    LED = 0;         //点亮LED
    while (1)
    {
        if (DirKey == 0)
            dir = 1 - dir;   //方向改变

/*        if (KeyUp == 0)
        {
            Delay(1330);
            if (KeyUp == 0)
                if ((phase_width + STEP_LEN) <250 )
                    phase_width += STEP_LEN;
        }

        if (KeyDown == 0)
        {
            Delay(1330);
            if (KeyDown == 0)
                if ((phase_width - STEP_LEN) > MIN_STEP)
                    phase_width -= STEP_LEN;
        }
*/    }
}

//定时器0中断,根据pluse_width产生驱动电机的脉冲
void timer0() interrupt 1 using 1  
{
    
    //Timer0采用模式1,即16位计数器,时钟模式,10ms中断一次
#if TIMER_TIME == 1
    //1ms
    TH0 = 0xFD;
    TL0 = 0x99;
#endif
#if TIMER_TIME == 10
    //10ms
    TH0 = 0xE8;
    TL0 = 0x0;
#endif
#if TIMER_TIME == 100
    //100ms
    TH0 = 0x10;
    TL0 = 0x0;
#endif

/*
    if (LedCount == 0)
    {
#if TIMER_TIME == 1
        //1ms
        LedCount = 500;
#endif
#if TIMER_TIME == 10
        //10ms
        LedCount = 50;
#endif
#if TIMER_TIME == 100
        //100ms
        LedCount = 5;
#endif

        LED = !LED;                      //LED取反
    }
    else
        LedCount--;
*/
    if (++TimerCount >= 5)
    {
        
        TimerCount = 0;
        if (CurrStatus > 7)   //如果当前状态处于错误状态:不在0 -- STEP_NUM 之间,则置为初始状态:0
            CurrStatus = 0;

        MOTOR_PORT =  (MOTOR_PORT & 0x0f) | ~MotorStatus[CurrStatus];
            CurrStatus = ++CurrStatus % 8;
/*        if (dir)
            CurrStatus = ++CurrStatus % STEP_NUM;
        else
            CurrStatus = (CurrStatus == 0 ? (STEP_NUM - 1) : CurrStatus--);
*/        LED = !LED;                      //LED取反
    }
}

//调用一次的时间为20uS,执行一次循环的时间为15uS,精确延时的计算公式是:(15*N+20)uS 10ms:665
/*void Delay(unsigned int utime)
{
    unsigned int t;
    t = utime;
    while(t--)
    {};
}

//外部中断int0,步进电机拍长增加一个步长值
void key_up() interrupt 0 using 2
{
//    phase_width++;
    if ((phase_width + STEP_LEN) <250 )
        phase_width += STEP_LEN;
    Delay(1330);
}

//外部中断int1,步进电机拍长减少一个步长值
void key_down() interrupt 2 using 3
{
//    phase_width--;
    if ((phase_width - STEP_LEN)> 3)
        phase_width -= STEP_LEN;
    Delay(1330);
}
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -