找回密码
 立即注册
楼主: 梁工

51开源,步进电机驱动 程序, 直接驱动, 或驱动步进电机驱动器 一共8个程序

  [复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2024-05-30 20:45:00

0

主题

2

回帖

16

积分

新手上路

积分
16
发表于 2024-6-1 10:22:01 | 显示全部楼层
请教梁工及各位前辈大侠,我把这个移植到STC12C5A60S2,PCA0 输出10ms周期的波形,改好几天都没改明白,麻烦各位看下。

#include "STC12C5A60S2.h"
#include <intrins.h>

#define MAIN_Fosc                24000000UL        //定义主时钟

#define u8  unsigned char
#define u16 unsigned int
#define u32 unsigned long

sbit STRAT_STOP = P2^0;       //开始键



void Delay_ms(unsigned char ms)
{ // 延时子程序 毫秒
        unsigned char i;
        while(ms--)
        {
                for(i = 0; i< 82; i++)
                {
                        _nop_();_nop_();_nop_();_nop_();
                }
        }
}

#define  PCA1_16bit_Timer()  CCAPM0 = (0x48 + 1)        /* 16位软件定时器模式 */
#define                PCA_VECTOR                        7
#define                TIMER0_VECTOR                1


/*************        功能说明        **************

用PCA高速脉冲输出控制步进电机驱动器.
为了简单, 利于初学者, 本例使用线性加减速, 如要使用别的加减速算法, 用户自行设计.

使用外设:
Timer0: 工作于1ms中断, 提供1ms时隙标志和串口超时处理.
Timer2: 串口1波特率.
串口1:  命令控制, 串口设置115200,8,1,n.
PCA0:   从P2.3输出驱动脉冲, 低驱动, 接步进电机驱动器脉冲输入端(一般是光耦输入, 低有效).
        从P2.0输出转向信号, 接步进电机驱动器方向输入端(一般是光耦输入, 低有效), 1:顺时针(正转), 0:逆时针(反转).

串口命令设置:
L1,500,1000   --> 马达1以500Hz正转1000个脉冲, 脉冲数为0则连续转动.
R1,500,1000   --> 马达1以500Hz反转1000个脉冲, 脉冲数为0则连续转动
s             --> 停止所有电机

******************************************/


/*************        本地变量声明        **************/

u16        CCAP1_tmp;

//================== 步进电机相关变量定义 ===================
sbit        P_M1_DIR   = P1^0;        // 运行方向, 接步进电机驱动器方向输入端(一般是光耦输入, 低有效), 1:顺时针(正转), 0:逆时针(反转)
sbit        P_M1_PULSE = P1^3;        // 驱动脉冲, 低驱动, 接步进电机驱动器脉冲输入端(一般是光耦输入, 低有效).

bit                B_M1_RunEn;                //运行允许
bit                B_f1_update;        //请求刷新频率值
bit                B_TIMER1_12T;        //定时器1时钟模式
u16                f1_period;                //当前频率对应的周期(半周期)(中断使用, 应用层不可操作)
u16                f1_period_set;        //需要刷新的目标频率对应的周期(半周期)
u16                f1;                                //当前频率
u16                f1_set;                        //目标频率
u16                f1_step;                //加减速频率变化的步长
u16                M1_UpPulse;                //加(减)速脉冲数
u16                M1_PulseCnt;        //电机运行总脉冲数, 为0则连续运行
u16                M1_DownCnt;                //运行到要减速输出的脉冲数
//===========================================================

bit        B_1ms;        //1ms时隙标志

/*************        本地函数声明        **************/
void        PCA_config(u8 clk);                //io: 选择IO, 0: 选择P12 P17 P16 P15 P14,   1:        选择P22 P23 P24 P25 P26,   2: 选择P74 P70 P71 P72 P73,   3: 选择P35 P33 P32 P31 P30.
                                                                                //clk: 选择时钟, 0: 12T,  1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T,  5: 4T,  6: 6T,  7: 8T
u8                Timer0_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us), 返回0正确, 返回1装载值过大错误.
u16                GetStep(u16 f, u16 f_set);        // 计算速度变化步进长度
void        GetFreq1(void);                                // 计算加减速频率
void        StopMotor1(void);                        // 停止运行一个电机
void        RunMotor1(u16 p);                        // 启动运行一个电机



