STM32 模拟IIC源代码 多个I2C减少冗余代码
当设计中使用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减少冗余代码相关推荐
- STM32模拟IIC协议驱动AD7991/AD7995/AD7999芯片
STM32模拟IIC协议驱动AD7991/AD7995/AD7999芯片 AD7991/AD7995/AD7999是12位/10位/8位 4通道模拟输入的AD转换芯片 通信方式采用的是:I2C 芯片供 ...
- STM32模拟IIC读取PCF8563
作者第一次开写博客,本着学习的态度,附上自己总结的代码,希望大家多多指点! 一.首先是对于PCF8563芯片的介绍与使用说明: PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接 ...
- STM32模拟IIC驱动sht30温湿度传感器
最近有在使用sht30这个传感器,相比于新手常用的dht11传感器,sht30更精确,自己花了半小时调好了 所以拿出来分享给大家. sht30外观 驱动不是自己写的, 是采用CSDN上的一位朋友的 , ...
- STM32 模拟IIC完整代码
void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPI ...
- STM32模拟IIC驱动OLED屏 原理+源码
处理器和芯片间的通信可以形象的比喻成两个人讲话:1.你说的别人得能听懂:双方约定信号的协议.2.你的语速别人得能接受:双方满足时序要求. 一.IIC总线的信号类型 1.开始信号:处理器让SCL时钟保持 ...
- STM32实现0.96寸OLED显示模拟IIC和IIC四种实现(标准库和HAL库)
目录 本文通过四种方法实现OLED显示 设备选择 OLED介绍 接线表设计 OLED应用 1.标准库模拟IIC实现OLED显示 2.标准库IIC实现OLED显示 3.HAL库模拟IIC实现OLED显示 ...
- 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 I ...
- 【蓝桥杯嵌入式】【STM32】5_IICEEPROM之软件模拟IIC
文章目录 1.原理图 2.源代码 下载工程文件: https://gitee.com/Joseph_Cooper/blue-bridge-embedded 1.原理图 顺便指出了该器件的地址. ...
- 基于stm32单片机的模拟IIC时序(附源码)
我下面要说的是基于stm32单片机的模拟IIC时序,以及是一些要注意的事项:结合自己所做的MMA7455加速度传感器,我把模拟IIC的源代码贴了出来,大家可以参考一下. 1.因为在IIC协议中,当总线 ...
最新文章
- html 搜索框 自动补全,自动完成的搜索框javascript实现
- linux命令积累之egrep命令
- 自动驾驶使用贝塞尔曲线进行静态障碍物避障测试
- Leetcode c语言-Divide Two Integers
- 如何解决inline-block元素的空白间距
- 防163网易邮箱登录界面html,网易邮箱163,网易邮箱163登录界面
- redfish、ipmi返回状态码
- AWS环境搭建(六):Linux上部署wowza,并配置ssl证书
- k近邻算法_面试|k近邻(KNN)算法与k均值(kmeans)聚类算法有何不同?
- 微信支付宝支付开发文档
- java switch语句的升级
- 数字孪生北京故宫,元宇宙推进旅游业进程
- Mysql分表,分区的区别和联系
- Java 征途:行者的地图(推荐好文)
- Enterprise Architect:绘制基本包图(详细步骤)
- 十年总结(15):产品化-有心杀敌,无力回天
- Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using backs
- PHP jqGrid 表格数据更新帮助代码
- Tomcat4.1、5.5、6.0的连接池配置及测试程序
- WPS表格如何快速制作工资条
热门文章
- ios html中文显示乱码,iOS读取txt文件出现中文乱码的解决方法
- [为梦想,千里行] 评论:35岁前买房没出息,说对了一半
- 外贸公司报价/换汇成本计算公式
- python中的strip()和split()函数
- 甜度犹如蜂蜜的蜂糖李,究竟有何不同之处?礼誉带你一探究竟
- MYSQL索引使用技巧及注意事项
- CISCO交换机开启SNMP配置团体名
- lisp提取长方形坐标_坐标提取lisp程序.doc
- TMS320C6748开发视频教程笔记 第12章 通用输入输出口 GPIO
- 搜索引擎优化指南教程