物联网实战--入门篇之(五)嵌入式-IIC驱动(SHT30温湿度)

2024-03-31 22:36

本文主要是介绍物联网实战--入门篇之(五)嵌入式-IIC驱动(SHT30温湿度),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、IIC简介

二、IIC驱动解析

三、SHT30驱动

四、总结


一、IIC简介

        不管是IIC还是串口,亦或SPI,它们的本质区别在于有各自的规则,就是时序图;它们的相同点就是只要你理解了时序图,你就可以用最普通的IO引脚模拟出各自的通讯总线,但是一般来讲没那必要,特别是串口,模拟比较麻烦,而且速率较高,使用频率较高,很费系统资源,不合算。可以发现 我的代码里IIC驱动是用自己模拟的,主要是因为1、硬件IIC有时候会卡死;2、IIC速率比较低,且使用频率较低;3、便于在各个芯片平台上移植;4、有时候IIC的设备比较多,模拟引脚选择灵活,便于PCB设计。

        那么,下面看下模拟IIC的文件,其实并不难,就是按时序图来就行了,具体时序图就不贴了,总的就下图这几个函数,然后再根据具体IIC从设备的要求读写相应数据就行了。

二、IIC驱动解析

        接下来讲解下驱动代码,先从结构体开始,主要就是保存应用层的SDA和SCL引脚信息,还有个延时,正常默认5us,不需要改动。SDA_0等这些宏定义主要是为了程序的简洁以及驱动文件移植时便于修改,只要替换各自平台的引脚操作函数即可。

        SCL是时钟引脚,总是作为输出,而SDA有时候是输出有时候是输入,所以需要IIC_SdaInMode()和IIC_SdaOutMode()进行引脚模式的切换。

        以下是IIC驱动的引脚相关函数,移植到其他平台的时候需要修改成相应的函数。

/*		
================================================================================
描述 : IIC引脚初始化
输入 : 
输出 : 
================================================================================
*/
void IIC_GPIOInit(I2cDriverStruct *pDriver)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = pDriver->pin_sda;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(pDriver->port_sda, &GPIO_InitStruct);	GPIO_InitStruct.GPIO_Pin = pDriver->pin_scl;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(pDriver->port_scl, &GPIO_InitStruct);		pDriver->delay_time=IIC_DELAY_TIME;
}/*		
================================================================================
描述 : SDA设置成输入模式
输入 : 
输出 : 
================================================================================
*/
void IIC_SdaInMode(I2cDriverStruct *pDriver)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = pDriver->pin_sda;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(pDriver->port_sda, &GPIO_InitStruct);
}/*		
================================================================================
描述 : SDA设置成输出模式
输入 : 
输出 : 
================================================================================
*/
void IIC_SdaOutMode(I2cDriverStruct *pDriver)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = pDriver->pin_sda;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(pDriver->port_sda, &GPIO_InitStruct);
}

        以下是根据IIC时序图写的信号代码,不同人模拟的代码首尾可能略有差别,但是最核心的信号状态是一样的,这个不用太纠结。具体的每个信号是什么作用、该怎么使用,等等结合SHT30温湿度的驱动再说明。