/******************** 主函数 **************************/
void main(void)
{
        P_M1_DIR   = 1;        // 运行方向, 接步进电机驱动器方向输入端(一般是光耦输入, 低有效), 1:顺时针(正转), 0:逆时针(反转)
        P_M1_PULSE = 1;        // 驱动脉冲, 低驱动, 接步进电机驱动器脉冲输入端(一般是光耦输入, 低有效).

        PCA_config(1);        //io: 选择IO, 0: 选择P12 P17 P16 P15 P14,   1:        选择P22 P23 P24 P25 P26,   2: 选择P74 P70 P71 P72 P73,   3: 选择P35 P33 P32 P31 P30.
                                                //clk: 选择时钟, 0: 12T,  1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T,  5: 4T,  6: 6T,  7: 8T
        Timer0_Config(0, MAIN_Fosc / 1000);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)

        EA = 1;
       
        B_M1_RunEn = 0;
        CCAPM0 &= ~0x04;        //禁止高速输出脉冲

        while (1)
        {
                if(B_1ms)        //1ms时隙
                {
                        B_1ms = 0;

                        if(B_M1_RunEn)        //加减速处理
                        {
                                GetFreq1();
                                if(f1 < 100)
                                {
                                        B_M1_RunEn = 0;                //停止
                                        P_M1_DIR   = 1;        // 运行方向
                                        CCAPM0 &= ~0x04;        //禁止高速输出脉冲
                                }
                        }

                        if(STRAT_STOP==0)
                        {
                                Delay_ms(10);//延时去抖动
                                if(STRAT_STOP==0)
                                {
                                        while(STRAT_STOP==0);//等待按键释放
                                        if(!B_M1_RunEn) f1 = 200;        //电机未启动则从200HZ开始启动
                                       
                                        f1_set=1000;
                                        RunMotor1(10000);
                                }
                        }
                }
        }
}
/**********************************************/

#define        UpTime        100                //加(减)速时间(ms)

u16        GetStep(u16 f, u16 f_set)        //计算速度变化步进长度
{
        u16        i;
        M1_UpPulse = (u16)((u32)(f + f_set)*UpTime / 2000);        // 理论加速脉冲数
        if(f_set >= f)        f_set = f_set - f;                //计算频率差
        else                        f_set = f - f_set;                //计算频率差
        i = f_set / UpTime;                                // 加(减)速步进
        if(i == 0)        i = 1;        //步进不能为0
        return        i;                        //返回加减速步进值
}

void        StopMotor1(void)                //停止运行一个电机
{
        f1_set  = 95;        //小于100Hz则停止
        f1_step = GetStep(f1, f1_set);
}

//========== 准备好 "当前频率f1 目标频率f1_set 运行总脉冲数" 后才能启动运行 =================
void        RunMotor1(u16 p)        //启动运行一个电机, p为要运行的脉冲数
{
        u16        pulse;
        f1_step = GetStep(f1, f1_set);        //计算步进
        if(p != 0)        //运行总脉冲数非0才有开始减速脉冲数
        {
                pulse = M1_UpPulse * 2;                //加减速脉冲数之和 = M1_UpPulse * 2
                if(p >= pulse)        pulse = M1_UpPulse;                        //运行脉冲数 >= 加减速脉冲数之和, 则减速脉冲数按理论计算值
                else                        pulse = p / 2;        //脉冲数 <  加减速脉冲数之和, 则平分脉冲
                pulse = p - pulse;                                                // 电机开始减速需要走过的脉冲数;
        }
        else        pulse = 0;

        EA = 0;        //临界保护
        M1_PulseCnt = p;
        M1_DownCnt  = pulse;
        B_M1_RunEn  = 1;
        CCAPM0 |= 0x04;        //允许高速输出脉冲
        EA = 1;
}

/************************************/
void                GetFreq1(void)        // 计算加减速频率
{
        F0 = 0;
        if(f1 < f1_set)                //当前速度小于目标速度, 加速
        {
                F0 = 1;                        //需要调速
                f1 += f1_step;
                if(f1 > f1_set)        f1 = f1_set;                //目标频率已到
        }
        else if(f1 > f1_set)                //当前速度大于目标速度, 减速
        {
                F0 = 1;                        //需要调速
                if(f1 < f1_step)        f1 = 0;
                else                                f1 -= f1_step;
                if(f1 < f1_set)                f1 = f1_set;        //目标频率已到
        }
        if(F0)        //需要调速
        {
                f1_period_set = MAIN_Fosc/2/2/f1;        //PCA时钟2T, 半周期
                B_f1_update = 1;        //请求刷新
        }
}


