没志青年
发布于 2025-07-21 / 18 阅读
0

32单片机 - I2C 通信

F103:

#ifndef __I2C_BUS_H
#define __I2C_BUS_H

#include "stm32f1xx_hal.h"
#include "gpio_mapping.h"


#define I2C_SDA_GPIO GPIOB
#define I2C_SDA_PIN GPIO_PIN_14


#define I2C_SCL_GPIO GPIOB
#define I2C_SCL_PIN GPIO_PIN_13


//IO操作函数
#define I2C_SCL    PBout(13) //SCL
#define I2C_SDA    PBout(14) //输出SDA	 
#define READ_SDA   PBin(14)  //输入SDA


// IIC操作函数
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);

uint8_t I2C_Send_Byte(uint8_t txd);
uint8_t I2C_Read_Byte(unsigned char ack);

uint8_t I2C_Write_One_Byte(uint8_t deviceAddr,uint8_t regAdr, uint8_t dat);
uint8_t I2C_Write_Bytes(uint8_t deviceAddr, uint8_t regAdr, uint8_t *buf, uint16_t size);
uint8_t I2C_Read_One_Byte(uint8_t deviceAddr, uint8_t regAdr, uint8_t *dat);
uint8_t I2C_Read_Bytes(uint8_t deviceAddr, uint8_t regAdr, uint8_t *buf, uint8_t size);

#endif
#ifndef _GPIO_MAPPING_H_
#define _GPIO_MAPPING_H_

#include "stm32f1xx_hal.h"

// 映射地址公式
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

// IO口输出寄存器地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C
// IO口输入寄存器地址映射
#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

// IO口操作,只对单一的IO口!
// 确保n的值为0~15
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入


#endif
#include "i2c_bus.h"


// 在 I2C 协议 中,ACK(Acknowledge,应答信号) 始终是由接收方发送的,用于向发送方确认已成功接收到数据。

/**
* 初始化 I2C
**/
void I2C_Init(void)
{
		GPIO_InitTypeDef init_struct = {0};

		HAL_GPIO_WritePin(I2C_SDA_GPIO, I2C_SDA_PIN, GPIO_PIN_SET);  // SCL
		HAL_GPIO_WritePin(I2C_SCL_GPIO, I2C_SCL_PIN, GPIO_PIN_SET);  // SDA
		
    init_struct.Pin = I2C_SDA_PIN;
    init_struct.Mode = GPIO_MODE_OUTPUT_OD;
    init_struct.Pull = GPIO_NOPULL;
    init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(I2C_SDA_GPIO, &init_struct);
	
		init_struct.Pin = I2C_SCL_PIN;
		HAL_GPIO_Init(I2C_SCL_GPIO, &init_struct);
}


/**
 * SDA引脚设置输出模式
 */
static void I2C_Set_Output(void)
{
    GPIO_InitTypeDef init_struct = {0};
    init_struct.Mode = GPIO_MODE_OUTPUT_OD;
    init_struct.Pin = I2C_SDA_PIN;
    init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(I2C_SDA_GPIO, &init_struct);
}

/**
 * SDA引脚设置输入模式
 */
static void I2C_Set_Input(void)
{
		// HAL_GPIO_WritePin(I2C_SDA_GPIO, I2C_SDA_PIN, GPIO_PIN_RESET);  
	
    GPIO_InitTypeDef init_struct = {0};
    init_struct.Mode = GPIO_MODE_INPUT;
    init_struct.Pin = I2C_SDA_PIN;
    init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(I2C_SDA_GPIO, &init_struct);
}


// ======================== 基础函数 ======================


// 产生IIC起始信号
void I2C_Start(void)
{
    I2C_Set_Output(); // sda线输出
    I2C_SDA = 1;//SDA高
    I2C_SCL = 1;
    delay_us(4);
    I2C_SDA = 0; // START:when CLK is high,DATA change form high to low
    delay_us(4);
    I2C_SCL = 0; // 钳住I2C总线,准备发送或接收数据
}

// 产生IIC停止信号
void I2C_Stop(void)
{
    I2C_Set_Output(); // sda线输出
    I2C_SCL = 0;
    I2C_SDA = 0; // STOP:when CLK is high DATA change form low to high
    delay_us(4);
    I2C_SCL = 1;
		delay_us(4);
    I2C_SDA = 1; // 发送I2C总线结束信号
}

// 等待应答信号到来
// 返回值:1,接收应答失败
//         0,接收应答成功
uint8_t I2C_Wait_Ack(void)
{
    uint8_t ucErrTime = 0;
    I2C_Set_Input(); // SDA设置为输入
    I2C_SDA = 1;
    delay_us(1);
    I2C_SCL = 1;
    delay_us(1);
    while(READ_SDA)   // 超时处理
    {
        ucErrTime++;
        if(ucErrTime > 250)
        {
            I2C_Stop();
            return 1;
        }
    }
    I2C_SCL = 0; // 时钟输出0
    return 0;
}

