BEMFDetect.c 15 KB

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