找回密码
 立即注册
查看: 945|回复: 10

分享一个低成本STC8H1K08无刷小电调,支持oneshot125协议

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-06-15 00:11:09
已绑定手机

5

主题

7

回帖

166

积分

荣誉版主

积分
166
发表于 2025-4-27 20:34:40 | 显示全部楼层 |阅读模式
非常便宜的STC小电调,成本不到3元,长宽1cm*1cm,
可以用在小飞机上,支持oneshot125协议,开启了PWM互补输出,
响应速度很快,适合用在四轴小飞机上,固定翼也能用,
但是开互补PWM会更费电一点。


我接3元老王电机测试过2S 5042三叶桨满油门发热很小,

主要是因为这个电机电流小,具体能承受多大电流我没测过,
没找到合适的电机测试,我拿它做了个小四轴没什么问题。
这个是参考梁工的BLDC方案修改来的,原帖传送门

硬件和软件
相比梁工原方案,硬件软件上做了一些修改,把原来的三极管反向换成了mos反向,mos用了集成P+Nmos,体积很小,一个半桥才3*3mm。
反馈电阻上并联的10nf滤波电容去掉了,这个本来是设计用来过滤PWM干扰,如果没有的话PWM会干扰过零检测,尤其是低速状态下非常明显,
我在程序上做了一些处理,启动的时候让过零检测和PWM同步,这样可以避开PWM干扰,具体说起来可能有点复杂,有空我再详细介绍一下。
启动部分的程序也重写了一遍,在启动时也检测过零信号,根据过零信号换向,转速到一定阈值后结束启动。
输入信号用PWM捕获检测oneshot125信号的高电平时间,转换成8位油门信号。

测试视频


原理图.png
源码和keil工程

