单片机调试IIC笔记 — 首先检测GPIO和协议能不能用
2026/3/20 1:18:44 网站建设 项目流程

单片机协议调试笔记 — GPIO和IIC测试

问题背景

最近在调一个IIC陀螺仪,发什么命令都没反应。折腾半天才发现——GPIO引脚根本没动!

原来是移植了正点原子的库,里面的IO操作是F103的位带操作,和F401不兼容。


分享两个实用的测试函数

1. GPIO电平测试 — 确认引脚真的在动

这个函数用来验证SCL和SDA能不能正常拉高/拉低。

voidGPIO_Test(void){printf("Starting GPIO test...\r\n");// 测试SCL引脚(PA8)printf("Testing SCL (PA8)...\r\n");IIC_SCL(1);delay_ms(100);printf("SCL = 1, PA8_IDR = %d\r\n",HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8));IIC_SCL(0);delay_ms(100);printf("SCL = 0, PA8_IDR = %d\r\n",HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8));// 测试SDA引脚(PC9)printf("Testing SDA (PC9)...\r\n");SDA_OUT();IIC_SDA(1);delay_ms(100);printf("SDA = 1 (output), PC9_IDR = %d\r\n",HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_9));IIC_SDA(0);delay_ms(100);printf("SDA = 0 (output), PC9_IDR = %d\r\n",HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_9));printf("GPIO test completed.\r\n");}

正常应该这样:

Starting GPIO test... Testing SCL (PA8)... SCL = 1, PA8_IDR = 1 SCL = 0, PA8_IDR = 0 ← 写0能读到0,说明拉低了 Testing SDA (PC9)... SDA = 1 (output), PC9_IDR = 1 SDA = 0 (output), PC9_IDR = 0

我当时的情况:

SCL = 0, PA8_IDR = 1 ← 写0还是读到1,根本没拉低! SDA = 0 (output), PC9_IDR = 1

2. IIC设备扫描 — 找设备地址

GPIO没问题后,用这个扫描总线上的设备。

voidI2C_Scan(void){u8 i,ack;printf("Starting I2C scan...\r\n");for(i=0;i<128;i++){IIC_Start();IIC_Send_Byte((i<<1)&0xFE);// 写地址ack=IIC_Wait_Ack();IIC_Stop();if(ack==0){printf("Found device at 0x%02X (7-bit: 0x%02X)\r\n",(i<<1),i);}delay_ms(1);}printf("I2C scan completed.\r\n");}

输出示例:

Starting I2C scan... Found device at 0xD0 (7-bit: 0x68) ← 找到陀螺仪了,地址0x68 I2C scan completed.

我遇到的坑:F103的位带操作库,不兼容F401

正点原子的库里有这么一段:

#defineBITBAND(addr,bitnum)((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))#defineGPIOA_ODR_Addr(GPIOA_BASE+12)// 0x4001080C#defineGPIOA_IDR_Addr(GPIOA_BASE+8)// 0x40010808...

这些地址是F103的!F401的寄存器布局不一样,直接用会导致IO操作失效。
F103的ODR偏移是+12
F103的IDR偏移是+8
F401的ODR偏移是+20
F401的IDR偏移是+16

解决办法

一:改为F403的位带操作

Cortex-M4编程手册 PM0214 第3.7节 Bit-Banding

#defineBITBAND(addr,bitnum)((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))// F401的GPIO寄存器偏移(参考RM0368手册)#defineGPIOA_ODR_Addr(GPIOA_BASE+20)// 0x40020014 ← F401的ODR偏移是+20#defineGPIOA_IDR_Addr(GPIOA_BASE+16)// 0x40020010 ← F401的IDR偏移是+16...
二:改为HAL函数,更直接,通用
// 别用位带了,直接HAL#defineIIC_SCL(n)HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,n)#defineIIC_SDA(n)HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,n)// 读取SDA切换方向#defineSDA_IN(){GPIOC->MODER&=~(3<<(9*2));GPIOC->MODER|=0<<(9*2);}#defineSDA_OUT(){GPIOC->MODER&=~(3<<(9*2));GPIOC->MODER|=1<<(9*2);}#defineREAD_SDAHAL_GPIO_ReadPin(GPIOC,GPIO_PIN_9)

快速排查流程

设备没反应? ↓ 跑 GPIO_Test() ↓ 写1读1,写0读0? ──否──→ 检查IO配置/上拉电阻/代码兼容性 ↓ 是 跑 I2C_Scan() ↓ 找到设备地址? ────否──→ 检查接线/供电/设备是否损坏 ↓ 是 开始正常读写调试

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询