【STM32】I2C协议完成温湿度检测

简介: I2C总线是英国的菲利普公司在八十年代初期退出来的一种串行的、半双工的总线,主要是用于一些近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根SDA用于收发数据、一根时钟线SCL用于通信双方时钟的同步。

📕 I2C总线协议简介

  I2C总线是英国的菲利普公司在八十年代初期退出来的一种串行的、半双工的总线,主要是用于一些近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根SDA用于收发数据、一根时钟线SCL用于通信双方时钟的同步。

在我们的嵌入式C语言当中,我们由其他的通信协议,我们分别还可以简单的将三种通信协议全部罗列出来进行一个大的比较一下,主要的区别我们可以通过一下的表格了解一下:

image.png

我们从上面的表格,我们可以往下延伸一下,我们的IIC总线有四信号:分别可以是,起始信号+应答信号+非应答+停止信号,那么就简单了,这我们只需要稍微的了解一下他们之间的通信的过程,我们就好往下走了。

💬 IIC通信过程

我们的IIC通信的过程可以分成以下几部分,

1、主机发送起始信号到我们的启动的总线上面;

2、主机发送一个字节数据指明到从机地址和后续字节的传送方式;

3、被寻址的从机部分发送应答信号回到我们的主机;

4、发送器发送一个字节数据;

5、接收器发送应答信号回应我们的发送器;

6、发送完,通信完成主机发送停止信号释放我们的总线。

但是,在这里要提醒的是,我们的第四第五步当中说的发送器和接收器不是我们的主机和从机,这是由我们的第一个直接的最后以为决定主机给到我们发送还是从机发送!

📝 时序图

IIC总线传送的数据可以包括地址,亦可以是真正的数据,主机上面在发送起始信号后必须先发送一个字节的数据,该数据的高7位是从机的地址,最低位表示后续字节的发送方向,‘0’代表的是主机发送数据给我们的从机,‘1’代表的是从机发送数据回到我们的主机。

  总线上面的所有的从机接收到的该字节数据后豆浆这7位地址和自己的地址进行一次就比较,相同的话,认为就是可以被主机寻到地址,然后再根据第八位将自己定为发送器或者接收器。

2345_image_file_copy_317.jpg

我们配置的功能就是根据上面的时序图来进行相应的配置就可以了,我们分别来大概的了解一下怎么配置,比如,我们可以看到起始信号,应该按照一下的方法进行一个功能的配置

✒️ 起始信号

 //函 数 名 : IIC_Start
 //功能说明 : 产生IIC起止信号
 //形    参 : 无
 //返 回 值 : 无
 //备    注 : SCL为高电平期间,SDA由高电平向低电平的跳变。
void IIC_Start(void)
{
  IIC_SCL = 1;  //时钟线为高
  IIC_SDA = 1;  //数据线为高
  Delay_Us(5);  //保持,为了产生下沿的动作
  IIC_SDA = 0;  //高电平期间,拉低SDA,产生起止信号
  Delay_Us(5);
  IIC_SCL = 0;  //占用总线,准备发送数据
  Delay_Us(5);
}

✒️ 停止信号

函 数 名 : IIC_Stop
功能说明 : 产生IIC结束信号
形    参 : 无
返 回 值 : 无
备    注 : SCL为高电平期间,SDA由低电平向高电平的跳变。
void IIC_Stop(void)
{
  IIC_SCL = 0;  //低电平时才能改变SDA的状态
  IIC_SDA = 0;  //拉低SDA,为产生上沿做准备
  //Delay_Us(5);
  IIC_SCL = 1;  //在SCL为高电平期间
  Delay_Us(5);
  IIC_SDA = 1;  //SDA由低向高跳变
  Delay_Us(5);
}

✒️  非应答信号

 函 数 名 : IIC_ACK_NACK
 功能说明 : 作为接收方时,每个字节(8bit)传输完成后的下一个时钟信号,发起应答或非应答信号
 形    参 : ack:0应答,1非应答
 返 回 值 : 
 备    注 : 在SCL为高电平期间,SDA为低,则表示一个应答信号(ACK);SDA为高,则表示一个非应答信号(NACK)。
void IIC_ACK_NACK(unsigned char ack)
{ 
  IIC_SCL = 0;  //SCL为低电平时才能改变SDA的状态
  Delay_Us(1);
  if(!ack)  IIC_SDA = 0;  //产生应答信号
  else    IIC_SDA = 1;  //产生非应答信号
  Delay_Us(5);
  IIC_SCL = 1;  //拉高SCL,从机读取应答信号
  Delay_Us(5);
  IIC_SCL = 0;  //拉低SCL,准备接收下一个数据
}