stc8h1k电调 1cm.rar (2.01 MB, 下载次数: 80)
  1. #include "STC8Hxxx.h"
  2. #include "intrins.h"
  3. #define MAIN_Fosc 37000000UL                            //定义主时钟
  4. #define BRT (65536UL - (MAIN_Fosc / 115200UL + 2) / 4)  //串口波特率
  5. #define STARTUP_INTERVAL 12000UL                        //启动时两次换向的最大间隔时间 us为单位
  6. #define STARTUP_POWER 20                                //启动时的功率
  7. #define STARTUP_THROTTLE 10                             //启动油门, 输入高于此值就启动电机
  8. #define STOP_THROTTLE 10
  9. sbit PWM1 = P1 ^ 0;
  10. sbit PWM1_L = P1 ^ 1;
  11. sbit PWM2 = P1 ^ 2;
  12. sbit PWM2_L = P1 ^ 3;
  13. sbit PWM3 = P1 ^ 4;
  14. sbit PWM3_L = P1 ^ 5;
  15. #define ADC_START (1 << 6) /* 自动清0 */
  16. #define ADC_FLAG (1 << 5)  /* 软件清0 */
  17. #define ADC_SPEED 1        /* 0~15, ADC时钟 = SYSclk/2/(n+1) */
  18. #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 */
  19. #define CSSETUP (0 << 7)   /* 0~1,  ADC通道选择时间      0: 1个ADC时钟, 1: 2个ADC时钟,  默认0(默认1个ADC时钟) */
  20. #define CSHOLD (1 << 5)    /* 0~3,  ADC通道选择保持时间  (n+1)个ADC时钟, 默认1(默认2个ADC时钟)                */
  21. #define SMPDUTY 20         /* 10~31, ADC模拟信号采样时间  (n+1)个ADC时钟, 默认10(默认11个ADC时钟)       */
  22.                            /* ADC转换时间: 10位ADC固定为10个ADC时钟, 12位ADC固定为12个ADC时钟.        */
  23. bit B_Timer2_OverFlow, flag_4ms, B_RUN, B_start;
  24. char step;
  25. u8 p16cnt, p17cnt, PWM_Value, PWM_Set, TimeOut, TimeIndex, Demagnetize, gpio_state, edgeState, inputSigCnt, delayCnt, startDone;
  26. u16 SIG_IN, PhaseTimeTmp[4], PWM_input, commutation_time[6], commutation_num, restart_delay, stallCnt, PhaseTime, commutate_interval;
  27. u32 commutation_time_sum;
  28. u16 ADC_Value;  //电位器ADC值
  29. typedef enum {
  30.   MOTOR_IDLE = 0,
  31.   MOTOR_PRE_POSITION,
  32.   MOTOR_STARTING,
  33.   MOTOR_STOP_STALL,
  34.   MOTOR_RESTART,
  35.   BYTE_LOW_VOLTAGE,
  36. } runFlagType;
  37. runFlagType run_flag;
  38. //========================================================================
  39. // 函数: u16        Get_ADC10bitResult(u8 channel))        //channel = 0~15
  40. //========================================================================
  41. u16 Get_ADC10bitResult(u8 channel)  //channel = 0~15
  42. {
  43.   u8 i;
  44.   ADC_RES = 0;
  45.   ADC_RESL = 0;
  46.   ADC_CONTR = 0x80 | ADC_START | channel;
  47.   NOP(5);  //
  48.            //        while((ADC_CONTR & ADC_FLAG) == 0)        ;        //等待ADC结束
  49.   i = 255;
  50.   while (i != 0) {
  51.     i--;
  52.     if ((ADC_CONTR & ADC_FLAG) != 0) break;  //等待ADC结束
  53.   }
  54.   ADC_CONTR &= ~ADC_FLAG;
  55.   return ((u16)ADC_RES * 256 + (u16)ADC_RESL);
  56. }
  57. void ADC_config(void)  //ADC初始化函数(为了使用ADC输入端做比较器信号, 实际没有启动ADC转换)
  58. {
  59.   // P1n_pure_input(0xc0);        //设置为高阻输入
  60.   // P0n_pure_input(0x0f);        //设置为高阻输入
  61.   // ADC_CONTR = 0x80 + 6;        //ADC on + channel
  62.   ADCCFG = RES_FMT + ADC_SPEED;
  63.   ADCTIM = CSSETUP + CSHOLD + SMPDUTY;
  64. }
  65. void delay_us(u8 us)  //N us延时函数
  66. {
  67.   do {
  68.     NOP(20);  //@24MHz
  69.   } while (--us);
  70. }
  71. void Delay_500ns(void) {
  72.   NOP(6);
  73. }
  74. #define USE_CONTEMPRATY_PWM 1  //互补PWM
  75. void commutate(void) {
  76.   EA = 0;
  77.   if (++step >= 6) step = 0;
  78.   switch (step) {
  79.     case 0:  // AB  PWM1, PWM2_L=1
  80.       PWMA_ENO = 0x00;
  81.       PWM1_L = 0;
  82.       PWM3_L = 0;
  83.       // Delay_500ns();
  84.       PWMA_ENO = 0x01 + 0x02 * USE_CONTEMPRATY_PWM;
  85.       PWM2_L = 1;
  86.       ADC_CONTR = 0x80 + 11;
  87.       if (!B_start) CMPCR1 = 0x8c + 0x10;
  88.       break;
  89.     case 1:  // AC  PWM1, PWM3_L=1
  90.       PWMA_ENO = 0x01 + 0x02 * USE_CONTEMPRATY_PWM;
  91.       PWM1_L = 0;
  92.       PWM2_L = 0;
  93.       // Delay_500ns();
  94.       PWM3_L = 1;
  95.       ADC_CONTR = 0x80 + 12;
  96.       if (!B_start) CMPCR1 = 0x8c + 0x20;
  97.       break;
  98.     case 2:  // BC  PWM2, PWM3_L=1
  99.       PWMA_ENO = 0x00;
  100.       PWM1_L = 0;
  101.       PWM2_L = 0;
  102.       // Delay_500ns();
  103.       PWMA_ENO = 0x04 + 0x08 * USE_CONTEMPRATY_PWM;
  104.       PWM3_L = 1;
  105.       ADC_CONTR = 0x80 + 13;
  106.       if (!B_start) CMPCR1 = 0x8c + 0x10;
  107.       break;
  108.     case 3:  // BA  PWM2, PWM1_L=1
  109.       PWMA_ENO = 0x04 + 0x08 * USE_CONTEMPRATY_PWM;
  110.       PWM2_L = 0;
  111.       PWM3_L = 0;
  112.       // Delay_500ns();
  113.       PWM1_L = 1;
  114.       ADC_CONTR = 0x80 + 11;
  115.       if (!B_start) CMPCR1 = 0x8c + 0x20;
  116.       break;
  117.     case 4:  // CA  PWM3, PWM1_L=1
  118.       PWMA_ENO = 0x00;
  119.       PWM2_L = 0;
  120.       PWM3_L = 0;
  121.       // Delay_500ns();
  122.       PWMA_ENO = 0x10 + 0x20 * USE_CONTEMPRATY_PWM;
  123.       PWM1_L = 1;
  124.       // ADC_Value = ((ADC_Value * 7) >> 3) + Get_ADC10bitResult(8);
  125.       ADC_CONTR = 0x80 + 12;
  126.       if (!B_start) CMPCR1 = 0x8c + 0x10;
  127.       break;
  128.     case 5:  // CB  PWM3, PWM2_L=1
  129.       PWMA_ENO = 0x10 + 0x20 * USE_CONTEMPRATY_PWM;
  130.       PWM1_L = 0;
  131.       PWM3_L = 0;
  132.       // Delay_500ns();
  133.       PWM2_L = 1;
  134.       ADC_CONTR = 0x80 + 13;
  135.       if (!B_start) CMPCR1 = 0x8c + 0x20;
  136.       break;
  137.     default:
  138.       break;
  139.   }
  140.   EA = 1;
  141. }
  142. void PWMA_init(void) {
  143.   PWM1 = PWM1_L = PWM2 = PWM2_L = PWM3 = PWM3_L = 0;
  144.   P1n_push_pull(0x3f);  // 0011 1111
  145.   PWMA_PSCR = 7;  // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
  146.   PWMA_DTR = 64;  // 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,
  147.   PWMA_ARR = 255;  // 自动重装载寄存器,  控制PWM周期
  148.   PWMA_CCER1 = 0;
  149.   PWMA_CCER2 = 0;
  150.   PWMA_SR1 = 0;
  151.   PWMA_SR2 = 0;
  152.   PWMA_ENO = 0;
  153.   PWMA_PS = 0;
  154.   PWMA_IER = 0;
  155.   PWMA_CCMR1 = 0x68;   // 通道模式配置, PWM模式1, 预装载允许
  156.   PWMA_CCR1 = 0;       // 比较值, 控制占空比(高电平时钟数)
  157.   PWMA_CCER1 |= 0x05;  // 开启比较输出, 高电平有效
  158.   PWMA_PS |= 0;        // 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1,
  159.   PWMA_CCMR2 = 0x68;    // 通道模式配置, PWM模式1, 预装载允许
  160.   PWMA_CCR2 = 0;        // 比较值, 控制占空比(高电平时钟数)
  161.   PWMA_CCER1 |= 0x50;   // 开启比较输出, 高电平有效
  162.   PWMA_PS |= (0 << 2);  // 选择IO, 0:选择P1.2 P1.3, 1:选择P2.2 P2.3, 2:选择P6.2 P6.3,
  163.   PWMA_CCMR3 = 0x68;    // 通道模式配置, PWM模式1, 预装载允许
  164.   PWMA_CCR3 = 0;        // 比较值, 控制占空比(高电平时钟数)
  165.   PWMA_CCER2 |= 0x05;   // 开启比较输出, 高电平有效
  166.   PWMA_PS |= (0 << 4);  // 选择IO, 0:选择P1.4 P1.5, 1:选择P2.4 P2.5, 2:选择P6.4 P6.5,
  167.   PWMA_CCMR4 = 0x68;   // 通道模式配置, PWM模式1, 预装载允许
  168.   PWMA_CCER2 |= 0x50;  // 开启比较输出, 高电平有效
  169.   PWMA_CCR4 = 0xF0;    //PWM4触发中断, 同步采样, 在PWM周期快结束时对比较器采样,这时候没有PWM干扰
  170.   PWMA_BKR = 0x80;  // 主输出使能 相当于总开关
  171.   PWMA_CR1 = 0x81;  // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
  172.   PWMA_EGR = 0x01;  //产生一次更新事件, 清除计数器和与分频计数器, 装载预分频寄存器的值
  173. }
  174. void UART_init() {
  175.   SCON = 0x50;     //8位数据,可变波特率
  176.   AUXR = 0x40;     //定时器时钟1T模式
  177.   TMOD = 0x00;     //设置定时器模式
  178.   TL1 = BRT;       //设置定时初始值
  179.   TH1 = BRT >> 8;  //设置定时初始值
  180.   TR1 = 1;         //定时器1开始计时
  181. }
  182. void CMP_init(void) {  //比较器初始化程序
  183.   CMPCR1 = 0x8C;       // 1000 1100 打开比较器,P3.6作为比较器的反相输入端,ADC引脚作为正输入端
  184.   CMPCR2 = 60;         //60个时钟滤波   比较结果变化延时周期数, 0~63
  185. }
  186. u8 PhaseTimeTMP2;
  187. void CMP_ISR(void) interrupt 21 {  //比较器中断函数, 检测到反电动势过0事件
  188.   u8 i;
  189.   CMPCR1 &= ~0x40;  // 需软件清除中断标志位
  190.   CMPCR1 = 0x8C;    // 关中断
  191.   if (Demagnetize == 0)  //消磁后才检测过0事件,   Demagnetize=1:需要消磁, =2:正在消磁, =0已经消磁
  192.   {
  193.     // P17=(++p17cnt)&1;
  194.     AUXR &= ~0x10;          //停止定时器
  195.     if (B_Timer2_OverFlow)  //切换时间间隔(Timer3)有溢出
  196.     {
  197.       B_Timer2_OverFlow = 0;
  198.       PhaseTime = 18000;  //换相时间最大8ms, 2212电机12V空转最高速130us切换一相(200RPS 12000RPM), 480mA
  199.     } else {
  200.       PhaseTime = (((u16)T2H << 8) + T2L);      //单位为1us
  201.       if (PhaseTime >= 8000) PhaseTime = 8000;  //换相时间最大8ms, 2212电机12V空转最高速130us切换一相(200RPS 12000RPM), 480mA
  202.     }
  203.     T2H = 0;
  204.     T2L = 0;
  205.     AUXR |= 0x10;                                                              //开定时器
  206.     commutation_time[TimeIndex] = PhaseTime;                                   //保存一次换相时间
  207.     if (++TimeIndex >= 4) TimeIndex = 0;                                       //累加8次
  208.     for (PhaseTime = 0, i = 0; i <= 3; i++) PhaseTime += commutation_time[i];  //求换相时间累加和
  209.     PhaseTime = PhaseTime >> 3;                                                //换相时间的平均值的一半, 即30度电角度
  210.     if ((PhaseTime >= 30) && (PhaseTime <= 15000)) TimeOut = 2;                //堵转超时
  211.     else PhaseTime = 30;
  212.     PhaseTime = 0 - PhaseTime * 3;  //T0是1/3us每个计数
  213.     TR0 = 0;
  214.     TH0 = (u8)(PhaseTime >> 8);  //装载30度角延时
  215.     TL0 = (u8)PhaseTime;
  216.     TR0 = ET0 = Demagnetize = 1;  //1:需要消磁, 2:正在消磁, 0已经消磁
  217.   }
  218. }
  219. void Timer0_init(void) {  //Timer0初始化函数
  220.   Timer0_16bit();
  221.   Timer0_12T();
  222.   TH0 = 0;
  223.   TL0 = 0;
  224.   ET0 = 1;  // 允许T0中断
  225. }
  226. void Timer0_ISR(void) interrupt TIMER0_VECTOR {
  227.   TR0 = 0;
  228.   if (Demagnetize == 1)  //标记需要消磁. 每次检测到过0事件后第一次中断为30度角延时, 设置消磁延时.
  229.   {
  230.     TH0 = (u8)((65536UL - 60) >> 8);  //装载消磁延时20us左右
  231.     TL0 = (u8)(65536UL - 60);
  232.     TR0 = 1;
  233.     Demagnetize = 2;  //1:需要消磁, 2:正在消磁, 0已经消磁
  234.     if (B_RUN)        //电机正在运行
  235.     {
  236.       commutate();
  237.     }
  238.   } else if (Demagnetize == 2) {
  239.     Demagnetize = 0;              //1:需要消磁, 2:正在消磁, 0已经消磁
  240.     if (step & 1) CMPCR1 = 0xAC;  //上升沿中断
  241.     else CMPCR1 = 0x9C;           //下降沿中断
  242.   }
  243. }
  244. void Timer2_init(void) {
  245.   TM2PS = 2;
  246.   AUXR &= ~0x1c;  //0001 1100 //停止计数, 定时模式, 12T模式
  247.   T2H = 0;
  248.   T2L = 0;
  249.   INTCLKO &= ~0x04;  // 不输出时钟
  250.   // IE2 = ET2;        //允许中断
  251.   AUXR |= 0x10;  //定时器2开始运行
  252. }
  253. void Timer2_Isr(void) interrupt TIMER2_VECTOR {
  254.   B_Timer2_OverFlow = 1;  //溢出标志
  255. }
  256. void PWMB_init(void) {  //检测输入PWM用
  257.   PWMB_PS = 4;          //输出选择PWM6_2
  258.   PWMB_PSCR = 1;        //分频
  259.   //CC5捕获TI6上升沿,CC6捕获TI6下降沿, 读取油门信号脉宽
  260.   PWMB_CCER1 = 0x00;   //先复位
  261.   PWMB_CCMR1 = 0x02;   //CC5为输入模式,且映射到TI6FP5上
  262.   PWMB_CCMR2 = 0x01;   //CC6为输入模式,且映射到TI6FP6上
  263.   PWMB_CCER1 = 0x11;   //使能CC5/CC6上的捕获功能
  264.   PWMB_CCER1 |= 0x00;  //设置捕获极性为CC5的上升沿
  265.   PWMB_CCER1 |= 0x20;  //设置捕获极性为CC6的下降沿
  266.   PWMB_CCER2 = 0x00;   //写CCMRx前必须先清零CCERx关闭通道
  267.   PWMB_CCMR3 = 0x60;   //设置CC7为PWM输出模式
  268.   PWMB_CCER2 = 0x01;   //使能CC7通道
  269.   PWMB_CCR3 = 0xEFFF;  //设置占空比时间
  270.   // PWMB_IER = 1<<2; //使能捕获中断
  271.   // PWMB_IER = 8;       //任务定时器中断
  272.   PWMB_CR1 = 0x01;  //使能计数器
  273. }
  274. void startMotor() {
  275.   u16 temp_commutation_time = (u16)(T2H << 8) | T2L;
  276.   u8 zcFound = 0;    //反电势过零信号
  277.   u8 pin_state = 0;  //比较器状态计数, 连续8次相同状态才认为是有效比较器信号
  278.   switch (run_flag) {
  279.     case MOTOR_PRE_POSITION:
  280.       {
  281.         CMPCR1 = 0x8C;  // 关比较器中断
  282.         ET0 = IE2 = 0;  // 关闭定时器3 定时器4中断
  283.         // 设置启动占空比
  284.         PWM_Value = STARTUP_POWER;
  285.         PWMA_CCR1L = STARTUP_POWER;
  286.         PWMA_CCR2L = STARTUP_POWER;
  287.         PWMA_CCR3L = STARTUP_POWER;
  288.         if (((T2H << 8) | T2L) >= STARTUP_INTERVAL) {
  289.           commutation_time[0] = 6000;
  290.           commutation_time[1] = 6000;
  291.           commutation_time[2] = 6000;
  292.           commutation_time[3] = 6000;
  293.           commutation_time[4] = 6000;
  294.           commutation_time[5] = 6000;
  295.           commutation_time_sum = commutation_time[0] + commutation_time[1] + commutation_time[2] + commutation_time[3];
  296.           // 清空定时器计数器值
  297.           AUXR &= ~0x10;  // 停止定时器
  298.           T2L = 0;
  299.           T2H = 0;
  300.           AUXR |= 0x10;  // 开启定时器
  301.           commutate();
  302.           run_flag = MOTOR_STARTING;
  303.           stallCnt = 0;
  304.           commutation_num = 0;
  305.           // SBUF=(T2H<<8)|T2L;
  306.         }
  307.       }
  308.       break;
  309.     case MOTOR_STARTING:
  310.       {
  311.         // 通过位移的方式, 将电平数据存入变量中, 连续8次检测到相同电平才认为有效
  312.         gpio_state = (gpio_state << 1) | edgeState;
  313.         if (step & 1) {
  314.           // 上升沿
  315.           if (gpio_state == 0xFF)  //(gpio_state == 0xFF)
  316.           {
  317.             zcFound = 1;
  318.             gpio_state = 0xFF;
  319.           }
  320.         } else {
  321.           //下降沿
  322.           if (gpio_state == 0)  //gpio_state == 0
  323.           {
  324.             zcFound = 1;
  325.             gpio_state = 0x00;
  326.           }
  327.         }
  328.         if (zcFound) {
  329.           // P17=(p17cnt++)&1;
  330.           AUXR &= ~0x10;  // 停止定时器
  331.           T2L = 0;
  332.           T2H = 0;
  333.           AUXR |= 0x10;  // 开启定时器
  334.           // 堵转计数清空
  335.           stallCnt = 0;
  336.           commutation_num++;
  337.           commutation_time[step] = temp_commutation_time;
  338.           //滤波
  339.           commutation_time_sum = commutation_time[0] + commutation_time[1] + commutation_time[2] + commutation_time[3] + commutation_time[4] + commutation_time[5];
  340.           // 等待30度
  341.           commutate_interval = commutation_time_sum / 15;  //这里应该是/12才对, 但是发现15好像好一点
  342.           while (((u16)(T2H << 8) | T2L) <= commutate_interval - 450)
  343.             ;  //-450补偿检测换向的时间
  344.           commutate();
  345.           // P16=1;
  346.           if ((commutation_num >= 11) && (commutation_time_sum <= 10000)) {
  347.             // P16=0;
  348.             commutation_time[0] = commutation_time[1] = commutation_time[2] = commutation_time[3] = commutation_time_sum / 6;
  349.             startDone = 1;
  350.             B_start = 0;
  351.             B_RUN = 1;
  352.             Demagnetize = 0;
  353.             TimeOut = 200;
  354.             PWM_Value = STARTUP_POWER;
  355.             // PWMA_CCR1L = 0;
  356.             // PWMA_CCR2L = 0;
  357.             // PWMA_CCR3L = 0;
  358.             delay_us(50);
  359.             CMPCR1 &= ~0x40;              // 清除中断标志位
  360.             if (step & 1) CMPCR1 = 0xAC;  //上升沿中断
  361.             else CMPCR1 = 0x9C;           //下降沿中断
  362.             IE2 |= (1 << 5);              //允许T2中断
  363.             return;
  364.           }
  365.         } else if (((u16)(T2H << 8) | T2L) >= STARTUP_INTERVAL) {
  366.           AUXR &= ~0x10;  // 停止定时器
  367.           T2L = 0;
  368.           T2H = 0;
  369.           AUXR |= 0x10;                   // 开启定时器
  370.           commutate();                    //P17=(p17cnt++)&1;
  371.           run_flag = MOTOR_PRE_POSITION;  //MOTOR_PRE_POSITION
  372.         }
  373.       }
  374.       break;
  375.     case MOTOR_IDLE:  //MOTOR_IDLE
  376.       {
  377.         B_RUN = 0;
  378.         PWMA_CCR1L = 0;
  379.         PWMA_CCR2L = 0;
  380.         PWMA_CCR3L = 0;
  381.       }
  382.       break;
  383.   }
  384. }
  385. void PWMA_Isr() interrupt PWMA_VECTOR  // CMP sample, read CMP state
  386. {
  387.   edgeState = CMPCR1 & 1;
  388.   PWMA_SR1 = 0;           //clear INT flag
  389.   PWMA_IER &= ~(1 << 4);  //disable PWMA 4 INT
  390.   startMotor();
  391.   if (B_RUN) PWMA_IER = 0;  //disable PWMA 4 INT
  392.   else PWMA_IER = 1 << 4;   //enable PWMA 4 INT
  393. }
  394. void delay_ms(u8 dly) {
  395.   u16 j;
  396.   do {
  397.     j = MAIN_Fosc / 10000;
  398.     while (--j)
  399.       ;
  400.   } while (--dly);
  401. }
  402. /*********************   main   *************************/
  403. void main(void) {
  404.   PWM1 = PWM1_L = PWM2 = PWM2_L = PWM3 = PWM3_L = 0;
  405.   P1n_push_pull(0x3f);  // 0011 1111
  406.   P_SW2 |= 0x80;        //SFR enable
  407.   PWMA_init();
  408.   PWMB_init();
  409.   CMP_init();
  410.   Timer0_init();  // Timer0初始化函数
  411.   Timer2_init();  // Timer2初始化函数
  412.   UART_init();
  413.   ADC_config();
  414.   PWM_Set = 0;
  415.   TimeOut = 0;
  416.   EA = 1;  // 打开总中断
  417.   PWMB_SR1 = 0;
  418.   ADC_Value = 0;
  419.   delay_ms(250);
  420.   PWMB_SR1 &= ~0x04;
  421.   while (1) {
  422.     if (PWMB_SR1 & 0x04) {
  423.       SIG_IN = PWMB_CCR2 - PWMB_CCR1;  //PWM输入捕获, 差值即为输入信号高电平宽度
  424.                                        // SBUF=SIG_IN;
  425.       if (SIG_IN < 0x08EC) SIG_IN = 0x08EC;
  426.       if (SIG_IN > 0x1146) SIG_IN = 0x1146;
  427.       SIG_IN = (((SIG_IN - 0x8EC) << 3) / 0x43);  //换算为8位整数
  428.       PWM_Set = SIG_IN;
  429.       // SBUF=SIG_IN;
  430.       if (B_RUN && (startDone == 0) && (B_start == 0)) {
  431.         PWMA_CCR1L = PWM_Set;
  432.         PWMA_CCR2L = PWM_Set;
  433.         PWMA_CCR3L = PWM_Set;
  434.       }
  435.     }
  436.     if (RI == 1) {
  437.       RI = 0;
  438.       if (SBUF == 0x7f) IAP_CONTR = 0X60;
  439.     }  //自动下载
  440.     if (PWMB_SR1 & 8)  // 4ms时
  441.     {
  442.       PWMB_SR1 &= ~8;
  443.       if (TimeOut != 0) {
  444.         if (--TimeOut == 0)  //堵转超时
  445.         {
  446.           CMPCR1 = 0x8C;  // 关比较器中断
  447.           B_start = B_RUN = PWM_Value = 0;
  448.           run_flag = MOTOR_IDLE;
  449.         }
  450.       }
  451.       if (!B_RUN && (PWM_Set >= STARTUP_THROTTLE))  // 占空比大于设定值, 并且电机未运行, 则启动电机
  452.       {
  453.         CMPCR1 = 0x8C;      // 关比较器中断
  454.         PWMA_IER = 1 << 4;  //使能PWMA 4 中断, 让过零采样与PWM同步, 避开PWM干扰
  455.         B_start = 1;        //启动模式
  456.         if (run_flag == MOTOR_IDLE) {
  457.           AUXR |= 0x10;  // 开启定时器2
  458.           run_flag = MOTOR_PRE_POSITION;
  459.         }
  460.       } else if (PWM_Set == 0) run_flag = MOTOR_IDLE;
  461.       if (B_RUN && startDone)  //启动完成后让油门缓慢变化
  462.       {
  463.         if (PWM_Value < PWM_Set) PWM_Value++;  //油门跟随电位器
  464.         if (PWM_Value > PWM_Set) PWM_Value--;
  465.         if (++startDone >= 150) startDone = 0;
  466.         PWMA_CCR1L = PWM_Value;
  467.         PWMA_CCR2L = PWM_Value;
  468.         PWMA_CCR3L = PWM_Value;
  469.       } else startDone = 0;
  470.       PWMB_SR1 &= ~0x04;
  471.     }
  472.   }
  473. }
