找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8849|回复: 7
收起左侧

STC15W401AS-实现四轴飞行器无刷电机的电调控制-参考程序和电路

  [复制链接]
ID:603344 发表于 2019-9-1 18:23 | 显示全部楼层 |阅读模式
STC15W401AS-实现四轴飞行器无刷电机的电调控制电路原理图如下:
0.png

单片机源程序如下:

  1. /*---------------------------------------------------------------------*/
  2. /* --- STC MCU International Limited ----------------------------------*/
  3. /* --- STC 1T Series MCU Demo Programme -------------------------------*/
  4. /* --- QQ:  800003751 -------------------------------------------------*/
  5. /* 如果要在程序中使用此代码,请在程序中注明使用了宏晶科技的资料及程序   */
  6. /*---------------------------------------------------------------------*/


  7. /*************        功能说明        **************

  8. 本程序试验使用STC15W401AS-35I-SOP16<RMB1.6>来驱动航模用的无传感器无刷三相直流马达.

  9. 本程序参考自网上的代码(作者: 瑞生), 改良而来.

  10. 电路图见文件 "BLDC-V10-实验电路.pdf".

  11. 控制信号由P3.2输入正脉冲信号, 间隔5~20ms, 脉冲宽度1.000~1.610ms.

  12. 1.160ms开始启动, 1.610ms为最高速度, 分辨率为2us.

  13. 本程序仅仅是简单控制, 软件没有处理 过0延时30度切换 过流检测.

  14. 由于过0检测部分有RC滤波, 所以改变电容值可以大约的对应在最高速时延时30度的时间.

  15. 有意者可自行完善电路和程序.

  16. ******************************************/




  17. #define MAIN_Fosc                24000000L        //定义主时钟

  18. #include "STC15Fxxxx.H"

  19. #define                MCU_PIN                16        /* 选择MCU引脚数, 只支持16或20脚(28脚或32脚跟20脚一样) */



  20. //CMPCR1
  21. #define        CMPEN        0x80        //1: 允许比较器, 0: 禁止,关闭比较器电源
  22. #define        CMPIF        0x40        //比较器中断标志, 包括上升沿或下降沿中断, 软件清0
  23. #define        PIE                0x20        //1: 比较结果由0变1, 产生上升沿中断
  24. #define        NIE                0x10        //1: 比较结果由1变0, 产生下降沿中断
  25. #define        PIS                0x08        //输入正极性选择, 0: 选择外部P5.5做正输入,           1: 由ADCIS[2:0]所选择的ADC输入端做正输入.
  26. #define        NIS                0x04        //输入负极性选择, 0: 选择内部BandGap电压BGv做负输入, 1: 选择外部P5.4做输入.
  27. #define        CMPOE        0x02        //1: 允许比较结果输出到P1.2, 0: 禁止.
  28. #define        CMPRES        0x01        //比较结果, 1: CMP+电平高于CMP-,  0: CMP+电平低于CMP-,  只读

  29. //CMPCR2
  30. #define        INVCMPO        0x80        //1: 比较器输出取反,  0: 不取反
  31. #define        DISFLT        0x40        //1: 关闭0.1uF滤波,   0: 允许
  32. #define        LCDTY        0x00        //0~63, 比较结果变化延时周期数

  33. #if        (MCU_PIN == 20)
  34.         sbit PWM2_L = P3^4;
  35.         sbit PWM1_L = P3^5;
  36.         sbit PWM0_L = P3^6;
  37. #endif

  38. #if        (MCU_PIN == 16)
  39.         sbit PWM2_L = P5^5;
  40.         sbit PWM1_L = P3^3;
  41.         sbit PWM0_L = P3^6;
  42. #endif

  43. u8        Step;
  44. u8        PWM_Value; // 决定PWM占空比的值
  45. u16        RxPulseWide;
  46. bit        B_RxOk;
  47. bit        B_RUN;
  48. u8        PWW_Set;
  49. u8        cnt10ms;
  50. u8        Rx_cnt;
  51. u8        TimeOut;        //堵转超时

  52. #define DISABLE_CMP_INT CMPCR1 &= ~0X40                // 关闭比较器中断
  53. #define ENABLE_CMP_INT  CMPCR1 |= 0X40                // 打开比较器中断

  54. /*************************/

  55. void        Delay_n_ms(u8 dly)
  56. {
  57.         u16        j;
  58.         do
  59.         {
  60.                 j = MAIN_Fosc / 13000;        //延时1ms, 主程序在此节拍下运行
  61.                 while(--j)        ;
  62.         }while(--dly);
  63. }


  64. void delay_us(u8 us)
  65. {
  66.         do
  67.         {
  68.                 NOP(20);        //@24MHz
  69.         }
  70.         while(--us);
  71. }

  72. void StepXL(void) // 换相序列函数
  73. {
  74. switch(Step)
  75.   {
  76.    case 0:  // AB
  77.                         PWM0_L=0;        PWM2_L=0;
  78.                         CCAP0H = PWM_Value;        CCAP1H=0;        CCAP2H=0;        // 打开A相的高端
  79.                         PWM1_L = 1;                 // 打开B相的低端
  80.                         ADC_CONTR = 0XED;        // 选择P1.5作为ADC输入 即c相电压
  81.                         CMPCR1 = 0x9C;                //bit7=1 允许比较器, bit4=1 比较结果由1变0, 产生下降沿中断 (不能响应下降沿中断?)
  82.                         break;
  83.    case 1:  // AC
  84.                         PWM0_L=0;        PWM1_L=0;
  85.                         CCAP0H = PWM_Value;        CCAP1H=0;        CCAP2H=0;        // 打开A相的高端
  86.                         PWM2_L = 1;                        // 打开C相的低端
  87.                         ADC_CONTR = 0XEC;        // 选择P1.4作为ADC输入 即B相电压
  88.                         CMPCR1 = 0xAC;                //上升沿中断
  89.          
  90.       break;
  91.    case 2:  // BC
  92.                         PWM0_L=0;        PWM1_L=0;
  93.                         CCAP0H=0;        CCAP2H=0;        CCAP1H = PWM_Value; // 打开B相的高端
  94.                         PWM2_L = 1;                        // 打开C相的低端
  95.                         ADC_CONTR = 0XEB;        // 选择P1.3作为ADC输入 即a相电压
  96.                         CMPCR1 = 0x9C;                //下降沿中断
  97.       break;
  98.    case 3:  // BA
  99.                         PWM1_L=0;        PWM2_L=0;
  100.                         CCAP0H=0;        CCAP2H=0;        CCAP1H = PWM_Value; // 打开B相的高端
  101.                         PWM0_L = 1;                        // 打开A相的低端
  102.                         ADC_CONTR = 0XED;        // 选择P1.5作为ADC输入 即c相电压
  103.                         CMPCR1 = 0xAC;                //上升沿中断
  104.                        
  105.       break;
  106.    case 4: // CA
  107.                         PWM1_L=0;        PWM2_L=0;
  108.                         CCAP0H=0;        CCAP1H=0;        CCAP2H = PWM_Value; // 打开C相的高端
  109.                         PWM0_L = 1;                        // 打开A相的低端
  110.                         ADC_CONTR = 0XEC;        // 选择P1.4作为ADC输入 即B相电压
  111.                         CMPCR1 = 0x9C;                //下降沿中断
  112.       break;
  113.    case 5: // CB
  114.                       PWM0_L=0;        PWM2_L=0;
  115.                         CCAP0H=0;        CCAP1H=0;        CCAP2H = PWM_Value;// 打开C相的高端
  116.                       PWM1_L = 1;                        // 打开B相的低端
  117.                         ADC_CONTR = 0XEB;        // 选择P1.3作为ADC输入 即a相电压
  118.                         CMPCR1 = 0xAC;                //上升沿中断
  119.          
  120.                 break;
  121.          
  122.         default:
  123.                 break;
  124.   }       
  125. }



  126. void PWM_Init(void)
  127. {
  128.         PWM0_L = 0;
  129.         PWM1_L = 0;
  130.         PWM2_L = 0;
  131.        
  132. #if        (MCU_PIN == 20)
  133.         P3n_push_pull(0x70);
  134. #endif
  135. #if        (MCU_PIN == 16)
  136.         P3n_push_pull(0x48);
  137.         P5n_push_pull(0x20);
  138. #endif

  139. //        CMOD = 1 << 1; //选择系统时钟/2为时钟源,即PWM频率=24M/2/256=46.9K
  140.         CMOD = 5 << 1; //选择系统时钟/4为时钟源,即PWM频率=24M/4/256=23.4K
  141. //        CMOD = 6 << 1; //选择系统时钟/6为时钟源,即PWM频率=24M/6/256=15.6K
  142.         CL=0;                        // PCA计数器清零
  143.         CH=0;
  144.        
  145.         PCA_PWM0 = 0X00;
  146.         CCAP0H=0;    // 初始化占空比为0% H的值装载到L中
  147.         CCAP0L=0;
  148.         CCAPM0=0x42;        // 设置为PWM模式
  149.        
  150.         PCA_PWM1 = 0X00;
  151.         CCAP1H=0;    // 初始化占空比为0%
  152.         CCAP1L=0;
  153.         CCAPM1=0x42;        // 设置为PWM模式
  154.        
  155.         PCA_PWM2 = 0X00;
  156.         CCAP2H=0;    // 初始化占空比为0%
  157.         CCAP2L=0;
  158.         CCAPM2=0x42;        // 设置为PWM模式
  159.        
  160.         CR = 1;
  161. }

  162. void ADC_Init(void)
  163. {
  164.         P1n_pure_input(0x38);
  165.         P1ASF = 0X38; // 开通P1.3 P1.4 P1.5的AD输入口
  166. }

  167. void CMP_INT(void) interrupt 21
  168. {
  169.         CMPCR1 &= ~0X40; // 需软件清除中断标志位
  170.         if(Step<5)        Step++;
  171.         else                Step = 0;
  172.         StepXL();
  173.         TimeOut = 10;        //10ms超时
  174. }

  175. void CMP_Init(void)
  176. {
  177.         CMPCR1 = 0X8C;        // 1000 1100 打开比较器,P5.4作为比较器的反相输入端,ADC引脚作为正输入端
  178.         CMPCR2 = 60;        // 60个时钟滤波
  179.         P5n_pure_input(0x10);
  180. }

  181. u8 StartMotor(void)
  182. {
  183.         u16 timer,i;
  184.         DISABLE_CMP_INT;        // 禁止比较器中断
  185.         PWM_Value = 30;                // 初始占空比=16/256=6%
  186.         Step = 0;
  187.         StepXL();                        // 初始位置
  188.         Delay_n_ms(5);//delay_ms(5);
  189.         timer = 300;

  190.         while(1)
  191.         {
  192.                 for(i=0; i<timer; i++)        delay_us(50);  //
  193.                 timer -= timer /15 + 1;
  194.                 if(timer < 25)        return(1);
  195.                 if( Step < 5)        Step++;
  196.                 else                        Step = 0;
  197.                 StepXL();
  198.         }
  199. }

  200. void T0_Iint(void)
  201. {
  202.         Timer0_AsTimer();        /* 时器0用做定时器        */
  203.         Timer0_12T();                /* Timer0 clodk = fo/12        12分频,        default        */
  204.         Timer0_16bit();
  205.         Timer0_Gate_INT0_P32();        /* 时器0由外部INT0高电平允许定时计数 */
  206.         TH0 = 0;
  207.         TL0 = 0;
  208.         TR0 = 1; // 打开定时器0
  209.         ET0 = 1;// 允许ET0中断
  210. }

  211. void T0_Interrupt(void) interrupt 1
  212. {
  213.         Rx_cnt = 0;                        //一旦出现溢出, 则开始的n个脉冲无效
  214.         RxPulseWide = 1000;        //停止
  215.         B_RxOk = 1;                        //虚拟收到一个脉冲
  216. }

  217. /********************* INT0中断函数 *************************/
  218. void INT0_int (void) interrupt INT0_VECTOR
  219. {
  220.         u16        j;
  221.        
  222.         TR0 = 0;
  223.         j = ((u16)TH0 << 8) + TL0;
  224.         TH0 = 0;
  225.         TL0 = 0;
  226.         TR0 = 1;

  227.         if(++Rx_cnt >= 5)        Rx_cnt = 5;
  228.         j >>= 1;        //为了好处理, 转成单位为us
  229.         if((j >= 800) && (j <= 2000) && (Rx_cnt == 5))
  230.         {
  231.                 RxPulseWide = j;
  232.                 B_RxOk = 1;                //标志收到一个脉冲
  233.         }

  234. }


  235. /**********************************************/
  236. void main(void)
  237. {
  238.         u16 j;

  239.         PWM_Init();
  240.         ADC_Init();
  241.         CMP_Init();
  242.         T0_Iint();

  243.         IE0 = 0;        // 清除外中断0标志位
  244.         EX0 = 1;        // INT0 Enable
  245.         IT0 = 1;        //INT0 下降沿中断
  246.        
  247.         RxPulseWide = 1000;
  248.         PWW_Set = 0;
  249.         cnt10ms = 0;
  250.         Rx_cnt  = 0;
  251.         TimeOut = 0;

  252.         EA  = 1; // 打开总中断
  253.        
  254.         while (1)
  255.         {
  256.                 Delay_n_ms(1);        //延时1ms, 主程序在此节拍下运行

  257.                 if(TimeOut > 0)
  258.                 {
  259.                         if(--TimeOut == 0)        //堵转超时
  260.                         {
  261.                                 CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
  262.                                 PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
  263.                                 DISABLE_CMP_INT; // 关比较器中断
  264.                                 Delay_n_ms(250);        //堵转时,延时1秒再启动
  265.                                 Delay_n_ms(250);
  266.                                 Delay_n_ms(250);
  267.                                 Delay_n_ms(250);

  268.                                 RxPulseWide = 1000;
  269.                                 PWW_Set   = 0;
  270.                                 PWM_Value = 0;
  271.                                 B_RxOk = 0;
  272.                                 B_RUN  = 0;
  273.                                 Rx_cnt = 0;
  274.                                 TimeOut = 0;
  275.                         }
  276.                 }
  277.                
  278.                 if(B_RxOk)        //收到一个脉冲
  279.                 {
  280.                         B_RxOk = 0;
  281.                         j = RxPulseWide;
  282.                         if(j >= 1100)                                // 1100~1610对应PWM占空比值0~255
  283.                         {
  284.                                 j = (j - 1100) >> 1;        //2us对应PWM一个步进
  285.                                 if(j > 256)        j = 255;
  286.                         }
  287.                         else        j = 0;
  288.                         PWW_Set = (u8)j;
  289.                 }
  290.                
  291.                 if(!B_RUN && (PWW_Set >= 30))                // PWM_Set >= 30, 并且马达未运行, 则启动马达
  292.                 {
  293.                         StartMotor();        // 启动马达
  294.                         CMPCR1 &= ~0X40; // 需软件清除中断标志位
  295.                         ENABLE_CMP_INT; // 打开比较器中断
  296.                         B_RUN = 1;
  297.                         TimeOut = 0;
  298.                 }
  299.                
  300.                
  301.                 if(++cnt10ms >= 10)                // 10ms时隙
  302.                 {
  303.                         cnt10ms = 0;
  304.                         if(B_RUN)
  305.                         {
  306.                                 if(PWM_Value < PWW_Set)        PWM_Value++;
  307.                                 if(PWM_Value > PWW_Set)        PWM_Value--;
  308.                                 if(PWM_Value < 20)        // 停转
  309.                                 {
  310.                                         PWM_Value = 0;
  311.                                         B_RUN = 0;
  312.                                         CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
  313.                                         PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
  314.                                         DISABLE_CMP_INT; // 关比较器中断
  315.                                 }
  316.                         }
  317.                 }
  318.        
  319.         }
  320. }
