当设计中使用I2C的数量多于1个时,其底层I2C的代码逻辑都是一样的,只有IO口变了,为此还要复制粘贴、修改IO,不仅费时,而且还浪费片内资源,因此可以使用指针来重复执行IIC底层代码,实现一个代码,多个IO使用。
注意:使用什么IO口,一定要打开其IO时钟,同时配置为输出开漏模式!!!
使用例程在最下面

Stm32f30x_SMLT_I2C.h

#ifndef __Stm32f30x_SMLT_I2C_H
#define __Stm32f30x_SMLT_I2C_H//========================= Include ===============================================================#include "stm32f30x.h"//========================= Variable ==============================================================typedef struct
{GPIO_TypeDef* SDA_GPIO;    //SDA的GPIO组地址GPIO_TypeDef* SCL_GPIO;    //SCL的GPIO组地址uint32_t SDA_SBIT;     //SDA 在 BSRR寄存器 中的置位uint32_t SDA_RBIT;      //SDA 在 BSRR寄存器 中的复位uint32_t SCL_SBIT;      //SCL 在 BSRR寄存器 中的置位uint32_t SCL_RBIT;      //SCL 在 BSRR寄存器 中的复位uint32_t SDA_MODER;     //SDA 在 MODER寄存器 中的配置位uint32_t SDA_MODER_0; //SDA 在 MODER寄存器 中的配置位低位uint32_t SDA_MODER_1;   //SDA 在 MODER寄存器 中的配置位高位uint8_t SCL_Delay;      //SCL的延时参数 调整波特率 越大波特率越大
}I2C_Struct;extern I2C_Struct S_I2C_IO[2];//------------------------------------- 修改处
//(想要3个的话,数组添加,下面的define也要添加,初始化函数S_I2C_Init中也要添加)//========================= I2C1_Define ================================================================
//--------------------------SDA-------------------------------------- 修改处
#define S_I2C1_SDA_GPIO     GPIOE
#define S_I2C1_SDA_BIT      0
//--------------------------SCL-------------------------------------- 修改处
#define S_I2C1_SCL_GPIO     GPIOE
#define S_I2C1_SCL_BIT      1
#define S_I2C1_SCL_DELAY    0x80
//还需配置结构体初始化函数 S_I2C_Init 别忘了打开时钟及开漏配置//========================= I2C2_Define ================================================================
//--------------------------SDA-------------------------------------- 修改处
#define S_I2C2_SDA_GPIO     GPIOE
#define S_I2C2_SDA_BIT      11
//--------------------------SCL-------------------------------------- 修改处
#define S_I2C2_SCL_GPIO     GPIOB
#define S_I2C2_SCL_BIT      13
#define S_I2C2_SCL_DELAY    0x10
//还需配置结构体初始化函数 S_I2C_Init 别忘了打开时钟及开漏配置// //========================= I2Cx_Define ================================================================
// //--------------------------SDA-------------------------------------- 修改处
// #define S_I2Cx_SDA_GPIO      GPIOx
// #define S_I2Cx_SDA_BIT       x
// //--------------------------SCL-------------------------------------- 修改处
// #define S_I2Cx_SCL_GPIO      GPIOx
// #define S_I2Cx_SCL_BIT       x
// #define S_I2Cx_SCL_DELAY     x
// //添加在此添加//========================= Function ==============================================================void S_I2C_Init(void);//--------------------------------------------- 修改处void S_I2C_Start(I2C_Struct I2C_temp);
void S_I2C_Stop(I2C_Struct I2C_temp);
uint8_t S_I2C_SendByte(I2C_Struct I2C_temp, uint8_t byte);
uint8_t S_I2C_ReceiveByte(I2C_Struct I2C_temp, uint8_t nack);
uint8_t S_I2C_WriteRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t data);
uint8_t S_I2C_ReadRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ);
uint8_t S_I2C_PointerRead(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ);//========================= Define ================================================================
//通过宏定义将IO结构体直接放入基础函数中
//-------------------------- I2C1 -----------------------------------
#define S_I2C1_Start()                                          S_I2C_Start(S_I2C_IO[0])
#define S_I2C1_Stop()                                           S_I2C_Stop(S_I2C_IO[0])
#define S_I2C1_SendByte(byte)                                   S_I2C_SendByte(S_I2C_IO[0], byte)
#define S_I2C1_ReceiveByte(nack)                                S_I2C_ReceiveByte(S_I2C_IO[0], nack)
#define S_I2C1_WriteRegister(addr, regAddr, data)               S_I2C_WriteRegister(S_I2C_IO[0], addr, regAddr, data)
#define S_I2C1_ReadRegister(addr, regAddr, amount, data, typ)   S_I2C_ReadRegister(S_I2C_IO[0], addr, regAddr, amount, data, typ)
#define S_I2C1_PointerRead(addr, regAddr, amount, data, typ)    S_I2C_PointerRead(S_I2C_IO[0], addr, regAddr, amount, data, typ)//-------------------------- I2C2 -----------------------------------
#define S_I2C2_Start()                                          S_I2C_Start(S_I2C_IO[1])
#define S_I2C2_Stop()                                           S_I2C_Stop(S_I2C_IO[1])
#define S_I2C2_SendByte(byte)                                   S_I2C_SendByte(S_I2C_IO[1], byte)
#define S_I2C2_ReceiveByte(nack)                                S_I2C_ReceiveByte(S_I2C_IO[1], nack)
#define S_I2C2_WriteRegister(addr, regAddr, data)               S_I2C_WriteRegister(S_I2C_IO[1], addr, regAddr, data)
#define S_I2C2_ReadRegister(addr, regAddr, amount, data, typ)   S_I2C_ReadRegister(S_I2C_IO[1], addr, regAddr, amount, data, typ)
#define S_I2C2_PointerRead(addr, regAddr, amount, data, typ)    S_I2C_PointerRead(S_I2C_IO[1], addr, regAddr, amount, data, typ)//-------------------------- Another --------------------------------
#define ACK     0
#define NACK    1#define FAILED 0
#define SUCCEED 1#define ARRAY  0
#define STRUCT  1
//=================================================================================================#endif