//========================================================================
// 函数: void        PCA_config(u8 io, u8 clk)
// 描述: PCA配置函数。
// 参数: io: 选择IO, 0: 选择P12 P17 P16 P15 P14,   1:        选择P22 P23 P24 P25 P26,   2: 选择P74 P70 P71 P72 P73,   3: 选择P35 P33 P32 P31 P30.
//       clk: 选择时钟, 0: 12T,  1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T,  5: 4T,  6: 6T,  7: 8T
// 返回: none.
// 版本: VER1.0
// 版本: V1.0, 2016-5-10
// 备注:
//========================================================================
void        PCA_config(u8 clk)
{

        CR = 0;
        CH = 0;
        CL = 0;


        CMOD = (CMOD & ~0x0E) | ((clk & 7) << 1);                // PCA时钟选择, 0: 12T,  1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T,  5: 4T,  6: 6T,  7: 8T

        PPCA = 1;        //高优先级中断

        PCA1_16bit_Timer();        //工作于16位软件定时模式
                                //        PCA0_High_PulseEnable();        //匹配时允许高速输出
        CCAP1_tmp = 0;                //按用户需要给一个初值
        CCAP1L = 0;                        //先写CCAP0L
        CCAP1H = 0;                        //后写CCAP0H


        CR = 1;                //运行PCA定时器
}

//========================================================================
// 函数: void PCA_ISR (void) interrupt PCA_VECTOR
// 描述: PCA中断服务程序.
// 参数: 无.
// 返回: 无.
// 作者: Coody
// 版本: VER1.0
// 日期: 2020-7-31
// 备注:
//========================================================================
void PCA_ISR (void) interrupt PCA_VECTOR
{
        if(CCF0 == 1)                //PCA模块0中断
        {
                CCF0 = 0;                //清PCA模块0中断标志
                if(B_M1_RunEn)
                {
                        if(B_f1_update)        //刷新频率值
                        {
                                B_f1_update = 0;
                                f1_period = f1_period_set;
                        }
                        CCAP1_tmp += f1_period;
                        CCAP1L = (u8)CCAP1_tmp;                        //将影射寄存器写入捕获寄存器,先写CCAP0L
                        CCAP1H = (u8)(CCAP1_tmp >> 8);        //后写CCAP0H
                        if(P_M1_PULSE)        //产生了完整的一个脉冲
                        {
                                if(M1_PulseCnt != 0)        // 脉冲数未完成
                                {
                                        if(--M1_PulseCnt == 0)        //若 脉冲数-1 == 0
                                        {
                                                B_M1_RunEn = 0;                // 关停电机
                                                P_M1_DIR   = 1;                // 转向光耦关闭
                                                CCAPM0 &= ~0x04;        //禁止高速输出脉冲
                                        }
                                }
                                if(M1_DownCnt != 0)                // 减速脉冲未完
                                {
                                        if(--M1_DownCnt == 0)        f1_set = 200;        //设置目标频率, 开始减速
                                }
                        }
                }
                else  P_M1_PULSE = 1;
        }

}

//========================================================================
// 函数:u8        Timer0_Config(u8 t, u32 reload)
// 描述: timer0初始化函数.
// 参数:      t: 重装值类型, 0表示重装的是系统时钟数, 其余值表示重装的是时间(us).
//       reload: 重装值.
// 返回: 0: 初始化正确, 1: 重装值过大, 初始化错误.
// 版本: V1.0, 2018-12-20
//========================================================================

u8        Timer0_Config(u8 t, u32 reload)        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
{
        TR0 = 0;        //停止计数

        if(t != 0)        reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL);        //重装的是时间(us), 计算所需要的系统时钟数.
        if(reload >= (65536UL * 12))        return 1;        //值过大, 返回错误
        if(reload < 65536UL)        AUXR |= 0x80;                //1T mode
        else
        {
                AUXR &= ~0x80;        //12T mode
                reload = reload / 12;
        }
        reload = 65536UL - reload;
        TH0 = (u8)(reload >> 8);
        TL0 = (u8)(reload);

        ET0 = 1;        //允许中断
        TMOD = (TMOD & ~0x03) | 0;        //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
        TR0 = 1;        //开始运行
        return 0;
}



