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

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

  [复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:15
  • 最近打卡:2025-03-26 09:09:59

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-27 16:14:23 | 显示全部楼层
huatl*** 发表于 2024-8-27 15:46
我没有细分吧,就是上面的程序

我现在想在您的程序基础上更改,我发给您看下
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-27 16:26:29 | 显示全部楼层
/*************        本地变量声明        **************/
sbit SLEEP = P1^4;
sbit DECAY = P1^0;
//================== 步进电机相关变量定义 ===================

bit                B_M1_RunEn;                //运行允许
bit                B_M1_RunEnTmp;        //用于检测电机从运行到停止的事件
bit                B_M1_DIR;                //运行方向, 0:顺时针(正转), 1:逆时针(反转)
bit                B_f1_update;        //请求刷新频率值
bit                B_TIMER1_12T;        //定时器1时钟模式
u16                f1_period;                //当前频率对应的周期
u16                f1;                                //当前频率
u16                f1_set;                        //目标频率
u16                f1_step;                //加减速频率变化的步长
u16                M1_UpPulse;                //加(减)速脉冲数
u16                M1_PulseCnt;        //电机运行总脉冲数, 为0则连续运行
u16                M1_DownCnt;                //运行到要减速输出的脉冲数
u8                M1_StepCnt;                //步数计数
u8                M1_devide;                //细分数  1, 2, 4, 8, 16, 32, 64
u8                M1_step;                //步距, M1_step = 64 / M1_devide.
//===========================================================

//================== 串口相关变量定义 =======================
#define        RX1_LENGTH        32
u8                RX1_Cnt;                //接收字节计数
u8                RX1_TimerOut;        //接收超时计数
u8                xdata RX1_Buffer[RX1_LENGTH];        //接收缓冲
bit         B_RX1_OK;                //接收到一块数据
bit                B_TX1_Busy;                //发送忙标志
//===========================================================


bit        B_1ms;        //1ms时隙标志


/*************        本地函数声明        **************/
//void         PWMB_config(void);
void         PWMA_config(void);
u8                Timer1_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
u8                Timer0_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us), 返回0正确, 返回1装载值过大错误.
void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
void         UART1_PrintString(u8 *puts);
void         UART1_TxByte(u8 dat);                // 串口1发送一个字节       
void         RX1_process(void);                        // 串口1处理函数
u16                GetStep(u16 f, u16 f_set);        // 计算速度变化步进长度
void        GetDownPulse(void);                        // 由M1_PulseCnt(总脉冲数) 和 M1_UpPulse(加速脉冲数) 计算开始减速的脉冲数, .
void        LoadTimer1(void);                        // 计算更新频率的时间参数
void        GetFreq1(void);                                // 计算加减速频率
void        StopMotor1(void);                        // 停止运行一个电机
void        RunMotor1(void);                        // 启动运行一个电机
void        LockMotor1(void);                        //电机停止时减小电流锁转子




/******************** 主函数 **************************/
void main(void)
{
//        PWMB_config();                        //PWM初始化
        P_SW2 |= 0x80;  //扩展寄存器(XFR)访问使能

    P1M1 = 0x00;   
        P1M0 = 0xff;   //设置P1推挽输出
    P3M1 = 0x2c;                                           //           0 0 1 0 1 1 0 0
        P3M0 = 0xd3;   //设置P3推挽输出和高阻输入           1 1 0 1 0 0 1 1
        DECAY = 0;
//        nFAULT = 0;
        SLEEP = 1;
        PWMA_config();
        Timer0_Config(0, MAIN_Fosc / 1000);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
        Timer1_Config(1, 20000);                        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us, 这里随便给个值)
        EA = 1;
       
        B_M1_RunEn    = 0;
        B_M1_RunEnTmp = 0;
        M1_StepCnt = 0;
        M1_devide = 4;                                 //细分数  1, 2, 4, 8, 16, 32, 64
        M1_step = 64 / M1_devide;         //倒数关系.

        UART1_config(115200UL, 2, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
        UART1_PrintString("2相步进电机细分驱动程序\r\n");
        UART1_PrintString("L1,500,1000   --> 马达1以500Hz正转1000个脉冲\r\n");
        UART1_PrintString("R1,500,1000   --> 马达1以500Hz反转1000个脉冲\r\n");
        UART1_PrintString("s  --> 停止所有电机\r\n");

        while (1)
        {
                if(B_1ms)        //1ms时隙
                {
                        B_1ms = 0;
                       
                        if(B_M1_RunEn)        //加减速处理
                        {
                                GetFreq1();
                                if(f1 < 100)        B_M1_RunEn = 0;        //停止
                        }

                        F0 = B_M1_RunEnTmp;
                        B_M1_RunEnTmp = B_M1_RunEn;
                        if(F0 && !B_M1_RunEnTmp)        LockMotor1();        //检测到电机停止, 则锁转子, 减小电流

                        if(B_RX1_OK)        //串口收到数据块
                        {
                                RX1_process();        //串口数据处理
                                B_RX1_OK = 0;
                                RX1_Cnt = 0;
                        }
                }
        }
}
/**********************************************/

