AddFunction.c 16 KB

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