//========================================================================
// 函数: void timer0_ISR(void) interrupt TIMER0_VECTOR
// 描述:  timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2018-12-20
//========================================================================
void timer0_ISR(void) interrupt TIMER0_VECTOR
{
        B_1ms = 1;        //标志1ms时隙

}

点评

STC12C5A60S2的定时器不能16位自动重装,PCA的16位软件定时器用法差不多的,可以参考STC12C5A60S2的PCA程序。  详情 回复 发表于 2024-6-1 15:16
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 2024-6-1 15:16:59 | 显示全部楼层
zgjy*** 发表于 2024-6-1 10:22
请教梁工及各位前辈大侠,我把这个移植到STC12C5A60S2,PCA0 输出10ms周期的波形,改好几天都没改明白,麻烦 ...

STC12C5A60S2的定时器不能16位自动重装,PCA的16位软件定时器用法差不多的,可以参考STC12C5A60S2的PCA程序。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2024-05-30 20:45:00

0

主题

2

回帖

16

积分

新手上路

积分
16
发表于 2024-6-2 10:09:34 | 显示全部楼层
感谢梁工指导,问题解决了,(差点笑出了猪叫),同时还发现我PCA两个口设置搞混了,设置的是1口和0口,测试的0口,虽然我很菜,但是会努力,会一直支持STC国产

点评

哇!您太厉害了,我现在还在转悠!  发表于 2024-8-19 11:36
为你感到高兴!每次成功都会得到很多的经验。  详情 回复 发表于 2024-6-2 11:42
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 2024-6-2 11:42:25 | 显示全部楼层
zgjy*** 发表于 2024-6-2 10:09
感谢梁工指导,问题解决了,(差点笑出了猪叫),同时还发现我PCA两个口设置搞混了,设置的是1口和0口,测 ...

为你感到高兴!每次成功都会得到很多的经验。
回复 支持 反对

使用道具 举报 送花

0

主题

1

回帖

8

积分

新手上路

积分
8
发表于 2024-6-28 13:35:17 | 显示全部楼层
感谢梁工分享
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:306
  • 最近打卡:2025-04-30 20:31:49

0

主题

46

回帖

1012

积分

金牌会员

积分
1012
发表于 2024-8-6 15:36:04 | 显示全部楼层
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:280
  • 最近打卡:2025-05-01 07:15:50

2

主题

52

回帖

882

积分

高级会员

积分
882
发表于 2024-8-7 10:17:28 | 显示全部楼层
跟着老师不断学习新知识~~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:15
  • 最近打卡:2025-03-26 09:09:59

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-16 16:10:43 | 显示全部楼层
梁工,您好,我是初学者,我现在想用STC8H1K08驱动步进电机,能否使用你的开源程序移植,能否给个思路,我看了STC8H1K08没有PWMA、PWMB的端口。需要怎么移植,谢谢您。

点评

你是直接用PWM驱动步进电机,还是给驱动器发送驱动脉冲?  详情 回复 发表于 2024-8-16 18:40
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-04-30 22:59:03

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 2024-8-16 18:40:38 | 显示全部楼层
huatl*** 发表于 2024-8-16 16:10
梁工,您好,我是初学者,我现在想用STC8H1K08驱动步进电机,能否使用你的开源程序移植,能否给个思路,我 ...

你是直接用PWM驱动步进电机,还是给驱动器发送驱动脉冲?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:15
  • 最近打卡:2025-03-26 09:09:59

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-19 10:34:06 | 显示全部楼层
您好,梁工 我自己用SS8841T+NSG2184制作的驱动,用PWM驱动

点评

我的例子是用PWM5、PWM6、PWM7、PWM8来做细分驱动的。 STC8H1K08 TSSOP20的P1.7、P5.4、P3.3、P3.4就是上述的4个PWM输出。 STC8H的PWMA就是PWM1、PWM2、PWM3、PWM4,。 STC8H的PWMB就是PWM5、PWM6、PWM7、PWM8,。  详情 回复 发表于 2024-8-19 15:48
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 19:53 , Processed in 0.129634 second(s), 115 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表