adc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /**********************************
  2. * 文件名称: adc.c
  3. * 功能描述: ADC采样和电机控制模块
  4. * 主要功能:
  5. * 1. 温度传感器采样与转换
  6. * 2. 电流偏移校准
  7. * 3. FOC算法计算
  8. * 4. ADC中断处理
  9. *
  10. * 注意事项:
  11. * - 使用ADC1进行电流和电压采样
  12. * - 使用ADC3进行UVW端电压和温度采样
  13. * - 采样频率为10kHz(与PWM频率同步)
  14. **********************************/
  15. #include "main.h"
  16. #include "arm_math.h"
  17. #include "adc.h"
  18. #include "board_config.h"
  19. #define _constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
  20. // 测试变量
  21. int32_t ia_test,ib_test,ic_test;
  22. float Ua,Ualpha,Ub,Ubeta, Uc, dc_a,dc_b,dc_c;
  23. //float err;
  24. // 电流和电压变量
  25. double Ia,Ib,Ic;
  26. float Ia_test,Ib_test,Ic_test;
  27. float Vbus;
  28. float Temp;
  29. // ADC采样值数组
  30. uint16_t ADC3ConvertedValue[ADC3_DMA_BUFFER_SIZE];
  31. uint16_t i = 0;
  32. // 电流偏移校准值
  33. uint32_t A_offset,B_offset,C_offset;
  34. uint8_t get_offset_flag = 0;
  35. uint8_t get_offset_sample_cnt = 0;
  36. // 速度闭环控制标志和参考电流
  37. u8 speed_close_loop_flag;
  38. float Iq_ref = 0.0f;
  39. float Id_ref = 0.0f;
  40. // EKF相关变量
  41. float EKF_Hz;
  42. // 角度变量
  43. float theta_add;
  44. float theta;
  45. // 电机参数(从其他模块导入)
  46. extern float Rs;
  47. extern float Ls;
  48. extern float flux;
  49. /**
  50. * @brief 根据热敏电阻阻值计算温度
  51. * @param rt_kohm: 热敏电阻阻值,单位为千欧姆
  52. * @retval 温度值,单位为摄氏度
  53. */
  54. float calculate_temperature(float rt_kohm)
  55. {
  56. float temp;
  57. const float Rp_kohm = 10.0f; /* 10K热敏电阻参考电阻 */
  58. const float T2 = (273.15f + 25.0f); /* T2温度,单位为K */
  59. const float Bx = 3380.0f; /* B值 */
  60. const float Ka = 273.15f; /* 绝对零度,单位为℃ */
  61. temp = rt_kohm / Rp_kohm; /* 电阻比值 */
  62. temp = log(temp); /* 取自然对数 */
  63. temp /= Bx; /* 除以B值 */
  64. temp += (1.0f / T2); /* 加上1/T2 */
  65. temp = 1.0f / temp; /* 取倒数 */
  66. temp -= Ka; /* 减去绝对零度 */
  67. return temp;
  68. }
  69. /**
  70. * @brief 获取电流偏移值
  71. * @param a_offset A相电流偏移值指针
  72. * @param b_offset B相电流偏移值指针
  73. * @note 采集128次求平均值,在PWM关闭时采集
  74. * - ADC1->JDR2: A相电流采样值
  75. * - ADC1->JDR3: B相电流采样值
  76. * - 右移7位 = 除以128求平均值
  77. */
  78. static void get_offset(uint32_t *a_offset, uint32_t *b_offset, uint32_t* c_offset)
  79. {
  80. if(get_offset_sample_cnt<128)
  81. {
  82. *a_offset += ADC1->JDR1;
  83. *b_offset += ADC2->JDR1;
  84. *c_offset += ADC3->JDR1;
  85. get_offset_sample_cnt++;
  86. }
  87. else
  88. {
  89. *a_offset >>= 7;
  90. *b_offset >>= 7;
  91. *c_offset >>= 7;
  92. get_offset_sample_cnt=0;
  93. TIM_CtrlPWMOutputs(PWM_TIM,DISABLE);
  94. get_offset_flag = 2;
  95. }
  96. }
  97. /**
  98. * @brief 开环角度更新
  99. */
  100. static void Angle_OpenLoop_Update(float step)
  101. {
  102. if(get_motor()->direction == MOTOR_CW)
  103. get_motor()->eleangle += step;
  104. else
  105. get_motor()->eleangle -= step;
  106. }
  107. static void FOC_parm_input(void)
  108. {
  109. get_foc_input()->Id_ref = 0.0f;
  110. get_foc_input()->Tpwm = PWM_TIM_PULSE_TPWM; // FOC算法需要的PWM周期
  111. get_foc_input()->Udc = Vbus;
  112. get_foc_input()->Rs = Rs;
  113. get_foc_input()->Ls = Ls;
  114. get_foc_input()->flux = flux;
  115. get_foc_input()->ia = Ia;
  116. get_foc_input()->ib = Ib;
  117. get_foc_input()->ic = Ic;
  118. }
  119. //static void FOC_parm_output(void)
  120. //{
  121. // EKF_Hz = get_foc_ouput()->EKF[2]/(2.0f*PI) ;
  122. //}
  123. static void uvw_current_and_vbus_get(float* vbus, double* iu, double* iv, double* iw)
  124. {
  125. *vbus = ADC_TO_VBUS( ADC3ConvertedValue[ADC3_VBUS_INDEX]);
  126. *iu = ADC_TO_CURRENT((int16_t)((int16_t)ADC1->JDR1 - (int16_t)A_offset ));
  127. *iv = ADC_TO_CURRENT((int16_t)((int16_t)ADC2->JDR1 - (int16_t)B_offset ));
  128. *iw = ADC_TO_CURRENT((int16_t)((int16_t)ADC3->JDR1 - (int16_t)C_offset ));
  129. Ia_test = *iu;
  130. Ib_test = *iv;
  131. Ic_test = *iw;
  132. }
  133. /**
  134. * @brief 修改后的motor_run()函数
  135. * @note 集成了完整的开环→闭环切换逻辑
  136. */
  137. void motor_run(void)
  138. {
  139. uvw_current_and_vbus_get(&Vbus, &Ia, &Ib, &Ic);
  140. //Hall_TypeDef* hall = Hall_Get();
  141. //MotorParam_t* motor = get_motor();
  142. // Hall_Update_Interpolated_Angle();
  143. if(speed_close_loop_flag==0) //速度环闭环切换控制,电机刚启动时速度环不闭环
  144. { //并且电流参考值缓慢增加(防冲击),速度达到一定值
  145. if((Iq_ref<MOTOR_STARTUP_CURRENT)) //速度切入闭环
  146. { //电流环在电机运行过程中全程闭环
  147. Iq_ref += 0.00003f; //角度在电机刚启动时就闭环运行,无需强拖,得益于卡尔曼滤波做
  148. } //状态观测器低速性能比教好
  149. else
  150. {
  151. speed_close_loop_flag=1;
  152. }
  153. }
  154. else
  155. {
  156. if(speed_close_loop_flag==1)
  157. {
  158. if(Iq_ref>(MOTOR_STARTUP_CURRENT/2.0f))
  159. {
  160. Iq_ref -= 0.001f;
  161. }
  162. else
  163. {
  164. speed_close_loop_flag=2;
  165. }
  166. }
  167. }
  168. // if(FOC_Output.EKF[2]>SPEED_LOOP_CLOSE_RAD_S) //无感方式运行,状态观测器得到角度和速度信息
  169. // {
  170. // FOC_Input.Id_ref = 0.0f;
  171. // Speed_Fdk = FOC_Output.EKF[2];
  172. // FOC_Input.Iq_ref = Speed_Pid_Out;
  173. // }
  174. // else
  175. // {
  176. // FOC_Input.Id_ref = 0.0f;
  177. // FOC_Input.Iq_ref = Iq_ref;
  178. // Speed_Pid.I_Sum = Iq_ref;
  179. // }
  180. // FOC_Input.theta = FOC_Output.EKF[3];
  181. // FOC_Input.speed_fdk = FOC_Output.EKF[2];
  182. // EKF_Hz = FOC_Output.EKF[2]/(2.0f*PI);
  183. // FOC_Input.Id_ref = 0.0f;
  184. // FOC_Input.Tpwm = PWM_TIM_PULSE_TPWM; //FOC运行函数需要用到的输入信息
  185. // FOC_Input.Udc = Vbus;
  186. // FOC_Input.Rs = Rs;
  187. // FOC_Input.Ls = Ls;
  188. // FOC_Input.flux = flux;
  189. //
  190. // FOC_Input.ia = Ia;
  191. // FOC_Input.ib = Ib;
  192. // FOC_Input.ic = Ic;
  193. // foc_algorithm_step(); //整个FOC运行函数(包括无感状态观测器,电流环,SVPWM,坐标变换,电机参数识别)
  194. // ========== FOC参数设置 ==========
  195. FOC_parm_input();
  196. get_foc_input()->Iq_ref = 1.0f;
  197. Hall_Update_Interpolated_Angle();
  198. static uint16_t cnt = 0;
  199. if(cnt <= 10000)
  200. {
  201. cnt++;
  202. theta += 0.01f;
  203. if(theta >= 2* PI)
  204. {
  205. theta -= 2 * PI;
  206. }
  207. if(theta < 0.0f)
  208. {
  209. theta += 2 * PI;
  210. }
  211. get_foc_input()->theta = theta;
  212. }else
  213. {
  214. get_foc_input()->theta = Hall_Get()->angle;
  215. }
  216. // ========== 执行FOC算法 ==========
  217. motor_foc_openloop_run();
  218. //motor_ekf_closeloop_run();
  219. // ========== PWM输出更新 ==========
  220. if(motor_start_stop == 1 )//&& motor->ctrl_state != CTRL_STATE_IDLE)
  221. {
  222. PWM_TIM->CCR1 = (u16)(FOC_Output.Tcmp1);
  223. PWM_TIM->CCR2 = (u16)(FOC_Output.Tcmp2);
  224. PWM_TIM->CCR3 = (u16)(FOC_Output.Tcmp3);
  225. }
  226. else
  227. {
  228. PWM_TIM->CCR1 = PWM_TIM_PULSE >> 1;
  229. PWM_TIM->CCR2 = PWM_TIM_PULSE >> 1;
  230. PWM_TIM->CCR3 = PWM_TIM_PULSE >> 1;
  231. }
  232. // ========== 停止命令处理 ==========
  233. // if(motor_start_stop == 0 && motor->ctrl_state != CTRL_STATE_IDLE &&
  234. // motor->ctrl_state != CTRL_STATE_STOPPING)
  235. // {
  236. // motor->ctrl_state = CTRL_STATE_STOPPING;
  237. // }
  238. }
  239. #if 0
  240. /**
  241. * @brief 电机运行函数
  242. * @note 在PWM中断中调用,频率10kHz
  243. * - 读取ADC采样值,获取A/B相电流
  244. * - 根据基尔霍夫定律计算C相电流(Ia + Ib + Ic = 0)
  245. * - 速度环控制,计算速度PID输出
  246. * - 根据控制模式选择开环/闭环控制
  247. * - 执行FOC算法,计算SVPWM占空比
  248. * - 更新PWM占空比
  249. */
  250. void motor_run(void)
  251. {
  252. uvw_current_and_vbus_get(&Vbus, &Ia, &Ib, &Ic); // 获取母线电压,相电流
  253. // 选择电机运行方式 霍尔 开环加闭环 无感EKF
  254. if(speed_close_loop_flag==0) // 启动阶段,逐渐增加电流
  255. { // 电流从零开始,避免启动冲击
  256. if((Iq_ref<MOTOR_STARTUP_CURRENT)) // 未达到启动电流
  257. {
  258. Iq_ref += 0.00004f; // 缓慢增加电流
  259. }
  260. else
  261. {
  262. speed_close_loop_flag=1;
  263. }
  264. }
  265. else
  266. {
  267. if(speed_close_loop_flag==1)
  268. {
  269. if(Iq_ref>(MOTOR_STARTUP_CURRENT/2.0f))
  270. {
  271. Iq_ref -= 0.001f;
  272. }
  273. else
  274. {
  275. speed_close_loop_flag=2;
  276. }
  277. }
  278. }
  279. // 根据传感器类型选择FOC控制模式
  280. #ifdef HALL_FOC_SELECT // 使用霍尔传感器的FOC控制
  281. // if((hall_speed*2.0f*PI)>SPEED_LOOP_CLOSE_RAD_S) // 速度达到闭环阈值
  282. // {
  283. // FOC_Input.Id_ref = 0.0f;
  284. // Speed_Fdk = hall_speed*2.0f*PI;
  285. // FOC_Input.Iq_ref = Speed_Pid_Out;
  286. // }
  287. // else
  288. // {
  289. // FOC_Input.Id_ref = 0.0f;
  290. // FOC_Input.Iq_ref = Iq_ref;
  291. // Speed_Pid.I_Sum = Iq_ref;
  292. // }
  293. // FOC_Input.theta = hall_angle;
  294. // FOC_Input.speed_fdk = hall_speed*2.0f*PI;
  295. #endif
  296. #ifdef SENSORLESS_FOC_SELECT // 无传感器FOC控制
  297. if(FOC_Output.EKF[2]>SPEED_LOOP_CLOSE_RAD_S) // 速度达到闭环阈值
  298. {
  299. FOC_Input.Id_ref = 0.0f;
  300. Speed_Fdk = FOC_Output.EKF[2];
  301. FOC_Input.Iq_ref = Speed_Pid_Out;
  302. }
  303. else
  304. {
  305. FOC_Input.Id_ref = 0.0f;
  306. FOC_Input.Iq_ref = Iq_ref;
  307. Speed_Pid.I_Sum = Iq_ref;
  308. }
  309. FOC_Input.theta = FOC_Output.EKF[3];
  310. FOC_Input.speed_fdk = FOC_Output.EKF[2];
  311. #endif
  312. //============================== FOC算法计算 ==============================
  313. FOC_parm_input();
  314. FOC_parm_output();
  315. if(get_motor()->direction == MOTOR_CW)
  316. get_motor()->eleangle += 0.01f; // 使用 float 后缀
  317. else if(get_motor()->direction == MOTOR_CCW)
  318. get_motor()->eleangle -= 0.01f;
  319. // if(speed_close_loop_flag == 2)
  320. // {
  321. // if(get_motor()->direction == MOTOR_CW)
  322. // get_motor()->eleangle += Hall_Get()->angle_add; // 使用 float 后缀
  323. // else if(get_motor()->direction == MOTOR_CCW)
  324. // get_motor()->eleangle -= Hall_Get()->angle_add;
  325. // }
  326. if(get_motor()->eleangle >= 2.0f * PI)
  327. {
  328. get_motor()->eleangle -= 2.0f * PI;
  329. }else if(get_motor()->eleangle <= 0.0f * PI)
  330. {
  331. get_motor()->eleangle += 2.0f * PI;
  332. }
  333. get_foc_input()->theta = get_motor()->eleangle;
  334. get_foc_input()->Id_ref = Id_ref;
  335. get_foc_input()->Iq_ref = Iq_ref;
  336. motor_foc_openloop_run();
  337. // foc_algorithm_step(); // 执行FOC算法,计算SVPWM占空比
  338. if(motor_start_stop==1)
  339. {
  340. PWM_TIM->CCR1 = (u16)(FOC_Output.Tcmp1); // 更新SVPWM占空比
  341. PWM_TIM->CCR2 = (u16)(FOC_Output.Tcmp2);
  342. PWM_TIM->CCR3 = (u16)(FOC_Output.Tcmp3);
  343. }
  344. else
  345. {
  346. PWM_TIM->CCR1 = PWM_TIM_PULSE>>1;
  347. PWM_TIM->CCR2 = PWM_TIM_PULSE>>1;
  348. PWM_TIM->CCR3 = PWM_TIM_PULSE>>1;
  349. }
  350. //communication_task();
  351. }
  352. #endif
  353. /**
  354. * @brief ADC中断处理函数
  355. * @note 处理ADC注入通道转换完成中断
  356. * - 当偏移校准完成后,执行电机运行函数
  357. * - 当需要校准偏移时,执行偏移校准函数
  358. * 为什么VBUS不需要零偏校准? 开始采样即VBUS已经接在电源上了
  359. */
  360. void ADC_IRQHandler(void)
  361. {
  362. // 检查ADC1注入组完成(三个ADC已同步完成)
  363. if((SAMPLE_ADC1->SR & ADC_FLAG_JEOC) == ADC_FLAG_JEOC)
  364. {
  365. // 处理数据
  366. if(get_offset_flag == 2)
  367. {
  368. // hall_angle += hall_angle_add;
  369. // if(hall_angle < 0.0f)
  370. // hall_angle += 2.0f * PI;
  371. // else if(hall_angle > (2.0f * PI))
  372. // hall_angle -= 2.0f * PI;
  373. motor_run();
  374. }
  375. else if(get_offset_flag == 1) // get_offset_flag = 2 表示偏移已经获取完成
  376. {
  377. get_offset(&A_offset, &B_offset, &C_offset);
  378. }
  379. // 清除所有三个ADC的JEOC标志
  380. SAMPLE_ADC1->SR = ~ADC_SR_JEOC;
  381. SAMPLE_ADC2->SR = ~ADC_SR_JEOC;
  382. SAMPLE_ADC3->SR = ~ADC_SR_JEOC;
  383. }
  384. }