Stm32f30x_SMLT_I2C.c


#include "Stm32f30x_SMLT_I2C.h"I2C_Struct S_I2C_IO[2];//IO口结构体,通过.h文件定义使用的引脚/*** @description: I2C结构体IO初始化* @param {I2C_Struct*} I2C_temp    I2C的IO结构体* @param {GPIO_TypeDef*}  SDA_GPIO        I2C SDA GPIO(GPIOA~GPIOx)* @param {uint8_t}         SDA_BIT         I2C SDA引脚号(1~16)* @param {GPIO_TypeDef*} SCL_GPIO        I2C SCL GPIO(GPIOA~GPIOx)* @param {uint8_t}         SCL_BIT         I2C SCL引脚号(1~16)* @param {uint8_t}           SCL_Delay       I2C SCL时钟延时(0x00~0xff)越大波特率越低* @return {*}*/
void S_I2C_Struct_Init(I2C_Struct* I2C_temp, GPIO_TypeDef* SDA_GPIO, uint8_t SDA_BIT, GPIO_TypeDef* SCL_GPIO, uint8_t SCL_BIT, uint8_t SCL_Delay)
{I2C_temp->SDA_GPIO = SDA_GPIO;I2C_temp->SCL_GPIO = SCL_GPIO;I2C_temp->SDA_SBIT = (0x00000001 << SDA_BIT);I2C_temp->SDA_RBIT = (0x00010000 << SDA_BIT);I2C_temp->SCL_SBIT = (0x00000001 << SCL_BIT);I2C_temp->SCL_RBIT = (0x00010000 << SCL_BIT);I2C_temp->SDA_MODER = 0x00000003 << (SDA_BIT << 1);I2C_temp->SDA_MODER_0 = 0x00000001 << (SDA_BIT << 1);I2C_temp->SDA_MODER_1 = 0x00000002 << (SDA_BIT << 1);I2C_temp->SCL_Delay = SCL_Delay;
}/*** @description: I2C结构体总初始化,将计算的各个变量存入结构体中* @param {*}* @return {*}*/
void S_I2C_Init(void)
{S_I2C_Struct_Init(&S_I2C_IO[0], S_I2C1_SDA_GPIO, S_I2C1_SDA_BIT, S_I2C1_SCL_GPIO, S_I2C1_SCL_BIT, S_I2C1_SCL_DELAY);S_I2C_Struct_Init(&S_I2C_IO[1], S_I2C2_SDA_GPIO, S_I2C2_SDA_BIT, S_I2C2_SCL_GPIO, S_I2C2_SCL_BIT, S_I2C2_SCL_DELAY);// S_I2C_Struct_Init(&S_I2C_IO[x], S_I2Cx_SDA_GPIO, S_I2Cx_SDA_BIT, S_I2Cx_SCL_GPIO, S_I2Cx_SCL_BIT, S_I2Cx_SCL_DELAY);//添加在此添加
}/*** @description: I2C时钟延时,调整波特率* @param {*}* @return {*}*/
void S_I2C_Delay(uint8_t temp)
{for ( ; temp; temp--){/* code */}
}/*** @description: 产生起始信号* @param {I2C_Struct} I2C_temp I2C_IO结构体* @return {*}*/
void S_I2C_Start(I2C_Struct I2C_temp)
{I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);
}/*** @description: 产生停止信号* @param {I2C_Struct} I2C_temp* @return {*}*/
void S_I2C_Stop(I2C_Struct I2C_temp)
{I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;S_I2C_Delay(I2C_temp.SCL_Delay);
}/*** @description: 发送一个字节数据* @param {I2C_Struct} I2C_temp    I2C_IO结构体* @param {uint8_t} byte   数据* @return {uint8_t}      NACK*                           ACK*/
uint8_t S_I2C_SendByte(I2C_Struct I2C_temp, uint8_t byte)
{uint8_t temp = 0x00;for(uint8_t i = 0x80; i; i >>= 1){I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;if(byte & i){I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;}else{I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;}S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;S_I2C_Delay(I2C_temp.SCL_Delay);}I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;I2C_temp.SDA_GPIO->MODER &= ~I2C_temp.SDA_MODER;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;if(I2C_temp.SDA_GPIO -> IDR & I2C_temp.SDA_SBIT){temp = NACK;}else{temp = ACK;}S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);return temp;
}/*** @description: 接收一个字节数据* @param {I2C_Struct} I2C_temp    I2C_IO结构体* @param {uint8_t} nack   接收后结束要发送的应答信号*                          NACK*                           ACK* @return {uint8_t} 接收到的字节*/
uint8_t S_I2C_ReceiveByte(I2C_Struct I2C_temp, uint8_t nack)
{uint8_t byte = 0x00;I2C_temp.SDA_GPIO->MODER &= ~I2C_temp.SDA_MODER;for (uint8_t i = 8; i; i--){I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);byte <<= 1;I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;if(I2C_temp.SDA_GPIO -> IDR & I2C_temp.SDA_SBIT){byte |= 0x01;}S_I2C_Delay(I2C_temp.SCL_Delay);}I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;if(nack)I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;elseI2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;S_I2C_Delay(I2C_temp.SCL_Delay);I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;S_I2C_Delay(I2C_temp.SCL_Delay);return byte;
}/*** @description: 写一个字节的寄存器* @param {I2C_Struct} I2C_temp   I2C_IO结构体* @param {uint8_t} addr   器件地址(0x00~0x7f)* @param {uint8_t} regAddr  寄存器地址(0x00~0xff)* @param {uint8_t} data    数据* @return {uint8_t}  FAILED  失败*                         SUCCEED 成功*/
uint8_t S_I2C_WriteRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t data)
{addr <<= 1;S_I2C_Start(I2C_temp);if(S_I2C_SendByte(I2C_temp, addr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}if(S_I2C_SendByte(I2C_temp, regAddr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}if(S_I2C_SendByte(I2C_temp, data) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}S_I2C_Stop(I2C_temp);return SUCCEED;
}/*** @description:        读取器件,读取格式:器件读-寄存器地址-读取数据* @param {I2C_Struct} I2C_temp   I2C_IO结构体* @param {uint8_t} addr   器件地址(0x00~0x7f)* @param {uint8_t} regAddr  寄存器地址(0x00~0xff)* @param {uint8_t} amount  读取数据数量(0x00~0xff)* @param {uint8_t*} data  返回数据指针* @param {uint8_t} typ       数据指针类型(由于结构体和数组存储方式不一样,因此需要区分)*                        ARRAY   数组*                         STRUCT  结构体* @return {*}           FAILD   读取失败 数据无效*                      SUCCEED 读取成功 数据有效*/
uint8_t S_I2C_ReadRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ)
{S_I2C_Start(I2C_temp);addr = (addr << 1) | 0x01;if(S_I2C_SendByte(I2C_temp, addr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}if(S_I2C_SendByte(I2C_temp, regAddr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}for(amount -= 1;amount;amount --){*data = S_I2C_ReceiveByte(I2C_temp, ACK);if(typ == ARRAY)data ++;elsedata --;}*data = S_I2C_ReceiveByte(I2C_temp, NACK);S_I2C_Stop(I2C_temp);return SUCCEED;
}/*** @description:        读取器件,读取格式:器件写-寄存器地址-器件读-读取数据* @param {I2C_Struct} I2C_temp   I2C_IO结构体* @param {uint8_t} addr   器件地址(0x00~0x7f)* @param {uint8_t} regAddr  寄存器地址(0x00~0xff)* @param {uint8_t} amount  读取数据数量(0x00~0xff)* @param {uint8_t*} data  返回数据指针* @param {uint8_t} typ       数据指针类型(由于结构体和数组存储方式不一样,因此需要区分)*                        ARRAY   数组*                         STRUCT  结构体* @return {uint8_t} FAILD   读取失败 数据无效*                      SUCCEED 读取成功 数据有效*/
uint8_t S_I2C_PointerRead(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ)
{addr <<= 1;S_I2C_Start(I2C_temp);if(S_I2C_SendByte(I2C_temp, addr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}if(S_I2C_SendByte(I2C_temp, regAddr) == NACK){S_I2C_Stop(I2C_temp);return FAILED;}S_I2C_Stop(I2C_temp);addr |= 0x01;S_I2C_Start(I2C_temp);if(S_I2C_SendByte(I2C_temp, addr) == NACK) //NACK{S_I2C_Stop(I2C_temp);return FAILED;}for(amount -= 1;amount;amount --){*data = S_I2C_ReceiveByte(I2C_temp, ACK);if(typ == ARRAY)data ++;elsedata --;}*data = S_I2C_ReceiveByte(I2C_temp, NACK);S_I2C_Stop(I2C_temp);return SUCCEED;
}

使用方法

void main(void)
{CLOCK_Init();GPIO_Init();S_I2C_Init();//初始化结构体,在宏定义中修改引脚等定义//接下来就可以调用I2C函数了
}

STM32 模拟IIC源代码 多个I2C减少冗余代码相关推荐

  1. STM32模拟IIC协议驱动AD7991/AD7995/AD7999芯片

    STM32模拟IIC协议驱动AD7991/AD7995/AD7999芯片 AD7991/AD7995/AD7999是12位/10位/8位 4通道模拟输入的AD转换芯片 通信方式采用的是:I2C 芯片供 ...

  2. STM32模拟IIC读取PCF8563

    作者第一次开写博客,本着学习的态度,附上自己总结的代码,希望大家多多指点! 一.首先是对于PCF8563芯片的介绍与使用说明: PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接 ...

  3. STM32模拟IIC驱动sht30温湿度传感器

    最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了 所以拿出来分享给大家. sht30外观 驱动不是自己写的, 是采用CSDN上的一位朋友的 , ...

  4. STM32 模拟IIC完整代码

    void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPI ...

  5. STM32模拟IIC驱动OLED屏 原理+源码

    处理器和芯片间的通信可以形象的比喻成两个人讲话:1.你说的别人得能听懂:双方约定信号的协议.2.你的语速别人得能接受:双方满足时序要求. 一.IIC总线的信号类型 1.开始信号:处理器让SCL时钟保持 ...

  6. STM32实现0.96寸OLED显示模拟IIC和IIC四种实现(标准库和HAL库)

    目录 本文通过四种方法实现OLED显示 设备选择 OLED介绍 接线表设计 OLED应用 1.标准库模拟IIC实现OLED显示 2.标准库IIC实现OLED显示 3.HAL库模拟IIC实现OLED显示 ...

  7. 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)

    版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 I ...

  8. 【蓝桥杯嵌入式】【STM32】5_IICEEPROM之软件模拟IIC

    文章目录 1.原理图 2.源代码   下载工程文件:   https://gitee.com/Joseph_Cooper/blue-bridge-embedded 1.原理图 顺便指出了该器件的地址. ...

  9. 基于stm32单片机的模拟IIC时序(附源码)

    我下面要说的是基于stm32单片机的模拟IIC时序,以及是一些要注意的事项:结合自己所做的MMA7455加速度传感器,我把模拟IIC的源代码贴了出来,大家可以参考一下. 1.因为在IIC协议中,当总线 ...

最新文章

  1. html 搜索框 自动补全,自动完成的搜索框javascript实现
  2. linux命令积累之egrep命令
  3. 自动驾驶使用贝塞尔曲线进行静态障碍物避障测试
  4. Leetcode c语言-Divide Two Integers
  5. 如何解决inline-block元素的空白间距
  6. 防163网易邮箱登录界面html,网易邮箱163,网易邮箱163登录界面
  7. redfish、ipmi返回状态码
  8. AWS环境搭建(六):Linux上部署wowza,并配置ssl证书
  9. k近邻算法_面试|k近邻(KNN)算法与k均值(kmeans)聚类算法有何不同?
  10. 微信支付宝支付开发文档
  11. java switch语句的升级
  12. 数字孪生北京故宫,元宇宙推进旅游业进程
  13. Mysql分表,分区的区别和联系
  14. Java 征途:行者的地图(推荐好文)
  15. Enterprise Architect:绘制基本包图(详细步骤)
  16. 十年总结(15):产品化-有心杀敌,无力回天
  17. Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backs
  18. PHP jqGrid 表格数据更新帮助代码
  19. Tomcat4.1、5.5、6.0的连接池配置及测试程序
  20. WPS表格如何快速制作工资条

热门文章

  1. ios html中文显示乱码,iOS读取txt文件出现中文乱码的解决方法
  2. [为梦想,千里行] 评论:35岁前买房没出息,说对了一半
  3. 外贸公司报价/换汇成本计算公式
  4. python中的strip()和split()函数
  5. 甜度犹如蜂蜜的蜂糖李,究竟有何不同之处?礼誉带你一探究竟
  6. MYSQL索引使用技巧及注意事项
  7. CISCO交换机开启SNMP配置团体名
  8. lisp提取长方形坐标_坐标提取lisp程序.doc
  9. TMS320C6748开发视频教程笔记 第12章 通用输入输出口 GPIO
  10. 搜索引擎优化指南教程