GPIO模拟I2C驱动的通用代码,I2C的寄存器地址有8位和16位的,主要解决了同一个MCU同时处理8位和16位寄存器地址芯片时候的驱动问题。
typedef enum {
IIC_8BIT_BASE_ADDR,
IIC_16BIT_BASE_ADDR
}iic_bits_e;
typedef struct {
uint8_t DevAddr;
uint16_t RegAddr;
uint8_t data_len;
uint8_t * data_buf;
uint8_t bit_flag;
uint16_t delay;
}iic_param_t;
以上是结构体,作为参数,其中DevAddr是芯片地址,RegAddr是寄存器地址,data_len是写入或者读取的数据长度,data_buf是写入或者读出的数据缓冲区,bit_flag是寄存器位数IIC_8BIT_BASE_ADDR是8位,IIC_16BIT_BASE_ADDR是16位。delay是根据需求读写数据时候的延时。根据芯片需求填写,用不到就填0
下面是用法:
写8bit寄存器
void bq27426_write_data(uint16_t reg, uint8_t * buf, uint8_t len)
{
iic_param_t bq27426 = {
BQ27426_DEV_ADDR,
0,
0,
NULL,
IIC_8BIT_BASE_ADDR,
30
};
bq27426.RegAddr = reg;
bq27426.data_buf = buf;
bq27426.data_len = len;
simulate_i2c_writeblock(&bq27426);
}
写16bit寄存器
void cypd3176_write_data(uint16_t reg, uint8_t * buf, uint8_t len)
{
iic_param_t cypd3176 = {
CYPD3176_DEV_ADDR,
0,
0,
NULL,
IIC_16BIT_BASE_ADDR,
0
};
cypd3176.RegAddr = reg;
cypd3176.data_buf = buf;
cypd3176.data_len = len;
simulate_i2c_writeblock(&cypd3176);
}
读8bit寄存器
void bq27426_read_data(uint16_t reg, uint8_t * buf, uint8_t len)
{
iic_param_t bq27426 = {
BQ27426_DEV_ADDR,
0,
0,
NULL,
IIC_8BIT_BASE_ADDR,
30
};
bq27426.RegAddr = reg;
bq27426.data_buf = buf;
bq27426.data_len = len;
simulate_i2c_readblock(&bq27426);
}
读16bit寄存器
void cypd3176_read_data(uint16_t reg, uint8_t * buf, uint8_t len)
{
iic_param_t cypd3176 = {
CYPD3176_DEV_ADDR,
0,
0,
NULL,
IIC_16BIT_BASE_ADDR,
0
};
cypd3176.RegAddr = reg;
cypd3176.data_buf = buf;
cypd3176.data_len = len;
simulate_i2c_readblock(&cypd3176);
}
下面是源码文章来源:https://www.toymoban.com/news/detail-860574.html
#include "stdio.h"
#include "simulate.h"
#define PORT_I2C_SCL GPIOB
#define PIN_I2C_SCL GPIO_Pin_6
#define PORT_I2C_SDA GPIOB
#define PIN_I2C_SDA GPIO_Pin_7
#define simulate_IIC_SCL PBout(6)
#define simulate_IIC_SDA PBout(7)
#define simulate_READ_SDA PBin(7)
static void i2c_Delay(void);
static void i2c_PinModeOutput(void);
static void i2c_PinModeInput(void);
static void i2c_SCL(uint8_t stat);
static void i2c_SDA(uint8_t stat);
static uint8_t i2c_ReadSDA(void);
static void i2c_Stop(void);
iic_param_t simulate = {
simulate_ADDR,
0,
0,
NULL,
IIC_16BIT_BASE_ADDR,
0
};
static void i2c_Delay(void)
{
unsigned char t = 3;
while (t--)
;
}
static void i2c_PinModeOutput(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // ʹ��A�˿�ʱ��
GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // �������
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // �ٶ�50MHz
GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); // ��ʼ��PA0,1
}
static void i2c_PinModeInput(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // ʹ��A�˿�ʱ��
GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // �������
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // �ٶ�50MHz
GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); // ��ʼ��PA0,1
}
static void i2c_SCL(uint8_t stat)
{
if (stat)
{
simulate_IIC_SCL = 1;
}
else
{
simulate_IIC_SCL = 0;
}
}
static void i2c_SDA(uint8_t stat)
{
if (stat)
{
simulate_IIC_SDA = 1;
}
else
{
simulate_IIC_SDA = 0;
}
}
static uint8_t i2c_ReadSDA(void)
{
if (simulate_READ_SDA)
{
return 1;
}
else
{
return 0;
}
}
void i2c_Start(void)
{
i2c_PinModeOutput();
i2c_SDA(1);
i2c_Delay();
i2c_SCL(1);
i2c_Delay();
i2c_SDA(0);
i2c_Delay();
i2c_SCL(0);
i2c_Delay();
}
void i2c_Stop(void)
{
i2c_PinModeOutput();
i2c_SCL(0);
i2c_SDA(0);
i2c_Delay();
i2c_SCL(1);
i2c_Delay();
i2c_SDA(1);
i2c_Delay();
}
void i2c_WriteByte(uint8_t _ucByte)
{
uint8_t i;
i2c_PinModeOutput();
i2c_SCL(0);
i2c_Delay();
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
i2c_SDA(1);
}
else
{
i2c_SDA(0);
}
_ucByte = _ucByte << 1;
i2c_SCL(1);
i2c_Delay();
i2c_SCL(0);
i2c_Delay();
}
i2c_SDA(1);
}
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t recv = 0;
i2c_PinModeOutput();
i2c_SDA(1);
i2c_Delay();
i2c_PinModeInput();
for (i = 0; i < 8; i++)
{
recv = recv << 1;
i2c_SCL(1);
i2c_Delay();
if (i2c_ReadSDA())
{
recv |= 0x01;
}
else
{
recv |= 0x00;
}
i2c_SCL(0);
i2c_Delay();
}
return recv;
}
void i2c_Ack(void)
{
i2c_PinModeOutput();
i2c_SCL(0);
i2c_SDA(0);
i2c_Delay();
i2c_SCL(1);
i2c_Delay();
i2c_SCL(0);
}
void i2c_NAck(void)
{
i2c_PinModeOutput();
i2c_SCL(0);
i2c_SDA(1);
i2c_Delay();
i2c_SCL(1);
i2c_Delay();
i2c_SCL(0);
}
uint8_t i2c_CheckAck(void)
{
uint8_t time = 0;
i2c_PinModeOutput();
i2c_SDA(1);
i2c_Delay();
i2c_SCL(1);
i2c_Delay();
i2c_PinModeInput();
while (i2c_ReadSDA())
{
time++;
if (time >= 100)
{
return 1;
}
}
i2c_SCL(0);
return 0;
}
#define I2C_WR 0x00
#define I2C_RD 0x01
#define ACK 0
#define NOACK 1
void simulate_i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
}
uint8_t iic_chip_select(iic_param_t *param, uint8_t rw_flag)
{
uint16_t i = 0;
if (param->data_len > 40)
{
return 0xf1;
}
if (param->data_buf == NULL)
{
return 0xF2;
}
for (i = 0; i < 3; i++)
{
i2c_Start();
i2c_WriteByte((param->DevAddr << 1) | rw_flag);
if (i2c_CheckAck() == ACK)
{
break;
}
}
if (i >= 3)
{
i2c_Stop();
return 0xf1;
}
return 0;
}
uint8_t simulate_i2c_writeblock(iic_param_t *param)
{
uint16_t i;
if (0 != iic_chip_select(param, I2C_WR))
{
return 0xF1;
}
if (IIC_16BIT_BASE_ADDR == param->bit_flag)
{
i2c_WriteByte((param->RegAddr & 0xFF00) >> 8);
if (i2c_CheckAck() == NOACK)
{
i2c_Stop();
return 0xf7;
}
}
i2c_WriteByte(param->RegAddr & 0x00FF);
if (i2c_CheckAck() == NOACK)
{
i2c_Stop();
return 0xf3;
}
for (i = 0; i < param->data_len; i++)
{
i2c_WriteByte(param->data_buf[i]);
if (i2c_CheckAck() == NOACK)
{
i2c_Stop();
return 0xf4;
}
}
i2c_Stop();
for (i = 0; i < 100; i++)
{
i2c_Delay();
}
return 0;
}
uint8_t simulate_i2c_readblock(iic_param_t *param)
{
uint16_t i;
int16_t j;
if (0 != iic_chip_select(param, I2C_WR))
{
return 0xF1;
}
/* 发送地址 */
if (IIC_16BIT_BASE_ADDR == param->bit_flag)
{
i2c_WriteByte((param->RegAddr & 0xFF00) >> 8);
if (i2c_CheckAck() == NOACK)
{
i2c_Stop();
return 0xf7;
}
}
i2c_WriteByte(param->RegAddr & 0x00FF);
if (i2c_CheckAck() == NOACK)
{
i2c_Stop();
return 0xf8;
}
if (0 != iic_chip_select(param, I2C_RD))
{
return 0xF1;
}
for (i = 0; i < param->data_len - 1; i++)
{
for (j = 0; j < param->delay; j++)
{
i2c_Delay();
}
param->data_buf[i] = i2c_ReadByte();
for (j = 0; j < param->delay; j++)
{
i2c_Delay();
}
i2c_Ack();
}
for (j = 0; j < param->delay; j++)
{
i2c_Delay();
}
param->data_buf[param->data_len - 1] = i2c_ReadByte();
i2c_NAck();
i2c_Stop();
return 0;
}
#ifndef __IIC_DRIVER_H__
#define __IIC_DRIVER_H__
#include "sys.h"
#include "stdlib.h"
#define simulate_ADDR (0x5F)
typedef enum {
IIC_8BIT_BASE_ADDR,
IIC_16BIT_BASE_ADDR
}iic_bits_e;
typedef struct {
uint8_t DevAddr;
uint16_t RegAddr;
uint8_t data_len;
uint8_t * data_buf;
uint8_t bit_flag;
uint16_t delay;
}iic_param_t;
void simulate_i2c_init(void);
uint8_t simulate_i2c_readblock(iic_param_t * param);
uint8_t simulate_i2c_writeblock(iic_param_t * param);
#endif
如果找不到PBout可用下面的头文件,其他平台可以自己实现设置管脚的输入和输出模式替换掉文中的PBout PBin的接口文章来源地址https://www.toymoban.com/news/detail-860574.html
/* Includes ------------------------------------------------------------------*/
#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.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))
#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
#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
#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
到了这里,关于STM32为基础的模拟I2C通用8bit和16bit读取以及多字节读取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!