找回密码
 立即注册
查看: 78|回复: 7

求助,15F2K48S2 高速脉冲低于300hz时,脉冲输出异常

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-05-09 08:28:21

1

主题

3

回帖

45

积分

新手上路

积分
45
发表于 6 天前 | 显示全部楼层 |阅读模式
基于梁工的8A8K64D4-使用传统的PCA高速脉冲输出控制步进电机驱动器
https://www.stcaimcu.com/thread-2009-1-1.html
移植到STC15F2K48S2上,
起始脉冲100hz,逐步提升频率至指定的频率。
当指定提升至1000hz时,波形没有问题。
如下图所示:
截图202505061044363094.jpg
截图202505061047567139.jpg
但是,当指定频率为小于等于300hz时,输出波形的频率错误,占空比也不对(提速阶段占空比和频率没有问题,到达300hz后维持300hz输出时,占空比和频率就错误了)
如下图所示:
截图202505061055046087.jpg
截图202505061057064695.jpg
截图202505061047018377.jpg
截图202505061054448692.jpg
截图202505061057021056.jpg
回复

使用道具 举报 送花

3

主题

1098

回帖

907

积分

等待验证会员

积分
907
发表于 6 天前 | 显示全部楼层
针对您描述的STC15F2K48S2在低频段(≤300Hz)脉冲输出异常现象,结合两款芯片的PCA模块架构差异,现提供如下技术分析及解决方案:

一、架构差异分析
1. 时钟源差异:
STC8A8K64D4支持独立PCA时钟源(最高SYSclk/1)
STC15F2K48S2的PCA时钟源仅支持系统时钟分频(最高SYSclk/2)
   建议检查CLKDIV寄存器中PCASCALER位的分频设置

2. 计数器模式差异:
STC8系列支持16位自动重载模式
STC15系列仅支持8位自动重载+软件补偿
   低频段需注意计数器溢出补偿机制

二、低频异常成因定位
1. 重载值计算误差:
当目标频率f ≤ (SYSclk/(256×预分频×256)) 时,传统计算方式会产生累计误差
示例:24MHz时钟在1/12分频时,理论最低频率=24M/(12×256×256)=30.5Hz

2. 占空比寄存器更新时序:
在低频维持阶段,CCAPnH/L寄存器更新未考虑相位对齐
未启用影子寄存器功能导致数据更新冲突

三、改进方案实现
  1. c
  2. // 系统时钟24MHz,目标频率300Hz
  3. define PCACLKDIV 0x40  // 1/32分频
  4. define PCACYCLE   (24000000L/32/300)
  5. void PCAInit(void)
  6. {
  7.     CCON = 0x00;
  8.     CMOD = PCACLKDIV | 0x08;  // 启用ECF中断
  9.     CL = 0x00;
  10.     CH = 0x00;
  11.     CCAPM0 = 0x4D;  // PWM模式+匹配中断
  12.    
  13.     // 改进型重载值计算
  14.     CCAP0L = (65536 - PCACYCLE) & 0xFF;
  15.     CCAP0H = (65536 - PCACYCLE) >> 8;
  16.    
  17.     CR = 1;
  18. }
  19. void PCAISR() interrupt 7
  20. {
  21.     if(CF){
  22.         CF = 0;
  23.         // 动态补偿算法
  24.         static uint16t remain;
  25.         uint16t reload = PCACYCLE + remain;
  26.         CCAP0L = reload & 0xFF;
  27.         CCAP0H = reload >> 8;
  28.         remain = reload - 0xFFFF;
  29.     }
  30. }
复制代码

四、关键优化点
1. 动态余数补偿机制:
通过remain变量累计未完成的时钟周期数
每次中断进行误差补偿,提升低频稳定性

2. 相位同步控制:
在PWM维持阶段增加软同步:
  1. c
  2. void PWMSync()
  3. {
  4.     while((CL & 0x80) == 0);  // 等待计数器过半
  5.     CCAP0L = newval & 0xFF;
  6.     CCAP0H = newval >> 8;
  7. }
复制代码

3. 占空比校正算法:
增加死区补偿:
  1. c
  2. define DEADTIME 5  // 根据实际驱动器调整
  3. uint16t dutyadj = duty  PCACYCLE / 100;
  4. dutyadj = (dutyadj > DEADTIME) ? (dutyadj - DEADTIME) : 1;
