STM32F103 系列 I2C 与串口通讯源码
一、系统架构设计
┌─────────────────────────────────────────────────────────────┐
│ STM32F103 通讯系统架构 │
├─────────────────────────────────────────────────────────────┤
│ USART 串口通讯 │ I2C 总线通讯 │ 应用层协议 │ 系统管理 │
│ │ │ │ │
│ • 轮询发送 │ • 硬件I2C │ • 自定义协议 │ • 时钟配置 │
│ • 中断接收 │ • 软件模拟I2C │ • 数据校验 │ • GPIO初始化 │
│ • DMA传输 │ • 7/10位地址 │ • 超时重试 │ • 中断管理 │
│ • 多串口支持 │ • 多设备挂载 │ • 错误处理 │ • 调试输出 │
└─────────────────────────────────────────────────────────────┘
二、硬件连接设计
2.1 引脚定义(STM32F103C8T6)
STM32F103C8T6 引脚分配:
┌─────────────┬─────────────────────┬──────────────────┐
│ 引脚 │ 功能描述 │ 连接说明 │
├─────────────┼─────────────────────┼──────────────────┤
│ PA9 (USART1_TX) │ 串口1发送 │ 连接USB-TTL RX │
│ PA10 (USART1_RX)│ 串口1接收 │ 连接USB-TTL TX │
│ PB6 (I2C1_SCL) │ I2C1时钟线 │ 连接I2C设备SCL │
│ PB7 (I2C1_SDA) │ I2C1数据线 │ 连接I2C设备SDA │
│ PB10 (I2C2_SCL)│ I2C2时钟线 │ 备用I2C接口 │
│ PB11 (I2C2_SDA)│ I2C2数据线 │ 备用I2C接口 │
│ PA2 (USART2_TX)│ 串口2发送 │ 备用串口 │
│ PA3 (USART2_RX)│ 串口2接收 │ 备用串口 │
│ GND │ 地线 │ 共地连接 │
│ 3.3V │ 电源 │ I2C设备上拉电源 │
└─────────────┴─────────────────────┴──────────────────┘
2.2 I2C设备连接示例
STM32F103 ── I2C总线 ── 多个I2C设备
├── SHT20 (温湿度传感器) - 地址: 0x40
├── AT24C02 (EEPROM) - 地址: 0x50
├── MPU6050 (陀螺仪) - 地址: 0x68
└── OLED (显示屏) - 地址: 0x78
三、完整源码实现
3.1 系统时钟配置 (system_clock.c)
#include "stm32f10x.h"
#include "system_clock.h"
// 系统时钟初始化 (72MHz)
void SystemClock_Init(void) {
ErrorStatus HSEStartUpStatus;
// 使能HSE
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS) {
// 设置PLL倍频系数为9倍 (8MHz * 9 = 72MHz)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
// 使能PLL
RCC_PLLCmd(ENABLE);
// 等待PLL就绪
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 设置系统时钟源为PLL
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 等待系统时钟源切换到PLL
while (RCC_GetSYSCLKSource() != 0x08);
// 设置AHB时钟 (HCLK = SYSCLK)
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// 设置APB1时钟 (PCLK1 = HCLK/2 = 36MHz)
RCC_PCLK1Config(RCC_HCLK_Div2);
// 设置APB2时钟 (PCLK2 = HCLK = 72MHz)
RCC_PCLK2Config(RCC_HCLK_Div1);
}
}
3.2 串口驱动 (usart.c)
#include "usart.h"
#include "stm32f10x_usart.h"
// 串口接收缓冲区
#define USART_RX_BUF_SIZE 128
static uint8_t usart_rx_buf[USART_RX_BUF_SIZE];
static uint8_t usart_rx_head = 0;
static uint8_t usart_rx_tail = 0;
// 串口初始化
void USART_InitConfig(uint32_t baudrate) {
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置TX引脚 (PA9)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置RX引脚 (PA10)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置串口参数
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 配置中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(USART1, ENABLE);
}
// 串口发送单个字节
void USART_SendByte(USART_TypeDef* USARTx, uint8_t data) {
USART_SendData(USARTx, data);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}
// 串口发送字符串
void USART_SendString(USART_TypeDef* USARTx, char *str) {
while (*str) {
USART_SendByte(USARTx, *str++);
}
}
// 串口发送数据缓冲区
void USART_SendDataBuffer(USART_TypeDef* USARTx, uint8_t *data, uint16_t len) {
for (uint16_t i = 0; i < len; i++) {
USART_SendByte(USARTx, data[i]);
}
}
// 串口接收中断处理函数
void USART1_IRQHandler(void) {
uint8_t data;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
data = USART_ReceiveData(USART1);
// 存储到接收缓冲区
uint8_t next_head = (usart_rx_head + 1) % USART_RX_BUF_SIZE;
if (next_head != usart_rx_tail) {
usart_rx_buf[usart_rx_head] = data;
usart_rx_head = next_head;
}
}
}
// 读取串口接收数据
uint8_t USART_ReadByte(uint8_t *data) {
if (usart_rx_head == usart_rx_tail) {
return 0; // 缓冲区为空
}
*data = usart_rx_buf[usart_rx_tail];
usart_rx_tail = (usart_rx_tail + 1) % USART_RX_BUF_SIZE;
return 1;
}
// 获取接收数据长度
uint16_t USART_GetRxDataLength(void) {
if (usart_rx_head >= usart_rx_tail) {
return usart_rx_head - usart_rx_tail;
} else {
return USART_RX_BUF_SIZE - usart_rx_tail + usart_rx_head;
}
}
// 重定向printf到串口
int fputc(int ch, FILE *f) {
USART_SendByte(USART1, (uint8_t)ch);
return ch;
}
3.3 硬件I2C驱动 (i2c_hardware.c)
#include "i2c_hardware.h"
#include "stm32f10x_i2c.h"
// I2C超时时间
#define I2C_TIMEOUT 10000
// I2C初始化
void I2C_Hardware_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 配置I2C引脚 (PB6-SCL, PB7-SDA)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏复用输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置I2C参数
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 主机模式不需要自身地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz标准模式
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C
I2C_Cmd(I2C1, ENABLE);
}
// I2C超时等待函数
static ErrorStatus I2C_WaitForFlag(uint32_t flag, FlagStatus status) {
uint32_t timeout = I2C_TIMEOUT;
while (I2C_GetFlagStatus(I2C1, flag) != status) {
if (--timeout == 0) {
return ERROR;
}
}
return SUCCESS;
}
// I2C写单个字节
ErrorStatus I2C_WriteByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
// 发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (写模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Transmitter);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 发送寄存器地址
I2C_SendData(I2C1, reg_addr);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
// 发送数据
I2C_SendData(I2C1, data);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
// 发送停止条件
I2C_GenerateSTOP(I2C1, ENABLE);
return SUCCESS;
}
// I2C读单个字节
ErrorStatus I2C_ReadByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data) {
// 发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (写模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Transmitter);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 发送寄存器地址
I2C_SendData(I2C1, reg_addr);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
// 重新发送起始条件 (重复起始)
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (读模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Receiver);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 禁用ACK,准备接收最后一个字节
I2C_AcknowledgeConfig(I2C1, DISABLE);
// 接收数据
if (I2C_WaitForFlag(I2C_FLAG_RXNE, SET) == ERROR) return ERROR;
*data = I2C_ReceiveData(I2C1);
// 发送停止条件
I2C_GenerateSTOP(I2C1, ENABLE);
// 重新使能ACK
I2C_AcknowledgeConfig(I2C1, ENABLE);
return SUCCESS;
}
// I2C连续写多个字节
ErrorStatus I2C_WriteMultiBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len) {
// 发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (写模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Transmitter);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 发送寄存器地址
I2C_SendData(I2C1, reg_addr);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
// 连续发送数据
for (uint16_t i = 0; i < len; i++) {
I2C_SendData(I2C1, data[i]);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
}
// 发送停止条件
I2C_GenerateSTOP(I2C1, ENABLE);
return SUCCESS;
}
// I2C连续读多个字节
ErrorStatus I2C_ReadMultiBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len) {
// 发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (写模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Transmitter);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 发送寄存器地址
I2C_SendData(I2C1, reg_addr);
if (I2C_WaitForFlag(I2C_FLAG_TXE, SET) == ERROR) return ERROR;
// 重新发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
if (I2C_WaitForFlag(I2C_FLAG_SB, SET) == ERROR) return ERROR;
// 发送设备地址 (读模式)
I2C_Send7bitAddress(I2C1, dev_addr, I2C_Direction_Receiver);
if (I2C_WaitForFlag(I2C_FLAG_ADDR, SET) == ERROR) return ERROR;
I2C_ClearFlag(I2C1, I2C_FLAG_ADDR);
// 连续接收数据
for (uint16_t i = 0; i < len; i++) {
if (i == len - 1) {
// 最后一个字节,禁用ACK
I2C_AcknowledgeConfig(I2C1, DISABLE);
}
if (I2C_WaitForFlag(I2C_FLAG_RXNE, SET) == ERROR) return ERROR;
data[i] = I2C_ReceiveData(I2C1);
}
// 发送停止条件
I2C_GenerateSTOP(I2C1, ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE); // 重新使能ACK
return SUCCESS;
}
3.4 软件模拟I2C驱动 (i2c_soft.c)
#include "i2c_soft.h"
#include "delay.h"
// 软件I2C引脚定义
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB
// 设置SDA为输出模式
static void SDA_OUT(void) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
}
// 设置SDA为输入模式
static void SDA_IN(void) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
}
// 设置SCL电平
static void SCL_HIGH(void) {
GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
}
static void SCL_LOW(void) {
GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
}
// 设置SDA电平
static void SDA_HIGH(void) {
GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
}
static void SDA_LOW(void) {
GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
}
// 读取SDA电平
static uint8_t SDA_READ(void) {
return GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN);
}
// 软件I2C初始化
void I2C_Soft_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
// 拉高总线
SCL_HIGH();
SDA_HIGH();
}
// I2C起始信号
void I2C_Soft_Start(void) {
SDA_OUT();
SDA_HIGH();
SCL_HIGH();
Delay_us(4);
SDA_LOW();
Delay_us(4);
SCL_LOW();
}
// I2C停止信号
void I2C_Soft_Stop(void) {
SDA_OUT();
SCL_LOW();
SDA_LOW();
Delay_us(4);
SCL_HIGH();
SDA_HIGH();
Delay_us(4);
}
// 等待应答
uint8_t I2C_Soft_WaitAck(void) {
uint8_t ack;
SDA_IN(); // SDA设为输入
SCL_HIGH(); // 时钟拉高
Delay_us(1);
ack = SDA_READ(); // 读取应答位
SCL_LOW(); // 时钟拉低
Delay_us(1);
return ack;
}
// 发送应答
void I2C_Soft_SendAck(uint8_t ack) {
SDA_OUT();
SCL_LOW();
if (ack) {
SDA_HIGH(); // 不应答
} else {
SDA_LOW(); // 应答
}
Delay_us(2);
SCL_HIGH();
Delay_us(2);
SCL_LOW();
}
// 发送一个字节
void I2C_Soft_SendByte(uint8_t byte) {
SDA_OUT();
for (uint8_t i = 0; i < 8; i++) {
SCL_LOW();
if (byte & 0x80) {
SDA_HIGH();
} else {
SDA_LOW();
}
Delay_us(2);
SCL_HIGH();
Delay_us(2);
byte <<= 1;
}
SCL_LOW();
I2C_Soft_WaitAck(); // 等待设备应答
}
// 接收一个字节
uint8_t I2C_Soft_ReadByte(uint8_t ack) {
uint8_t byte = 0;
SDA_IN(); // SDA设为输入
for (uint8_t i = 0; i < 8; i++) {
byte <<= 1;
SCL_LOW();
Delay_us(2);
SCL_HIGH();
Delay_us(2);
if (SDA_READ()) {
byte |= 0x01;
}
}
SCL_LOW();
I2C_Soft_SendAck(ack); // 发送应答
return byte;
}
// 软件I2C写寄存器
ErrorStatus I2C_Soft_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
I2C_Soft_Start();
I2C_Soft_SendByte(dev_addr << 1); // 设备地址 + 写位
I2C_Soft_SendByte(reg_addr); // 寄存器地址
I2C_Soft_SendByte(data); // 数据
I2C_Soft_Stop();
return SUCCESS;
}
// 软件I2C读寄存器
ErrorStatus I2C_Soft_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data) {
I2C_Soft_Start();
I2C_Soft_SendByte(dev_addr << 1); // 设备地址 + 写位
I2C_Soft_SendByte(reg_addr); // 寄存器地址
I2C_Soft_Start(); // 重复起始
I2C_Soft_SendByte((dev_addr << 1) | 0x01); // 设备地址 + 读位
*data = I2C_Soft_ReadByte(1); // 读数据,发送不应答
I2C_Soft_Stop();
return SUCCESS;
}
3.5 主程序 (main.c)
#include "stm32f10x.h"
#include "system_clock.h"
#include "usart.h"
#include "i2c_hardware.h"
#include "i2c_soft.h"
#include "delay.h"
// I2C设备地址定义
#define SHT20_ADDR 0x40
#define AT24C02_ADDR 0x50
#define MPU6050_ADDR 0x68
#define OLED_ADDR 0x78
// 全局变量
uint8_t rx_buffer[128];
uint16_t rx_length = 0;
int main(void) {
// 系统初始化
SystemClock_Init();
Delay_Init();
// 串口初始化
USART_InitConfig(115200);
printf("STM32F103 I2C & USART Test Started!\r\n");
// 硬件I2C初始化
I2C_Hardware_Init();
printf("Hardware I2C Initialized\r\n");
// 软件I2C初始化
I2C_Soft_Init();
printf("Software I2C Initialized\r\n");
// 测试硬件I2C - 读取MPU6050 WHO_AM_I寄存器
uint8_t who_am_i = 0;
if (I2C_ReadByte(MPU6050_ADDR, 0x75, &who_am_i) == SUCCESS) {
printf("MPU6050 WHO_AM_I: 0x%02X\r\n", who_am_i);
} else {
printf("MPU6050 Read Failed!\r\n");
}
// 测试软件I2C - 读取AT24C02
uint8_t eeprom_data = 0;
if (I2C_Soft_ReadReg(AT24C02_ADDR, 0x00, &eeprom_data) == SUCCESS) {
printf("EEPROM Data: 0x%02X\r\n", eeprom_data);
}
// 主循环
while (1) {
// 检查串口接收数据
uint8_t data;
if (USART_ReadByte(&data)) {
if (rx_length < sizeof(rx_buffer) - 1) {
rx_buffer[rx_length++] = data;
}
// 回显接收到的数据
USART_SendByte(USART1, data);
// 如果接收到换行符,处理命令
if (data == '\n' || data == '\r') {
rx_buffer[rx_length] = '\0';
Process_Command((char*)rx_buffer);
rx_length = 0;
}
}
Delay_ms(10);
}
}
// 处理串口命令
void Process_Command(char *cmd) {
printf("Received Command: %s\r\n", cmd);
if (strstr(cmd, "READ")) {
uint8_t data;
if (I2C_ReadByte(MPU6050_ADDR, 0x75, &data) == SUCCESS) {
printf("MPU6050 WHO_AM_I: 0x%02X\r\n", data);
}
} else if (strstr(cmd, "WRITE")) {
if (I2C_WriteByte(MPU6050_ADDR, 0x6B, 0x00) == SUCCESS) {
printf("MPU6050 Power ON\r\n");
}
} else if (strstr(cmd, "TEST")) {
printf("System Test OK!\r\n");
}
}
四、头文件定义
4.1 usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
void USART_InitConfig(uint32_t baudrate);
void USART_SendByte(USART_TypeDef* USARTx, uint8_t data);
void USART_SendString(USART_TypeDef* USARTx, char *str);
void USART_SendDataBuffer(USART_TypeDef* USARTx, uint8_t *data, uint16_t len);
uint8_t USART_ReadByte(uint8_t *data);
uint16_t USART_GetRxDataLength(void);
#endif
4.2 i2c_hardware.h
#ifndef __I2C_HARDWARE_H
#define __I2C_HARDWARE_H
#include "stm32f10x.h"
typedef enum {ERROR = 0, SUCCESS = 1} ErrorStatus;
void I2C_Hardware_Init(void);
ErrorStatus I2C_WriteByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t data);
ErrorStatus I2C_ReadByte(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data);
ErrorStatus I2C_WriteMultiBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len);
ErrorStatus I2C_ReadMultiBytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len);
#endif
4.3 i2c_soft.h
#ifndef __I2C_SOFT_H
#define __I2C_SOFT_H
#include "stm32f10x.h"
typedef enum {ERROR = 0, SUCCESS = 1} ErrorStatus;
void I2C_Soft_Init(void);
void I2C_Soft_Start(void);
void I2C_Soft_Stop(void);
uint8_t I2C_Soft_WaitAck(void);
void I2C_Soft_SendAck(uint8_t ack);
void I2C_Soft_SendByte(uint8_t byte);
uint8_t I2C_Soft_ReadByte(uint8_t ack);
ErrorStatus I2C_Soft_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t data);
ErrorStatus I2C_Soft_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data);
#endif
参考代码 stm32f103系列I2C串口通讯源码 www.youwenfan.com/contentcsu/60820.html
五、编译与调试
5.1 Keil工程配置
Project Structure:
├── User/
│ ├── main.c
│ ├── system_clock.c
│ ├── usart.c
│ ├── i2c_hardware.c
│ └── i2c_soft.c
├── Drivers/
│ └── STM32F10x_StdPeriph_Driver/
└── CMSIS/
└── core_cm3.c
5.2 常见问题解决
| 问题 | 原因 | 解决方案 |
|---|---|---|
| I2C总线挂死 | 从设备拉低SDA | 发送9个时钟脉冲复位总线 |
| 串口乱码 | 波特率不匹配 | 检查系统时钟配置 |
| 硬件I2C无响应 | 引脚配置错误 | 确认使用开漏输出模式 |
| 软件I2C时序混乱 | 延时不足 | 增加I2C延时时间 |