#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        GetDownPulse(void)        // 由M1_PulseCnt(总脉冲数) 和 M1_UpPulse(加速脉冲数) 计算开始减速的脉冲数, .
{
        u16 pulse;
        if(M1_PulseCnt != 0)        //运行总脉冲数非0才有开始减速脉冲数
        {
                pulse = M1_UpPulse * 2;                //加减速脉冲数之和 = M1_UpPulse * 2
                if(M1_PulseCnt >= pulse)        pulse = M1_UpPulse;                        //脉冲数 >= 加减速脉冲数之和, 则减速脉冲数按理论计算值
                else                                                pulse = M1_PulseCnt / 2;        //脉冲数 <  加减速脉冲数之和, 则平分脉冲
                M1_DownCnt = M1_PulseCnt - pulse;                                                // 电机开始减速需要走过的脉冲数;
        }
}

void        LoadTimer1(void)        //计算更新频率的时间参数
{
        if(f1 < 100)        f1 = 90;
        if(f1 < 800)        //频率太低用12T模式
        {
                B_TIMER1_12T = 1;
                f1_period = 65536UL - MAIN_Fosc/12/f1;
        }
        else
        {
                B_TIMER1_12T = 0;
                f1_period = 65536UL - MAIN_Fosc/f1;
        }

        B_f1_update = 1;        //请求刷新
}

/************************************/
void                GetFreq1(void)        // 计算加减速频率
{
        if(f1 < f1_set)                //加速
        {
                f1 += f1_step;
                if(f1 > f1_set)        f1 = f1_set;                //目标频率已到
                LoadTimer1();
        }
        else if(f1 > f1_set)                //减速
        {
                if(f1 < f1_step)        f1 = 0;
                else                                f1 -= f1_step;
                if(f1 < f1_set)                f1 = f1_set;        //目标频率已到
                LoadTimer1();
        }
}

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

void        RunMotor1(void)                //启动运行一个电机
{
        if(!TR1 || !B_M1_RunEn)
        {
                B_M1_RunEn = 1;
                TR1 = 0;
                LoadTimer1();
                TL1 = (u8)(f1_period % 256);
                TH1 = (u8)(f1_period / 256);
                TR1 = 1;
        }
}

