123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- #include "MT6813CT.h"
- #include "cmsis_os.h"
- #include "i2c.h"
- #include "uType.h"
- #include "math.h"
- #include "DRV8837D.h"
- float diff_speed = 0.0f;
- uint8_t no_mag_flag = 0; // 磁铁状态标志位
- uint16_t angle = 0; // 读取到的磁角度寄存器数据
- float cur_angle_deg = 0.0f; // 读取到的磁角度转成单位度deg
- float prev_angle_deg = 0.0f; // 上一次角度(单位:度)
- uint32_t prev_time = 0; // 上一次采样的时间(单位:ms)
- extern float Motor_spe; // 电机转速
- float delta_time = 0.0f; // 读取角度间隔时间(毫秒)
- static float last_angle_deg = 0;
- extern uint32_t period_buffer[CAPTURE_DEPTH]; // PWM周期
- extern uint32_t high_buffer[CAPTURE_DEPTH]; // PWM高电平时间
- #define SPEED_NOISE_THRESHOLD 40.0f // 速度突变阈值
- static float speed_buffer[3] = {0}; // 三点速度缓存:前一帧、中间、后一帧
- static int speed_index = 0;
- void Scanning_I2C_ID(void)
- {
- HAL_StatusTypeDef result;
- uint8_t found = 0;
- while (!found) // 直到发现 0x06 地址
- {
- result = HAL_I2C_IsDeviceReady(&hi2c2, 0x06 << 1, 2, 20);
- if (result == HAL_OK)
- {
- found = 1;
- break;
- }else{
- printf("I2C Slave ID incorrect\n");
- }
- osDelay(100);
- printf("HAL_I2C_IsDeviceReady fail\n");
- HAL_I2C_DeInit(&hi2c2); // 停止并释放 I2C 硬件资源
- osDelay(100);
- MX_I2C2_Init();
- osDelay(100);
- }
- }
- void read_angle(void) // 硬件iic读取角度
- {
- uint8_t angle_data[2];
- Scanning_I2C_ID();
- HAL_I2C_Mem_Read(&hi2c2, 0xc, 0x03, I2C_MEMADD_SIZE_8BIT, angle_data, 1, 1000);
- osDelay(10);
- HAL_I2C_Mem_Read(&hi2c2, 0xc, 0x04, I2C_MEMADD_SIZE_8BIT, &angle_data[1], 1, 1000);
- angle = ((angle_data[0]&0xfe) << 5) | ((angle_data[1] & 0xFC) >> 2);
- no_mag_flag = (angle_data[1] & 0x02) >> 1; // 提取磁铁状态标志位
- cur_angle_deg = (angle * 360.0f)*2 / 16384.0f;
- if(no_mag_flag == 1)
- {
- angle = 0;
- diff_speed = 0.0f;
- Motor_spe = 0.0f;
- return;
- }
- // 转速计算部分
- uint32_t now_time = HAL_GetTick(); // 当前时间
- delta_time = now_time - prev_time; // 毫秒
- float delta_angle = cur_angle_deg - prev_angle_deg;
- // 处理角度跳变(例如从359°跳到0°)
- if (delta_angle > 180.0f)
- delta_angle -= 360.0f;
- else if (delta_angle < -180.0f)
- delta_angle += 360.0f;
- if (delta_time > 0)
- {
- Motor_spe = (delta_angle / delta_time) * 1000.0f; // 单位:度/秒
- }
- // 更新上一帧数据
- prev_angle_deg = cur_angle_deg;
- prev_time = now_time;
- }
- // 输入捕获+DMA
- void Process_One_Capture(void)
- {
- static uint32_t last_angle_tick = 0;
- uint32_t now_tick = HAL_GetTick(); // ms
- static float last_motor_spe = 0;
- // static float last_delta_angle = 0;
-
- // 读取当前 DMA 写入位置
- uint16_t pos = (CAPTURE_DEPTH - __HAL_DMA_GET_COUNTER(htim1.hdma[TIM_DMA_ID_CC1])) % CAPTURE_DEPTH;
- uint32_t high = high_buffer[pos];
- uint32_t period = period_buffer[pos];
- if (period == 0) return;
- float duty = (float)high / period;
- float angle_now = duty * 360.0f;
- // 简单一阶滤波
- angle_now = 0.2f * angle_now + (1.0f - 0.2f) * last_angle_deg;
- cur_angle_deg = angle_now;
- // 计算速度(角度差 / 时间差)
- float dt = (now_tick - last_angle_tick) / 1000.0f; // 秒
-
- if (dt > 0.001f) // > 1ms
- {
- delta_time = dt;
-
- float delta_angle = angle_now - last_angle_deg; // 角度差
- if (delta_angle > 180.0f) delta_angle -= 360.0f;
- else if (delta_angle < -180.0f) delta_angle += 360.0f;
- delta_angle = roundf(delta_angle * 10.0f) / 10.0f; // 保留1位小数
-
- float new_speed = 0;
- if (fabsf(delta_angle) < 60.0f) // 忽略大跳变
- new_speed = delta_angle / dt; // deg/s
- else
- new_speed = last_motor_spe; // 保持上一次值
- // 抑制突变(速度差大于 800)
- if (fabsf(new_speed - last_motor_spe) > 400.0f)
- new_speed = last_motor_spe;
- // 方向修正(防止正转/反转状态下出现反方向速度)
- static float last_valid_positive_speed = 0;
- static float last_valid_negative_speed = 0;
- if (Motormode == MOTOR_FORWARD) // 电机正转
- {
- if (new_speed < 0)
- new_speed = last_valid_positive_speed; // 替换为上一次正向速度
- else
- last_valid_positive_speed = new_speed; // 更新正向速度
- }
- else if (Motormode == MOTOR_REVERSE) // 电机反转
- {
- if (new_speed > 0)
- new_speed = last_valid_negative_speed; // 替换为上一次负向速度
- else
- last_valid_negative_speed = new_speed; // 更新反向速度
- }
- if((angle_now > 15.0f && angle_now < 55.0f)||
- (angle_now > 350.0f && angle_now < 359.9f)) // 死区
- {
- new_speed = last_motor_spe; // 替换为上一次速度
- }
-
- UpdateMotorSpeed(new_speed);
- // 一阶滤波
- // Motor_spe = 0.3f * new_speed + 0.7f * last_motor_spe;
- last_motor_spe = new_speed;
-
- // last_delta_angle = delta_angle;
- last_angle_tick = now_tick;
- last_angle_deg = angle_now;
- }
- }
- void UpdateMotorSpeed(float new_speed)
- {
- // 先把新速度放入缓存,循环覆盖三个点
- speed_buffer[speed_index] = new_speed;
- speed_index = (speed_index + 1) % 3;
- // 只有当缓冲满三点时才判断滤波
- if (speed_buffer[0] != 0 && speed_buffer[1] != 0 && speed_buffer[2] != 0)
- {
- // 中间点是当前速度,比较前后点
- float prev_speed = speed_buffer[(speed_index + 2) % 3];
- float curr_speed = speed_buffer[(speed_index + 1) % 3];
- float next_speed = speed_buffer[speed_index];
- // 识别中间值为低值但前后较高,视为噪点
- if ((curr_speed < 80) &&
- (prev_speed > 80) &&
- (next_speed > 80))
- {
- Motor_spe = (prev_speed + next_speed) / 2.0f;
- }
- // 普通速度噪点跳变抑制
- else if (fabsf(curr_speed - prev_speed) > SPEED_NOISE_THRESHOLD &&
- fabsf(curr_speed - next_speed) > SPEED_NOISE_THRESHOLD)
- {
- Motor_spe = (prev_speed + next_speed) / 2.0f;
- }
- else
- {
- Motor_spe = curr_speed;
- }
- }
- else
- {
- Motor_spe = new_speed; // 缓存没满时直接用新速度
- }
- }
- // printf("\n");
- // printf("Angle(deg): %.2f \n", diff_speed);
- // printf("Raw: %d / 0x%04X \n", angle, angle);
- // printf("Magnet_Status: %s\n", no_mag_flag ? "NO" : "YES");
- /*
- void read_angle(void)
- {
- uint8_t temp[2];
- int16_t angle;
- float angle_f;
- HAL_I2C_Mem_Read(&hi2c2, 0x06 << 1, 0x03, I2C_MEMADD_SIZE_8BIT, temp, 2, 50);
- angle = ((temp[0]&0xfe) << 5) | ((temp[1] & 0xFC) >> 2);
- angle_f = (float)angle * 360 / 16384;
- printf("angle = %d\tangle_f: %.03f\r\n", angle, angle_f);
- }
- */
- /* SlaveAddress:0x6<<1
- * IIC 方式读取角度信息
- * 返回数据为 0 ~ 360 之间的浮点数
- */
- /*
- void read_angle(void)
- {
- uint32_t angle = 0;
- float fangle = 0.0f;
- uint8_t ReadBuffer1,ReadBuffer2;
- HAL_I2C_Mem_Read(&hi2c2,0xc,0x3,I2C_MEMADD_SIZE_8BIT,&ReadBuffer1,1,0XFF);
- angle = ReadBuffer1;
- angle <<= 8;
- HAL_I2C_Mem_Read(&hi2c2,0xc,0x4,I2C_MEMADD_SIZE_8BIT,&ReadBuffer2,1,0XFF);
- angle += ReadBuffer2;
- angle >>= 2; //取数据高 14 位
- printf("\n");
- printf("ReadBuffer1: 0x%2x\n",ReadBuffer1);
- printf("ReadBuffer2: 0x%2x\n",ReadBuffer2);
- fangle = (float)(angle * 360.0f) / 16384.0f;
- printf("fangle(deg): %.2f\n",fangle);
- }
- */
|