/*		
================================================================================
描述 : 起始信号
输入 : 
输出 : 
================================================================================
*/
void IIC_Start(I2cDriverStruct *pDriver)
{SCL_1;SDA_1;delay_us(pDriver->delay_time);SDA_0;delay_us(pDriver->delay_time);SCL_0;delay_us(pDriver->delay_time);
}/*		
================================================================================
描述 : 停止信号
输入 : 
输出 : 
================================================================================
*/
void IIC_Stop(I2cDriverStruct *pDriver)
{SDA_0;SCL_1;delay_us(pDriver->delay_time);SDA_1;delay_us(pDriver->delay_time);SCL_0;
}/*		
================================================================================
描述 : 应答
输入 : 
输出 : 
================================================================================
*/
void IIC_Ack(I2cDriverStruct *pDriver)
{SDA_0;delay_us(pDriver->delay_time);SCL_1;delay_us(pDriver->delay_time);SCL_0;delay_us(pDriver->delay_time);SDA_1;delay_us(pDriver->delay_time);
}/*		
================================================================================
描述 : 非应答
输入 : 
输出 : 
================================================================================
*/
void IIC_NAck(I2cDriverStruct *pDriver)
{SCL_0;delay_us(pDriver->delay_time);SDA_1;SCL_1;delay_us(pDriver->delay_time);}/*		
================================================================================
描述 : 等待回复
输入 : 
输出 : 
================================================================================
*/
bool IIC_WaitAck(I2cDriverStruct *pDriver)
{u32 wait_tickets=0;SCL_0;IIC_SdaInMode(pDriver);delay_us(pDriver->delay_time);while(SDA_READ()>0){wait_tickets++;if(wait_tickets>250){IIC_SdaOutMode(pDriver);delay_us(pDriver->delay_time);IIC_Stop(pDriver);return false;}delay_us(1);}SCL_1;delay_us(pDriver->delay_time);SCL_0;delay_us(pDriver->delay_time);IIC_SdaOutMode(pDriver);return true;
}

        以下是IIC的字节读写函数,也是根据时序来就行了,传输过程是先高位后低位,读的时候SDA引脚要先设置成输入模式。