/**********************************************/
void RX1_process(void)                        //串口1处理函数
{
        u8        i;
        u16        f, p;
        if(RX1_Cnt == 1)
        {
                i = RX1_Buffer[0];
                if((i == 's') || (i == 'S'))        //大小写均停止
                {
                        StopMotor1();                        //"s"   --> 停止所有电机
                        UART1_TxByte(i);                //返回一个提示
                }
        }

        if((RX1_Buffer[2] == ',') && (RX1_Cnt >= 5))        //有参数
        {
                for(f=0,i=3; i<RX1_Cnt; i++)        //取频率        "L1,500,1000"   --> 马达1以500Hz正转1000个脉冲
                {                                                                //                        "R1,500,1000"   --> 马达1以500Hz反转1000个脉冲
                        if(RX1_Buffer[i] == ',')        break;                //碰到逗号结束
                        f = f * 10 + RX1_Buffer[i] - '0';
                }
                if(RX1_Buffer[i] != ',')        f = 0;        //数据异常
                i++;
                for(p=0; i<RX1_Cnt; i++)        //取脉冲数
                {
                        p = p * 10 + RX1_Buffer[i] - '0';
                }
                if(f >= 100)        //有频率
                {
                        if(RX1_Buffer[1] == '1')                //电机1
                        {
                                M1_PulseCnt = p;                        //电机运行脉冲数, 如果为0, 则连续转动
                                f1_set  = f;                                //目标频率
                                if(!B_M1_RunEn)        f1 = 200;        //电机未启动则从200HZ开始启动
                                f1_step = GetStep(f1, f1_set);        //计算步进, 这个要先计算.
                                GetDownPulse();                                        //计算开始减速的脉冲数, 这个要后计算.
                                if(RX1_Buffer[0] == 'L')        //顺时针
                                {
                                        B_M1_DIR = 0;
                                        RunMotor1();        //电机转向, 启动电机
                                        UART1_TxByte('L');                //返回一个提示
                                }
                                if(RX1_Buffer[0] == 'R')        //逆时针
                                {
                                        B_M1_DIR = 1;
                                        RunMotor1();        //电机转向, 启动电机
                                        UART1_TxByte('R');                //返回一个提示
                                }
                        }
                }
        }
}


//========================================================================
// 函数: u8        Timer1_Config(u8 t, u32 reload)
// 描述: timer1初始化函数.
// 参数:      t: 重装值类型, 0表示重装的是系统时钟数, 其余值表示重装的是时间(us).
//       reload: 重装值.
// 返回: 0: 初始化正确,  1: 重装值过大, 初始化错误.
// 版本: V1.0, 2018-3-5
//========================================================================
u8        Timer1_Config(u8 t, u32 reload)        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
{
        TR1 = 0;        //停止计数

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

        ET1 = 1;        //允许中断
        PT1 = 1;        //高优先级中断
        TMOD = (TMOD & ~0x30) | (0 << 4);        //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装
        TR1 = 1;        //开始运行
        return 0;
}





//========================================================================
// 函数: void timer1_ISR (void) interrupt TIMER1_VECTOR
// 描述:  timer1中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2016-5-12
//========================================================================
void timer1_ISR (void) interrupt TIMER1_VECTOR
{
        u8                area;                //区间0~3
        u8                pwm_A;                //A相spwm
        u8                pwm_B;                //B相spwm

        if(B_M1_RunEn)        //电机允许运转
        {
                pwm_A = M1_StepCnt * M1_step;        // A相步数计数, M1_step为细分对应的步距
                area  = pwm_A / 64;                                // 区间0~3
                pwm_B = pwm_A + 64;                                // B相步数计数
                pwm_A = T_SIN[pwm_A];                        // A相sPWM值
                pwm_B = T_SIN[pwm_B];                        // A相sPWM值
               
                if(area == 0)                        //0区间
                {
                        PWMB_CCR5L = pwm_A;                // A+ = sin(A)
                        PWMB_CCR6L = 0;                        // A- = 0
                        PWMB_CCR7L = pwm_B;                // B+ = cos(A) = sin(A+64)
                        PWMB_CCR8L = 0;                        // B- = 0
                }
                else if(area == 1)                //1区间
                {
                        PWMB_CCR5L = pwm_A;                // A+ = sin(A)
                        PWMB_CCR6L = 0;                        // A- = 0
                        PWMB_CCR7L = 0;                        // B+ = 0
                        PWMB_CCR8L = pwm_B;                // B- = cos(A) = sin(A+64)
                }
                else if(area == 2)                //2区间
                {
                        PWMB_CCR5L = 0;                        // A+ = sin(A)
                        PWMB_CCR6L = pwm_A;                // A- = 0
                        PWMB_CCR7L = 0;                        // B+ = 0
                        PWMB_CCR8L = pwm_B;                // B- = cos(A) = sin(A+64)
                }
                else                                        //3区间
                {
                        PWMB_CCR5L = 0;                        // A+ = sin(A)
                        PWMB_CCR6L = pwm_A;                // A- = 0
                        PWMB_CCR7L = pwm_B;                // B+ = cos(A) = sin(A+64)
                        PWMB_CCR8L = 0;                        // B- = 0
                }

                if(B_M1_DIR == 0)        M1_StepCnt++;        //正转, 下一步, M1_step为细分对应的步距
                else                                M1_StepCnt--;        //反转, 下一步, M1_step为细分对应的步距

                if(M1_PulseCnt != 0)        //总脉冲数非0减1
                {
                        if(--M1_PulseCnt == 0)        B_M1_RunEn = 0;
                }
                if(M1_DownCnt  != 0)        //减速时刻脉冲数减1
                {
                        if(--M1_DownCnt  == 0)        f1_set  = 200;
                }
        }

        if(B_f1_update)        //刷新频率数据
        {
                B_f1_update = 0;
                TR1 = 0;
                TL1 = (u8)(f1_period % 256);
                TH1 = (u8)(f1_period / 256);
                if(B_TIMER1_12T)        AUXR &= ~0x40;        //12T mode
                else                                AUXR |=  0x40;        //1T mode
                TR1 = 1;
        }
}

