AddFunction.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /**
  2. * @copyright None
  3. * @file AddFunction.c
  4. * @author Comment Vivre
  5. * @date 2024-08-28
  6. * @brief None
  7. */
  8. #include <MyProject.h>
  9. /* Public variables --------------------------------------------------------- */
  10. bit isCtrlPowOn = false; ///< 开关机控制
  11. PWMINPUTCAL xdata mcPwmInput; ///< PWM捕获结构体变量
  12. FOCCTRL xdata mcFocCtrl; ///< FOC电机控制相关结构体变量
  13. debugONOFFTypeDef xdata debug_ONOFFTest; ///< ONOFF启停测试小工具结构体变量
  14. RefRamp data LoopRefRamp; ///< 控制指令爬坡结构体相关变量
  15. /**
  16. @brief 对变量取16位的绝对值
  17. @param[in] value
  18. @return 绝对值
  19. @date 2022-07-13
  20. */
  21. uint16 Abs_F16(int16 value)
  22. {
  23. if (value < 0)
  24. {
  25. return (-value);
  26. }
  27. else
  28. {
  29. return (value);
  30. }
  31. }
  32. /**
  33. @brief 对变量取32位的绝对值
  34. @param[in] value
  35. @return 绝对值
  36. @date 2022-07-13
  37. */
  38. uint32 Abs_F32(int32 value)
  39. {
  40. if (value < 0)
  41. {
  42. return (-value);
  43. }
  44. else
  45. {
  46. return (value);
  47. }
  48. }
  49. /**
  50. @brief PWM调速信号计算,本例程提供Duty计算,如需频率信号可自行使用mcPwmInput.Period周期值计算
  51. @date 2022-07-14
  52. */
  53. void PWMDutyCal(void)
  54. {
  55. static uint16 dutyTemp = 0;
  56. if (mcPwmInput.isUpdate) // 有新的duty更新
  57. {
  58. if ((Abs_F32(mcPwmInput.TimerDR - mcPwmInput.TimerDROld) < 0xFF) // 误差在1个Byte之间再处理
  59. && (Abs_F32(mcPwmInput.TimerARROld - mcPwmInput.TimerARR) < 0xFF)) // 误差在1个Byte之间再处理
  60. {
  61. mcPwmInput.Compare = mcPwmInput.TimerDR; // 读取DR与ARR值
  62. mcPwmInput.Period = mcPwmInput.TimerARR;
  63. mcPwmInput.Duty = DivQ_L_MDU(mcPwmInput.Compare >> 1, 0x0000, mcPwmInput.Period);
  64. /***速度随PWM增大而增大***/
  65. #if (PWMDUTY_POLARITY == NegaPWMDUTY)
  66. {
  67. dutyTemp = 32768 - mcPwmInput.Duty;
  68. }
  69. /***速度随PWM增大而减小***/
  70. #else
  71. {
  72. dutyTemp = mcPwmInput.Duty;
  73. }
  74. #endif
  75. if ((dutyTemp > ONPWMDuty) && (dutyTemp <= OFFPWMDutyHigh))
  76. {
  77. isCtrlPowOn = 1; // 开机
  78. }
  79. else if ((dutyTemp < OFFPWMDuty) || (dutyTemp > OFFPWMDutyHigh))
  80. {
  81. isCtrlPowOn = 0; // 关机
  82. }
  83. else
  84. {
  85. // 不做处理,保持前一个状态
  86. }
  87. // 转速曲线计算
  88. if (isCtrlPowOn)
  89. {
  90. if (dutyTemp <= MINPWMDuty)
  91. {
  92. mcFocCtrl.Ref = MOTOR_SPEED_MIN_RPM;
  93. }
  94. else if (dutyTemp >= MAXPWMDuty)
  95. {
  96. mcFocCtrl.Ref = MOTOR_SPEED_MAX_RPM;
  97. }
  98. else
  99. {
  100. mcFocCtrl.Ref = MOTOR_SPEED_MIN_RPM + SPEED_K * (dutyTemp - MINPWMDuty);
  101. }
  102. }
  103. else
  104. {
  105. mcFocCtrl.Ref = 0;
  106. }
  107. }
  108. mcPwmInput.isUpdate = 0;
  109. mcPwmInput.TimerDROld = mcPwmInput.TimerDR; // 将此次比较值赋值给上次比较值
  110. mcPwmInput.TimerARROld = mcPwmInput.TimerARR; // 将此次周期值赋值给上次周期值
  111. }
  112. }
  113. /**
  114. @brief VSP调速信号处理
  115. @date 2022-07-14
  116. */
  117. void VSPSample(void)
  118. {
  119. static int16 VSP = 0;
  120. VSP = LPFFunction(ADC7_DR, VSP, 10); // 注意低通滤波器系数范围为0---127
  121. if (VSP > ONPWMDuty)
  122. {
  123. isCtrlPowOn = 1; // 开机
  124. }
  125. else if ((VSP < OFFPWMDuty)) // 电机停机
  126. {
  127. isCtrlPowOn = 0; // 关机
  128. }
  129. // 转速曲线计算
  130. if (isCtrlPowOn) //
  131. {
  132. #if (MOTOR_CTRL_MODE == SPEED_LOOP_CONTROL)
  133. {
  134. if (VSP <= MINPWMDuty) // 最小转速运行
  135. {
  136. mcFocCtrl.Ref = MOTOR_SPEED_MIN_RPM;
  137. }
  138. else if (VSP < MAXPWMDuty) // 调速
  139. {
  140. mcFocCtrl.Ref = MOTOR_SPEED_MIN_RPM + SPEED_K * (VSP - MINPWMDuty);
  141. }
  142. else // 最大转速运行
  143. {
  144. mcFocCtrl.Ref = MOTOR_SPEED_MAX_RPM;
  145. }
  146. }
  147. #endif
  148. }
  149. else
  150. {
  151. mcFocCtrl.Ref = 0;
  152. }
  153. }
  154. /**
  155. * @function GetSrefKeyGear
  156. * @brief 根据电压挡位确定输出
  157. * @param[in] None
  158. * @return None
  159. * @date 2024-08-28
  160. */
  161. void GetSrefKeyGear(void)
  162. {
  163. static uint8 powONHoldCnt = 0;
  164. static uint8 powOFFHoldCnt = 0;
  165. if (isCtrlPowOn) // 开机状态
  166. {
  167. if (mcFocCtrl.SREFValue < VSP_OFF_MIN)
  168. {
  169. powOFFHoldCnt ++;
  170. if (powOFFHoldCnt > 50)
  171. {
  172. powOFFHoldCnt = 0;
  173. isCtrlPowOn = false; // 关机
  174. }
  175. powONHoldCnt = 0;
  176. }
  177. }
  178. else // 关机状态
  179. {
  180. if (mcFocCtrl.SREFValue > VSP_ON_MIN)
  181. {
  182. powONHoldCnt ++;
  183. if (powONHoldCnt > 50)
  184. {
  185. powONHoldCnt = 0;
  186. isCtrlPowOn = true; // 开机
  187. }
  188. powOFFHoldCnt = 0;
  189. }
  190. }
  191. //转速曲线计算
  192. if (isCtrlPowOn)
  193. {
  194. // 计算公式为
  195. // Ref = ( 区间UQ差 / 区间调速电压差) * (VSP - 调速下限) + 区间最小UQ值
  196. if (mcFocCtrl.SREFValue <= 1408)
  197. { mcFocCtrl.Ref = _Q15(0.120); }
  198. else if (mcFocCtrl.SREFValue <= 11640 )
  199. { mcFocCtrl.Ref = 0.864 * (mcFocCtrl.SREFValue - 1408) + _Q15(0.120); }
  200. else if (mcFocCtrl.SREFValue <= 15530 )
  201. { mcFocCtrl.Ref = 1.238 * (mcFocCtrl.SREFValue - 11640) + _Q15(0.390); }
  202. else if (mcFocCtrl.SREFValue <= 19480 )
  203. { mcFocCtrl.Ref = 1.543 * (mcFocCtrl.SREFValue - 15530) + _Q15(0.537); }
  204. else if (mcFocCtrl.SREFValue <= 21962 )
  205. { mcFocCtrl.Ref = 1.755 * (mcFocCtrl.SREFValue - 19480) + _Q15(0.723); }
  206. else if (mcFocCtrl.SREFValue <= 23368 )
  207. { mcFocCtrl.Ref = 2.004 * (mcFocCtrl.SREFValue - 21962) + _Q15(0.856); }
  208. else
  209. { mcFocCtrl.Ref = _Q15(0.942); }
  210. }
  211. else
  212. { mcFocCtrl.Ref = 0; }
  213. }
  214. /**
  215. @brief 启停测试工具,用于测试启动可靠性
  216. @date 2022-07-14
  217. */
  218. void ONOFF_Test(void)
  219. {
  220. if (debug_ONOFFTest.State == 1) // 开机状态
  221. {
  222. debug_ONOFFTest.TimeCnt++;
  223. if (debug_ONOFFTest.TimeCnt > ONOFFTEST_ON_TIME)
  224. {
  225. debug_ONOFFTest.Times++; // 启停次数+1
  226. debug_ONOFFTest.State = 0; // 切换到关机状态
  227. debug_ONOFFTest.TimeCnt = 0;
  228. mcFocCtrl.Ref = 0; // 目标值也给0
  229. isCtrlPowOn = 0; // 关机
  230. }
  231. }
  232. else // 关机状态
  233. {
  234. debug_ONOFFTest.TimeCnt++;
  235. if (debug_ONOFFTest.TimeCnt > ONOFFTEST_OFF_TIME)
  236. {
  237. debug_ONOFFTest.TimeCnt = 0;
  238. if (mcState != mcFault)
  239. {
  240. debug_ONOFFTest.State = 1; // 切换到开机状态
  241. mcFocCtrl.Ref = ONOFFTEST_REF;
  242. isCtrlPowOn = 1; // 开机
  243. mcFocCtrl.PowerLimitValue = POWERLPFLIMIT;
  244. }
  245. }
  246. }
  247. }
  248. /**
  249. @brief 调速信号处理包含:开关机控制、将调速信号处理成控制目标给定信号
  250. @date 2022-07-14
  251. */
  252. void GetTargetRef(void)
  253. {
  254. #if (SPEED_MODE == PWMMODE)
  255. {
  256. PWMDutyCal();
  257. mcFocCtrl.PowerLimitValue = POWERLPFLIMIT;
  258. }
  259. #elif (SPEED_MODE == SREFMODE)
  260. {
  261. VSPSample();
  262. mcFocCtrl.PowerLimitValue = POWERLPFLIMIT;
  263. }
  264. #elif (SPEED_MODE == SREFKEYMODE)
  265. {
  266. GetSrefKeyGear();
  267. mcFocCtrl.PowerLimitValue = POWERLPFLIMIT;
  268. }
  269. #elif (SPEED_MODE == NONEMODE)
  270. {
  271. isCtrlPowOn = true;
  272. mcFocCtrl.Ref = NONE_MODE_SPEED;
  273. mcFocCtrl.PowerLimitValue = POWERLPFLIMIT;
  274. }
  275. #elif (SPEED_MODE == ONOFFTEST)
  276. {
  277. ONOFF_Test();
  278. }
  279. #endif
  280. }
  281. /**
  282. @brief 外部闭环控制函数,示例代码提供 电流环,速度环,功率环,UQ控制示例代码,可根据需要自行修改
  283. 建议使用默认1ms周期运行
  284. @date 2022-07-14
  285. */
  286. void LoopResponse(void)
  287. {
  288. static int16 refRampOut = 0;
  289. switch (mcFocCtrl.CtrlMode)
  290. {
  291. case 0:
  292. {
  293. if (mcFocCtrl.SpeedFlt > MOTOR_LOOP_RPM)
  294. {
  295. mcFocCtrl.Mode0HoldCnt++;
  296. if (mcFocCtrl.Mode0HoldCnt > 10)
  297. {
  298. FOC_QKP = QKP;
  299. FOC_QKI = QKI;
  300. FOC_DKP = DKP;
  301. FOC_DKI = DKI;
  302. // FOC_THECOMP = _Q15(-25.0 / 180.0); // SMO 估算补偿角
  303. // 启动电流环与外环给定衔接
  304. #if (MOTOR_CTRL_MODE == SPEED_LOOP_CONTROL)
  305. LoopRefRamp.Out = mcFocCtrl.SpeedFlt;
  306. #elif (MOTOR_CTRL_MODE == POWER_LOOP_CONTROL)
  307. LoopRefRamp.Out = mcFocCtrl.Power;
  308. #elif (MOTOR_CTRL_MODE == UQ_LOOP_CONTROL)
  309. LoopRefRamp.Out = mcFocCtrl.UqFlt;
  310. #elif (MOTOR_CTRL_MODE == UQ_POWER_CONTROL)
  311. LoopRefRamp.Out = mcFocCtrl.UqFlt;
  312. #endif
  313. mcFocCtrl.LoopTime = LOOP_TIME;
  314. LoopRefRamp.Inc = RAMP_INC;
  315. LoopRefRamp.Dec = RAMP_DEC;
  316. mcFocCtrl.IqRef = FOC_IQREF;
  317. FOC_IDREF = ID_RUN_CURRENT; // D轴启动电流
  318. PI1_UKH = mcFocCtrl.IqRef;
  319. PI2_Init(); // PI初始化
  320. // 弱磁
  321. #if (MotorFiledWeakenEn)
  322. FiledWeakenInit();
  323. #endif
  324. // 电压补偿
  325. VoltageComp.Undervoltage_flag = 0;
  326. VoltageComp.IncVoltage = _Q15(40.0 / HW_BOARD_VOLT_MAX);
  327. VoltageComp.LineAngel = LinearCompensationAngel;
  328. VoltageComp.LineAngelMax = LinearCompensationAngel_MAX;
  329. VoltageComp.LineAngelMin = LinearCompensationAngel_MIN;
  330. VoltageComp.VCDelayCnt = VoltageCompensationDelayCnt;
  331. mcFocCtrl.CtrlMode = 1;
  332. }
  333. }
  334. else
  335. { mcFocCtrl.Mode0HoldCnt = 0; }
  336. break;
  337. }
  338. case 1:
  339. {
  340. mcFocCtrl.LoopTime++;
  341. if (mcFocCtrl.LoopTime >= LOOP_TIME)
  342. {
  343. mcFocCtrl.LoopTime = 0;
  344. refRampOut = LoopRamp(mcFocCtrl.Ref); // 控制命令爬坡函数,用于实现调速信号之间平滑过渡
  345. #if (MOTOR_CTRL_MODE == CURRENT_LOOP_CONTROL)
  346. {
  347. mcFocCtrl.IqRef = refRampOut;
  348. FOC_IQREF = mcFocCtrl.IqRef;
  349. }
  350. #elif (MOTOR_CTRL_MODE == SPEED_LOOP_CONTROL)
  351. {
  352. mcFocCtrl.IqSpeedRef = HW_One_PI(refRampOut - mcFocCtrl.SpeedFlt);
  353. mcFocCtrl.LimitIqOut = HW_One_PI2(mcFocCtrl.PowerLimitValue - mcFocCtrl.Power); // 限制功率
  354. if ((mcFocCtrl.LimitIqOut < mcFocCtrl.IqSpeedRef)) // 限制输出电流
  355. {
  356. mcFocCtrl.ExtDec = (mcFocCtrl.IqRef - mcFocCtrl.LimitIqOut) / 3;
  357. mcFocCtrl.IqRef -= mcFocCtrl.ExtDec;
  358. }
  359. else
  360. { mcFocCtrl.IqRef = mcFocCtrl.IqSpeedRef; }
  361. #if (MotorFiledWeakenEn)
  362. FileWeakenControl();
  363. #else
  364. FOC_IQREF = mcFocCtrl.IqRef;
  365. #endif
  366. }
  367. #elif (MOTOR_CTRL_MODE == POWER_LOOP_CONTROL)
  368. {
  369. mcFocCtrl.IqRef = HW_One_PI(refRampOut - mcFocCtrl.Power);
  370. FOC_IQREF = mcFocCtrl.IqRef;
  371. }
  372. #elif (MOTOR_CTRL_MODE == UQ_LOOP_CONTROL)
  373. {
  374. mcFocCtrl.IqRef = HW_One_PI(refRampOut - mcFocCtrl.UqFlt);
  375. FOC_IQREF = mcFocCtrl.IqRef;
  376. }
  377. #elif (MOTOR_CTRL_MODE == UQ_POWER_CONTROL)
  378. {
  379. // 反馈计算
  380. mcFocCtrl.LoopCalcValue = mcFocCtrl.UqFlt * 0.65 + mcFocCtrl.Power * 0.61;
  381. // 限幅
  382. if (mcFocCtrl.LoopCalcValue > 32440)
  383. { mcFocCtrl.LoopCalcValue = 32440;}
  384. mcFocCtrl.IqRef = HW_One_PI(refRampOut - mcFocCtrl.LoopCalcValue);
  385. FOC_IQREF = mcFocCtrl.IqRef;
  386. }
  387. #endif
  388. }
  389. #if (SVPWM_5_Segment_Run_Enale == 1) // 开启五段式
  390. {
  391. if (mcFocCtrl.SpeedFlt > Motor_F5SEG_Speed)
  392. { SetBit(FOC_CR2, F5SEG); }
  393. else if (mcFocCtrl.SpeedFlt < Motor_F7SEG_Speed)
  394. { ClrBit(FOC_CR2, F5SEG); }
  395. }
  396. #endif
  397. break;
  398. }
  399. }
  400. }
  401. /**
  402. @brief 控制给定爬坡函数
  403. 以浮点进行计算,解决整数爬坡由于精度的影响,导致爬坡结果阶梯变化
  404. 函数控制周期默认为闭环控制周期,建议使用默认1ms周期运行
  405. @param[in] ref 给定目标值
  406. @return 爬坡结果(int16)
  407. @date 2022-07-14
  408. */
  409. int16 LoopRamp(int16 Xn0)
  410. {
  411. LoopRefRamp.In = Xn0; // 爬坡函数输入
  412. // 数据爬坡处理
  413. if ((LoopRefRamp.Out + LoopRefRamp.Inc) < LoopRefRamp.In)
  414. { LoopRefRamp.Out += LoopRefRamp.Inc; }
  415. else if ((LoopRefRamp.Out - LoopRefRamp.Dec) > LoopRefRamp.In)
  416. { LoopRefRamp.Out -= LoopRefRamp.Dec; }
  417. return (int16)LoopRefRamp.Out;
  418. }
  419. /**
  420. @brief 启动ATO爬坡函数,用于静止启动时候对ATO进行爬坡,提高启动可靠性
  421. @date 2022-07-14
  422. */
  423. void ATORamp(void)
  424. {
  425. if (mcFocCtrl.State_Count == (ATO_RAMP_PERIOD << 2))
  426. {
  427. FOC_EKP = OBSW_KP_GAIN_RUN1; // 估算器里的PI的KP
  428. FOC_EKI = OBSW_KI_GAIN_RUN1; // 估算器里的PI的KI
  429. }
  430. else if (mcFocCtrl.State_Count == ((ATO_RAMP_PERIOD << 1) + ATO_RAMP_PERIOD))
  431. {
  432. FOC_EKP = OBSW_KP_GAIN_RUN2; // 估算器里的PI的KP
  433. FOC_EKI = OBSW_KI_GAIN_RUN2; // 估算器里的PI的KI
  434. }
  435. else if (mcFocCtrl.State_Count == (ATO_RAMP_PERIOD << 1))
  436. {
  437. FOC_EKP = OBSW_KP_GAIN_RUN3; // 估算器里的PI的KP
  438. FOC_EKI = OBSW_KI_GAIN_RUN3; // 估算器里的PI的KI
  439. }
  440. else if (mcFocCtrl.State_Count <= ATO_RAMP_PERIOD && mcFocCtrl.Flg_ATORampEnd == 0)
  441. {
  442. FOC_EKP = OBSW_KP_GAIN_RUN4; // 估算器里的PI的KP
  443. FOC_EKI = OBSW_KI_GAIN_RUN4; // 估算器里的PI的KI
  444. mcFocCtrl.Flg_ATORampEnd = 1; // ATO 爬坡结束
  445. }
  446. }