目录
传感器和控制模块的分类:
通过电平信号来检测或者控制
通过ADC转换获取数据
通过通信来获取数据或者控制---->IIC SPI USART 自定义
一、SHT20特点
①通信接口:IIC
②可以测量温湿度
③分辨率可以设置
④器件地址:0x80(写) 和 0x81(读)
二、SHT20的通信及配置
1、通信方式
通过手册已经知道要用IIC通信:
IIC所有IO口初始化配置函数
IIC起始信号函数
IIC停止信号函数
IIC发送应答/不应答函数
IIC检测应答/不应答函数
IIC发送一个字节数据函数
IIC接收一个字节数据函数
在多个传感器共用一个通信方式的情况下,为了方便使用,可以单独创建一个通信文件;
当只有单个传感器用一个通信方式的情况下,可以跟这个传感器共用同一个文件
2、器件命令
主机模式:在SHT20测量过程中,SCL锁定.挂载在同一个IIC总线上的其他设备是不能通信
非主机模式:在SHT20测量过程中,SCL开放.挂载在同一个IIC总线上的其他设备是能通信
根据需求:选择用非主机模
3、软复位时序
所以:封装一个软复位函数,调用在初始化中
4、用户寄存器配置
用户寄存器中有保留位,要配置此寄存器,先将寄存器中的所有值读出到一个变量,改变要配置的位,预留位不要动,然后再将变量写入到寄存器中.
经过分析,寄存器的值都用默认值,所以不需要配置此寄存器.
三、SHT20获取温湿度
根据时序图测量温度或湿度过程
思路:
/*发送测量命令*/
起始信号
主机发送器件地址(W)
主机检测应答/不应答信号
主机发送测温度/湿度命令
主机检测应答/不应答信号
/*等待测量完成*/
do
{
起始信号
主机发送器件地址(R)
主机检测应答/不应答信号
}while(不应答)
/*接收数字量*/
主机读高8位数据
主机发送应答信号
主机读低8位数据
主机发送不应答信号.
停止信号.
/*计算出温度或者湿度*/
//合成数据
//选择命令并且通过对应的公式转换成对应的数字量
所以:封装一个获取温度/湿度数据函数
四、程序设计
所用到的宏定义
IIC.h
//时钟线宏定义
#define IIC_SCL_L (GPIOB->ODR &= ~(1<<8))
#define IIC_SCL_H (GPIOB->ODR |= (1<<8))
//数据线宏定义
//输出
#define IIC_SDA_OUT_L (GPIOB->ODR &= ~(1<<9))
#define IIC_SDA_OUT_H (GPIOB->ODR |= (1<<9))
//输入
#define IIC_SDA_IN (GPIOB->IDR & (1<<9))
SHT20.h
//声明一个共用体类型
typedef union trh
{
float t; //温度成员
u8 rh; //湿度成员
}TRH_n;
#define SHT20_ADDR_W 0x80
#define SHT20_ADDR_R 0x81
#define SHT20_SOFT 0xfe
#define SHT20_T 0xf3
#define SHT20_RH 0xf5
①IIC通信相关程序
/***********************************************
*函数名 :iic_IO_init
*函数功能 :IIC所用IO口初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :SCL----PB8
SDA----PB9
************************************************/
void iic_IO_init(void)
{
//端口时钟使能
RCC->AHB1ENR |= (1<<1);
//端口模式配置
GPIOB->MODER &= ~((3<<16)|(3<<18));
GPIOB->MODER |= ((1<<16)|(1<<18));
//输出类型
GPIOB->OTYPER &= ~(1<<8); //时钟线配置位推挽输出
GPIOB->OTYPER |= (1<<9); //数据线配置为开漏输出
//输出速度
GPIOB->OSPEEDR &= ~((3<<16)|(3<<18));
//上下拉
GPIOB->PUPDR &= ~((3<<16)|(3<<18));
//输出数据寄存器让时钟线和数据线处于空闲转态
GPIOB->ODR |= ((1<<8) | (1<<9));
}
/***********************************************
*函数名 :iic_star
*函数功能 :IIC起始信号函数
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void iic_star(void)
{
//时钟线拉低 可以动数据线
IIC_SCL_L;
//数据线拉高 保证可以出现下降沿
IIC_SDA_OUT_H;
//时钟线拉高 起始信号的条件
IIC_SCL_H;
TIM11_delay_us(5);
//数据线拉低 产生了起始信号
IIC_SDA_OUT_L;
TIM11_delay_us(5);
IIC_SCL_L;//安全作用
}
/***********************************************
*函数名 :iic_stop
*函数功能 :IIC停止信号函数
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void iic_stop(void)
{
IIC_SCL_L;
IIC_SDA_OUT_L;
IIC_SCL_H;
TIM11_delay_us(5);
IIC_SDA_OUT_H;
TIM11_delay_us(5);
}
/***********************************************
*函数名 :iic_send_ack
*函数功能 :IIC发送应答/不应答信号函数
*函数参数 :u8 ack
*函数返回值:无
*函数描述 :ack 传入 0 表示发送应答
ack 传入 1 表示发送不应答
************************************************/
void iic_send_ack(u8 ack)
{
IIC_SCL_L;
TIM11_delay_us(3);
if(ack == 0) IIC_SDA_OUT_L;
else IIC_SDA_OUT_H;
TIM11_delay_us(2);
IIC_SCL_H;
TIM11_delay_us(5);
IIC_SCL_L;//安全作用
}
/***********************************************
*函数名 :iic_get_ack
*函数功能 :IIC检测应答/不应答信号函数
*函数参数 :无
*函数返回值:u8
*函数描述 :0 应答信号
1 不应答信号
************************************************/
u8 iic_get_ack(void)
{
u8 ack;
/*将数据线切换位输入模式*/
IIC_SCL_L;
IIC_SDA_OUT_H;
/*检测应答*/
IIC_SCL_L; //主机帮助从机把时钟线拉低,从机才可以自动改变数据线
TIM11_delay_us(5);
IIC_SCL_H; //主机拉高时钟线才可以读数据线
TIM11_delay_us(5);
if(IIC_SDA_IN) ack = 1; //不应答信号
else ack = 0; //应答信号
IIC_SCL_L; //安全作用
return ack;
}
/***********************************************
*函数名 :iic_send_byte
*函数功能 :IIC发送一个字节函数
*函数参数 :u8 data
*函数返回值:无
*函数描述 :
************************************************/
void iic_send_byte(u8 data)
{
u8 i;
for(i=0;i<8;i++)
{
IIC_SCL_L;
TIM11_delay_us(3);
if(data & 0x80)
{
IIC_SDA_OUT_H;
}
else
{
IIC_SDA_OUT_L;
}
TIM11_delay_us(2);
IIC_SCL_H; //帮助从机拉高时钟线,从机才可以读这一位数据
TIM11_delay_us(5);
//下一位数据
data = data << 1;
}
IIC_SCL_L; //安全作用
}
/***********************************************
*函数名 :iic_rec_byte
*函数功能 :IIC接收一个字节函数
*函数参数 :无
*函数返回值:u8
*函数描述 :
************************************************/
u8 iic_rec_byte(void)
{
u8 i;
u8 data;
/*IO切换为输入模式*/
IIC_SCL_L;
IIC_SDA_OUT_H;
/*接收一个字节数据*/
for(i=0;i<8;i++)
{
IIC_SCL_L; //帮助从机拉低时钟线,从才会改变数据线
TIM11_delay_us(5);
IIC_SCL_H; //主机可以读数据线
TIM11_delay_us(5);
data = data << 1;
if(IIC_SDA_IN)
{
data |= 0x01;
}
}
IIC_SCL_L; //安全作用
return data;
}
②SHT20相关程序
SHT20初始化配置函数
/***********************************************
*函数名 :sht20_init
*函数功能 :sht20初始化配置
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void sht20_init(void)
{
//所用IIC初始化
iic_IO_init();
//软复位
sht20_soft();
}
软复位函数
/***********************************************
*函数名 :sht20_soft
*函数功能 :sht20软复位
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void sht20_soft(void)
{
u8 ack;
iic_star();
iic_send_byte(SHT20_ADDR_W);
ack = iic_get_ack();
if(ack == 1)
{
iic_stop();
return;
}
iic_send_byte(SHT20_SOFT);
ack = iic_get_ack();
if(ack == 1)
{
iic_stop();
return;
}
iic_stop();
tim11_delay_ms(15);
}
获取温度或湿度函数
根据时序获取
将获取到的两个八位数据和成一个十六位数据
带入到公式中计算出温度或者湿度
返回
/***********************************************
*函数名 :sht20_rec_val
*函数功能 :获取温度或者湿度函数
*函数参数 :u8 cmd
*函数返回值:TRH_n
*函数描述 :
************************************************/
TRH_n sht20_rec_val(u8 cmd)
{
u8 ack;
u8 temp_h,temp_l;
u16 temp;
TRH_n val;
/*接收数字量*/
iic_star();
iic_send_byte(SHT20_ADDR_W);
ack = iic_get_ack();
iic_send_byte(cmd);
ack = iic_get_ack();
//等待测量完成
//TIM11_delay_ms(85);
do
{
iic_star();
iic_send_byte(SHT20_ADDR_R);
ack = iic_get_ack();
}while(ack!=0);
//读数据
temp_h = iic_rec_byte();
iic_send_ack(0);
temp_l = iic_rec_byte();
iic_send_ack(1);
iic_stop();
/*计算出温度或者湿度*/
//合成数据
temp = (temp_h<<8) | temp_l;
if(cmd == SHT20_T)
{
//计算温度
val.t = -46.85+175.72 * temp / 65536;
}
else if(cmd == SHT20_RH)
{
//计算湿度
val.rh = -6 + 125 * temp / 65536;
}
return val;
}