void        LockMotor1(void)        //电机停止时减小电流锁转子
{
        u8                area;                //区间0~3
        u8                pwm_A;                //A相spwm
        u8                pwm_B;                //B相spwm
       
        pwm_A = M1_StepCnt * M1_step;        // A相步数计数
        area  = pwm_A / 64;                                // 区间0~3
        pwm_B = pwm_A + 64;                                // B相步数计数
        pwm_A = T_SIN[pwm_A]/2;                        // A相sPWM值
        pwm_B = T_SIN[pwm_B]/2;                        // A相sPWM值

        if(area == 0)                        //0区间
        {
                PWMB_CCR5L = pwm_A;                // A+ = sin(A)
                PWMB_CCR6L = 0;                        // A- = 0
                PWMB_CCR7L = pwm_B;                // B+ = cos(A) = sin(A+64)
                PWMB_CCR8L = 0;                        // B- = 0
        }
        else if(area == 1)                //1区间
        {
                PWMB_CCR5L = pwm_A;                // A+ = sin(A)
                PWMB_CCR6L = 0;                        // A- = 0
                PWMB_CCR7L = 0;                        // B+ = 0
                PWMB_CCR8L = pwm_B;                // B- = cos(A) = sin(A+64)
        }
        else if(area == 2)                //2区间
        {
                PWMB_CCR5L = 0;                        // A+ = sin(A)
                PWMB_CCR6L = pwm_A;                // A- = 0
                PWMB_CCR7L = 0;                        // B+ = 0
                PWMB_CCR8L = pwm_B;                // B- = cos(A) = sin(A+64)
        }
        else                                        //3区间
        {
                PWMB_CCR5L = 0;                        // A+ = sin(A)
                PWMB_CCR6L = pwm_A;                // A- = 0
                PWMB_CCR7L = pwm_B;                // B+ = cos(A) = sin(A+64)
                PWMB_CCR8L = 0;                        // B- = 0
        }
}