// 产生ACK应答
void I2C_Ack(void)
{
    I2C_SCL = 0;
    I2C_Set_Output();
    I2C_SDA = 0;
    delay_us(2);
    I2C_SCL = 1;
    delay_us(2);
    I2C_SCL = 0;
}

// 不产生ACK应答
void I2C_NAck(void)
{
    I2C_SCL = 0;
    I2C_Set_Output();
    I2C_SDA = 1;
    delay_us(2);
    I2C_SCL = 1;
    delay_us(2);
    I2C_SCL = 0;
}

// IIC发送一个字节
// 返回从机有无应答
// 1,有应答
// 0,无应答
uint8_t I2C_Send_Byte(uint8_t txd)
{
    uint8_t t;
    I2C_Set_Output();
    I2C_SCL = 0; // 拉低时钟开始数据传输
    for(t = 0; t < 8; t++)
    {
        I2C_SDA = (txd & 0x80) >> 7;
        txd <<= 1;
        delay_us(2);
        I2C_SCL = 1;
        delay_us(2);
        I2C_SCL = 0;
        delay_us(2);
    }
		return I2C_Wait_Ack();
}

// 诿1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t I2C_Read_Byte(unsigned char ack)
{
    unsigned char i, receive = 0;
    I2C_Set_Input(); // SDA设置为输入
    for(i = 0; i < 8; i++)
    {
        I2C_SCL = 0;
        delay_us(2);
        I2C_SCL = 1;
        receive <<= 1;
        if(READ_SDA)
            receive++;
        delay_us(1);
    }
    if(ack)
			 I2C_Ack(); // 发送ACK
    else
       I2C_NAck(); // 发送nACK
    return receive;
}



//========================= 功能函数 ==========================

/**
*  时序:启动-写地址-ACK-寄存器地址-ACK-数据-ACK-停止
*/
uint8_t I2C_Write_One_Byte(uint8_t deviceAddr,uint8_t regAdr, uint8_t dat)
{
    I2C_Start();
		if (I2C_Send_Byte((deviceAddr << 1) | 0)) {
			goto cmd_fail; 
		}
		if (I2C_Send_Byte(regAdr)) {
			goto cmd_fail; 
		}
		if (I2C_Send_Byte(dat)) {
			goto cmd_fail; 
		}
    I2C_Stop();
    return 0; 

cmd_fail:
    I2C_Stop();
    return 1;
}


/**
*  时序:启动-写地址-ACK-寄存器地址-ACK-(数据-ACK)*n-停止
*/
uint8_t I2C_Write_Bytes(uint8_t deviceAddr, uint8_t regAdr, uint8_t *buf, uint16_t size)
{
    I2C_Start();
		if (I2C_Send_Byte((deviceAddr << 1) | 0)) {
			goto cmd_fail; 
		}
		if (I2C_Send_Byte(regAdr)) {
			goto cmd_fail; 
		}
		for (int i = 0; i < size - 1; i++) {
			(void) I2C_Send_Byte(*(buf + i));
		}
    I2C_Stop();
    return 0; 

cmd_fail:
    I2C_Stop();
    return 1;
}



/**
* 时序:启动-写地址-ACK-寄存器地址-ACK-重新启动-读地址-ACK-读数据-NACK-停止
失败返回1
**/
uint8_t I2C_Read_One_Byte(uint8_t deviceAddr, uint8_t regAdr, uint8_t *dat)
{
    I2C_Start();
		if (I2C_Send_Byte((deviceAddr << 1) | 0 )) {
			goto cmd_fail; 
		}
		if (I2C_Send_Byte(regAdr)) {
			goto cmd_fail; 
		}
    I2C_Start();
		if (I2C_Send_Byte((deviceAddr << 1) | 1  )) {
			goto cmd_fail; 
		}
		*dat = I2C_Read_Byte(0);
    I2C_Stop();
    return 0;

cmd_fail:
    I2C_Stop();
    return 1;
}


/**
* 时序:启动-写地址-ACK-寄存器地址-ACK-重新启动-读地址-ACK-(读数据-ACK)*(n-1)-读最后一个数据-NACK-停止
*/
uint8_t I2C_Read_Bytes(uint8_t deviceAddr, uint8_t regAdr, uint8_t *buf, uint8_t size)
{
    I2C_Start();
				if (I2C_Send_Byte((deviceAddr << 1) | 0)) {
			goto cmd_fail; 
		}
		if (I2C_Send_Byte(regAdr)) {
			goto cmd_fail; 
		}
    I2C_Start();
		if (I2C_Send_Byte((deviceAddr << 1) | 1  )) {
			goto cmd_fail; 
		}
		for (int i = 0; i < size - 1; i++) {
			*(buf + i) = I2C_Read_Byte(1);
		}
		*(buf + size - 1) = I2C_Read_Byte(0);
    I2C_Stop();
		return 0;

cmd_fail:
    I2C_Stop();
		return 1;
}