STM32F103ZET6+IIC+SHT20温湿度传感

STM32F103ZET6+IIC+SHT20温湿度传感

IIC概述

IIC:两线式串行总线,它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。

在CPU与被控IIC之间、IIC与IIC之间进行双向传送,高速IIC总线一般可达400kbs以上。总线上可以接多个从设备,从设备的地址必须不同。也可也接多个主设备,但同一时刻只能有一个主设备控制总线。最大设备数量受总线的最大负载电容400pf限制。每个从设备有自己的设备地址,主设备发送START信号后,紧跟着发送想要通信的从设备地址字节,7位器件地址+1位读写标志位(0为写,1为读)。

时钟线SCL:在通信过程起到控制作用。
数据线SDA:用来一位一位的传送数据。

IIC总共由五个核心函数,分别为:①起始信号②停止信号③应答信号④发送数据⑤接收数据,通过这五个核心基本函数就能于大多数的传感进行通信了。

起始信号
当SCL为高电平期间,SDA由高电平到低电平的跳变过程;起始信号是一种电平跳变时序信号,而不是一个电平信号,如图虚线框所示。

停止信号
当SCL为高电平期间,SDA由低电平到高电平的跳变过程;停止信号也是一种电平跳变时序信号,而不是一个电平信号,如图虚线框所示。
在这里插入图片描述
应答信号
IIC的数据字节定义为8位长,对于发送端每发送1个字节后,需要将数据线(SDA)释放,由接收端反馈一个应答信号(ACK)。应答信号为低电平时,则将其规定为有效信号(ACK简称应答位),表示接收端已经成功接收了该字节;应答位为高电平时,规定为非应答位(NACK),一般表示接收端没有成功接收该字节。
对于反馈有效应答位ACK的要求是,接收端在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收端是主机,则在它接收到最后一个字节后,发送一个NACK信号,以通知发送端结束数据发送,并释放SDA线,以便主机接收端发送一个停止信号。
在这里插入图片描述
发送数据
在发送起始信号后开始通信,主机发送一个8位数据。然后,主机释放SDA线并等待从从机发出得确认信号(ACK)。

接收数据
在发送起始信号后开始通信,主机发送一个8位数据。然后,从机收到数据返回一个确认信号(ACK)给主机,这时候主机才开始接收数据,待主机接收数据完成后,发送一个NACK信号给从机,以通知接收端结束数据接收。

数据有效性
IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

IIC通信总过程
在这里插入图片描述
大概地了解了一下,IIC协议的基本情况,接下来,使用STM32驱动SHT20温湿度传感器为例,熟悉一下IIC协议的应用。

准备IIC协议
1、声明GPIO和IIC初始化