//========================================================================
// 函数: void PWMB_config(void)
// 描述: PWMB配置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-5-17
// 备注:
//========================================================================
/*void PWMB_config(void)
{
        P_SW2 |= 0x80;                //SFR enable   

        PWMB_PSCR = 3;                // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
        PWMB_DTR  = 0;                // 死区时间配置,   n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
                                                // 对PWMB没有意义  0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
        PWMB_ARR    = 256;        // 自动重装载寄存器,  控制PWM周期
        PWMB_CCER1  = 0;
        PWMB_CCER2  = 0;
        PWMB_SR1    = 0;
        PWMB_SR2    = 0;
        PWMB_ENO    = 0;                // IO输出允许,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5P
        PWMB_PS     = 0;
        PWMB_IER    = 0;

        PWMB_CCMR1  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMB_CCR5   = 128;                // 比较值, 控制占空比(高电平时钟数)
        PWMB_CCER1 |= 0x01;                // 开启比较输出, 高电平有效
        PWMB_PS    |= 0;                // 选择IO, 0:选择P2.0, 1:选择P1.7, 2:选择P0.0, 3:选择P7.4,
        PWMB_ENO   |= 0x01;                // IO输出允许,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5P
//        PWMB_IER   |= 0x02;                // 使能中断

        PWMB_CCMR2  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMB_CCR6   = 0;                // 比较值, 控制占空比(高电平时钟数)
        PWMB_CCER1 |= 0x10;                // 开启比较输出, 高电平有效
        PWMB_PS    |= (0<<2);        // 0:选择P2.1, 1:选择P5.4, 2:选择P0.1, 3:选择P7.5,
        PWMB_ENO   |= 0x04;                // IO输出允许,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5P
//        PWMB_IER   |= 0x04;                // 使能中断

        PWMB_CCMR3  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMB_CCR7   = 0;                // 比较值, 控制占空比(高电平时钟数)
        PWMB_CCER2 |= 0x01;                // 开启比较输出, 高电平有效
        PWMB_PS    |= (0<<4);        // 选择IO, 0:选择P2.2, 1:选择P3.3, 2:选择P0.2, 3:选择P7.6,
        PWMB_ENO   |= 0x10;                // IO输出允许,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5P
//        PWMB_IER   |= 0x08;                // 使能中断

        PWMB_CCMR4  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMB_CCR8   = 0;                // 比较值, 控制占空比(高电平时钟数)
        PWMB_CCER2 |= 0x10;                // 开启比较输出, 高电平有效
        PWMB_PS    |= (0<<6);        // 选择IO, 0:选择P2.3, 1:选择P3.4, 2:选择P0.3, 3:选择P7.7,
        PWMB_ENO   |= 0x40;                // IO输出允许,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5P
//        PWMB_IER   |= 0x10;                // 使能中断

        PWMB_EGR    = 0x01;                //产生一次更新事件, 清除计数器和预分频计数器, 装载预分频寄存器的值
        PWMB_BKR    = 0x80;                // 主输出使能 相当于总开关
        PWMB_CR1    = 0x81;                // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
}

//        PWMB_PS   = (0<<6)+(0<<4)+(0<<2)+0;        //选择IO, 4项从高到低(从左到右)对应PWM8 PWM7 PWM6 PWM5
//  PWMB_PS    PWM8    PWM7    PWM6    PWM5
//    00       P2.3    P2.2    P2.1    P2.0
//    01       P3.4    P3.3    P5.4    P1.7
//    02       P0.3    P0.2    P0.1    P0.0
//    03       P7.7    P7.6    P7.5    P7.4
*/
void PWMA_config(void)
{
        P_SW2 |= 0x80;                //SFR enable   

        PWMA_PSCR = 0x0000;        // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
        PWMA_DTR  = 24;                // 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
                                                //                                0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
        PWMA_ARR = 2400;        // 自动重装载寄存器,  控制PWM周期
        PWMA_CCER1  = 0;
        PWMA_CCER2  = 0;
        PWMA_SR1    = 0;
        PWMA_SR2    = 0;
        PWMA_ENO    = 0;
        PWMA_PS     = 0;
        PWMA_IER    = 0;
//        PWMA_ISR_En = 0;

        PWMA_CCMR1  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMA_CCR1   = 400;                // 比较值, 控制占空比(高电平时钟数)
        PWMA_CCER1 |= 0x05;                // 开启比较输出, 高电平有效
        PWMA_PS    |= 0;                // 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1,
        PWMA_ENO   |= 0x02;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//        PWMA_IER   |= 0x02;                // 使能中断

        PWMA_CCMR2  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMA_CCR2   = 800;                // 比较值, 控制占空比(高电平时钟数)
        PWMA_CCER1 |= 0x50;                // 开启比较输出, 高电平有效
        PWMA_PS    |= (0<<2);        // 选择IO, 0:选择P1.2 P1.3, 1:选择P2.2 P2.3, 2:选择P6.2 P6.3,
        PWMA_ENO   |= 0x08;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//        PWMA_IER   |= 0x04;                // 使能中断

        PWMA_CCMR3  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMA_CCR3   = 1200;                // 比较值, 控制占空比(高电平时钟数)
        PWMA_CCER2 |= 0x05;                // 开启比较输出, 高电平有效
        PWMA_PS    |= (0<<4);        // 选择IO, 0:选择P1.4 P1.5, 1:选择P2.4 P2.5, 2:选择P6.4 P6.5,
        PWMA_ENO   |= 0x20;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//        PWMA_IER   |= 0x08;                // 使能中断

        PWMA_CCMR4  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
        PWMA_CCR4   = 1600;                // 比较值, 控制占空比(高电平时钟数)
        PWMA_CCER2 |= 0x50;                // 开启比较输出, 高电平有效
        PWMA_PS    |= (3<<6);        // 选择IO, 0:选择P1.6 P1.7, 1:选择P2.6 P2.7, 2:选择P6.6 P6.7, 3:选择P3.3 P3.4
        PWMA_ENO   |= 0x80;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//        PWMA_IER   |= 0x10;                // 使能中断

        PWMA_BKR    = 0x80;                // 主输出使能 相当于总开关
        PWMA_CR1    = 0x81;                // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
        PWMA_EGR    = 0x01;                //产生一次更新事件, 清除计数器和预分频计数器, 装载预分频寄存器的值
//        PWMA_ISR_En = PWMA_IER;        //设置标志允许通道1~4中断处理
}

