STM32F103C8T6 HAL库模拟IIC驱动MT6701磁编码器实战指南1. 项目概述与硬件准备磁编码器在工业控制、机器人关节定位等领域应用广泛而MT6701作为一款14位单圈绝对值磁编码器以其高精度和IIC接口的便捷性受到开发者青睐。对于嵌入式初学者而言使用STM32F103C8T6这款性价比极高的MCU驱动MT6701是掌握IIC通信协议的绝佳实践。所需硬件清单STM32F103C8T6开发板蓝色PCB版本常见于学生项目MT6701磁编码器模块含磁铁USB转TTL串口模块用于调试输出杜邦线若干0.96寸OLED显示屏可选用于实时显示角度硬件连接时需特别注意磁铁与MT6701的安装距离建议保持在1-3mm范围内SDA/SCL线上建议添加4.7kΩ上拉电阻部分模块已内置避免强磁场干扰源靠近工作区域2. CubeMX工程配置使用STM32CubeMX进行初始化配置可以大幅提升开发效率。以下是关键配置步骤2.1 时钟树配置// 在SystemClock_Config()中确保时钟配置为72MHz RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); }2.2 GPIO设置引脚功能引脚号模式设置备注IIC_SDAPB7GPIO_OUTPUT开漏输出IIC_SCLPB6GPIO_OUTPUT开漏输出UART_TXPA9Alternate Function用于调试输出提示虽然HAL库提供硬件IIC驱动但在STM32F1系列上软件模拟IIC往往更稳定可靠3. IIC时序模拟实现3.1 基础时序函数// IIC起始信号 void I2C_Start(void) { HAL_GPIO_WritePin(IIC_SDA_GPIO_Port, IIC_SDA_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(IIC_SCL_GPIO_Port, IIC_SCL_Pin, GPIO_PIN_SET); Delay_us(4); HAL_GPIO_WritePin(IIC_SDA_GPIO_Port, IIC_SDA_Pin, GPIO_PIN_RESET); Delay_us(4); HAL_GPIO_WritePin(IIC_SCL_GPIO_Port, IIC_SCL_Pin, GPIO_PIN_RESET); } // 字节写入函数 void I2C_WriteByte(uint8_t data) { for(uint8_t i0; i8; i) { HAL_GPIO_WritePin(IIC_SDA_GPIO_Port, IIC_SDA_Pin, (data 0x80) ? GPIO_PIN_SET : GPIO_PIN_RESET); data 1; HAL_GPIO_WritePin(IIC_SCL_GPIO_Port, IIC_SCL_Pin, GPIO_PIN_SET); Delay_us(5); HAL_GPIO_WritePin(IIC_SCL_GPIO_Port, IIC_SCL_Pin, GPIO_PIN_RESET); Delay_us(5); } }3.2 MT6701通信协议解析MT6701采用标准IIC通信协议主要寄存器包括0x03角度数据高8位0x04角度数据低6位14位有效数据数据转换公式实际角度 (原始数据 × 360°) / 163844. 完整驱动实现4.1 头文件定义// mt6701.h #ifndef __MT6701_H #define __MT6701_H #include stm32f1xx_hal.h #define MT6701_ADDRESS 0x06 1 // 默认IIC地址 #define ANGLE_HIGH_REG 0x03 #define ANGLE_LOW_REG 0x04 float MT6701_GetAngle(void); uint8_t MT6701_CheckDevice(void); #endif4.2 核心读取函数float MT6701_GetAngle(void) { uint16_t raw_angle 0; uint8_t buffer[2]; // 读取高字节 I2C_Start(); I2C_WriteByte(MT6701_ADDRESS | 0x00); I2C_WriteByte(ANGLE_HIGH_REG); I2C_Start(); I2C_WriteByte(MT6701_ADDRESS | 0x01); buffer[0] I2C_ReadByte(); I2C_SendACK(1); I2C_Stop(); // 读取低字节 I2C_Start(); I2C_WriteByte(MT6701_ADDRESS | 0x00); I2C_WriteByte(ANGLE_LOW_REG); I2C_Start(); I2C_WriteByte(MT6701_ADDRESS | 0x01); buffer[1] I2C_ReadByte(); I2C_SendACK(1); I2C_Stop(); // 数据合成 raw_angle ((buffer[0] 8) | buffer[1]) 2; return (raw_angle * 360.0f) / 16384.0f; }5. 调试技巧与常见问题5.1 典型问题排查表现象可能原因解决方案读取值始终为0IIC地址错误检查0x06/0x46地址跳线数据跳变严重磁铁距离不当调整磁铁与芯片间距通信无响应上拉电阻缺失SDA/SCL添加4.7k上拉角度值不连续电源干扰增加滤波电容5.2 进阶优化建议实现DMA传输提升读取效率添加滑动滤波算法平滑输出结合定时器实现定时采样扩展多圈计数功能// 滑动滤波示例 #define FILTER_LEN 5 float angle_filter[FILTER_LEN] {0}; float GetFilteredAngle(void) { static uint8_t index 0; float sum 0; angle_filter[index] MT6701_GetAngle(); index (index 1) % FILTER_LEN; for(uint8_t i0; iFILTER_LEN; i) { sum angle_filter[i]; } return sum / FILTER_LEN; }6. 项目扩展应用将磁编码器数据通过串口实时输出while(1) { float angle MT6701_GetAngle(); printf(Current Angle: %.2f°\r\n, angle); HAL_Delay(100); // 通过LED闪烁指示工作状态 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); }结合PID控制实现位置闭环void PositionControl(float target_angle) { static float last_error 0; float current MT6701_GetAngle(); float error target_angle - current; float derivative error - last_error; // 简易PID实现 float output Kp*error Kd*derivative; SetMotorOutput(output); last_error error; }实际测试中发现使用硬件IIC时偶尔会出现锁死现象这通常是由于总线冲突或从设备无响应导致。软件模拟IIC虽然速度稍慢但稳定性显著提升特别适合教学和原型开发场景。