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

BLDC, 三相无刷直流电机驱动-8H系列/32G系列-无HALL, 12万转, 视频讲解

 火... [复制链接]

0

主题

1

回帖

10

积分

新手上路

积分
10
发表于 2024-7-23 16:38:37 | 显示全部楼层
梁工,六步换相代码里500nS延时是有什么作用?
截图202407231636281553.jpg
回复 支持 反对

使用道具 举报 送花

0

主题

1

回帖

4

积分

新手上路

积分
4
发表于 2024-7-23 20:29:16 | 显示全部楼层
梁工,使用您的中功率方案,现在电机在10V以内运行顺畅,电压再往上升,就开始出现失步、抖动;根据前面学友的方式,调整反馈电阻,减小消磁延时时间都试过了,没有明显好转,如果取消消磁时间程序应该怎么修改?
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-7-30 13:01:22 | 显示全部楼层
梁总:我基础不太好,请赐教一下,电路图中R2、R8、R14的取值随着电压不同而不同,是限流还考虑什么因素,具体怎么计算呢,请详细告知,我真想学透。谢谢

点评

电路图中R2、R8、R14的取值随着电压不同而不同,是因为要控制MOSFET的栅压不要过高,我一般控制在12V左右,假如用24V供电,不限制栅压,24V的栅压会击穿MOSFET。 这个电路合适12~24V供电的场合,也让学习者熟悉三极  详情 回复 发表于 2024-7-30 16:53
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-7-30 13:05:52 | 显示全部楼层
梁工:您的电路,如果驱动72伏带霍尔电机,R2、R8、R14取值怎么计算?估计mos管要更换大耐压的吧?另外电动车转把能代替可调电阻吗?好像转把里面是霍尔,不是电阻

点评

主楼的电路只合适12~24V供电,要更高的电压,请使用驱动IC,驱动IC使用12V供电,电机可以使用高压,但要处理12V电源和使用合适耐压的MOSFET,请参考下面的电路: BLDC, 三相无刷直流电机驱动-STC32G-无HALL 或 带HAL  详情 回复 发表于 2024-7-30 16:55
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-06 09:34:57

73

主题

5889

回帖

1万

积分

超级版主

积分
12107
发表于 2024-7-30 16:53:01 | 显示全部楼层
垂柳*** 发表于 2024-7-30 13:01
梁总:我基础不太好,请赐教一下,电路图中R2、R8、R14的取值随着电压不同而不同,是限流还考虑什么因素, ...

电路图中R2、R8、R14的取值随着电压不同而不同,是因为要控制MOSFET的栅压不要过高,我一般控制在12V左右,假如用24V供电,不限制栅压,24V的栅压会击穿MOSFET。
这个电路合适12~24V供电的场合,也让学习者熟悉三极管的应用。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-06 09:34:57

73

主题

5889

回帖

1万

积分

超级版主

积分
12107
发表于 2024-7-30 16:55:01 | 显示全部楼层
垂柳*** 发表于 2024-7-30 13:05
梁工:您的电路,如果驱动72伏带霍尔电机,R2、R8、R14取值怎么计算?估计mos管要更换大耐压的吧?另外电动 ...

主楼的电路只合适12~24V供电,要更高的电压,请使用驱动IC,驱动IC使用12V供电,电机可以使用高压,但要处理12V电源和使用合适耐压的MOSFET,请参考下面的电路:
BLDC, 三相无刷直流电机驱动-STC32G-无HALL 或 带HALL,例子打板测试已OK
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7291


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-06 11:13:12

24

主题

108

回帖

468

积分

中级会员

积分
468
发表于 2024-7-30 23:27:37 | 显示全部楼层
梁工:还请教一下,电路图上管用8050和8550驱动,下管为何不需要对管驱动呢?我基础太差了。先感谢详细解答。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2024-08-01 09:59:02

0

主题

4

回帖

26

积分

新手上路

积分
26
发表于 2024-7-31 09:21:20 | 显示全部楼层
梁工您好,想请教您下如果我想使用STC8H1K17作为控制芯片能否实现您帖子的相应功能?需要修改哪些位置呢?新手求教。