//        PWMA_PS   = (0<<6)+(0<<4)+(0<<2)+0;        //选择IO, 4项从高到低(从左到右)对应PWM1 PWM2 PWM3 PWM4, 0:选择P1.x, 1:选择P2.x, 2:选择P6.x,
//  PWMA_PS    PWM4N PWM4P    PWM3N PWM3P    PWM2N PWM2P    PWM1N PWM1P
//    00       P1.7  P1.6     P1.5  P1.4     P1.3  P1.2     P1.1  P1.0
//    01       P2.7  P2.6     P2.5  P2.4     P2.3  P2.2     P2.1  P2.0
//    02       P6.7  P6.6     P6.5  P6.4     P6.3  P6.2     P6.1  P6.0
//    03       P3.3  P3.4      --    --       --    --       --    --

//========================================================================
// 函数: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时隙
       
        if(RX1_TimerOut != 0)                //串口接收超时处理
        {
                if(--RX1_TimerOut == 0)
                {
                        if(RX1_Cnt != 0)        B_RX1_OK = 1;        //接收到一块数据
                }
        }
}


//========================================================================
// 函数: SetTimer2Baudraye(u16 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 备注:
//========================================================================
void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{
        AUXR &= ~(1<<4);        //Timer stop
        AUXR &= ~(1<<3);        //Timer2 set As Timer
        AUXR |=  (1<<2);        //Timer2 set as 1T mode
        TH2 = (u8)(dat >> 8);
        TL2 = (u8)dat;
        IE2  &= ~(1<<2);        //禁止中断
        AUXR |=  (1<<4);        //Timer run enable
}


//========================================================================
// 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
// 描述: UART1初始化函数。
// 参数:   brt: 通信波特率.
//       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
//          io: 串口1切换到的IO,  io=1: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7,  =3: 切换到P4.3 P4.4
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 备注:
//========================================================================
void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =3: 切换到P4.3 P4.4
{
        brt = 65536UL - (MAIN_Fosc / 4) / brt;
        if(timer == 2)        //波特率使用定时器2
        {
                AUXR |= 0x01;                //S1 BRT Use Timer2;
                SetTimer2Baudraye((u16)brt);
        }

        else                //波特率使用定时器1
        {
                TR1 = 0;
                AUXR &= ~0x01;                //S1 BRT Use Timer1;
                AUXR |=  (1<<6);        //Timer1 set as 1T mode
                TMOD &= ~(1<<6);        //Timer1 set As Timer
                TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                TH1 = (u8)(brt >> 8);
                TL1 = (u8)brt;
                ET1 = 0;                        // 禁止Timer1中断
                INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
                TR1  = 1;                        // 运行Timer1
        }

                 if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
        else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
        else if(io == 3)        {S1_USE_P43P44();        P4n_standard(0x18);}        //切换到 P4.3 P4.4
        else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

        SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
//        PS  = 1;        //高优先级中断
        ES  = 1;        //允许中断
        REN = 1;        //允许接收
}

