BEMFDetect.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /* --------------------------- (C) COPYRIGHT 2022 Fortiortech ShenZhen -----------------------------
  2. File Name : BEMFDetect.c
  3. Author : Fortiortech Appliction Team
  4. Version : V1.1
  5. Date : 2022-07-08
  6. Description : This file contains Bemf detection function used for Motor Control.
  7. ----------------------------------------------------------------------------------------------------
  8. All Rights Reserved
  9. ------------------------------------------------------------------------------------------------- */
  10. #include <MyProject.h>
  11. uint8 code table_Bemf_CWNext[6] = {3, 6, 2, 5, 1, 4};
  12. uint8 code table_Bemf_CWPre[6] = {5, 3, 1, 6, 4, 2};
  13. BEMFDetect_TypeDef xdata mcBemf;
  14. #if (TAILWIND_MODE == BEMFMethod)
  15. static void Cmp_Bemf_Init(void);
  16. static uint8 FR_Detect(uint8 bemfStatus, uint8 setFr);
  17. static void BEMFTailWindStart(void);
  18. /**
  19. @brief Bemf的顺逆风检测,比较器硬件初始化,注意需要核对IO是否对应
  20. @date 2022-07-09
  21. */
  22. static void Cmp_Bemf_Init(void)
  23. {
  24. /* -------------------------------------------------------------------------------------------------
  25. CMP Input Pin Mode
  26. 0: GPIO Mode, P1.4--CMP0_IN+, P1.6--CMP1_IN+, P2.1--CMP2_IN+
  27. P1.5--CMP0_IN-, P1.7--CMP1_IN-, P2.2--CMP2_IN-
  28. 1: BEMF Mode, 比较器正端连接到内部星型连接电阻U、V、W的BMEF采样点,
  29. 比较器负端连接到内部星型连接电阻的虚拟中性点
  30. 比较器负端与P1.5/P1.7/P2.2断开,这三个GPIO可做其他用途
  31. -------------------------------------------------------------------------------------------------*/
  32. SetBit(P1_AN, P14 | P16); // CMP0/1 Pin设置为模拟模式 +
  33. SetBit(P2_AN, P21); // CMP2 Pin设置为模拟模式 +
  34. ClrBit(P1_PU, P14); // P14上拉关闭
  35. /* -------------------------------------------------------------------------------------------------
  36. CMP0_MOD:
  37. 00: 无内置虚拟中心点电阻的BEMF模式
  38. 01: 内置虚拟中心点电阻的BEMF模式
  39. 10: 3差分比较器模式
  40. 11: 2比较器模式
  41. -------------------------------------------------------------------------------------------------*/
  42. SetReg(CMP_CR2, CMP0MOD0 | CMP0MOD1, CMP0MOD0);
  43. /* -------------------------------------------------------------------------------------------------
  44. 比较器输出选择配置,与CMP0_MOD配合使用
  45. CMP0_SEL[1:0]=00,比较器0工作在3比较器轮询模式,正端在CMP0P、CMP1P、CMP2P之间自动轮流选择,
  46. 负端固定接内置BEMF电阻的中心点,其输出结果分别送至CMP0_OUT、CMP1_OUT、CMP2_OUT
  47. CMP0_SEL[1:0]=01,比较器0选择CMP0对应的端口组合,正端接CMP0P,负端接内置BEMF电阻的中心点,输出接CMP0_OUT
  48. CMP0_SEL[1:0]=10,比较器0选择CMP1对应的端口组合,正端接CMP1P,负端接内置BEMF电阻的中心点,输出接CMP1_OUT
  49. CMP0_SEL[1:0]=11,比较器0选择CMP2对应的端口组合,正端接CMP2P,负端接内置BEMF电阻的中心点,输出接CMP2_OUT
  50. -----------------------------------------------------------------------------*/
  51. SetReg(CMP_CR2, CMP0SEL0 | CMP0SEL1, 0x00);
  52. /* -------------------------------------------------------------------------------------------------
  53. 比较器迟滞电压选择
  54. 000: 无迟滞 001: ±2.5mV 010: -5mV 011: +5mV
  55. 100: +-5mV 101: -10mV 110: +10mV 111: +-10mV
  56. -------------------------------------------------------------------------------------------------*/
  57. SetReg(CMP_CR1, CMP0HYS0 | CMP0HYS1 | CMP0HYS2, CMP0HYS0);
  58. /* -------------------------------------------------------------------------------------------------
  59. CMP0的轮询时间设置
  60. -------------------------------------------------------------------------------------------------*/
  61. SetReg(CMP_CR2, CMP0CSEL1 | CMP0CSEL0, 0x00);
  62. /* -------------------------------------------------------------------------------------------------
  63. 比较器中断模式配置 CMP_CR0[CMP2IM1], CMP_CR0[CMP2IM0]
  64. 00: 不产生中断 01: 上升沿产生中断 10: 下降沿产生中断 11: 上升/下降沿产生中断
  65. -------------------------------------------------------------------------------------------------*/
  66. SetReg(CMP_CR0, CMP2IM0 | CMP2IM1, CMP2IM0 | CMP2IM1);
  67. SetReg(CMP_CR0, CMP1IM0 | CMP1IM1, CMP1IM0 | CMP1IM1);
  68. SetReg(CMP_CR0, CMP0IM0 | CMP0IM1, CMP0IM0 | CMP0IM1);
  69. ClrBit(CMP_CR4, CMP0_FS); //CMP1/2功能转移 仅CMP0_MOD=01时有效
  70. SetBit(CMP_CR2, CMP0EN); //开三个比较器
  71. }
  72. /**
  73. @brief Timer2 初始化函数
  74. @date 2022-07-09
  75. */
  76. static void Time2_Bemf_Init(void)
  77. {
  78. /* -------------------------------------------------------------------------------------------------
  79. 先停止计数,配置完寄存器后,最后启动计数
  80. -------------------------------------------------------------------------------------------------*/
  81. ClrBit(TIM2_CR1, T2CEN); // 0,停止计数;1,使能计数
  82. /* -------------------------------------------------------------------------------------------------
  83. 时钟分频设置(T2PSC)
  84. 000:cpuclk(24MHz) 001:cpuclk/2^1(12MHz) 010:cpuclk/2^2(6MHz) 011:cpuclk/2^3(3MHz)
  85. 100:cpuclk/2^4(1.5MHz) 101:cpuclk/2^5(750KHz) 110:cpuclk/2^6(375KHz) 111:cpuclk/2^7(187.5KHz)
  86. -------------------------------------------------------------------------------------------------*/
  87. SetReg(TIM2_CR0, T2PSC0 | T2PSC1 | T2PSC2, T2PSC0 | T2PSC1 | T2PSC2);
  88. /* -------------------------------------------------------------------------------------------------
  89. /模式选择
  90. T2MODE1,T2MODE0
  91. 00--输入Timer模式;01--输出模式
  92. 10--输入Count模式;11--QEP或者ISD模式
  93. -------------------------------------------------------------------------------------------------*/
  94. SetReg(TIM2_CR0, T2MOD0 | T2MOD1, T2MOD0);
  95. /* -------------------------------------------------------------------------------------------------
  96. 清除中断标志位
  97. 禁止PWM周期检测中断使能
  98. -------------------------------------------------------------------------------------------------*/
  99. ClrBit(TIM2_CR0, T2CES); // 清零脉冲计数器不使能
  100. SetBit(TIM2_CR1, T2IFE); // 溢出中断使能
  101. ClrBit(TIM2_CR1, T2IR | T2IF | T2IP); // 清零中断标志位
  102. /* -------------------------------------------------------------------------------------------------
  103. 配置周期值、比较值、计数值
  104. 禁止PWM周期检测中断使能
  105. 使能计数器上溢中断使能
  106. -------------------------------------------------------------------------------------------------*/
  107. TIM2__ARR = 60000; // TIM2 Period = 0.32s
  108. TIM2__DR = TIM2__ARR;
  109. TIM2__CNTR = 0;
  110. /*-----------启动计数------------------------------------------------*/
  111. SetBit(TIM2_CR1, T2CEN); //启动计数
  112. }
  113. /**
  114. @brief 基于Bemf的顺逆风检测初始化函数,电机状态切入 顺逆风检测状态时 运行一次
  115. @date 2022-07-09
  116. */
  117. void BEMFDetectInit(void)
  118. {
  119. //BEMF检测前关闭mos输出
  120. mcBemf.BEMFSpeed = 0;
  121. mcBemf.BEMFSpeedBase = 0;
  122. mcBemf.Status = 0;
  123. mcBemf.FR = BEMF_FR_ERR;
  124. mcBemf.FRPre = BEMF_FR_ERR;
  125. mcBemf.SpeedUpdate = 0;
  126. mcBemf.BEMFSpeedBase = BEMFSpeedCalBase;
  127. mcBemf.HighSpdStart = 0;
  128. mcBemf.FR_SET = mcFocCtrl.FR;
  129. /* -----使能比较器----- */
  130. Cmp_Bemf_Init();
  131. /* -----使能定时器1用于检测时间----- */
  132. Time2_Bemf_Init();
  133. }
  134. /**
  135. @brief bemf顺序为 5,1,3,2,6,4
  136. @param bemfStatus 当前bemf状态
  137. @return BEMF_FR_CCW 反转
  138. @return BEMF_FR_CW 正转
  139. @return BEMF_FR_ERR 错误
  140. @date 2022-07-09
  141. */
  142. static uint8 FR_Detect(uint8 bemfStatus, uint8 setFr)
  143. {
  144. static uint8 temp_FR = 0;
  145. static uint8 temp_bemfStatusPre = 0;
  146. if (temp_bemfStatusPre == 0)
  147. {
  148. temp_bemfStatusPre = bemfStatus;
  149. temp_FR = BEMF_FR_ERR;
  150. }
  151. if (temp_bemfStatusPre != bemfStatus)
  152. {
  153. if (temp_bemfStatusPre == table_Bemf_CWPre[bemfStatus - 1])
  154. {
  155. if (setFr == CW) ///< 转向设置
  156. {
  157. temp_FR = BEMF_FR_CW;
  158. }
  159. else
  160. {
  161. temp_FR = BEMF_FR_CCW;
  162. }
  163. }
  164. else if (temp_bemfStatusPre == table_Bemf_CWNext[bemfStatus - 1])
  165. {
  166. if (setFr == CW) ///< 转向设置
  167. {
  168. temp_FR = BEMF_FR_CCW;
  169. }
  170. else
  171. {
  172. temp_FR = BEMF_FR_CW;
  173. }
  174. }
  175. else
  176. {
  177. temp_FR = BEMF_FR_ERR;
  178. }
  179. temp_bemfStatusPre = bemfStatus;
  180. }
  181. return temp_FR;
  182. }
  183. /**
  184. @brief void BemfProcess(void)基于Bemf的顺逆风检测,运行于Bemf检测比较器中断
  185. @date 2022-07-09
  186. */
  187. void BemfProcess(void)
  188. {
  189. static uint8 temp_Cnt = 0;
  190. static uint8 temp_SumCnt = 0;
  191. uint16 temp_Sum = 0;
  192. int16 temp_speedCal;
  193. mcBemf.FRPre = mcBemf.FR; // 获取上一次的转向
  194. mcBemf.FR = FR_Detect(CMP_SR & 0x07, mcBemf.FR_SET); // 获取当前转向
  195. if (mcBemf.FR == BEMF_FR_CW) // 当前为正转
  196. {
  197. if (mcBemf.FRPre == mcBemf.FR)
  198. {
  199. if (temp_Cnt > 5) // 防溢出越界
  200. {
  201. temp_Cnt = 0;
  202. }
  203. mcBemf.SectorTime[temp_Cnt++] = TIM2__CNTR;
  204. if (mcBemf.FRCount < 100)
  205. {
  206. mcBemf.FRCount++; // 连续两次均为正转则 正转计数+1
  207. }
  208. if (mcBemf.FRCount > 12)
  209. {
  210. temp_Sum = 0;
  211. for (temp_SumCnt = 0; temp_SumCnt < 6; temp_SumCnt++)
  212. {
  213. temp_Sum += (mcBemf.SectorTime[temp_SumCnt] >> 3); // 防止溢出
  214. }
  215. mcBemf.PeriodTime = temp_Sum;
  216. mcBemf.Status = BEMF_FORWARD; // 连续12次均为正向转动,则bemf状态切换为 BEMF_FORWARD
  217. }
  218. }
  219. else
  220. {
  221. mcBemf.FRCount = 0;
  222. mcBemf.Status = BEMF_DETECTING;
  223. }
  224. }
  225. else if (mcBemf.FR == BEMF_FR_CCW)
  226. {
  227. if (mcBemf.FRPre == mcBemf.FR)
  228. {
  229. if (temp_Cnt > 5) // 防溢出越界
  230. {
  231. temp_Cnt = 0;
  232. }
  233. mcBemf.SectorTime[temp_Cnt++] = TIM2__CNTR;
  234. if (mcBemf.FRCount > - 100)
  235. {
  236. mcBemf.FRCount--;// 连续两次均为反转则 反转计数+1
  237. }
  238. if (mcBemf.FRCount < -12)
  239. {
  240. temp_Sum = 0;
  241. for (temp_SumCnt = 0; temp_SumCnt < 6; temp_SumCnt++)
  242. {
  243. temp_Sum += (mcBemf.SectorTime[temp_SumCnt] >> 3); // 防止溢出
  244. }
  245. mcBemf.PeriodTime = temp_Sum;
  246. mcBemf.Status = BEMF_REVERSE;
  247. }
  248. }
  249. else
  250. {
  251. mcBemf.FRCount = 0;
  252. mcBemf.Status = BEMF_DETECTING;
  253. }
  254. }
  255. else
  256. {
  257. mcBemf.FRCount = 0; // 转向检测错误则清零转向计数
  258. mcBemf.Status = BEMF_DETECTING;
  259. }
  260. TIM2__CNTR = 0;
  261. if (mcBemf.Status == BEMF_FORWARD || mcBemf.Status == BEMF_REVERSE ) // 有效转向
  262. {
  263. // if (mcBemf.SpeedUpdate == 0)
  264. {
  265. if (mcBemf.PeriodTime < BEMFSpeedCalMinPeriod)
  266. {
  267. mcBemf.PeriodTime = BEMFSpeedCalMinPeriod ; // 防止mcRsd.PeriodTime 太小导致计算出错
  268. }
  269. temp_speedCal = DivQ_L_MDU(mcBemf.BEMFSpeedBase >> 16, mcBemf.BEMFSpeedBase, mcBemf.PeriodTime);
  270. if (mcBemf.Status == BEMF_REVERSE)
  271. {
  272. mcBemf.BEMFSpeed = -temp_speedCal;
  273. }
  274. else
  275. {
  276. mcBemf.BEMFSpeed = temp_speedCal;
  277. }
  278. mcBemf.SpeedUpdate = 1;
  279. }
  280. }
  281. if (mcBemf.HighSpdStart == 1) // 高速顺风启动
  282. {
  283. if ((CMP_SR & 0x07) == 0x01) // 01状态 对应0启动
  284. {
  285. ClrBit(CMP_CR2, CMP0EN); // 关闭比较器
  286. ClrBit(TIM2_CR1, T2CEN); // 关闭定时器
  287. BEMFTailWindStart();
  288. mcBemf.HighSpdStart = 2; // 启动完成
  289. }
  290. }
  291. }
  292. MotStateType Bemf_Start_Process(void)
  293. {
  294. MotStateType returnStatus;
  295. returnStatus = mcTailWind;
  296. if (mcBemf.SpeedUpdate == 1)
  297. {
  298. if (mcBemf.BEMFSpeed < S_Value(-100)) // 逆风
  299. {
  300. mcFocCtrl.State_Count = 3000;
  301. ClrBit(CMP_CR2, CMP0EN); // 关闭比较器
  302. ClrBit(TIM2_CR1, T2CEN); // 关闭定时器
  303. returnStatus = mcStart;
  304. mcFocCtrl.Start_Mode = HEADWIND_START;
  305. }
  306. // else if (mcBemf.BEMFSpeed < S_Value(-50)) //正转
  307. // {
  308. // mcBemf.SpeedUpdate = 0;
  309. // }
  310. else if (mcBemf.BEMFSpeed > S_Value(100)) //正转
  311. {
  312. if (mcBemf.HighSpdStart == 2) //启动完成,切状态机
  313. {
  314. mcFocCtrl.Start_Mode = TAILWIND_START;
  315. returnStatus = mcStart;
  316. }
  317. if (mcBemf.HighSpdStart == 0)
  318. {
  319. mcBemf.HighSpdStart = 1; // 设置启动
  320. }
  321. }
  322. else //其他,如静止
  323. {
  324. mcFocCtrl.Start_Mode = STATIC_START;
  325. returnStatus = mcStart;
  326. ClrBit(CMP_CR2, CMP0EN); // 关闭比较器
  327. ClrBit(TIM1_CR0, T1BCEN); // 关闭定时器
  328. #if (PosCheckEnable == Enable)
  329. returnStatus = mcPosiCheck;
  330. McStaSet.SetFlag.PosiCheckSetFlag = 0;
  331. mcFocCtrl.mcPosCheckAngle = 0xffff; // 角度赋初值
  332. #elif (ALIGN_MOME != ALIGN_DSIABLE)
  333. mcFocCtrl.mcPosCheckAngle = Align_Angle;
  334. returnStatus = mcAlign;
  335. mcFocCtrl.State_Count = Align_Time;
  336. #else
  337. returnStatus = mcStart;
  338. #endif
  339. }
  340. }
  341. return returnStatus;
  342. }
  343. static void BEMFTailWindStart(void)
  344. {
  345. /* FOC初始化 */
  346. FOC_Init();
  347. /* 启动电流、KP、KI */
  348. FOC_IDREF = ID_RUN_CURRENT; // D轴启动电流
  349. FOC_IQREF = IQ_RUN_CURRENT; // Q轴启动电流
  350. mcFocCtrl.IqRef = IQ_RUN_CURRENT; // Q轴启动电流
  351. FOC_DKP = _Q12(5.0);
  352. FOC_DKI = _Q15(0.5);
  353. FOC_QKP = _Q12(5.0);
  354. FOC_QKI = _Q15(0.5);
  355. FOC_EFREQACC = 500;
  356. FOC_EFREQMIN = MOTOR_OMEGA_RAMP_MIN;
  357. FOC_EFREQHOLD = MOTOR_OMEGA_RAMP_END;
  358. SetBit(FOC_CR1, ANGM); // 估算模式
  359. ClrBit(FOC_CR1, RFAE); // 禁止强拉
  360. SetBit(FOC_CR1, EFAE); // 估算器强制输出
  361. FOC_EKP = OBSW_KP_GAIN_RUN4;
  362. FOC_EKI = OBSW_KI_GAIN_RUN4;
  363. FOC_OMEKLPF = SPEED_KLPF;
  364. mcFocCtrl.CtrlMode = 0;
  365. /* 使能输出 */
  366. DRV_CMR |= 0x3F; // U、V、W相输出
  367. MOE = 1;
  368. EA = 1;
  369. }
  370. #endif