复制代码










实物图 (1).jpg
实物图 (2).jpg

STC小电调.epro

81.56 KB, 下载次数: 12

2 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-05-21 17:06:00
已绑定手机

1

主题

5

回帖

43

积分

新手上路

积分
43
发表于 2025-5-8 14:48:26 | 显示全部楼层
麻烦问一下,这三个是?
截图202505081447544396.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:6
  • 最近打卡:2025-05-21 17:06:00
已绑定手机

1

主题

5

回帖

43

积分

新手上路

积分
43
发表于 2025-5-8 15:02:08 | 显示全部楼层
是这三个电阻吗?
截图202505081501314742.jpg

点评

对,就是这几个上拉电阻,要用0603的,功率大一点  详情 回复 发表于 2025-5-9 21:17
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-06-15 00:11:09
已绑定手机

5

主题

7

回帖

166

积分

荣誉版主

积分
166
发表于 2025-5-9 21:17:30 | 显示全部楼层
Jeffr*** 发表于 2025-5-8 15:02
是这三个电阻吗?

对,就是这几个上拉电阻,要用0603的,功率大一点
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-06-15 09:46:00

733

主题

1万

回帖

1万

积分

管理员

积分
16603
发表于 2025-5-15 12:41:52 | 显示全部楼层
oneshot125,是为了发送速度更快而定义的协议,跟老的协议类似(1~2ms宽度),
就是速度快了8(125~250us)倍或16倍(62.5~125us),
通常用在要求响应速度快的穿越机上。属于脉位调制(PPM)。

