MT6813CT.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include "MT6813CT.h"
  2. #include "cmsis_os.h"
  3. #include "i2c.h"
  4. #include "uType.h"
  5. #include "math.h"
  6. #include "DRV8837D.h"
  7. float diff_speed = 0.0f;
  8. uint8_t no_mag_flag = 0; // 磁铁状态标志位
  9. uint16_t angle = 0; // 读取到的磁角度寄存器数据
  10. float cur_angle_deg = 0.0f; // 读取到的磁角度转成单位度deg
  11. float prev_angle_deg = 0.0f; // 上一次角度(单位:度)
  12. uint32_t prev_time = 0; // 上一次采样的时间(单位:ms)
  13. extern float Motor_spe; // 电机转速
  14. float delta_time = 0.0f; // 读取角度间隔时间(毫秒)
  15. static float last_angle_deg = 0;
  16. extern uint32_t period_buffer[CAPTURE_DEPTH]; // PWM周期
  17. extern uint32_t high_buffer[CAPTURE_DEPTH]; // PWM高电平时间
  18. #define SPEED_NOISE_THRESHOLD 40.0f // 速度突变阈值
  19. static float speed_buffer[3] = {0}; // 三点速度缓存:前一帧、中间、后一帧
  20. static int speed_index = 0;
  21. void Scanning_I2C_ID(void)
  22. {
  23. HAL_StatusTypeDef result;
  24. uint8_t found = 0;
  25. while (!found) // 直到发现 0x06 地址
  26. {
  27. result = HAL_I2C_IsDeviceReady(&hi2c2, 0x06 << 1, 2, 20);
  28. if (result == HAL_OK)
  29. {
  30. found = 1;
  31. break;
  32. }else{
  33. printf("I2C Slave ID incorrect\n");
  34. }
  35. osDelay(100);
  36. printf("HAL_I2C_IsDeviceReady fail\n");
  37. HAL_I2C_DeInit(&hi2c2); // 停止并释放 I2C 硬件资源
  38. osDelay(100);
  39. MX_I2C2_Init();
  40. osDelay(100);
  41. }
  42. }
  43. void read_angle(void) // 硬件iic读取角度
  44. {
  45. uint8_t angle_data[2];
  46. Scanning_I2C_ID();
  47. HAL_I2C_Mem_Read(&hi2c2, 0xc, 0x03, I2C_MEMADD_SIZE_8BIT, angle_data, 1, 1000);
  48. osDelay(10);
  49. HAL_I2C_Mem_Read(&hi2c2, 0xc, 0x04, I2C_MEMADD_SIZE_8BIT, &angle_data[1], 1, 1000);
  50. angle = ((angle_data[0]&0xfe) << 5) | ((angle_data[1] & 0xFC) >> 2);
  51. no_mag_flag = (angle_data[1] & 0x02) >> 1; // 提取磁铁状态标志位
  52. cur_angle_deg = (angle * 360.0f)*2 / 16384.0f;
  53. if(no_mag_flag == 1)
  54. {
  55. angle = 0;
  56. diff_speed = 0.0f;
  57. Motor_spe = 0.0f;
  58. return;
  59. }
  60. // 转速计算部分
  61. uint32_t now_time = HAL_GetTick(); // 当前时间
  62. delta_time = now_time - prev_time; // 毫秒
  63. float delta_angle = cur_angle_deg - prev_angle_deg;
  64. // 处理角度跳变(例如从359°跳到0°)
  65. if (delta_angle > 180.0f)
  66. delta_angle -= 360.0f;
  67. else if (delta_angle < -180.0f)
  68. delta_angle += 360.0f;
  69. if (delta_time > 0)
  70. {
  71. Motor_spe = (delta_angle / delta_time) * 1000.0f; // 单位:度/秒
  72. }
  73. // 更新上一帧数据
  74. prev_angle_deg = cur_angle_deg;
  75. prev_time = now_time;
  76. }
  77. // 输入捕获+DMA
  78. void Process_One_Capture(void)
  79. {
  80. static uint32_t last_angle_tick = 0;
  81. uint32_t now_tick = HAL_GetTick(); // ms
  82. static float last_motor_spe = 0;
  83. // static float last_delta_angle = 0;
  84. // 读取当前 DMA 写入位置
  85. uint16_t pos = (CAPTURE_DEPTH - __HAL_DMA_GET_COUNTER(htim1.hdma[TIM_DMA_ID_CC1])) % CAPTURE_DEPTH;
  86. uint32_t high = high_buffer[pos];
  87. uint32_t period = period_buffer[pos];
  88. if (period == 0) return;
  89. float duty = (float)high / period;
  90. float angle_now = duty * 360.0f;
  91. // 简单一阶滤波
  92. angle_now = 0.2f * angle_now + (1.0f - 0.2f) * last_angle_deg;
  93. cur_angle_deg = angle_now;
  94. // 计算速度(角度差 / 时间差)
  95. float dt = (now_tick - last_angle_tick) / 1000.0f; // 秒
  96. if (dt > 0.001f) // > 1ms
  97. {
  98. delta_time = dt;
  99. float delta_angle = angle_now - last_angle_deg; // 角度差
  100. if (delta_angle > 180.0f) delta_angle -= 360.0f;
  101. else if (delta_angle < -180.0f) delta_angle += 360.0f;
  102. delta_angle = roundf(delta_angle * 10.0f) / 10.0f; // 保留1位小数
  103. float new_speed = 0;
  104. if (fabsf(delta_angle) < 60.0f) // 忽略大跳变
  105. new_speed = delta_angle / dt; // deg/s
  106. else
  107. new_speed = last_motor_spe; // 保持上一次值
  108. // 抑制突变(速度差大于 800)
  109. if (fabsf(new_speed - last_motor_spe) > 400.0f)
  110. new_speed = last_motor_spe;
  111. // 方向修正(防止正转/反转状态下出现反方向速度)
  112. static float last_valid_positive_speed = 0;
  113. static float last_valid_negative_speed = 0;
  114. if (Motormode == MOTOR_FORWARD) // 电机正转
  115. {
  116. if (new_speed < 0)
  117. new_speed = last_valid_positive_speed; // 替换为上一次正向速度
  118. else
  119. last_valid_positive_speed = new_speed; // 更新正向速度
  120. }
  121. else if (Motormode == MOTOR_REVERSE) // 电机反转
  122. {
  123. if (new_speed > 0)
  124. new_speed = last_valid_negative_speed; // 替换为上一次负向速度
  125. else
  126. last_valid_negative_speed = new_speed; // 更新反向速度
  127. }
  128. if((angle_now > 15.0f && angle_now < 55.0f)||
  129. (angle_now > 350.0f && angle_now < 359.9f)) // 死区
  130. {
  131. new_speed = last_motor_spe; // 替换为上一次速度
  132. }
  133. UpdateMotorSpeed(new_speed);
  134. // 一阶滤波
  135. // Motor_spe = 0.3f * new_speed + 0.7f * last_motor_spe;
  136. last_motor_spe = new_speed;
  137. // last_delta_angle = delta_angle;
  138. last_angle_tick = now_tick;
  139. last_angle_deg = angle_now;
  140. }
  141. }
  142. void UpdateMotorSpeed(float new_speed)
  143. {
  144. // 先把新速度放入缓存,循环覆盖三个点
  145. speed_buffer[speed_index] = new_speed;
  146. speed_index = (speed_index + 1) % 3;
  147. // 只有当缓冲满三点时才判断滤波
  148. if (speed_buffer[0] != 0 && speed_buffer[1] != 0 && speed_buffer[2] != 0)
  149. {
  150. // 中间点是当前速度,比较前后点
  151. float prev_speed = speed_buffer[(speed_index + 2) % 3];
  152. float curr_speed = speed_buffer[(speed_index + 1) % 3];
  153. float next_speed = speed_buffer[speed_index];
  154. // 识别中间值为低值但前后较高,视为噪点
  155. if ((curr_speed < 80) &&
  156. (prev_speed > 80) &&
  157. (next_speed > 80))
  158. {
  159. Motor_spe = (prev_speed + next_speed) / 2.0f;
  160. }
  161. // 普通速度噪点跳变抑制
  162. else if (fabsf(curr_speed - prev_speed) > SPEED_NOISE_THRESHOLD &&
  163. fabsf(curr_speed - next_speed) > SPEED_NOISE_THRESHOLD)
  164. {
  165. Motor_spe = (prev_speed + next_speed) / 2.0f;
  166. }
  167. else
  168. {
  169. Motor_spe = curr_speed;
  170. }
  171. }
  172. else
  173. {
  174. Motor_spe = new_speed; // 缓存没满时直接用新速度
  175. }
  176. }
  177. // printf("\n");
  178. // printf("Angle(deg): %.2f \n", diff_speed);
  179. // printf("Raw: %d / 0x%04X \n", angle, angle);
  180. // printf("Magnet_Status: %s\n", no_mag_flag ? "NO" : "YES");
  181. /*
  182. void read_angle(void)
  183. {
  184. uint8_t temp[2];
  185. int16_t angle;
  186. float angle_f;
  187. HAL_I2C_Mem_Read(&hi2c2, 0x06 << 1, 0x03, I2C_MEMADD_SIZE_8BIT, temp, 2, 50);
  188. angle = ((temp[0]&0xfe) << 5) | ((temp[1] & 0xFC) >> 2);
  189. angle_f = (float)angle * 360 / 16384;
  190. printf("angle = %d\tangle_f: %.03f\r\n", angle, angle_f);
  191. }
  192. */
  193. /* SlaveAddress:0x6<<1
  194. * IIC 方式读取角度信息
  195. * 返回数据为 0 ~ 360 之间的浮点数
  196. */
  197. /*
  198. void read_angle(void)
  199. {
  200. uint32_t angle = 0;
  201. float fangle = 0.0f;
  202. uint8_t ReadBuffer1,ReadBuffer2;
  203. HAL_I2C_Mem_Read(&hi2c2,0xc,0x3,I2C_MEMADD_SIZE_8BIT,&ReadBuffer1,1,0XFF);
  204. angle = ReadBuffer1;
  205. angle <<= 8;
  206. HAL_I2C_Mem_Read(&hi2c2,0xc,0x4,I2C_MEMADD_SIZE_8BIT,&ReadBuffer2,1,0XFF);
  207. angle += ReadBuffer2;
  208. angle >>= 2; //取数据高 14 位
  209. printf("\n");
  210. printf("ReadBuffer1: 0x%2x\n",ReadBuffer1);
  211. printf("ReadBuffer2: 0x%2x\n",ReadBuffer2);
  212. fangle = (float)(angle * 360.0f) / 16384.0f;
  213. printf("fangle(deg): %.2f\n",fangle);
  214. }
  215. */