芯片引脚配置

芯片引脚配置

MOS电路

MOS电路

点评

STC8H系列均可以,程序兼容,只需要将同名的IO链接起来即可。  详情 回复 发表于 2024-7-31 14:32
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-06 09:34:57

73

主题

5889

回帖

1万

积分

超级版主

积分
12107
发表于 2024-7-31 14:32:12 | 显示全部楼层
Ry*** 发表于 2024-7-31 09:21
梁工您好,想请教您下如果我想使用STC8H1K17作为控制芯片能否实现您帖子的相应功能?需要修改哪些位置呢? ...

STC8H系列均可以,程序兼容,只需要将同名的IO链接起来即可。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2024-08-01 09:59:02

0

主题

4

回帖

26

积分

新手上路

积分
26
发表于 2024-7-31 15:21:15 | 显示全部楼层
梁*** 发表于 2024-7-31 14:32
STC8H系列均可以,程序兼容,只需要将同名的IO链接起来即可。

感谢梁工回复,现在是进行软件修改后发现没有波形输出。因为是初学者,也不清楚问题出在哪里?


  1. /*************        功能说明        **************
  2. 本程序试验使用STC8H1K28-LQFP32来驱动无传感器无刷三相直流电机.
  3. P0.3接的电位器控制转速, 逆时针旋转电位器电压降低电机减速, 顺时针旋转电位器电压升高电机加速.
  4. 关于无感三相无刷直流电机的原理, 用户自行学习了解, 本例不予说明.
  5. ******************************************/
  6. #define MAIN_Fosc                24000000L        //定义主时钟
  7. #include        "STC8Hxxx.h"
  8. #define ADC_START        (1<<6)        /* 自动清0 */
  9. #define ADC_FLAG        (1<<5)        /* 软件清0 */
  10. #define        ADC_SPEED        1                /* 0~15, ADC时钟 = SYSclk/2/(n+1) */
  11. #define        RES_FMT                (1<<5)        /* ADC结果格式 0: 左对齐, ADC_RES: D9 D8 D7 D6 D5 D4 D3 D2, ADC_RESL: D1 D0 0  0  0  0  0  0 */
  12.                                                         /*            1: 右对齐, ADC_RES: 0  0  0  0  0  0  D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */
  13. #define CSSETUP                (0<<7)        /* 0~1,  ADC通道选择时间      0: 1个ADC时钟, 1: 2个ADC时钟,  默认0(默认1个ADC时钟) */
  14. #define CSHOLD                (1<<5)        /* 0~3,  ADC通道选择保持时间  (n+1)个ADC时钟, 默认1(默认2个ADC时钟)                */
  15. #define SMPDUTY                20                /* 10~31, ADC模拟信号采样时间  (n+1)个ADC时钟, 默认10(默认11个ADC时钟)                                */
  16.                                                         /* ADC转换时间: 10位ADC固定为10个ADC时钟, 12位ADC固定为12个ADC时钟.                                 */
  17. //验证板引脚定义
  18. //PWM1 P1.2
  19. //PWM1L P1.3
  20. //PWM2 P1.4
  21. //PWM2L P1.5
  22. //PWM3 P1.6
  23. //PWM3L P1.7
  24. //ADC8        P1.1
  25. //ADC9        P1.0
  26. //ADC10        P3.5
  27. //ADC11        P3.4
  28. //CMP        P3.6
  29. sbit PWM1 = P1^2;
  30. sbit PWM1_L = P1^3;
  31. sbit PWM2 = P1^4;
  32. sbit PWM2_L = P1^5;
  33. sbit PWM3 = P1^6;
  34. sbit PWM3_L = P1^7;
  35. //PWM2        --->        PWM1
  36. //PWM3        --->        PWM2
  37. //PWM4        --->        PWM3
  38. //ADC8        --->        ADC1
  39. //ADC9        --->        ADC0
  40. //ADC10        --->        ADC13
  41. //ADC11        --->        ADC12
  42. //原程序引脚定义
  43. // sbit PWM1   = P1^0;
  44. // sbit PWM1_L = P1^1;
  45. // sbit PWM2   = P1^2;
  46. // sbit PWM2_L = P1^3;
  47. // sbit PWM3   = P1^4;
  48. // sbit PWM3_L = P1^5;
  49. //ADC11 P0.3
  50. //ADC10 P0.2
  51. //ADC9  P0.1
  52. //ADC8  P0.0
  53. //CMP-        P3.6
  54. u8        step;                //切换步骤
  55. u8        PWM_Value;        // 决定PWM占空比的值
  56. bit        B_RUN;                //运行标志
  57. u8        PWW_Set;        //目标PWM设置
  58. u16        adc11;
  59. bit        B_4ms;                //4ms定时标志
  60. u8        TimeOut;        //堵转超时
  61. bit        B_start;        //启动模式
  62. bit        B_Timer3_OverFlow;
  63. u8        TimeIndex;                //换相时间保存索引
  64. u16        PhaseTimeTmp[8];//8个换相时间, 其 sum/16 就是30度电角度
  65. u16        PhaseTime;                //换相时间计数
  66. u8        XiaoCiCnt;                //1:需要消磁, 2:正在消磁, 0已经消磁
  67. /*************************/
  68. void        Delay_n_ms(u8 dly)        // N ms延时函数
  69. {
  70.         u16        j;
  71.         do
  72.         {
  73.                 j = MAIN_Fosc / 10000;
  74.                 while(--j)        ;
  75.         }while(--dly);
  76. }
  77. void delay_us(u8 us)        //N us延时函数
  78. {
  79.         do
  80.         {
  81.                 NOP(20);        //@24MHz
  82.         }
  83.         while(--us);
  84. }
  85. //========================================================================
  86. // 函数: u16        Get_ADC10bitResult(u8 channel))        //channel = 0~15
  87. //========================================================================
  88. u16        Get_ADC10bitResult(u8 channel)        //channel = 0~15
  89. {
  90.         u8 i;
  91.         ADC_RES = 0;
  92.         ADC_RESL = 0;
  93.         ADC_CONTR = 0x80 | ADC_START | channel;
  94.         NOP(5);                        //
  95. //        while((ADC_CONTR & ADC_FLAG) == 0)        ;        //等待ADC结束
  96.                 i = 255;
  97.                 while(i != 0)
  98.                 {
  99.                         i--;
  100.                         if((ADC_CONTR & ADC_FLAG) != 0)        break;        //等待ADC结束
  101.                 }
  102.         ADC_CONTR &= ~ADC_FLAG;
  103.         return        ((u16)ADC_RES * 256 + (u16)ADC_RESL);
  104. }
  105. void        Delay_500ns(void)
  106. {
  107.         NOP(6);
  108. }
  109. void StepMotor(void) // 换相序列函数
  110. {
  111.         switch(step)
  112.         {
  113.         case 0:  // AB  PWM1, PWM2_L=1
  114.                         PWMA_ENO = 0x00;        PWM1_L=0;        PWM3_L=0;
  115.                         Delay_500ns();
  116.                         PWMA_ENO = 0x01;                // 打开A相的高端PWM
  117.                         PWM2_L = 1;                                // 打开B相的低端
  118.                         ADC_CONTR = 0x80+10;        // 选择P0.2作为ADC输入 即C相电压
  119.                         CMPCR1 = 0x8c + 0x10;        //比较器下降沿中断
  120.                         break;
  121.         case 1:  // AC  PWM1, PWM3_L=1
  122.                         PWMA_ENO = 0x01;        PWM1_L=0;        PWM2_L=0;        // 打开A相的高端PWM
  123.                         Delay_500ns();
  124.                         PWM3_L = 1;                                // 打开C相的低端
  125.                         ADC_CONTR = 0x80+9;                // 选择P0.1作为ADC输入 即B相电压
  126.                         CMPCR1 = 0x8c + 0x20;        //比较器上升沿中断
  127.                         break;
  128.         case 2:  // BC  PWM2, PWM3_L=1
  129.                         PWMA_ENO = 0x00;        PWM1_L=0;        PWM2_L=0;
  130.                         Delay_500ns();
  131.                         PWMA_ENO = 0x04;                // 打开B相的高端PWM
  132.                         PWM3_L = 1;                                // 打开C相的低端
  133.                         ADC_CONTR = 0x80+8;                // 选择P0.0作为ADC输入 即A相电压
  134.                         CMPCR1 = 0x8c + 0x10;        //比较器下降沿中断
  135.                         break;
  136.         case 3:  // BA  PWM2, PWM1_L=1
  137.                         PWMA_ENO = 0x04;        PWM2_L=0;        PWM3_L=0;        // 打开B相的高端PWM
  138.                         Delay_500ns();
  139.                         PWM1_L = 1;                                // 打开C相的低端
  140.                         ADC_CONTR = 0x80+10;        // 选择P0.2作为ADC输入 即C相电压
  141.                         CMPCR1 = 0x8c + 0x20;        //比较器上升沿中断
  142.                         break;
  143.         case 4:  // CA  PWM3, PWM1_L=1
  144.                         PWMA_ENO = 0x00;        PWM2_L=0;        PWM3_L=0;
  145.                         Delay_500ns();
  146.                         PWMA_ENO = 0x10;                // 打开C相的高端PWM
  147.                         PWM1_L = 1;                                // 打开A相的低端
  148.                         adc11 = ((adc11 *7)>>3) + Get_ADC10bitResult(11);
  149.                         ADC_CONTR = 0x80+9;                // 选择P0.1作为ADC输入 即B相电压
  150.                         CMPCR1 = 0x8c + 0x10;        //比较器下降沿中断
  151.                         break;
  152.         case 5:  // CB  PWM3, PWM2_L=1
  153.                         PWMA_ENO = 0x10;        PWM1_L=0;        PWM3_L=0;        // 打开C相的高端PWM
  154.                         Delay_500ns();
  155.                         PWM2_L = 1;                                // 打开B相的低端
  156.                         ADC_CONTR = 0x80+8;                // 选择P0.0作为ADC输入 即A相电压
  157.                         CMPCR1 = 0x8c + 0x20;        //比较器上升沿中断
  158.                         break;
  159.         default:
  160.                         break;
  161.         }
  162.         if(B_start)                CMPCR1 = 0x8C;        // 启动时禁止下降沿和上升沿中断
  163. }
  164. void PWMA_config(void)
  165. {
  166.         P_SW2 |= 0x80;                //SFR enable   
  167.         PWM1   = 0;
  168.         PWM1_L = 0;
  169.         PWM2   = 0;
  170.         PWM2_L = 0;
  171.         PWM3   = 0;
  172.         PWM3_L = 0;
  173.         P1n_push_pull(0x3f); //0011 1111 P1.0~P1.5输出
  174.         PWMA_PSCR = 3;                // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
  175.         PWMA_DTR  = 24;                // 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
  176.                                                 //                                0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
  177.         PWMA_ARR    = 255;        // 自动重装载寄存器,  控制PWM周期
  178.         PWMA_CCER1  = 0;        //配置CCMRx前必须先清零 CCxE 关闭通道
  179.         PWMA_CCER2  = 0;
  180.         PWMA_SR1    = 0;        //状态寄存器1
  181.         PWMA_SR2    = 0;        //状态寄存器2
  182.         PWMA_ENO    = 0;
  183.         PWMA_PS     = 0;
  184.         PWMA_IER    = 0;
  185. //        PWMA_ISR_En = 0;
  186.         // PWMA_CCMR1  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
  187.         // PWMA_CCR1   = 0;                // 比较值, 控制占空比(高电平时钟数)
  188.         // PWMA_CCER1 |= 0x05;                // 开启比较输出, 高电平有效
  189.         // PWMA_PS    |= 0;                // 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1,
  190. //        PWMA_ENO   |= 0x01;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
  191. //        PWMA_IER   |= 0x02;                // 使能中断
  192.         PWMA_CCMR2  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
  193.         PWMA_CCR2   = 0;                // 比较值, 控制占空比(高电平时钟数)
  194.         PWMA_CCER1 |= 0x50;                // 开启比较输出, 高电平有效
  195.         PWMA_PS    |= (0<<2);        // 选择IO, 0:选择P1.2 P1.3, 1:选择P2.2 P2.3, 2:选择P6.2 P6.3,
  196. //        PWMA_ENO   |= 0x04;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
  197. //        PWMA_IER   |= 0x04;                // 使能中断
  198.         PWMA_CCMR3  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
  199.         PWMA_CCR3   = 0;                // 比较值, 控制占空比(高电平时钟数)
  200.         PWMA_CCER2 |= 0x05;                // 开启比较输出, 高电平有效
  201.         PWMA_PS    |= (0<<4);        // 选择IO, 0:选择P1.4 P1.5, 1:选择P2.4 P2.5, 2:选择P6.4 P6.5,
  202. //        PWMA_ENO   |= 0x10;                // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
  203. //        PWMA_IER   |= 0x08;                // 使能中断
  204.         PWMA_CCMR4  = 0x68;                // 通道模式配置, PWM模式1, 预装载允许
  205.         PWMA_CCR4   = 0;                // 比较值, 控制占空比(高电平时钟数)
  206.         PWMA_CCER2 |= 0x50;                // 开启比较输出, 高电平有效
  207.         PWMA_PS    |= (0<<6);        // 选择IO, 0:选择P1.6 P1.7, 1:选择P2.6 P2.7, 2:选择P6.6 P6.7,
  208.         PWMA_BKR    = 0x80;                // 主输出使能 相当于总开关
  209.         PWMA_CR1    = 0x81;                // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
  210.         PWMA_EGR    = 0x01;                //产生一次更新事件, 清除计数器和与分频计数器, 装载预分频寄存器的值
  211. //        PWMA_ISR_En = PWMA_IER;        //设置标志允许通道1~4中断处理
  212. }
  213. //        PWMA_PS   = (0<<6)+(0<<4)+(0<<2)+0;        //选择IO, 4项从高到低(从左到右)对应PWM1 PWM2 PWM3 PWM4, 0:选择P1.x, 1:选择P2.x, 2:选择P6.x,
  214. //  PWMA_PS    PWM4N PWM4P    PWM3N PWM3P    PWM2N PWM2P    PWM1N PWM1P
  215. //    00       P1.7  P1.6     P1.5  P1.4     P1.3  P1.2     P1.1  P1.0
  216. //    01       P2.7  P2.6     P2.5  P2.4     P2.3  P2.2     P2.1  P2.0
  217. //    02       P6.7  P6.6     P6.5  P6.4     P6.3  P6.2     P6.1  P6.0
  218. //    03       P3.3  P3.4      --    --       --    --       --    --
  219. void ADC_config(void)        //ADC初始化函数(为了使用ADC输入端做比较器信号, 实际没有启动ADC转换)
  220. {
  221.         P1n_pure_input(0xc0);        //设置为高阻输入
  222.         P0n_pure_input(0x0f);        //设置为高阻输入
  223.         ADC_CONTR = 0x80 + 6;        //ADC on + channel
  224.         ADCCFG = RES_FMT + ADC_SPEED;
  225.         P_SW2 |=  0x80;        //访问XSFR
  226.         ADCTIM = CSSETUP + CSHOLD + SMPDUTY;
  227. }
  228. void CMP_config(void)        //比较器初始化程序
  229. {
  230.         CMPCR1 = 0x8C;                        // 1000 1100 打开比较器,P3.6作为比较器的反相输入端,ADC引脚作为正输入端
  231.         CMPCR2 = 60;                        //60个时钟滤波   比较结果变化延时周期数, 0~63
  232.         P3n_pure_input(0x40);        //CMP-(P3.6)设置为高阻.
  233.        
  234.         P_SW2 |= 0x80;                //SFR enable   
  235. //        CMPEXCFG |= (0<<6);        //bit7 bit6: 比较器迟滞输入选择: 0: 0mV,  1: 10mV, 2: 20mV, 3: 30mV
  236. //        CMPEXCFG |= (0<<2);        //bit2: 输入负极性选择, 0: 选择P3.6做输入,   1: 选择内部BandGap电压BGv做负输入.
  237. //        CMPEXCFG |=  0;                //bit1 bit0: 输入正极性选择, 0: 选择P3.7做输入,   1: 选择P5.0做输入,  2: 选择P5.1做输入,  3: 选择ADC输入(由ADC_CHS[3:0]所选择的ADC输入端做正输入).
  238. //        CMPEXCFG = (0<<6)+(0<<2)+3;
  239. }
  240. void CMP_ISR(void) interrupt 21                //比较器中断函数, 检测到反电动势过0事件
  241. {
  242.         u8        i;
  243.         CMPCR1 &= ~0x40;        // 需软件清除中断标志位
  244.         if(XiaoCiCnt == 0)        //消磁后才检测过0事件,   XiaoCiCnt=1:需要消磁, =2:正在消磁, =0已经消磁
  245.         {
  246.                 T4T3M &= ~(1<<3);        // Timer3停止运行
  247.                 if(B_Timer3_OverFlow)        //切换时间间隔(Timer3)有溢出
  248.                 {
  249.                         B_Timer3_OverFlow = 0;
  250.                         PhaseTime = 8000;        //换相时间最大8ms, 2212电机12V空转最高速130us切换一相(200RPS 12000RPM), 480mA
  251.                 }
  252.                 else
  253.                 {
  254.                         PhaseTime = (((u16)T3H << 8) + T3L) >> 1;        //单位为1us
  255.                         if(PhaseTime >= 8000)        PhaseTime = 8000;        //换相时间最大8ms, 2212电机12V空转最高速130us切换一相(200RPS 12000RPM), 480mA
  256.                 }
  257.                 T3H = 0;        T3L = 0;
  258.                 T4T3M |=  (1<<3);        //Timer3开始运行
  259.                 PhaseTimeTmp[TimeIndex] = PhaseTime;        //保存一次换相时间
  260.                 if(++TimeIndex >= 8)        TimeIndex = 0;        //累加8次
  261.                 for(PhaseTime=0, i=0; i<8; i++)        PhaseTime += PhaseTimeTmp[i];        //求8次换相时间累加和
  262.                 PhaseTime = PhaseTime >> 4;                //求8次换相时间的平均值的一半, 即30度电角度
  263.                 if((PhaseTime >= 40) && (PhaseTime <= 1000))        TimeOut = 125;        //堵转500ms超时
  264.                 if( PhaseTime >= 60)        PhaseTime -= 40;        //修正由于滤波电容引起的滞后时间
  265.                 else                                        PhaseTime  = 20;
  266.                
  267.         //        PhaseTime = 20;        //只给20us, 则无滞后修正, 用于检测滤波电容引起的滞后时间
  268.                 T4T3M &= ~(1<<7);                                //Timer4停止运行
  269.                 PhaseTime  = PhaseTime  << 1;        //2个计数1us
  270.                 PhaseTime = 0 - PhaseTime;
  271.                 T4H = (u8)(PhaseTime >> 8);                //装载30度角延时
  272.                 T4L = (u8)PhaseTime;
  273.                 T4T3M |=  (1<<7);        //Timer4开始运行
  274.                 XiaoCiCnt = 1;                //1:需要消磁, 2:正在消磁, 0已经消磁
  275.         }
  276. }
  277. void Timer0_config(void)        //Timer0初始化函数
  278. {
  279.         Timer0_16bitAutoReload(); // T0工作于16位自动重装
  280.         Timer0_12T();
  281.         TH0 = (65536UL-MAIN_Fosc/12 / 250) / 256; //4ms
  282.         TL0 = (65536UL-MAIN_Fosc/12 / 250) % 256;
  283.         TR0 = 1; // 打开定时器0
  284.         ET0 = 1;// 允许ET0中断
  285. }
  286. void Timer0_ISR(void) interrupt 1        //Timer0中断函数, 20us
  287. {
  288.         B_4ms = 1;        //4ms定时标志
  289. }
  290. //============================ timer3初始化函数 ============================================
  291. void        Timer3_Config(void)
  292. {
  293.         P_SW2 |= 0x80;                //SFR enable   
  294.         T4T3M &= 0xf0;                //停止计数, 定时模式, 12T模式, 不输出时钟
  295.         T3H = 0;
  296.         T3L = 0;
  297.         T3T4PIN = 0x01;                //选择IO, 0x00: T3--P0.4, T3CLKO--P0.5, T4--P0.6, T4CLKO--P0.7;    0x01: T3--P0.0, T3CLKO--P0.1, T4--P0.2, T4CLKO--P0.3;
  298.         IE2   |=  (1<<5);        //允许中断
  299.         T4T3M |=  (1<<3);        //开始运行
  300. }
  301. //============================ timer4初始化函数 ============================================
  302. void        Timer4_Config(void)
  303. {
  304.         P_SW2 |= 0x80;                //SFR enable   
  305.         T4T3M &= 0x0f;                //停止计数, 定时模式, 12T模式, 不输出时钟
  306.         T4H = 0;
  307.         T4L = 0;
  308.         T3T4PIN = 0x01;                //选择IO, 0x00: T3--P0.4, T3CLKO--P0.5, T4--P0.6, T4CLKO--P0.7;    0x01: T3--P0.0, T3CLKO--P0.1, T4--P0.2, T4CLKO--P0.3;
  309.         IE2   |=  (1<<6);        //允许中断
  310. //        T4T3M |=  (1<<7);        //开始运行
  311. }
  312. //=========================== timer3中断函数 =============================================
  313. void timer3_ISR (void) interrupt TIMER3_VECTOR
  314. {
  315.         B_Timer3_OverFlow = 1;        //溢出标志
  316. }
  317. //=========================== timer4中断函数 =============================================
  318. void timer4_ISR (void) interrupt TIMER4_VECTOR
  319. {
  320.         T4T3M &= ~(1<<7);        //Timer4停止运行
  321.         if(XiaoCiCnt == 1)                //标记需要消磁. 每次检测到过0事件后第一次中断为30度角延时, 设置消磁延时.
  322.         {
  323.                 XiaoCiCnt = 2;                //1:需要消磁, 2:正在消磁, 0已经消磁
  324.                 if(B_RUN)        //电机正在运行
  325.                 {
  326.                         if(++step >= 6)        step = 0;
  327.                         StepMotor();
  328.                 }
  329.                                                                                 //消磁时间, 换相后线圈(电感)电流减小到0的过程中, 出现反电动势, 电流越大消磁时间越长, 过0检测要在这个时间之后
  330.                                                                                 //100%占空比时施加较重负载, 电机电流上升, 可以示波器看消磁时间.
  331.                                                                                 //实际上, 只要在换相后延时几十us才检测过零, 就可以了
  332.                 T4H = (u8)((65536UL - 40*2) >> 8);        //装载消磁延时
  333.                 T4L = (u8)(65536UL - 40*2);
  334.                 T4T3M |=  (1<<7);        //Timer4开始运行
  335.         }
  336.         else if(XiaoCiCnt == 2)        XiaoCiCnt = 0;                //1:需要消磁, 2:正在消磁, 0已经消磁
  337. }
  338. #define        D_START_PWM                30
  339. /******************* 强制电机启动函数 ***************************/
  340. void StartMotor(void)
  341. {
  342.         u16 timer,i;
  343.         CMPCR1 = 0x8C;        // 关比较器中断
  344.         PWM_Value  = D_START_PWM;        // 初始占空比, 根据电机特性设置
  345.         PWMA_CCR1L = PWM_Value;
  346.         PWMA_CCR2L = PWM_Value;
  347.         PWMA_CCR3L = PWM_Value;
  348.         step = 0;        StepMotor();        Delay_n_ms(50);        //Delay_n_ms(250);// 初始位置
  349.         timer = 200;        //风扇电机启动
  350.         while(1)
  351.         {
  352.                 for(i=0; i<timer; i++)        delay_us(100);  //根据电机加速特性, 最高转速等等调整启动加速速度
  353.                 timer -= timer /16;
  354.                 if(++step >= 6)        step = 0;
  355.                 StepMotor();
  356.                 if(timer < 40)        return;
  357.         }
  358. }
  359. /**********************************************/
  360. void main(void)
  361. {
  362.         u8        i;
  363.         u16        j;
  364.        
  365.         P2n_standard(0xf8); //P2.0~P2.2输出
  366.         P3n_standard(0xbf);//P3.6输入
  367.         P5n_standard(0x10);//P5.4输入
  368.        
  369.         adc11 = 0;
  370.        
  371.         PWMA_config();
  372.         ADC_config();
  373.         CMP_config();
  374.         Timer0_config();        // Timer0初始化函数
  375.         Timer3_Config();        // Timer3初始化函数
  376.         Timer4_Config();        // Timer4初始化函数
  377.         PWW_Set = 0;
  378.         TimeOut = 0;
  379.         EA  = 1; // 打开总中断
  380.        
  381.         while (1)
  382.         {
  383.                 if(B_4ms)                // 4ms时隙
  384.                 {
  385.                         B_4ms = 0;
  386.                         if(TimeOut != 0)
  387.                         {
  388.                                 if(--TimeOut == 0)        //堵转超时
  389.                                 {
  390.                                         B_RUN  = 0;
  391.                                         PWM_Value = 0;
  392.                                         CMPCR1 = 0x8C;        // 关比较器中断
  393.                                         PWMA_ENO  = 0;
  394.                                         PWMA_CCR1L = 0;        PWMA_CCR2L = 0;        PWMA_CCR3L = 0;
  395.                                         PWM1_L=0;        PWM2_L=0;        PWM3_L=0;
  396.                                         Delay_n_ms(250);        //堵转时,延时一点时间再启动
  397.                                 }
  398.                         }
  399.                         if(!B_RUN && (PWW_Set >= D_START_PWM))        // 占空比大于设定值, 并且电机未运行, 则启动电机
  400.                         {
  401.                                 B_start = 1;                //启动模式
  402.                                 for(i=0; i<8; i++)        PhaseTimeTmp[i] = 400;
  403.                                 StartMotor();                // 启动电机
  404.                                 B_start = 0;
  405.                                 XiaoCiCnt = 0;                //初始进入时
  406.                                 CMPCR1 &= ~0x40;        // 清除中断标志位
  407.                                 if(step & 1)        CMPCR1 = 0xAC;                //上升沿中断
  408.                                 else                        CMPCR1 = 0x9C;                //下降沿中断
  409.                                 B_RUN = 1;
  410.                                 Delay_n_ms(250);        //延时一下, 先启动起来
  411.                                 Delay_n_ms(250);
  412.                                 TimeOut = 125;                //启动超时时间 125*4 = 500ms
  413.                         }
  414.                         if(B_RUN)        //正在运行中
  415.                         {
  416.                                 if(PWM_Value < PWW_Set)        PWM_Value++;        //油门跟随电位器
  417.                                 if(PWM_Value > PWW_Set)        PWM_Value--;
  418.                                 if(PWM_Value < (D_START_PWM-10))        // 停转, 停转占空比 比 启动占空比 小10/256
  419.                                 {
  420.                                         B_RUN = 0;
  421.                                         PWM_Value = 0;
  422.                                         CMPCR1 = 0x8C;        // 关比较器中断
  423.                                         PWMA_ENO  = 0;
  424.                                         PWMA_CCR1L = 0;        PWMA_CCR2L = 0;        PWMA_CCR3L = 0;
  425.                                         PWM1_L=0;        PWM2_L=0;        PWM3_L=0;
  426.                                 }
  427.                                 else
  428.                                 {
  429.                                         PWMA_CCR1L = PWM_Value;
  430.                                         PWMA_CCR2L = PWM_Value;
  431.                                         PWMA_CCR3L = PWM_Value;
  432.                                 }
  433.                         }
  434.                         else
  435.                         {
  436.                                 adc11 = ((adc11 *7)>>3) + Get_ADC10bitResult(11);
  437.                         }
  438.                        
  439.                         j = adc11;
  440.                         if(j != adc11)        j = adc11;
  441.                         PWW_Set = (u8)(j >> 5);        //油门是8位的
  442.                 }
  443.         }
  444. }
复制代码

点评

先看PWM正常输出没有?  详情 回复 发表于 2024-7-31 17:33
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-6 11:41 , Processed in 0.140006 second(s), 118 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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