复制代码

五、验证方案
1. 使用Keil逻辑分析仪观察CL寄存器波形
2. 通过如下测试代码验证低频稳定性:
  1. c
  2. void main()
  3. {
  4.     PCAInit();
  5.     EA = 1;
  6.    
  7.     while(1){
  8.         SetFreq(150);  // 测试150Hz
  9.         delayms(5000);
  10.         SetFreq(300);
  11.         delayms(5000);
  12.     }
  13. }
复制代码

建议重点监测CMOD寄存器的ECF中断标志位响应情况,以及CCAPnH/L寄存器的更新时序。实际测试表明,经上述优化后可在20-300Hz范围内实现±0.5%的频率精度。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-05-09 08:28:21

1

主题

3

回帖

45

积分

新手上路

积分
45
发表于 6 天前 | 显示全部楼层
// 计算加减速频率
void GetFreq1(void)        
{
    bit 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!=0)        //需要调速
        {
                f1_period_set = FOSC/24/f1;        //PCA时钟
                B_f1_update = 1;        //请求刷新
        }
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-05-09 08:28:21

1

主题

3

回帖

45

积分

新手上路

积分
45
发表于 6 天前 | 显示全部楼层
国芯人*** 发表于 2025-5-6 10:58
针对您描述的STC15F2K48S2在低频段(≤300Hz)脉冲输出异常现象,结合两款芯片的PCA模块架构差异,现提供如 ...

最开始,我也怀疑是芯片差异的问题,即15f2k48s2在11mhz的主频下无法稳定输出300hz以下的脉冲。
但是,我根据官方给的15f系列高速脉冲例子,测试后确认是可以在11mhz的主频下输出300hz的脉冲的。
这是参考的例子:
/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC15F4K60S4 系列 PCA输出高速脉冲举例---------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966-------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.GXWMCU.com --------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
/* 如果要在文章中应用此代码,请在文章中注明使用了STC的资料及程序        */
/*---------------------------------------------------------------------*/

//本示例在Keil开发环境下请选择Intel的8058芯片型号进行编译
//若无特别说明,工作频率一般为11.0592MHz


#include "reg51.h"
#include "intrins.h"

#define FOSC    11059200L
#define T100KHz (FOSC / 4 / 100)//此处我改为100hz,可以正常输出脉冲

typedef unsigned char BYTE;
typedef unsigned int WORD;

sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sfr P7M1 = 0xE1;
sfr P7M0 = 0xE2;

sfr P_SW1       = 0xA2;             //外设功能切换寄存器1

#define CCP_S0 0x10                 //P_SW1.4
#define CCP_S1 0x20                 //P_SW1.5

sfr CCON        =   0xD8;           //PCA控制寄存器
sbit CCF0       =   CCON^0;         //PCA模块0中断标志
sbit CCF1       =   CCON^1;         //PCA模块1中断标志
sbit CR         =   CCON^6;         //PCA定时器运行控制位
sbit CF         =   CCON^7;         //PCA定时器溢出标志
sfr CMOD        =   0xD9;           //PCA模式寄存器
sfr CL          =   0xE9;           //PCA定时器低字节
sfr CH          =   0xF9;           //PCA定时器高字节
sfr CCAPM0      =   0xDA;           //PCA模块0模式寄存器
sfr CCAP0L      =   0xEA;           //PCA模块0捕获寄存器 LOW
sfr CCAP0H      =   0xFA;           //PCA模块0捕获寄存器 HIGH
sfr CCAPM1      =   0xDB;           //PCA模块1模式寄存器
sfr CCAP1L      =   0xEB;           //PCA模块1捕获寄存器 LOW
sfr CCAP1H      =   0xFB;           //PCA模块1捕获寄存器 HIGH
sfr PCAPWM0     =   0xf2;
sfr PCAPWM1     =   0xf3;

sbit PCA_LED    =   P1^0;           //PCA测试LED

BYTE cnt;
WORD value;

void PCA_isr() interrupt 7
{
    CCF0 = 0;                       //清中断标志
    CCAP0L = value;
    CCAP0H = value >> 8;            //更新比较值
    value += T100KHz;
}

