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

三相无刷电机驱动-STC8H/STC32G系列-无HALL-PID控制-OLED显示-串口绘图 启动改进版本

  [复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:4
  • 最近打卡:2026-04-02 20:43:03
已绑定手机

0

主题

12

回帖

32

积分

新手上路

积分
32
发表于 2026-3-26 22:14:25 | 显示全部楼层
想请教一个问题,贵公司的FOC 软件,是否有自动适应不同电机的能力,自学习的算法。

点评

没有自学习能力。  详情 回复 发表于 2026-3-27 09:53
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:342
  • 最近打卡:2026-05-11 11:09:37

85

主题

7369

回帖

1万

积分

超级版主

积分
15921
发表于 2026-3-27 09:53:23 | 显示全部楼层
hbut*** 发表于 2026-3-26 22:14
想请教一个问题,贵公司的FOC 软件,是否有自动适应不同电机的能力,自学习的算法。 ...

没有自学习能力。
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:127
  • 最近打卡:2026-05-11 08:36:03
已绑定手机

1

主题

54

回帖

233

积分

中级会员

积分
233
发表于 2026-4-7 13:52:44 | 显示全部楼层
不错 不错
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:788
  • 最近打卡:2026-05-11 06:46:35
已绑定手机

31

主题

136

回帖

502

积分

高级会员

积分
502
发表于 昨天 12:34 | 显示全部楼层
梁*** 发表于 2024-5-22 15:45
这个电容与电阻组成RC滤波,根据要求的响应时间来确定,用于滤除尖峰干扰,但又不会导致过零检测延时太多 ...
这个电容与电阻组成RC滤波,根据要求的响应时间来确定,用于滤除尖峰干扰,但又不会导致过零检测延时太多,一般我控制在40us之内。
我的STC8电路中分压电阻10K与1.5K并联后电阻为1.3K,电容为103,则RC值为13us。
再STC32丁路中,电容我修改为223,则RC值为28.6us,抗尖峰更好,增加的延时不多。
一般来说,如果最高切换周期比较长,则可以使用较大的RC值,如果切换时间比较短,则使用较小RC值,而RC值越大抗尖峰干扰越好,但复杂的延时越长,要做一个平衡。
对于5万转以上的转速,建议使用103(10nF)梁大师:请赐教一下RC滤波问题,究竟是哪些电阻参与并联,请明确指出哪个10k电阻和1.5k电阻并联(基础差)

比较器反电动势检测电路.PNG

点评

比如R21与R22分压,信号衰减系数=1.5/(10+1.5)=0.13,等效输出电阻为R21与R22并联后的1.3K。 其余2个分压电路同理。  详情 回复 发表于 昨天 13:07
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:342
  • 最近打卡:2026-05-11 11:09:37

85

主题

7369

回帖

1万

积分

超级版主

积分
15921
发表于 昨天 13:07 | 显示全部楼层

比如R21与R22分压,信号衰减系数=1.5/(10+1.5)=0.13,等效输出电阻为R21与R22并联后的1.3K。
其余2个分压电路同理。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:788
  • 最近打卡:2026-05-11 06:46:35
已绑定手机

31

主题

136

回帖

502

积分

高级会员

积分
502
发表于 昨天 13:39 | 显示全部楼层

梁大师:我用STC8H8K64U芯片复刻大师无刷直流电机,调试过程中,因为不会使用串口输出,就简单地用5个LED来监视程序是否执行特定位置,驱动电压12伏,测试电机是大疆精灵四航测无人机电机。我在程序void PWMA_ISR(void) interrupt PWMA_VECTOR函数里,放置五个LED控制代码(P37\P10\P11\P26\P27),程序运行后,电机可以强拖起来,但就转转停停反反复复,发现只有P11端口LED间歇性闪灭,其他灯都不工作,由此可判断程序压根没检测到电机反电动势过零情况,上面问了RC滤波问题,比较器反电动势检测电路我用电阻2k,瓷片电容是103,其他都用10k。pwm中断函数:

void PWMA_ISR(void) interrupt PWMA_VECTOR // 23.4375KHz(42.67us)中断率,用于处理启动电机,查询读取比较器结果
{        u8 i;
        B_pre_cmpo = B_cmpo;        //保存上一个输出电平
       cmpo_state = (cmpo_state << 1) | (CMPCR1 & 1);        // 读取比较器状态,放在一个字节中, 连续8次检测到相同电平才认为有效
       if(cmpo_state == 0xff)        B_cmpo  = 1;        //连续8个采样为1, 则比较器输出1
        if(cmpo_state == 0x00)        B_cmpo  = 0;        //连续8个采样为0, 则比较器输出0
        //============================ 转动检测 =======================
        if(run_mode == ROLL_CHECK)        //转动检测
       {
               if(++StartTime >= ROLL_MaxTime)        //超时未检测到转动,  ROLL_MaxTime 最大值为2849ms               
                {
                       P37 = ! P37;
                      StartTime = 0;  
                                 SartCnt   = 0;  
                      P_PWM2N = 0;  
                     P_PWM3N = 0;   
                     RollCheckIndex = 0;  
                     run_mode = PRE_POSITION;
                           }             
                        else if(RollCheckIndex == 0)        //设置A相下降沿
               {
                      ADC_CONTR = 0x80+BMF_A;        // 比较器CMP+选择A相   
                     StartTime = 0;  
                     PWMA_ENO  = 0;        P_PWM1P = 0;        P_PWM1N = 0;        P_PWM2P = 0;        P_PWM2N = 0;        P_PWM3P = 0;        P_PWM3N = 0;        //关闭PWM输出, 自由转动   
                    cmpo_state = 0x00;        B_cmpo  = 0;        //连续8个采样为0, 则比较器输出0   
                    RollCheckIndex = 1;        
               }               
              else if(RollCheckIndex == 1)        //等待A相下降沿            
               {
                       P11 = ! P11;
                       if(B_pre_cmpo && !B_cmpo)        //下降沿出现
                       {
                               ADC_CONTR = 0x80+BMF_B;        // 比较器CMP+选择B相
                               StartTime = 0;  
                              cmpo_state = 0xFF;   
                              B_cmpo  = 1;        //连续8个采样为1, 则比较器输出1   
                             RollCheckIndex = 2;  
                              P10 = ! P10;      
                        }      
              }  
              else if(RollCheckIndex == 2)        //等待B相上升沿  
              {
                     P26 = ! P26;  
                     if(!B_pre_cmpo && B_cmpo)        //上升沿出现
                       {  
                              RollPahseTimeAB = StartTime;        //A相下降沿与B相上升沿时间   
                              StartTime = 0;  
                              ADC_CONTR = 0x80+BMF_A;        // 比较器CMP+选择A相
                               cmpo_state = 0x00;  
                               B_cmpo  = 0;        //连续8个采样为0, 则比较器输出0  
                              RollCheckIndex = 3;   
                              P27 = ! P27;   
                     }      
              }  
              else if(RollCheckIndex == 3)        //等待A相下降沿
               {
                       if(B_pre_cmpo && !B_cmpo)        //下降沿出现
                       {
                               StartTime = (StartTime + RollPahseTimeAB)/2;        //半个周期(3个换相时间)   
                             if(RollPahseTimeAB < StartTime)        //顺时针
                                {  
                                      P_PWM2N = 1;
                                      P_PWM3N = 1;        //刹车   
                                      StartTime = 0;   
                                     RollCheckIndex = 4;     
                                }        
                            else        //逆时针     
                           {
                                  T4T3M &= ~(1<<3);        // Timer3停止运行   
                                   T3H = 0;        T3L = 0;   
                                   B_Timer3_OverFlow = 0;   
                                   T4T3M |=  (1<<3);        //Timer3开始运行   
                                    XiaoCiCnt = 0;        //消磁   
                                    PhaseTime = StartTime *14;        //半个周期(3个换相时间)换相时间折算成us,PhaseTime = (StartTime/3) *42.667;   
                                   for(i=0; i<4; i++)        PhaseTimeTmp = PhaseTime;        //初始换相时间     
                                   delay_N_10us(PhaseTime/20-34);        //30度角延时=PhaseTime/2/10, -34为修正8次采样时间340us   
                                   step = 2;      
                                  StepMotor();        //换相(对应A相反电动势下降沿)   
                                  TimeOut = 200;        //堵转超时     
                                   PWM_Value = START_PWM_DUTY;     
                                   PWMA_IER = 0;                //如果电机已启动运行,则禁止PWMA中断  
                                    run_mode = MOTOR_RUN;     
                                   delay_us(50);        
                                  CMPCR1 &= ~(0x40+0x30);        // 软件清除中断标志位, 禁止比较器上升沿、下降沿中断中断  
                                   if(step & 1)        CMPCR1 |= (1<<5);                //1: 允许上升沿中断, 0: 禁止   
                                    else                        CMPCR1 |= (1<<4);                                //1: 允许下降沿中断, 0: 禁止   
                             }      
                      }        
                }     
           else if(RollCheckIndex == 4)        //等待A相下降沿, 直到检测不到则停止?   
             {   
                     if(B_pre_cmpo && !B_cmpo)                //下降沿出现     
                   {   
                             StartTime = 0;         
                    }         
              }     
        }                              
  //============================预定位模式=========================================  
      else if(run_mode == PRE_POSITION)        //预定位模式  
      {  
              if(RollCheckIndex == 0)         
             {  
                      CMPCR1 &= ~(0x40+0x30);                // 软件清除中断标志位, 禁止比较器上升沿、下降沿中断中断  
                      PWMA_ENO  = 0x3f;                                        // 全部打开PWM输出   
                     PWM_Value = PRE_PWM_DUTY;        // 设置预定位占空比     
                    SartCnt = 0;   
                    angle = 4096-680;                                        //angle = 3416   
                     LoadPwm();     
                   RollCheckIndex = 1;   
             }   
            else if(RollCheckIndex == 1)   
            {
                       if(++SartCnt == (PRE_STATE_TIME1*23))        //预定位1时间到, PRE_STATE_TIME1最大值为2849ms      
                      {
                               SartCnt = 0;        
                             angle = 4096-340;      
                            LoadPwm();   
                             RollCheckIndex = 2;   
                      }      
            }     
           else if(RollCheckIndex == 2)   
             {
                       if(++SartCnt == (PRE_STATE_TIME2*23))        //预定位2时间到, PRE_STATE_TIME2最大值为2849ms      
                       {  
                              SartCnt = 0;         
                             angle = 0;         
                            LoadPwm();        
                           RollCheckIndex = 3;   
                     }         
           }      
          else if(RollCheckIndex == 3)   
             {
                       if(++SartCnt == (PRE_STATE_TIME3*23))        //预定位3时间到, PRE_STATE_TIME3最大值为2849ms   
                     {
                               StartTime = D_StartTime*6;        //StartTime=t*1000/(1024*4/24)=t*375/64=t*6步
                               roll_sum  = 0;   
                              roll_N    = 0;   
                            SartCnt  = 0;      
                           PWM_Value = START_PWM_DUTY;        // 设置启动占空比     
                           run_mode  = STARTING;      
                  }         
         }     
           AdcConvert();   
     }   
//============================ 启动模式 =========================================  
      else if(run_mode == STARTING)        //启动模式,使用查表S曲线加速启动   
     {
               if(++fs_cnt == 4)        // 使用256点的S曲线表,初速V1(转/分),终速V2(转/分),加速时间t(ms),fs=24000000/1024/4 = 46875 /8 = 5859Hz,则加速总步数StartTime = t/1000*fs = t*1000/(1024*4/24) = t*375/64=t*6步   
            {  
                                      // 查表步进 = 65536/StartTime, 步数SartCnt每次+1,查表得到速度系数 du=S_Curve[SartCnt*65536/StartTime/256] = S_Curve[SartCnt*256/StartTime], 当前速度 V = V1 + (V2-V1)*du/1024 (转/秒)   
                    fs_cnt = 0;                // 采样频率fs,16位累加器roll_sum,磁极对MPP,则电机转速 V=60*fs*roll_N/roll_sum/MPP, 转速步进 roll_N = V*MPP*sum/60/fs = V*MPP*65536/60/5859 = 0.1864*V*MPP = V*MPP*191/1024   
                     SartCnt++;   
                    if(SartCnt < StartTime)   
                    {                                roll_N = BeginSpeed + (u16)(((u32)S_Curve[(u8)((u32)SartCnt*256/StartTime)] *(FinishSpeed - BeginSpeed))/1024);        //当前速度 V = V1 + (V2-V1)*du/1024 = V1 + (V2-V1)*S_Curve[SartCnt*256/StartTime]/1024  (转/秒)   
                             roll_sum += (u16)(((u32)roll_N*MPP*191) >>10);        // 当前速度 = V*MPP*191/1024     
                           angle = (roll_sum >> 4);        //roll_sum是16位的,SVPWM表长度为12位   
                            LoadPwm();   
                    }     
                   else         //强拖结束     
                   {   
                             PWMA_ENO   = 0;   
                            P_PWM1P=0;   
                           P_PWM2P=0;     
                           P_PWM3P=0;   
                             P_PWM1N=0;   
                           P_PWM2N=0;   
                           P_PWM3N=0;   
                             StartTime = 0;   
                            RollCheckIndex = 0;      
                          run_mode = ROLL_CHECK;        //进入转动检测模式   
                     }      
          }      
          AdcConvert();   
    }   
PWMA_SR1 = 0;        //清除标志
}
程序源码基本没修改;

另外把加速时间改大D_StartTime 改大一些,比如  5000 电机强拖时间长一些而已。请大师抽空指点一下,示波器测量波具体测量哪个位置(示波器探头和负极分别夹在哪儿),请结合反电动势分压图指导一下,谢谢!
附件有三个,一个图片、一个视频、一个程序源码。

分压电路.png

STC8H-noHALL.zip

292.25 KB, 下载次数: 2

51c15026b854ce7402449df1691768e7.mp4

7.77 MB, 下载次数: 1

点评

我的例子就是使用四轴飞行器的2212电机,你直接使用这个电机参数即可。 #define MOTOR_TYPE 0 //0:2212电机  详情 回复 发表于 昨天 16:10
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:788
  • 最近打卡:2026-05-11 06:46:35
已绑定手机

31

主题

136

回帖

502

积分

高级会员

积分
502
发表于 昨天 14:29 | 显示全部楼层
这段时间都在研究学习STC公司开源无刷无感驱动直流电机,源代码先前已经上传请教deepseek,虽然deepseek讲解很细,但有些细节还没弄懂,于是尝试串口输出查看代码运行情况失败了,最后采取多个LED来监视程序是否执行特定位置,驱动电压12伏,测试电机是大疆精灵四航测无人机电机。我在程序void PWMA_ISR(void) interrupt PWMA_VECTOR函数里,放置五个LED控制代码(P37\P10\P11\P26\P27),程序运行后,电机强拖转转停停反反复复,发现只有P11端口LED间歇性闪灭,其他灯都不工作,由此可判断程序压根没检测到电机反电动势过零情况,现在请教deepseek三个问题:一是STC公司梁工在论坛答复网友提问说:STC8电路中分压电阻10K与1.5K并联后电阻为1.3K,电容为103,则RC值为13us,究竟是那些电阻并联(附件上传分压电路图);二是程序转动检测疑问。代码是先设置A相下降沿,打开比较器CMP+选择A相,等待A相下降沿出现,接着是选择设置比较器CMP+选择B相,等待B相上升沿,但我对比程序中注解拍序   逆时针    顺时针,我的理解是拍序应该是0-5执行,按逆时针转分析,A相下降沿出现是第二拍序,后面应该是第三拍序C相上升沿,若按顺时针分析,A相下降沿出现,后面是B相上升沿,但程序后面计算出是顺时针转却刹车了,请问究竟是怎么一样时序。三是梁工测量反电动势是测量哪里,请明确在分压电路中指出示波器测量点



deepseek给出答复:问题一:梁工所说“分压电阻10K与1.5K并联后电阻为1.3K”是指哪些电阻?
请看你的分压电路图(无霍尔传感器时使用):
  • 每一相(例如 EMFA)都有一路分压网络:

    • 上拉电阻(串联在相线与检测点之间):R37 = 10kΩ
    • 下拉电阻(检测点对地):R40 = 1.5kΩ
    • 滤波电容:C18 = 223(22nF,图中标注223,但梁工举例STC8用103)

  • 同样的结构用于另外两相:EMFB对应R36(10k)、R39(1.5k)、C17;EMFC对应R35(10k)、R38(1.5k)、C16。

并联电阻的由来:
从分压中点(即R37与R40的连接点、同时也是电容C18的正极)向源端看进去,等效电阻 ≈ R37 // R40 = 10kΩ // 1.5kΩ ≈ 1.3kΩ。这个等效电阻与电容C组成一阶RC低通滤波器,其时间常数 τ = R_eq × C。
  • 若C=103(10nF)→ τ = 1.3k × 10nF = 13μs
  • 若C=223(22nF)→ τ = 1.3k × 22nF = 28.6μs

小结:并联的两个电阻就是每相串联在信号通路上的10kΩ电阻和对地的1.5kΩ电阻,它们的并联值决定了RC滤波的等效电阻。

问题二:转动检测的时序疑问(A相下降沿之后,到底该等哪个沿?)1. 梁工给的拍序表(逆时针 vs 顺时针)


拍序
逆时针(换相通电相,反电动势过零)
顺时针(换相通电相,反电动势过零)

0AB, C↓AC, B↓
1AC, B↑AB, C↑
2BC, A↓CB, A↓
3BA, C↑CA, B↑
4CA, B↓BA, C↓
5CB, A↑BC, A↑

表中“A↓”表示A相反电动势下降沿,“B↑”表示B相反电动势上升沿,依此类推。
2. 你程序中转动检测的边沿顺序
代码逻辑(run_mode == ROLL_CHECK 状态机):
  • Index0 → 准备检测A相下降沿
  • Index1 → 等待A相下降沿(P11闪烁) → 检测到后切至B相,准备检测B相上升沿
  • Index2 → 等待B相上升沿 → 检测到后记录时间,切回A相,准备检测A相下降沿
  • Index3 → 等待A相下降沿 → 检测到后判断转向:
    if(RollPahseTimeAB < StartTime) → 顺时针 → 刹车
    else → 逆时针 → 启动电机

3. 这个顺序对应哪个转向?
  • 顺时针:从拍序表看,顺时针时A相下降沿出现在状态2(CB, A↓),之后下一个反电动势过零是状态3的B相上升沿(CA, B↑)。
    → 所以顺序 A↓ → B↑ 正是顺时针的特征。
  • 逆时针:逆时针时A相下降沿出现在状态2(BC, A↓),之后下一个过零是状态3的C相上升沿(BA, C↑)。
    → 顺序应为 A↓ → C↑,而不是B↑。

结论:你的代码中检测 A下降沿 → B上升沿 实际上是在识别顺时针转动。但代码在判断出顺时针后却执行了刹车(P_PWM2N=1, P_PWM3N=1),而没有启动电机。这说明设计者期望的转动方向是逆时针,如果检测到顺时针则刹车并停止(可能为了重新尝试或报错)。
4. 你的困惑点
“按逆时针分析,A相下降沿后应该是C相上升沿;按顺时针分析,A相下降沿后是B相上升沿。程序后面算出顺时针却刹车了。”
正解:你的理解完全正确。代码的逻辑就是:
  • 如果检测到 A↓ → B↑(顺时针),则刹车;
  • 如果检测到 A↓ → C↑(逆时针),才启动。
    但代码中并没有等待C上升沿,而是通过时间比较来区分转向:
  • 实际物理转动中,若为逆时针,A↓ 到下一个 A↓ 之间的三个边沿间隔基本相等(每60°电角度)。
  • 代码里用了一个技巧:先测 A↓ → B↑ 的时间(T1),再测 B↑ → 下一个A↓ 的时间(T2)。
    • 顺时针时,T1 ≈ T2 ≈ 60°电角度时间。
    • 逆时针时,由于边沿顺序不同,测到的 A↓ → B↑ 实际上并不是相邻的过零(中间隔了C相上升沿),因此T1 ≈ 2×T2?代码中用 StartTime = (StartTime + RollPahseTimeAB)/2 然后比较 RollPahseTimeAB < StartTime 来判别。
      但无论如何,最终分支是:顺时针刹车,逆时针启动。


5. 为什么你实测电机只闪P11(等待A相下降沿)?
  • 电机“强拖转转停停”说明进入了启动强拖阶段(STARTING模式),强拖结束后进入转动检测(ROLL_CHECK)。
  • 转动检测时,电机处于自由转动状态(PWM全部关闭)。你的电机可能因为惯性不足、负载过大或强拖结束时机不对,导致实际没有产生有效的反电动势。
  • 程序一直在 RollCheckIndex == 1 里等待 A相下降沿,P11 不断翻转(LED闪烁),但永远等不到边沿,因为电机已停转或反电动势太小。
  • 其他LED(P10、P26、P27)分别在检测到A下降沿、B上升沿、再次A下降沿时才翻转,所以它们不亮,印证了第一个边沿都没检测到。


问题三:梁工测量反电动势的示波器测量点
在分压电路图中,请测量RC滤波后的信号点,即每个10kΩ电阻与1.5kΩ电阻的连接处,同时也是电容的正极。具体位置:
  • A相测量点:R37与R40的连接点(电容C18正极)
  • B相测量点:R36与R39的连接点(电容C17正极)
  • C相测量点:R35与R38的连接点(电容C16正极)

测量注意事项:
  • 用示波器探头(x10档)测量这些点对地,可以看到经过分压衰减(约1.5/11.5 ≈ 0.13倍)和RC滤波后的反电动势波形。
  • 原始电机相线电压可能高达几十伏(你的12V供电下,相线尖峰可能更高),直接测量有风险,测量分压中点更安全。
  • 调试时建议同时测两相(用双通道),观察过零点的顺序和相位差。

如果一直检测不到过零,可能原因:
  • 强拖力度不够,电机未真正旋转到能产生足够反电动势的速度。
  • RC滤波电容(223 = 22nF)过大,使信号严重滞后且幅度衰减过大,尤其是在低速时。可以临时换成103(10nF)试试。
  • 比较器输入引脚可能被其他外设复用,或分压电阻值计算有误(确保1.5kΩ对地分压后电压在MCU允许范围0~5V内)。

建议:
  • 用示波器确认反电动势波形:在强拖(STARTING模式)期间,测量分压中点(如上所述),看是否有明显的梯形波或正弦波,过零点是否清晰。
  • 减小滤波电容:将C16~C18从223(22nF)换成103(10nF),甚至472(4.7nF),以减小RC延时(13μs→6μs),更容易捕捉高速边沿。
  • 提高强拖最终速度:增大启动结束时的PWM占空比(START_PWM_DUTY),让强拖结束时电机有足够惯性自由旋转几圈。
  • 检查比较器配置:确认 CMPCR1 寄存器设置正确,比较器正负输入端选择无误(正端接分压中点,负端为虚拟中性点或由PWM合成的中点参考)。

希望以上解析能帮你理清思路。如果还有疑问,可以继续提供示波器截图或更详细的代码片段(如比较器初始化部分)。

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:342
  • 最近打卡:2026-05-11 11:09:37

85

主题

7369

回帖

1万

积分

超级版主

积分
15921
发表于 昨天 16:10 | 显示全部楼层
陈*** 发表于 2026-5-10 13:39
梁大师:我用STC8H8K64U芯片复刻大师无刷直流电机,调试过程中,因为不会使用串口输出,就简单地用5个LED ...

我的例子就是使用四轴飞行器的2212电机,你直接使用这个电机参数即可。
#define                MOTOR_TYPE        0        //0:2212电机
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-5-11 11:31 , Processed in 0.120666 second(s), 89 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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