复制代码

所有资料51hei提供下载:
STC15W401AS-实现四轴飞行器无刷电机的电调控制-参考程序和电路.zip (161.85 KB, 下载次数: 237)
回复

使用道具 举报

ID:56665 发表于 2019-9-2 19:27 | 显示全部楼层
我怎么没有看到哪里有过流检测。
回复

使用道具 举报

ID:639666 发表于 2021-2-11 10:48 | 显示全部楼层
本电路和程序没过流保护,要用到大功率P沟场管,限制了高电源电压的应用,在15伏左右的电源电压下玩玩是可以的。食之无味,弃之可惜。
回复

使用道具 举报

ID:671687 发表于 2021-3-30 12:44 | 显示全部楼层
问个问题,楼主P13 P14 P15 P54是干嘛用的 ,可以省吗?
回复

使用道具 举报

ID:73327 发表于 2021-8-26 22:37 | 显示全部楼层
感谢楼主分享!学习学习啦!
回复

使用道具 举报

ID:73327 发表于 2021-8-26 22:38 | 显示全部楼层
stc8a864a12 发表于 2021-3-30 12:44
问个问题,楼主P13 P14 P15 P54是干嘛用的 ,可以省吗?

不可以省,过零点检测用的!
回复

使用道具 举报

ID:1014955 发表于 2022-4-1 17:07 | 显示全部楼层
可以做普通单相电机吗?4极矽钢片,普通散热风扇。有做过程序吗?
回复

使用道具 举报

ID:378732 发表于 2022-4-3 16:55 | 显示全部楼层
这不是STC官网的例程吗
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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