DShot150/300/600/1200是数字协议,使用数字通信方式栓地控制数据,
每个目标16位数据(11位油门信号 + 1位电调信息回传 + 4位循环冗余校验),
150/300/600/1200表示位速率,
比如DShot600表示600Kbit/S,一位时间为1.667us,
数据0高电平0.625us(占空比为37.5%),数据1高电平1.25us(占空比为75%)。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:455
  • 最近打卡:2025-06-10 13:10:51
已绑定手机

236

主题

340

回帖

1650

积分

金牌会员

积分
1650
发表于 2025-5-17 08:18:05 | 显示全部楼层
截图202505170816119803.jpg
你这反电动势有点问题啊?
ADC引脚上的电压要将近6V了

点评

对,这个确实有点问题,从别的电路图改过来忘了改电源了,实际是用2节锂电供电,再高得换分压电阻比值  详情 回复 发表于 2025-5-17 18:22
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-06-15 00:11:09
已绑定手机

5

主题

7

回帖

166

积分

荣誉版主

积分
166
发表于 2025-5-17 18:22:20 | 显示全部楼层
QQ6243*** 发表于 2025-5-17 08:18
你这反电动势有点问题啊?
ADC引脚上的电压要将近6V了

对,这个确实有点问题,从别的电路图改过来忘了改电源了,实际是用2节锂电供电,再高得换分压电阻比值
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:455
  • 最近打卡:2025-06-10 13:10:51