✒️ 应答信号

 函 数 名 : IIC_Wait_ACK
 功能说明 : 作为发送方时,检测从机返回的应答信号
 形    参 : 无
 返 回 值 : 0:应答,1:非应答
 备    注 : 
unsigned char IIC_Wait_ACK(void)
{
  unsigned char ErrorCounter = 0;
  IIC_SDA = 1;  //释放数据线
  IIC_SCL = 1;  //拉高SCL
  Delay_Us(5);
  while(IIC_SDAIN)      //SDA被拉低则认为从机给的应答信号
  {
    ErrorCounter++;
    if(ErrorCounter > 250)  //如果过了一段时间数据线还是为高,那么表示非应答信号
    {
      IIC_Stop();
      return 1;
    }
  }
  IIC_SCL = 0;  //拉低SCL,准备下一个数据的接受
  Delay_Us(5);
  return 0;
}

⏰ SHT31温湿度传感器

  稍微简单的介绍一下这个温湿度传感器,这主要是一款较为低成本的温湿度检测模块,一般的工作电压是2.4V-5.5V功耗比较低,体积比较小,它的工作原理是通过我们单片机的上面读取温湿度的数据,使用我们的IIC通信协议这个方式进行输出。

 工作原理:

温度检测:主要的工作的原理是采用的是热电偶的方法,由两种不同的材料的金属丝进行组成,两种金属丝材料相互链接在一起,形成一个工作的端口,放在我们的被检测温度下米线;另一个端口就是我们的自由端口,和测量仪相互链接在一起,形成一个闭合回路,当两个端温度不一样的时候,回路就会出现热电动势,经过电路的转换就能将这个电压的变化送佛啊单片机。

湿度检测:是使用沉积在两个导电电极上的聚胺盐或醋酸纤维聚合物薄膜(—种高分子化合物)当薄膜吸水或失水后,会改变两个电极间的介电常数。进而引起电容器容量的变化,利用外部测量电路可将电容器的容量变化进行捕捉、转化处理,最终在输出端显示成易识别的信号.

 将它转换成我们的代码就是:1主机多个从机,通过寻址地址的方式将每个从机有的每一个地址,将信号发送到对我们的单片机上显示出来就可以了。

代码奉上

sht31.c

#include "iic.h"  //要包含IIC.h头文件
#include "sht3x.h"
#include "systick.h"
static unsigned char crc8(const unsigned char *data, int len);
/*********************************************************************************************************
* 函 数 名 : Sht3x_Init,设置为通用开漏输出,先看rcc章节
* 功能说明 : 初始化SHT3x端口
* 形    参 : 无
* 返 回 值 : 无
* 备    注 : IIC_SCL:PB6,IIC_SDA:PB7
*********************************************************************************************************/ 
void Sht3x_Init(void)//window命名规则,init要大写
{
  GPIO_InitTypeDef GPIO_InitStructure = {0}; 
  //io口的配置就到gpio.c里面就好了,rcc那一栏  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  //时钟你不知道的话,你可以到rcc文件右键RCC_AHB1PeriphClockCmd就可以看到了
  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_25MHz;  //速度配置
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL; //浮空(无上下拉)
  GPIO_Init(GPIOB, &GPIO_InitStructure);            //初始化
  //配置的内容我们直接到手册就可以就好了
  //配置完全部都要拉高,强制处于空闲状态
  IIC_SCL = 1;
  IIC_SDA = 1;
}
/*********************************************************************************************************
* 函 数 名 : Sht3x_Read_TemperatureHumidity
* 功能说明 : 读取SHT3x温湿度数据
* 形    参 : HT:存储温湿度的结构体指针
* 返 回 值 : 无
* 备    注 : 无
*********************************************************************************************************/ 
int Sht3x_Read_TemperatureHumidity(Sht3x_TypeDef *temp)
{
  unsigned char buff[6] = {0};
  unsigned char i = 0;
  IIC_Start();                    //第一步,先调用起止信号
  IIC_WriteByte(SHT3X_ADDR<<1 | IIC_WRITE);     //器件地址+写
  if(IIC_Wait_ACK() == ACK){              //对方应答了,继续执行,从机应答
    IIC_WriteByte(SHT3X_READ_TEMP_HUM>>8);      //命令的高位
    if(IIC_Wait_ACK() == ACK){            //对方应答了,继续执行
      IIC_WriteByte(SHT3X_READ_TEMP_HUM&0xff);  //命令的低位
      if(IIC_Wait_ACK() == ACK){          //对方应答了,继续执行
        do{
          if(++i > 20){
            return 4;
          }
          IIC_Stop();
          Delay_Ms(2);              //等待对方采集好数据
          IIC_Start();
          IIC_WriteByte(SHT3X_ADDR<<1 | IIC_READ);//询问是否采集好了数据
        }while(IIC_Wait_ACK() != ACK);        //如果条件成立,表示传感器采集数据未完成
        for(i=0; i<5; i++){
          buff[i] = IIC_ReadByte(ACK);
        }
        buff[5] = IIC_ReadByte(NACK);
        IIC_Stop();
        //转换温湿度
        if(crc8(buff, 2) == buff[2] && crc8(&buff[3], 2) == buff[5]){
          temp->temperature = (buff[0]<<8|buff[1])/65535.0*175-45;
          temp->humidity = (buff[3]<<8|buff[4])/65535.0*100;
        }else return 5;
      }else return 3;
    }else return 2;
  }else return 1;
  return 0;
}
/*********************************************************************************************************
* 函 数 名 : Sht3x_Read_TemperatureHumidity
* 功能说明 : 读取SHT3x温湿度数据(第二种写法啊)
* 形    参 : HT:存储温湿度的结构体指针
* 返 回 值 : 无
* 备    注 : 无,24,0b设置时间采样的个数(数据),设置时钟的延伸
*********************************************************************************************************/ 
//void sht3x_read_T_H(void)
//{
//    int i;
//    IIC_Start();    
//    IIC_WriteByte((0x44<<1)|0); 
//    if(IIC_Wait_ACK()==1)
//    {
//       printf("没有响应,请你监测总线是否挂接有从机或从机损坏\r\n");
//      return ;
//    }
//    IIC_WriteByte(0x24);
//}
unsigned char crc8(const unsigned char *data, int len)
{
  const unsigned char POLYNOMIAL = 0x31;
  unsigned char crc = 0xFF;
  int j, i;
  for (j=len; j; --j){
    crc ^= *data++;
    for ( i = 8; i; --i ){
      crc = ( crc & 0x80 )
        ? (crc << 1) ^ POLYNOMIAL
        : (crc << 1);
    }
  }
  return crc;//这不都是一样的嘛
}

