|
某一個寶買了一個SHT35模塊,直接用STM32ZET6的正點原子開發板接的,數據波動巨大無比,各位大佬幫忙,下面是單片機代碼
/*
設定溫度閾值范圍:-20℃——125℃
設定相對濕度范圍:0%——100%
*/
#include"stm32f103xe.h"
#include"SHT30.h"
#include"stdio.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
#include "usbd_ctlreq.h"
#include "hw_config.h"
#include "usbd_core.h"
#include "usart.h"
#include <stdbool.h> // 引入標準布爾類型定義
#define write 0 //IIC設備地址一般是7位,也有10位,本程序使用7位IIC設備地址,第8位是寫命令
#define read 1 //IIC設備地址一般是7位,也有10位,本程序使用7位IIC設備地址,第8位是讀命令
// SHT30標準單次高精度測量命令
//#define MEAS_HIGHREP_STRETCH 0x2C06
//IIC總線接口定義
#define SCL PBout(6)//設置時鐘端口
//SHT30數據SDA傳輸口,有輸出也有輸入,所以需配置它的輸入和輸出
#define SDA_OUT PBout(7)//設置輸出數據端口
#define SDA_IN PBin(7)//設置輸入數據端口
//設置端口高8位的工作模式(具體可以參照端口位配置表),即I/O輸入輸出方向設置,先用與(&)對PB7引腳的四個位清0,再用或(|)置1
#define IIC_INPUT_MODE_SET() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=8<<28;}//改變PB7對應位為1000(CNF[1:0]MODE[1:0]),設置成上拉或者下拉輸入
#define IIC_OUTPUT_MODE_SET() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=3<<28;}//改變PB7對應位為0011,設置成通用推挽輸出
//#define IIC_INPUT_MODE_SET() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}//改變PB7對應位為1000(CNF[1:0]MODE[1:0]),設置成上拉或者下拉輸入
//#define IIC_OUTPUT_MODE_SET() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}//改變PB7對應位為0011,設置成通用推挽輸出
//定義溫濕度存儲變量
u8 humiture_buff1[20];
void SHT30_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
}
//主機發送確認字符ACK
void IIC_ACK(void)//IIC協議,需要主機發送確認字符ACK來判斷數據是否接收無誤
{
IIC_OUTPUT_MODE_SET();//配置PB7的SDA輸出為推挽輸出模式
SCL=0;
delay_us(2);
SDA_OUT=0;
delay_us(2);
SCL=1;//數據接收完成之后,將SCL拉高,以便與后面主機發送ACK給從機
delay_us(2);
SCL=0;//數據接收完成,主機發送ACK
delay_us(1);
}
//主機不發送確認字符ACK
void IIC_NACK(void)//IIC協議,數據傳輸未完成或者數據傳輸有誤,主機不發送確認字符ACK
{
IIC_OUTPUT_MODE_SET();//配置PB7的SDA輸出為推挽輸出模式
SCL=0;
delay_us(2);
SDA_OUT=1;
delay_us(2);
SCL=1;
delay_us(2);
SCL=0;
delay_us(1);
}
//主機等待從機的確認字符ACK
u8 IIC_wait_ACK(void)//主機等待從機發送ACK,從而判斷數據是否接收完成
{
u8 t = 200;
IIC_OUTPUT_MODE_SET();
SDA_OUT=1;//8位發送完后釋放數據線,準備接收應答位
delay_us(1);
SCL=0;
delay_us(1);
IIC_INPUT_MODE_SET();
delay_us(1);
while(SDA_IN)//等待SHT30應答
{
t--;
delay_us(1);
if(t==0)
{
SCL=0;
return 1;
}
delay_us(1);
}
delay_us(1);
SCL=1;
delay_us(1);
SCL=0;
delay_us(1);
return 0;
}
void IIC_Start(void)//啟動IIC通訊 標準庫
{
IIC_OUTPUT_MODE_SET();//設置PB7的SDA為推挽輸出
SDA_OUT=1;//根據SHT30時序,啟動之前,SDA配置為高電平
SCL=1;//根據SHT30時序,啟動之前,SCL配置為高電平
delay_us(4);//延時4us,給硬件一個反應時間
SDA_OUT=0;//SDA引腳拉低,開始數據的傳輸
delay_us(4);
SCL=0;//SCL拉低,與SDA對應,響應SDA數據的拉低,表示正式開始數據的傳輸
}
//結束IIC總線通訊,發送IIC通訊的結束條件
void IIC_Stop(void)
{
IIC_OUTPUT_MODE_SET();
SCL=0;//結束IIC通訊之前,查看SCL是否是拉低狀態
SDA_OUT=0;//結束IIC通訊之前,查看SDA是否是拉低狀態
delay_us(4);
SCL=1;//將時鐘拉高,表示已經結束IIC通訊
delay_us(4);
SDA_OUT=1;//將數據傳輸引腳拉高,表示正式結束數據的傳輸
delay_us(4);
}
//將byte數據發送出去
void IIC_SendByte(u8 byte)
{
u8 Count;
IIC_OUTPUT_MODE_SET();
SCL=0;//將時鐘拉低,開始數據的傳輸
for(Count=0;Count<8;Count++)//要傳送的數據長度為8位
{
if(byte&0x80) SDA_OUT=1;//判斷發送位,發送位為1,則還未發送數據
else SDA_OUT=0; //判斷發送位為0,則開始數據的發送
byte<<=1;
delay_us(2);
SCL=1;
delay_us(2);
SCL=0;
delay_us(2);
}
}
// 用來接收從器件傳來的數據
u8 IIC_RcvByte(void)
{
u8 retc;
u8 Count;
retc=0;
IIC_INPUT_MODE_SET();//配置數據線為輸入方式
delay_us(1);
for(Count=0;Count<8;Count++)
{
SCL=0;//配置時鐘線為低,準備接收數據位
delay_us(1);
SCL=1;//配置時鐘線為高使數據線上數據有效
delay_us(1);
retc=retc<<1;
if(SDA_IN) retc |=1;//讀數據位,接收的數據位放入retc中
delay_us(1);
}
SCL=0;
return(retc);
}
//用來接收從器件采集并合成溫濕度
void SHT30_read_result(u8 addr)
{
//SHT30有兩種讀取數值的方法,分別是狀態查詢和數值查詢,這里我使用的是數值查詢,發送指令為0x2C06
u16 tem,hum;//定義存放溫濕度計算公式的變量
u16 buff[6];//定義6個字節的數組,存放溫度高、低八位,濕度高、低八位,兩個字節的CRC校驗位
float Temperature=0;//定義存放溫度拼接的變量Temperature,初始化溫度為0
float Humidity=0;//定義存放濕度拼接的變量Humidity,初始化濕度為0
//發送指令為0x2C06(默認)
IIC_Start();
IIC_SendByte(addr<<1 | write);//寫7位I2C設備地址加0作為寫取位,1為寫取位
IIC_wait_ACK();
//delay_us(1);
IIC_SendByte(0x2C);//前半段發送指令為0x2C
IIC_wait_ACK();
//delay_us(1);
IIC_SendByte(0x06);//后半段發送指令為0x06
IIC_wait_ACK();
//delay_us(1);
IIC_Stop();
delay_ms(20);//等待傳感器讀取數據
IIC_Start();
IIC_SendByte(addr<<1 | read);//寫7位I2C設備地址加1作為讀取位,1為讀取位
//SHT30返回的數值是6個元素的數組
if(IIC_wait_ACK()==0)
{
delay_us(1);
buff[0]=IIC_RcvByte();//返回溫度高8位
IIC_ACK();
buff[1]=IIC_RcvByte();//返回溫度低8位
IIC_ACK();
buff[2]=IIC_RcvByte();//溫度crc校驗位
IIC_ACK();
buff[3]=IIC_RcvByte();//返回濕度高8位
IIC_ACK();
buff[4]=IIC_RcvByte();//返回濕度低8位
IIC_ACK();
buff[5]=IIC_RcvByte();//濕度crc校驗位
IIC_NACK();
IIC_Stop();
}
tem = ((buff[0]<<8) | buff[1]);//將buff[0]采集到的溫度8位數據與buff[1]采集到的低8位數據相或,實現溫度拼接
hum = ((buff[3]<<8) | buff[4]);//將buff[3]采集到的濕度8位數據與buff[4]采集到的低8位數據相或,實現濕度拼接
// 將溫度和濕度轉換為浮點值
Temperature = -45 + 175 * ((float)tem / 65535.0); // T = -45 + 175 * ST / (2^16-1)
Humidity = 100 * ((float)hum / 65535.0); // RH = 100 * SRH / (2^16-1)
if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//設定溫度和濕度的閾值,超過這個閾值則返回錯誤提示
{
USB_Printf("\r\n溫度:%6.2f℃\r\n",Temperature);
USB_Printf("濕度:%6.2f%%\r\n",Humidity);
hum=0;
tem=0;
}
else
{
USB_Printf("\r\n溫濕度超過給定閾值!\r\n");
}
}
3.3V供電,SDA接PB7,SCL接PB6,電腦串口115200,能讀到溫濕度,但數據穩定性特別差,嘗試改了部分代碼,也改了電壓,但都不太行,手里現在沒有別的工具,各位大佬先淺看下代碼,我是找不到什么毛病,好難
|
|