void SHT20_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(SHT20_SCL_GPIO_CLK | SHT20_SDA_GPIO_SDA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = SHT20_SCL_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SHT20_SCL_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

2、IIC数据线的输出模式
因为在IIC数据线输出数据前,需要将数据线设置为输出模式才行

void SDA_OUT(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

3、IIC数据线的输入模式
同样在IIC数据线输入数据前,需要将数据线设置为输入模式才行

void SDA_IN(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

4、IIC起始信号

void IIC_Start(void)
{
  SDA_OUT();
  SHT20_SDA = 1;
  SHT20_SCL = 1;
  delay_us(20);

  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 0;
}

5、IIC停止信号

void IIC_Stop(void)
{
  SDA_OUT();
  SHT20_SCL = 0;
  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 1;
  SHT20_SDA = 1;
  delay_us(20);
}

6、IIC等待应答信号
返回值:1,接收应答失败;0,接收应答成功。

u8 IIC_Wait_Ack(void)
{
  u8 ucErrTime = 0;
  SDA_IN();
  SHT20_SDA = 1;
  delay_us(10);
  SHT20_SCL = 1;
  delay_us(10);
  while(SHT20_SDA_READ())
  {
    ucErrTime++;
    if(ucErrTime > 250)
    {
      IIC_Stop();
      return 1;
    }
  }
  SHT20_SCL = 0;  
  return 0;
}

7、IIC产生应答信号

void IIC_Ack(void)
{
  SHT20_SCL = 0;
  SDA_OUT();
  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 1;
  delay_us(20);
  SHT20_SCL = 0;
}

8、IIC不产生应答信号

void IIC_NAck(void)
{
  SHT20_SCL = 0;
  SDA_OUT();
  SHT20_SDA = 1;
  delay_us(20);
  SHT20_SCL = 1;
  delay_us(20);
  SHT20_SCL = 0;
}

9、IIC发送一个字节
返回从机有无应答,1,有应答;0,无应答。

void IIC_Send_Byte(u8 txd)
{
  u8 t;
  SDA_OUT();
  SHT20_SCL = 0; 	
  for(t = 0; t < 8; t++)
  {
    if((txd & 0x80) >> 7)
      SHT20_SDA = 1;
    else
      SHT20_SDA = 0;
    txd <<= 1;
    delay_us(20);
    SHT20_SCL = 1;
    delay_us(20);
    SHT20_SCL = 0;
    delay_us(20);
  }
  delay_us(20);

}

10、IIC读取一个字节
读取字节时,ask=1,产生应答;ask=0,不产生应答

u16 IIC_Read_Byte(u8 ack)
{
  u8 i;
  u16 receive = 0;
  SDA_IN();
  for(i = 0; i < 8; i++ )
  {
    SHT20_SCL = 0;
    delay_us(20);
    SHT20_SCL = 1;
    receive <<= 1;
    if(SHT20_SDA_READ())
      receive++;
    delay_us(20);
  }
  if (!ack)
    IIC_NAck();
  else
    IIC_Ack(); 
  return receive;
}

温湿度传感器的驱动过程

STH20数据手册下载链接

有两种不同的操作模式与传感器通信:保持主模式或无保持主模式。在第一种情况下,SCL 线路在测量过程中阻塞(由传感器控制),而在后一种情况下,在传感器处理测量时,SCL线路保持打开状态,以进行其他通信。在传感器测量时,无保持主2模式允许处理总线上的其他 I 2 C 通信任务。

在保持主模式下,SHT20 在测量时拉下 SCL 线以等待状态。通过释放 SCL 线路 ,传感器指示内部处理已终止,并且传输可能继续。

在这里插入图片描述
在无保持主模式下,MCU 必须轮询,以终止 Sensor 的内部处理。这是通过发送开始条件后跟 II C 标头完成的,如果内部处理完成,传感器将确认 MCU 的轮询,MCU 可以读取数据。如果测量处理未完成,传感器应答无 ACK 位,并且必须再次发出"启动"条件。使用无保持主模式 mode时,建议在接收传感器的 ACK 位后包括 20 μs的等待时间,并处于"停止"状态之前。

在这里插入图片描述
驱动代码如下:

float ReadSht20(unsigned char whatdo)
{
	float temp;
  unsigned char MSB,LSB;
  float Humidity,Temperature;

	IIC_Start();
	IIC_Send_Byte(0x80);
	if(IIC_Wait_Ack()==0)
	{
		IIC_Send_Byte(whatdo);
		if(IIC_Wait_Ack()==0)
		{
			do
			{
				delay_us(8);
				IIC_Start();	
				IIC_Send_Byte(0x81);
			}while(IIC_Wait_Ack()==1);

			MSB = IIC_Read_Byte(1);
			LSB = IIC_Read_Byte(1);
			IIC_Read_Byte(0); 
			IIC_Stop();

			LSB &= 0xfc;
    	temp = MSB*256 + LSB;

			if (whatdo==((unsigned char)0xf5))
    		{        
        		Humidity =(temp*125)/65536-6;

        		return Humidity;
    		}                                                                                                  
    		else      
    		{        
        		Temperature = (temp*175.72)/65536-46.85;

        		return Temperature; 
    		}
		}
	}

	return 0;
}

在之前的USART工程上,新建两个文件,一个是SHT20.h文件,另一个是SHT20.c文件

SHT20.h文件的代码如下:

#ifndef __HX711_H
#define __HX711_H

#include "sys.h"
#include "delay.h"

#define  SHT20_SCL   PEout(11)
#define  SHT20_SDA   PEout(12)


// GPIO 引脚定义
#define  SHT20_SCL_GPIO_CLK        RCC_APB2Periph_GPIOE
#define  SHT20_SCL_GPIO_PORT       GPIOE
#define  SHT20_SCL_GPIO_PIN        GPIO_Pin_11

#define  SHT20_SDA_GPIO_SDA        RCC_APB2Periph_GPIOE
#define  SHT20_SDA_GPIO_PORT       GPIOE
#define  SHT20_SDA_GPIO_PIN        GPIO_Pin_12

#define  SHT20_SDA_READ()          GPIO_ReadInputDataBit(SHT20_SDA_GPIO_PORT, SHT20_SDA_GPIO_PIN)


//IIC 所有操作函数
void SHT20_GPIO_Init(void);


void SDA_OUT(void);
void SDA_IN(void);
void IIC_Start(void);
void IIC_Stop(void);
u8 IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
void IIC_Send_Byte(u8 txd);
u16 IIC_Read_Byte(u8 ack);


float ReadSht20(unsigned char whatdo);


#endif

SHT20.c文件的代码如下:

#include "SHT20.h"


void SHT20_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(SHT20_SCL_GPIO_CLK | SHT20_SDA_GPIO_SDA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = SHT20_SCL_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SHT20_SCL_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

void SDA_OUT(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

void SDA_IN(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SHT20_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(SHT20_SDA_GPIO_PORT, &GPIO_InitStructure);
}

void IIC_Start(void)
{
  SDA_OUT();
  SHT20_SDA = 1;
  SHT20_SCL = 1;
  delay_us(20);

  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 0;
}

void IIC_Stop(void)
{
  SDA_OUT();
  SHT20_SCL = 0;
  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 1;
  SHT20_SDA = 1;
  delay_us(20);
}

u8 IIC_Wait_Ack(void)
{
  u8 ucErrTime = 0;
  SDA_IN();
  SHT20_SDA = 1;
  delay_us(10);
  SHT20_SCL = 1;
  delay_us(10);
  while(SHT20_SDA_READ())
  {
    ucErrTime++;
    if(ucErrTime > 250)
    {
      IIC_Stop();
      return 1;
    }
  }
  SHT20_SCL = 0;  
  return 0;
}

void IIC_Ack(void)
{
  SHT20_SCL = 0;
  SDA_OUT();
  SHT20_SDA = 0;
  delay_us(20);
  SHT20_SCL = 1;
  delay_us(20);
  SHT20_SCL = 0;
}

void IIC_NAck(void)
{
  SHT20_SCL = 0;
  SDA_OUT();
  SHT20_SDA = 1;
  delay_us(20);
  SHT20_SCL = 1;
  delay_us(20);
  SHT20_SCL = 0;
}

void IIC_Send_Byte(u8 txd)
{
  u8 t;
  SDA_OUT();
  SHT20_SCL = 0; 	
  for(t = 0; t < 8; t++)
  {
    if((txd & 0x80) >> 7)
      SHT20_SDA = 1;
    else
      SHT20_SDA = 0;
    txd <<= 1;
    delay_us(20);
    SHT20_SCL = 1;
    delay_us(20);
    SHT20_SCL = 0;
    delay_us(20);
  }
  delay_us(20);

}

u16 IIC_Read_Byte(u8 ack)
{
  u8 i;
  u16 receive = 0;
  SDA_IN();
  for(i = 0; i < 8; i++ )
  {
    SHT20_SCL = 0;
    delay_us(20);
    SHT20_SCL = 1;
    receive <<= 1;
    if(SHT20_SDA_READ())
      receive++;
    delay_us(20);
  }
  if (!ack)
    IIC_NAck();
  else
    IIC_Ack();
  return receive;
}

float ReadSht20(unsigned char whatdo)
{
	float temp;
  unsigned char MSB,LSB;
  float Humidity,Temperature;

	IIC_Start();
	IIC_Send_Byte(0x80);
	if(IIC_Wait_Ack()==0)
	{
		IIC_Send_Byte(whatdo);
		if(IIC_Wait_Ack()==0)
		{
			do
			{
				delay_us(8);
				IIC_Start();	
				IIC_Send_Byte(0x81);
			}while(IIC_Wait_Ack()==1);

			MSB = IIC_Read_Byte(1);
			LSB = IIC_Read_Byte(1);
			IIC_Read_Byte(0); 
			IIC_Stop();

			LSB &= 0xfc;
    	temp = MSB*256 + LSB;

			if (whatdo==((unsigned char)0xf5))
    		{        
        		Humidity =(temp*125)/65536-6;

        		return Humidity;
    		}                                                                                                  
    		else      
    		{        
        		Temperature = (temp*175.72)/65536-46.85;

        		return Temperature; 
    		}
		}
	}

	return 0;
}

main.c文件的代码如下:

#include "stm32f10x.h"
#include <stdio.h>
#include "led.h"
#include "USART_Init_Config.h"
#include "SHT20.h"


int main(void)
{
	float Humidity,Temperature;   //定义温度和湿度变量
	
	delay_init();	     //延时函数初始化
	LED_Init();          //LED灯初始化
    USART_Init_Config(); //串口初始化
	SHT20_GPIO_Init();   //SHT20初始化

		while(1)
		{
				Humidity = ReadSht20(0xf3);	       //读取温度
				printf("温度为:%0.2f",Humidity);
				Temperature = ReadSht20(0xf5);	   //读取湿度
				printf("湿度为:%0.2f",Temperature);
				delay_ms(1000);
		}
		
}

运行效果

打开串口调试助手
在这里插入图片描述
完整工程下载!!!

  • 28
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值