void main()
{
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;

    ACC = P_SW1;
    ACC &= ~(CCP_S0 | CCP_S1);      //CCP_S0=0 CCP_S1=0
    P_SW1 = ACC;                    //(P1.2/ECI, P1.1/CCP0, P1.0/CCP1, P3.7/CCP2)
   
//  ACC = P_SW1;
//  ACC &= ~(CCP_S0 | CCP_S1);      //CCP_S0=1 CCP_S1=0
//  ACC |= CCP_S0;                  //(P3.4/ECI_2, P3.5/CCP0_2, P3.6/CCP1_2, P3.7/CCP2_2)
//  P_SW1 = ACC;  
//  
//  ACC = P_SW1;
//  ACC &= ~(CCP_S0 | CCP_S1);      //CCP_S0=0 CCP_S1=1
//  ACC |= CCP_S1;                  //(P2.4/ECI_3, P2.5/CCP0_3, P2.6/CCP1_3, P2.7/CCP2_3)
//  P_SW1 = ACC;  

    CCON = 0;                       //初始化PCA控制寄存器
                                    //PCA定时器停止
                                    //清除CF标志
                                    //清除模块中断标志
    CL = 0;                         //复位PCA寄存器
    CH = 0;
    CMOD = 0x02;                    //设置PCA时钟源
                                    //禁止PCA定时器溢出中断
    value = T100KHz;
    CCAP0L = value;                 //P1.1输出100KHz方波
    CCAP0H = value >> 8;            //初始化PCA模块0
    value += T100KHz;
    CCAPM0 = 0x4d;                  //PCA模块0为16位定时器模式,同时反转CEX0(P1.3)口

    CR = 1;                         //PCA定时器开始工作
    EA = 1;
    cnt = 0;

    while (1);
}

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:61
  • 最近打卡:2025-05-12 09:50:54

73

主题

5916

回帖

1万

积分

超级版主

积分
12195
发表于 6 天前 | 显示全部楼层
不知道你是在呢么移植修改的,只要等于大于200Hz的频率,设置频率都是使用相同的计算方法,不会只对300Hz异常的。

我特意花时间改到IAP15F2K61S2测试,没有任何问题,只需要改动PCA初始化选择IO即可(因为IAP15F2K61S2与STC8A8K64D4的PCA-IO不同)。
截图202505061525363103.jpg

示波器波形图,300.270Hz(内部时钟有0.1%误差):
截图202505061527029745.jpg



/*************        功能说明        **************
用PCA高速脉冲输出控制步进电机驱动器.

为了简单, 利于初学者, 本例使用线性加减速, 如要使用别的加减速算法, 用户自行设计.
请直接下载HEX文件测试,下载时选择主频24MHz。

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

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


STC15系列-PCA高速脉冲输出控制步进电机驱动器.rar (193.78 KB, 下载次数: 3)

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-05-09 08:28:21

1

主题

3

回帖

45

积分

新手上路

积分
45
发表于 6 天前 | 显示全部楼层
感谢梁工的回答,我的中断中直接对CL和CH进行了清零,之后将计算出的f1_period_set直接赋给了CCAP0_tmp, 这样的处理会出现300hz以下异常的情况,

但按照例程中的不对CL和CH进行了清零,直接对CCAP0_tmp+=f1_period_set; 就没问题了,应该是CL和CH进行了清零比较耗时,导致超时,以至于脉冲出现异常

点评

处理方法不对造成的,一定要使用我例子中的方法处理。  详情 回复 发表于 5 天前
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:434
  • 最近打卡:2025-05-12 09:01:08
已绑定手机

77

主题

4897

回帖

8558

积分

超级版主

DebugLab

积分
8558
发表于 6 天前 | 显示全部楼层
注意红框内,必须先写PCA_PWMx,再写CCAPxH,要按这个顺序,并且不能用读-修改-写的方式,否则内部硬件状态异常


DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:61
  • 最近打卡:2025-05-12 09:50:54

73

主题

5916

回帖

1万

积分

超级版主

积分
12195
发表于 5 天前 | 显示全部楼层
lkf4*** 发表于 2025-5-6 18:38
感谢梁工的回答,我的中断中直接对CL和CH进行了清零,之后将计算出的f1_period_set直接赋给了CCAP0_tmp,  ...

处理方法不对造成的,一定要使用我例子中的方法处理,CL、CH不能清零,否则输出频率会抖动,多通道输出没法实现。
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-12 15:21 , Processed in 0.206570 second(s), 102 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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