找回密码
 立即注册
查看: 164|回复: 1

AI8H1K08航模电调 适用于多旋翼固定翼等 低成本

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:32
  • 最近打卡:2025-06-08 17:27:57
已绑定手机

5

主题

7

回帖

112

积分

荣誉版主

积分
112
发表于 2025-5-31 17:38:48 | 显示全部楼层 |阅读模式
在梁工方案基础上修改做的一个电调(这是原帖),目前测试应该没什么大问题,水平有限,也许还有bug没发现,欢迎交流讨论互相学习。
AI8H1K08做的无感方波电调,大小2*2CM
接XXD2212 1400KV电机测试正常,电流最大可以20A左右,再高就烫手
适用于用于多旋翼、固定翼、小风扇等,智能车的下压风扇应该也能用,我没详细看规则
用三个5毛钱SP2011做功率MOS的话总成本只要3块钱,推荐用2块钱的AGM305MD更好
可以输入舵机信号或者OneShot125信号,可以打开或者关闭互补PWM,要在程序里设置再编译
改进的启动算法,比直接盲启动成功率更高
原理图.png
PCB (1).png
PCB (2).png
焊接 (2).jpg
焊接 (4).jpg
焊接 (3).jpg
焊接 (1).jpg
测试视频

keil工程
keil工程.rar (90.9 KB, 下载次数: 5)
原理图和PCB
ProPrj_stc8h1k电调_2025-05-31.epro (275.08 KB, 下载次数: 23)

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




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

使用道具 举报 送花

3

主题

832

回帖

375

积分

等待验证会员

积分
375
发表于 2025-5-31 17:48:00 | 显示全部楼层
这是一篇关于智能车(如智能车、多旋翼无人机或固定翼无人机)的测试报告,涉及电调、电机测试、功率管理、启动算法等技术细节。以下是文章的详细内容:

1. 电调测试与结果
使用STC8H1K08航模电调,尺寸为22cm,测试表明电调效果良好,适用于多旋翼、固定翼和小风扇等用途。接上XXD2212 1400KV电机,测试正常,最大电流为20A,略高时可能会烫手。

2. 电机测试
测试后发现电机运行正常,最大电流为20A,超出范围时会发热。电机适用于多旋翼、固定翼、小风扇等用途,特别是智能车的下压风扇,建议详细查看规则以确认适用性。

3. 应用用途
该智能车适用于以下用途:
多旋翼无人机:在旋翼的无感电调和电机驱动下,实现高效飞行。
固定翼无人机:适合在固定翼模式下进行稳定飞行。
小风扇:可用于小型风扇的控制和调节。
智能车:下压风扇的稳定控制,确保车辆在低速行驶时的稳定性。

4. 功率管理与改进
使用三个5毛钱SP2011功率MOS,总成本为3元,推荐使用2元的AGM305MD。改进后的启动算法显著提高了成功率,特别是在低电流和高电流模式下的成功率。

5. 初步测试视频与原理图
视频展示了该智能车的初步测试场景,包括电机驱动、电调操作以及小风扇的控制。原理图和PCB文档附上后,可以进一步验证测试效果。

6. 可用MOS推荐
根据测试,以下MOS推荐:
AGM305MD:内阻最小,VGS最大20V,适合2-3节锂电池供电,22元一个。
AGM400L:VGS最大25V,适合4-5节锂电池供电,25元一个。

7. 总结
该智能车通过电调、电机测试、功率管理等技术,具备稳定性和高效性,适用于多种飞行和调节需求。未来可以参考Keil工程和原理图,进一步验证其性能和适用性。

以上内容涵盖了文章的核心内容,保持了专业性的同时,也确保了信息的完整性。

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

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-6-9 13:00 , Processed in 0.219583 second(s), 57 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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