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;
}