明天开始准备画电路图,设计PCB板,并初步把外观做出来。
共享SHT31温湿度传感器完整操作代码如下:
/********* SHT31温湿度传感器驱动及相关数据处理操作 **********/
//SHT31读取温湿度数据
/***********************************************************
函数名: SHT31_Read()
功 能: STM8S207 MCU通过硬件I2C通信读取SHT31内温湿度数据(单次数据采集模式)
参 数: data_buff --- 从SHT31读取的多字节数据指针
data_len --- 从SHT31读取的多字节数据长度(6个)
返回值: 无
***********************************************************/
void SHT31_Read(uchar *data_buff,uchar data_len)
{
uchar temp; //定义一下,读取MCU状态寄存器用
uchar i; //定义一下,供循环使用
uint time; //定义一下,供等待延时用
//以下程序为I2C通信防锁死操作,非常重要!
if((PE_IDR&0x04) == 0x00) //检测总线是否真的忙碌中(忙碌则SCL=1,SDA=0)
{
I2C_CR1 &= 0xFE; //PE=0,禁用硬件I2C模块,准备直接操作MCU端口
PE_DDR |= 0x02; //设置SCL端口为输出
PE_CR1 |= 0x02; //上拉输出
for(i=0;i<9;i++) //SCL端口发出9个时钟脉冲,让从设备SHT31释放总线(恢复SDA=1)
{
PE_ODR &= 0xFD; //SCL=0;
delay_us(50); //延时(I2C通信频率10KHz)
PE_ODR |= 0x02; //SCL=1
delay_us(50); //延时(I2C通信频率10KHz)
}
time = 500; //变量赋值,准备延迟等待500次
while(!(PE_IDR&0x04)) //等待数据线SDA=1
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
PE_DDR &= 0xFD; //SCL端口恢复输入方式
PE_CR1 &= 0xFD; //浮空输入
PE_ODR &= 0xFD; //清零输出寄存器
I2C_CR1 |= 0x01; //重新启动硬件I2C模块,接管SCL、SDA端口
return; //退出函数,放弃本次数据读取操作
}
//以上程序为I2C通信防锁死操作,非常重要!
//以下程序为STM8S硬件I2C通信防BUSY锁死操作,非常重要!
if((I2C_SR3&0x02) == 0x02) //检测总线是否正确释放空闲中(总线正确释放则I2C_SR3状态寄存器BUSY=0,否则BUSY=1)
{
I2C_CR2 |= 0x80; //I2C_CR2控制寄存器SWRST=1,软件复位硬件I2C模块
I2C_CR2 &= 0x7F; //I2C_CR2控制寄存器SWRST=0,软件复位硬件I2C模块结束
I2C_FREQR = 0x02; //配置I2C外设时钟2MHz
I2C_CCRH = 0x00; //配置I2C为标准模式及速率
I2C_CCRL = 0x64; //I2C通信速率半周期=((1/2)*100us=50us,速率=1/100us=10KHz
I2C_TRISER = 0x03; //配置I2C上升时间寄存器,1000ns(SCL最大值)/500ns(2MHz周期)+1
I2C_CR1 |= 0x01; //启动I2C硬件模块
return; //退出函数,放弃本次数据读取操作
}
//以上程序为STM8S硬件I2C通信防BUSY锁死操作,非常重要!
//以下为SHT31温湿度传感器读数据操作时序(1-10步)
//*** 1.先检测I2C总线是否忙碌 ***//
time = 500; //变量赋值,准备延迟等待500次
while(I2C_SR3&0x02) //检测总线是否忙碌中(I2C_SR3状态寄存器BUSY位=1表示总线上有通信/忙碌)
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
//*** 2.发起始条件 ***//
I2C_CR2 |= 0x01; //发起始条件(置位I2C_CR2控制寄存器START位)
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x01)) //I2C_SR1状态寄存器SB位=1表示发送成功
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
delay_us(5); //短暂延时
//*** 3.发"地址+写操作"指令 ***//
temp = I2C_SR1; //读取状态寄存器I2C_SR1值
I2C_DR = 0x88; //发送SHT31从设备地址("器件地址<0x44>+写操作<左移一位>"),同时清除I2C_SR1中BFT位
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x02)) //I2C_SR1状态寄存器ADDR位=1时表示地址发送结束(主模式)
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
delay_us(5); //短暂延时
temp = I2C_SR1; //读取状态寄存器I2C_SR1数值
temp = I2C_SR3; //清除状态寄存器I2C_SR1中ADDR标志位(地址已发送结束)
//*** 4.发16位测试指令高八位 ***//
I2C_DR = 0x2C; //发送SHT31 16位测试指令代码(高八位)
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x84)) //等待数据发送完毕(I2C_SR1状态寄存器TxE、BTF位为1时,表示发送时数据寄存器为空且数据字节发送完毕)
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
//*** 5.发16位测试指令低八位 ***//
I2C_DR = 0x06; //发送SHT31 16位测试指令代码(低八位)(高可重复性,使能时钟拉伸,单次数据采集模式)
/*备注: 如果使能时钟拉伸,在没有数据发送时,传感器会发出一个ACK信号,并随后拉下SCL线,SCL线被拖到
测量完成为止,一旦测量完成,传感器释放SCL线并发送测量结果; 如果未使能时钟拉伸,在没有
数据发送时,传感器响发出一个NACK.*/
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x84)) //等待数据发送完毕(I2C_SR1状态寄存器TxE、BTF位为1时,表示发送时数据寄存器为空且数据字节发送完毕)
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
//*** 6.发停止条件 + SCL Free延时 ***//
temp = I2C_SR1; //读取状态寄存器I2C_SR1值
temp = I2C_DR; //清除I2C_SR1中BFT位
I2C_CR2 |= 0x02; //发停止条件(置位I2C_CR2控制寄存器STOP位///必须先清除I2C_SR1状态寄存器BTF位)
delay_us(10); //短暂延时
//*** 7.重发起始条件 ***//
I2C_CR2 |= 0x01; //重复发起始条件(置位I2C_CR2控制寄存器START位)
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x01)) //I2C_SR1状态寄存器SB位=1表示发送成功
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
delay_us(5); //短暂延时
//*** 8.发"地址+读操作"指令 ***//
temp = I2C_SR1; //读取状态寄存器I2C_SR1值
I2C_DR = 0x89; //发送SHT31从设备地址("器件地址<0x44>+读操作<左移1位|0x01>"),同时清除I2C_SR1中BFT位
time = 500; //变量赋值,准备延迟等待500次
while(!(I2C_SR1&0x02)) //I2C_SR1状态寄存器ADDR位=1时表示地址发送结束(主模式)
{
if(!--time) //变量自减
return; //延迟等待500次后,未达到预期效果,退出子函数以防程序死机状态
}
delay_us(5); //短暂延时
//*** 9.延时等待测量完毕(时钟拉伸已使能) ***//
delay_us(100); //等待测量完毕
//*** 10.循环读取SHT31返回的6个测试数据值 ***//
temp = I2C_SR1; //读取状态寄存器I2C_SR1数值
temp = I2C_SR3; //清除状态寄存器I2C_SR1中ADDR标志位(地址已发送结束)
I2C_CR2 |= 0x04; //使能ACK应答(置位I2C_CR2控制寄存器ACK位,收到一个字节数据或地址后返回应答)
while(data_len) //循环读取数据
{
if(data_len == 1) //如果是接收最后一位数据(特殊处理)
{
I2C_CR2 &= 0xFB; //关闭ACK应答(清零I2C_CR2控制寄存器ACK位,收到一个字节数据或地址后不返回应答)
I2C_CR2 |= 0x02; //发停止条件(置位I2C_CR2控制寄存器STOP位///必须先清除I2C_SR1状态寄存器BTF位)
}
if(I2C_SR1 & 0x40) //数据寄存器为满(I2C_SR1状态寄存器RxNE位为1时,表示接收寄存器数据非空)
{
*data_buff = I2C_DR; //读取数据寄存器内数值,同时清除BTF位
data_buff++; //准备接收下一字节数据
data_len--;
}
}
temp = I2C_SR1; //读取状态寄存器I2C_SR1值
temp = I2C_DR; //清除I2C_SR1中BFT位
}
/***********************************************************
函数名: Tem_Hum_Get()
功 能: STM8S207 MCU通过硬件I2C通信读取SHT31内温湿度数据,
并转换数据,保存成独立的显示用十进制数据
参 数: 无
返回值: 无
***********************************************************/
void Tem_Hum_Get(void)
{
long a=0; //定义一下,数据转换使用
float b=0; //定义一下,数据转换使用
SHT31_Read(SHT31_R_Data,6); //读取SHT31内部温湿度数据
a = ((long)SHT31_R_Data[0]*256)+(long)SHT31_R_Data[1];
a = a*175; //计算温度数值(℃)
b = (float)a/65535; //计算温度数值(℃)
b = b-45; //计算温度数值(℃)
temperature = b*10; //得到10倍温度数值(℃)
a = ((long)SHT31_R_Data[3]*256)+(long)SHT31_R_Data[4];
a = a*100; //计算湿度数值(%)
b = (float)a/65535; //计算湿度数值(%)
humidity = b*10; //得到10倍温度数值(%)
}
|