我们写单片机代码时常常会用到软件IIC,网上大部分软件I2C协议将底层GPIO和时序写在了一起,而且要是用到了多条I2C总线时,移植时往往很尴尬,这里给大家提供一个封装好的简易I2C模块,只需要提供单片机上的GPIO读写操作方法就能完成I2C的读写操作。
注:该代码不建议初学者使用,希望刚接触I2C的小工程师们能踏踏实实先写一两次时序代码,读懂时序图。
源代码下载地址:
百度云代码下载:https://pan.baidu.com/s/1v9WADsHb73a0k7sHF-w3hg 提取码:3h8l
Github下载地址:https://github.com/diceTZ/I2C.git
Z_I2C.h(由于篇幅过大Z_I2C.c未贴出,下载地址中含有Z_I2C.c文件)
//@作者 :tou_zi
//@编写时间 :2019年4月6日
//@修改时间 :2019年4月6日
//@文件名 :Z_I2C.h
//@描述 :模拟I2C时序结构模块
#ifndef _Z_I2C_H
#define _Z_I2C_H
#ifndef u8
#define u8 unsigned char
#endif
#define I2C_NORMAL 0
#define I2C_FAST 1
typedef struct I2C_SCLInterface
{
void(*write)(u8 lH);
}I2C_SCLInterface;
typedef struct I2C_SDAInterface
{
void(*selectRW)(u8 rW);
void(*write)(u8 lH);
u8(*read)(void);
}I2C_SDAInterface;
typedef struct I2C_Interface
{
u8 mode;
I2C_SCLInterface scl;
I2C_SDAInterface sda;
}I2C_Interface;
//初始化结构体
void initI2C_Interface(I2C_Interface *interface, u8 mode);
void setModeI2C_Interface(I2C_Interface *interface, u8 mode);
//I2CAPI
u8 writeByteI2C(I2C_Interface *interface, u8 dev, u8 reg, u8 data);
u8 readByteI2C(I2C_Interface *interface, u8 dev, u8 reg, u8 *data);
u8 writenByteI2C(I2C_Interface *interface, u8 dev, u8 reg, u8 len, u8 *data);
u8 readnByteI2C(I2C_Interface *interface, u8 dev, u8 reg, u8 len, u8 *data);
#endif
模块概述:I2C模块包含mode标志位、SCL子模块以及SDA子模块。
mode标志位:用于选择I2C的速率,在.c文件中可以自行修改
SCL子模块:SCL总线只需要写操作,不需要读操作,所以模块内是写(0或1)的函数指针。
SDA子模块:SDA总线需要读写操作,所以模块内含有写、读、以及读写转换的函数指针。
用户需要自己编写GPIO读、写函数,完成模块接口的连接。
使用方法(例程):
1、stm32F4
#include "Z_I2C.h
I2C_Interface i2c;
//SCL总线的写函数
static void writelH_SCL(u8 lH)
{
PBout(6) = (lH == 0) ? 0: 1;
}
//SDA总线的读写转换操作函数
static void selectRW_SDA(u8 rW)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
if (rW == 0)
{
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
else
{
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
}
//SDA总线的写函数
static void writelH_SDA(u8 lH)
{
PBout(7) = (lH == 0) ? 0: 1;
}
//SDA总线的读函数
static u8 readlH_SDA()
{
return PBin(7);
}
//配置I2C
void configI2C()
{
//GPIO初始化
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//模块初始化
initI2C_Interface(&i2c, 0);
i2c.scl.write = writelH_SCL; //将上面的方法与模块接口相连接
i2c.sda.selectRW = selectRW_SDA;
i2c.sda.write = writelH_SDA;
i2c.sda.read = readlH_SDA;
u8 data[2] = {0x01, 0x02};
//向地址0x68,寄存器地址为0x05连续写入2个数据
writenByteI2C(&i2c, 0x68, 0x05, 2, data);
//向地址0x68,寄存器地址为0x05连续读入2个数据
readnByteI2C(&i2c, 0x68, 0x05, 2, data);
}
2、TM4C123
#include "Z_I2C.h
I2C_Interface i2c;
//SCL写方法
static void writelH_SCL(u8 lH)
{
if (lH == 0)
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, 0);
else
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, GPIO_PIN_6);
}
//SDA读写转换方法
static void selectRW_SDA(u8 rW)
{
if (rW == 0)
{
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; //解锁
HWREG(GPIO_PORTA_BASE + GPIO_O_CR) = GPIO_PIN_7; //确认
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = 0; //重新锁定
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_7);
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}
else
{
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; //解锁
HWREG(GPIO_PORTA_BASE + GPIO_O_CR) |= GPIO_PIN_7; //确认
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = 0; //重新锁定
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7);
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}
}
//SDA写方法
static void writelH_SDA(u8 lH)
{
if (lH == 0)
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0);
else
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_PIN_7);
}
//SDA读方法
static u8 readlH_SDA()
{
return (GPIOPinRead(GPIO_PORTA_BASE, GPIO_PIN_7) & GPIO_PIN_7) == 0 ? 0 : 1;
}
//配置I2C
void configI2C()
{
//GPIO设置
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; //解锁
HWREG(GPIO_PORTA_BASE + GPIO_O_CR) |= GPIO_PIN_7; //确认
HWREG(GPIO_PORTA_BASE + GPIO_O_LOCK) = 0; //重新锁定
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_6);
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7);
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, GPIO_PIN_6);//设置高
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, GPIO_PIN_7);//设置高
//I2C模块配置
initI2C_Interface(&i2c, 0);
i2c.scl.write = writelH_SCL;
i2c.sda.selectRW = selectRW_SDA;
i2c.sda.write = writelH_SDA;
i2c.sda.read = readlH_SDA;
u8 data[2] = {0x01, 0x02};
//向地址0x68,寄存器地址为0x05连续写入2个数据
writenByteI2C(&i2c, 0x68, 0x05, 2, data);
//向地址0x68,寄存器地址为0x05连续读入2个数据
readnByteI2C(&i2c, 0x68, 0x05, 2, data);
}
“望小小的举动,能改变世界“