/*		
================================================================================
描述 : 读取一个字节
输入 : 
输出 : 
================================================================================
*/
u8 IIC_ReadByte(I2cDriverStruct *pDriver)
{u8 i, data=0;IIC_SdaInMode(pDriver);for(i=0;i<8;i++){SCL_0;delay_us(pDriver->delay_time);SCL_1;delay_us(pDriver->delay_time);data=data<<1;//左移,高位先读取if(SDA_READ()>0){data|=0x01;}}SCL_0;IIC_SdaOutMode(pDriver);delay_us(pDriver->delay_time);return data;
}
/*		
================================================================================
描述 : 写入一个字节
输入 : 
输出 : 
================================================================================
*/
void IIC_WriteByte(I2cDriverStruct *pDriver, u8 data)
{u8 i;for(i=0;i<8;i++){SCL_0;if(data&0x80)//高位先写{SDA_1;			}else{SDA_0;}delay_us(pDriver->delay_time);SCL_1;delay_us(pDriver->delay_time);data=data<<1;  }}

        以上基本是模拟IIC的驱动文件的全部内容了,自己看会发现每个函数输入都有一个I2cDriverStruct结构体,这样便于多个IIC设备驱动,比如2个SHT30+2个AT24C64一起使用都是没问题的,只要把各自的引脚定义清楚来就行了,互不干扰。

三、SHT30驱动

        净化器项目跟IIC相关的就是SHT30温湿度传感器了,我们一般就是读取温湿度值就行了,所以用起来比较简单,具体看下图,其中结构体Sht30WorkStruct内容就是器件地址、IIC结构体和温湿度数值,函数主要是初始化和读取温湿度,设置地址在特殊情况下才用。

        以下是初始化代码,主要是引脚初始化和配置默认的器件地址,这个器件地址是所有IIC从机设备都有的,根据芯片厂家和硬件设计来确定,比如这里的STH30,默认是0x44;如果ADDR引脚上拉则是0x45,数据手册截图如下所示。如果器件地址是0x45的话那就在应用层调用drv_sht30_set_addr进行设置即可。

/*		
================================================================================
描述 : 器件引脚初始化
输入 : 
输出 : 
================================================================================
*/
void drv_sht30_init(Sht30WorkStruct *pSht30Work)
{IIC_GPIOInit(&pSht30Work->tag_iic);pSht30Work->dev_addr=0x44;//默认器件地址
}

        核心的就是温湿度读取了,具体代码如下,其中0x2C06是温湿度所在的寄存器地址,要读取6个字节,分别是温度高8位、温度低8位、温度校验码、湿度高8位、湿度低8位和湿度校验码,按顺序先读取出来后再自己根据公式进行整合即可。

        IIC读取的常规流程是先写入器件地址,同时通过配置器件地址的最低位说明下一步是写数据,也就是写入寄存器地址,这里是两个字节,先高8位后低8位,写完后先停止并充分延时下,让SHT30做好准备,否则不能正确读取;随后再次启动传输,写入器件地址并配置读数据需求,紧接着连续读取6字节数据,最后就是根据公式转换成实际的温湿度值就行了。

        在读取温湿度过程中会发现,IIC的时序函数起到了调度指挥的作用,起始、等待回复、停止等等,都是按顺序来的,具体自己结合代码看下。


/*		
================================================================================
描述 : 读取温湿度数据
输入 : 
输出 : 
================================================================================
*/
void drv_sht30_read_th(Sht30WorkStruct *pSht30Work)
{u16 reg_addr=0x2C06;//温湿度的寄存器地址,由数据手册得来u8 dev_addr=pSht30Work->dev_addr;I2cDriverStruct *pIIC=&pSht30Work->tag_iic;IIC_Start(pIIC);IIC_WriteByte(pIIC, dev_addr<<1|0x00);//准备写入寄存器地址IIC_WaitAck(pIIC);IIC_WriteByte(pIIC, reg_addr>>8);//写入寄存器地址高8位IIC_WaitAck(pIIC);	IIC_WriteByte(pIIC, reg_addr&0xFF);//写入寄存器地址低8位IIC_WaitAck(pIIC);		IIC_Stop(pIIC);delay_ms(20);//这个延时要稍微长点20ms以上IIC_Start(pIIC);IIC_WriteByte(pIIC, dev_addr<<1|0x01);//准备读取数据IIC_WaitAck(pIIC);	u8 buff[10]={0};for(u8 i=0; i<6; i++)//读取温湿度和校验值状态{buff[i]=IIC_ReadByte(pIIC);if(i<5)IIC_Ack(pIIC);else IIC_NAck(pIIC);}IIC_Stop(pIIC);u16 temp=buff[0]<<8|buff[1];//温度寄存器值u16 humi=buff[3]<<8|buff[4];//湿度寄存器值pSht30Work->temp_value=175.f*(float)temp/65535.f-45.f ;//转换成温度-℃pSht30Work->humi_value=100.f*(float)humi/65535.f;//转换为湿度-%printf("temp=%.1f C, humi=%.1f%%\n", pSht30Work->temp_value, pSht30Work->humi_value);
}

        由于系统可能挂载多个温湿度传感器,所以SHT30驱动程序函数入口都有一个Sht30WorkStruct结构体。

        在应用层,主要就是定义SHT30结构体、初始化引脚和读取操作了,具体如下所示。

四、总结

        IIC模拟驱动可以用在其它各种IIC器件,比如AT24Cxx系列的EEPROM、RC522 RFID感应模块等等,底层的IIC驱动过程都是一样的,剩下的就是根据数据手册,配置不同的器件地址和操作不同的寄存器地址了,基本原理是一样的,后续有机会再多写一些IIC设备的驱动。

        

本项目的交流QQ群:701889554

   写于2024-3-30

这篇关于物联网实战--入门篇之(五)嵌入式-IIC驱动(SHT30温湿度)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/865528

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

嵌入式方向的毕业生,找工作很迷茫

一个应届硕士生的问题: 虽然我明白想成为技术大牛需要日积月累的磨练,但我总感觉自己学习方法或者哪些方面有问题,时间一天天过去,自己也每天不停学习,但总感觉自己没有想象中那样进步,总感觉找不到一个很清晰的学习规划……眼看 9 月份就要参加秋招了,我想毕业了去大城市磨练几年,涨涨见识,拓开眼界多学点东西。但是感觉自己的实力还是很不够,内心慌得不行,总怕浪费了这人生唯一的校招机会,当然我也明白,毕业

Spring Boot 入门篇

一、简介 Spring Boot是一款开源的Java Web应用框架,旨在简化Spring应用的初始搭建以及开发过程。它整合了Spring技术栈中的诸多关键组件,为开发者提供了一种快速、简便的Spring应用开发方式。Spring Boot遵循“约定优于配置”的原则,通过自动配置、起步依赖和内置的Servlet容器,极大地简化了传统Spring应用的配置和部署过程。 二、Spring Boot