sht31.h,我们这里温湿度的话,我们在.h进行宏定义一个结构体就可以在main使用了。

#ifndef SHT30_H
#define SHT30_H
#include "io_bit.h"
#define SHT3X_ADDR  0X44      //从机地址
#define SHT3X_READ_TEMP_HUM 0x240b  //非时钟延伸,中等重复性
typedef struct
{
  float temperature;
  float humidity;
}Sht3x_TypeDef; 
void Sht3x_Init(void);
int Sht3x_Read_TemperatureHumidity(Sht3x_TypeDef *HT);
#endif

🎮 效果展示

2345_image_file_copy_318.jpg


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
7月前
|
传感器 数据采集 数据处理
基于STM32的温湿度监测系统设计与实现
基于STM32的温湿度监测系统设计与实现
1002 1
|
7月前
|
传感器 编解码 数据处理
毕业设计|基于STM32单片机的水位浑浊度检测设计
毕业设计|基于STM32单片机的水位浑浊度检测设计
874 0
|
7月前
|
传感器
【STM32】I2C练习,SHT3X温度传感器的数据读取
【STM32】I2C练习,SHT3X温度传感器的数据读取
113 0
|
7月前
|
传感器 算法
【STM32】I2C练习,HAL库读取MPU6050角度陀螺仪
【STM32】I2C练习,HAL库读取MPU6050角度陀螺仪
385 0
|
2月前
|
传感器 数据采集 监控
基于STM32的温室大棚环境检测及自动浇灌系统设计
基于STM32的温室大棚环境检测及自动浇灌系统设计
449 0
|
5月前
|
传感器 数据安全/隐私保护 数据格式
STM32CubeMX DHT11温湿度传感器
STM32CubeMX DHT11温湿度传感器
362 11
|
6月前
|
传感器
【经典案例】STM32F407使用HAL库配置I2C详解
STM32F407是一个强大的微控制器,广泛应用于嵌入式系统中。在许多应用中,我们需要使用I2C总线来与传感器、EEPROM、显示屏等外设进行通信。本文将详细介绍如何使用STM32 HAL库来配置和使用I2C接口。
790 2
|
5月前
|
传感器 编解码 API
【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析
SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。
202 0
|
6月前
|
传感器 数据格式
【STM32】DHT11温湿度模块传感器详解&代码
【STM32】DHT11温湿度模块传感器详解&代码
|
7月前
|
传感器 存储 缓存