STM32F103 系列 I2C 与串口通讯源码

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延时时间

专注于matlab/simulink,电子电路,编程