已绑定手机

236

主题

340

回帖

1650

积分

金牌会员

积分
1650
发表于 2025-5-17 20:05:13 | 显示全部楼层
bh*** 发表于 2025-5-17 18:22
对,这个确实有点问题,从别的电路图改过来忘了改电源了,实际是用2节锂电供电,再高得换分压电阻比值 ...

我玩无刷电机已经有大半年了,现在已经在哪吃灰了,还没有驱动成功。能不能指导我一下,我也是用官方的例程改的,还是有不解之处,能不能加个QQ
6-2-4-3-5-3-7-6-5

点评

先直接拿梁工原版硬件软件做一个一模一样的,能正常转起来再一点点修改。我加你了。  详情 回复 发表于 2025-5-18 20:57
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-06-15 00:11:09
已绑定手机

5

主题

7

回帖

166

积分

荣誉版主

积分
166
发表于 2025-5-18 20:57:17 | 显示全部楼层
QQ6243*** 发表于 2025-5-17 20:05
我玩无刷电机已经有大半年了,现在已经在哪吃灰了,还没有驱动成功。能不能指导我一下,我也是用官方的例 ...

先直接拿梁工原版硬件软件做一个一模一样的,能正常转起来再一点点修改。我加你了。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2025-05-22 09:42:38
已绑定手机

0

主题

8

回帖

30

积分

新手上路

积分
30
发表于 2025-5-20 17:06:26 | 显示全部楼层
bh*** 发表于 2025-5-18 20:57
先直接拿梁工原版硬件软件做一个一模一样的,能正常转起来再一点点修改。我加你了。 ...

这个是逐飞+梁工的结合啊

点评

对,把逐飞的启动改了一下放进来了  详情 回复 发表于 2025-5-25 00:35
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-6-16 04:09 , Processed in 0.152550 second(s), 112 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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