//========================================================================
// 函数: void UART1_PrintString(u8 *puts)
// 描述: 串口1字符串打印函数
// 参数: puts: 字符串指针.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 备注:
//========================================================================
void UART1_PrintString(u8 *puts)
{
    for (; *puts != 0;        puts++)
        {
                B_TX1_Busy = 1;                //标志发送忙
                SBUF = *puts;                //发一个字节
                while(B_TX1_Busy);        //等待发送完成
        }
}

void UART1_TxByte(u8 dat)        //串口1发送一个字节
{
        B_TX1_Busy = 1;                //标志发送忙
        SBUF = dat;                        //发一个字节
        while(B_TX1_Busy);        //等待发送完成
}

//========================================================================
// 函数: void UART1_ISR(void) interrupt UART1_VECTOR
// 描述: 串口1中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 备注:
//========================================================================
void UART1_ISR(void) interrupt UART1_VECTOR
{
        if(RI)
        {
                RI = 0;
                if(!B_RX1_OK)
                {
                        if(RX1_Cnt >= RX1_LENGTH)                RX1_Cnt = 0;
                        RX1_Buffer[RX1_Cnt++] = SBUF;
                        RX1_TimerOut = 5;
                }
        }

        if(TI)
        {
                TI = 0;
                B_TX1_Busy = 0;
        }
}
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-27 17:26:57 | 显示全部楼层
我现在移植的已将PWM更改至所需的引脚了,但是串口发送数据后没反应,单片机没有接受到数据

点评

你改PWM引脚不应该影响串口的,都是独立的外设,检查一下程序。  详情 回复 发表于 2024-8-28 09:32
回复 支持 反对

使用道具 举报 送花

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

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 2024-8-28 09:32:53 | 显示全部楼层
huatl*** 发表于 2024-8-27 17:26
我现在移植的已将PWM更改至所需的引脚了,但是串口发送数据后没反应,单片机没有接受到数据 ...

你改PWM引脚不应该影响串口的,都是独立的外设,检查一下程序。
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-28 14:41:29 | 显示全部楼层
梁*** 发表于 2024-8-28 09:32
你改PWM引脚不应该影响串口的,都是独立的外设,检查一下程序。

在线DEBUG发现程序一直停在 等到发送完成
void UART1_PrintString(u8 *puts)
{
    for (; *puts != 0;        puts++)
        {
                B_TX1_Busy = 1;                //标志发送忙
                SBUF = *puts;                //发一个字节
                while(B_TX1_Busy);        //等待发送完成
        }
}
卡在这里
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-28 15:00:25 | 显示全部楼层
梁工 你方便留下邮箱吗
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-28 15:46:18 | 显示全部楼层
huatl*** 发表于 2024-8-28 14:41
在线DEBUG发现程序一直停在 等到发送完成
void UART1_PrintString(u8 *puts)
{

会不会是时钟的问题
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-29 09:28:17 | 显示全部楼层
B_TX1_Busy 这个标注位,一直不为0,应该是串口中断没工作,什么原因呢

点评

哪一个例子?  详情 回复 发表于 2024-8-29 10:33
回复 支持 反对

使用道具 举报 送花

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

73

主题

5882

回帖

1万

积分

超级版主

积分
12073
发表于 2024-8-29 10:33:32 | 显示全部楼层
huatl*** 发表于 2024-8-29 09:28
B_TX1_Busy 这个标注位,一直不为0,应该是串口中断没工作,什么原因呢

哪一个例子?
回复 支持 反对

使用道具 举报 送花

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

6

主题

104

回帖

351

积分

中级会员

积分
351
发表于 2024-8-29 11:00:11 | 显示全部楼层

两相步进电机-细分驱动-STC8H-高级PWMB输出

点评

这些都是严格测试过的程序,无数用户验证过的程序,没有问题: [attachimg]55121[/attachimg]  详情 回复 发表于 2024-8-29 13:53
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 02:35 , Processed in 0.159377 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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