SHT30原理图如下
软件准备
- 工作需要软件用到的是workspace IAR
- 准备一个串口工具,用到的是sscom5.12.1
I2C
IIC总线在传送数据过程中共有四种类型信号:
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据;
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据;
数据传输信号:在开始条件以后,时钟信号SCL的高电平周期期间,当数据线稳定时,数据线SDA的状态表示数据有效,即数据可以被读走,开始进行读操作。在时钟信号SCL的低电平周期期间,数据线上数据才允许改变。每位数据需要一个时钟脉冲。
应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
写代码时注意I2C的时序。
IIC时序及温湿度读取 iic.c
注意时序问题!!!
每个OUT后都必须给SDA和SCL赋值!!
延时按实际情况自行定义!!
/* Includes ------------------------------------------------------------------*/
#include "iic.h"
#include <stdio.h>
#include "stm8l15x.h"
/* Private typedef -----------------------------------------------------------*/
#define BYTE unsigned char
uint8_t am2320_data_buf[4];
#define POLYNOMIAL 0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
/* Private define ------------------------------------------------------------*/
const u8 IIC_TX_Buffer[]={0x2c,0x06};
uint8_t iic_recv_buf[6]={0xff,0xff,0xff,0xff,0xff,0xff};
uint8_t WR_Flag=0;
#define IIC_Add 0x88
void I2C_delay(void)//10us
{
int i=2*880; //
while(i>0)
{
i--;
}
}
/**
* @brief IIC Init
* @param A:
* @retval None
*/
void IIC_Init(void)
{
//CLK_PeripheralClockConfig (CLK_Peripheral_I2C1,ENABLE);
GPIO_Init(GPIOC, GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Fast);
GPIO_Init(GPIOC, GPIO_Pin_1, GPIO_Mode_Out_PP_Low_Fast);
}
void IIC_DeInit(void){
GPIO_Init(GPIOC, GPIO_Pin_0, GPIO_Mode_In_FL_No_IT);
GPIO_Init(GPIOC, GPIO_Pin_1, GPIO_Mode_In_FL_No_IT);
}
/**
* @brief Set SDA Pin as Output Mode
* @retval None
*/
void SDA_OUT()
{
// 可能有问题
GPIO_Init(GPIOC, GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Fast);
}
/**
* @brief Set SDA Pin as Input Mode
* @retval None
*/
void SDA_IN()
{
GPIO_Init(GPIOC, GPIO_Pin_0, GPIO_Mode_In_PU_No_IT);
}
/**
* @brief read input voltage from SDA pin
* @retval None
*/
BYTE SDA_READ()
{
return GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0);
}
/**
* @brief output high form SDA pin
* @retval None
*/
void IIC_SDA_1()
{
GPIO_SetBits(GPIOC, GPIO_Pin_0);
}
/**
* @brief output low form SDA pin
* @retval None
*/
void IIC_SDA_0()
{
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
}
/**
* @brief output high form SCL pin
* @retval None
*/
void IIC_SCL_1()
{
GPIO_SetBits(GPIOC, GPIO_Pin_1);
}
/**
* @brief output LOW form SCL pin
* @retval None
*/
void IIC_SCL_0()
{
GPIO_ResetBits(GPIOC, GPIO_Pin_1);
}
u8 Test_Ack() //注意这个函数
{
u8 ACK_Flag=0;
SDA_IN();
IIC_SCL_0();
IIC_SDA_1();
I2C_delay();
IIC_SCL_1();
I2C_delay();
if(SDA_READ()==0)
ACK_Flag = 1;
else
ACK_Flag = 0;
IIC_SCL_0();
return ACK_Flag;
}
/**
* @brief Simulate IIC conmunication :Create Start signal
* @retval None
*/
// I2C 启动信号
void I2C_Start(void)
{
SDA_OUT();
IIC_SDA_1();
IIC_SCL_1();
I2C_delay();
IIC_SDA_0(); //START:when CLK is high,DATA change form high to low
I2C_delay();
IIC_SCL_0(); //hold scl line, prepare to transmit data
}
//产生停止信号
void I2C_Stop()
{
SDA_OUT();
IIC_SDA_0();
I2C_delay();
IIC_SCL_1();
I2C_delay();
IIC_SDA_1();
}
//生成应答ACK
void Ack(void)
{
SDA_OUT();
IIC_SDA_0();
IIC_SCL_0();
I2C_delay();
IIC_SCL_1();
I2C_delay();
IIC_SCL_0();
IIC_SDA_1();
}
// 不生成ACK应答
void NoAck(void)
{ SDA_OUT();
IIC_SDA_1();
IIC_SCL_0();
I2C_delay();
IIC_SCL_1();
I2C_delay();
IIC_SDA_1();
IIC_SCL_0();
}
void SendData(unsigned char buffer)
{
unsigned char BitCnt=8;
SDA_OUT();
do
{
IIC_SCL_0();
I2C_delay();
if((buffer&0x80)==0)
IIC_SDA_0();
else
IIC_SDA_1();
IIC_SCL_1();
I2C_delay();
buffer=buffer<<1;
BitCnt--;
}
while(BitCnt);
IIC_SCL_0();
}
unsigned char ReceiveData() //可能有问题
{
unsigned char BitCnt=8,IIC_RX_Data=0;
SDA_IN();
IIC_SDA_1(); //
do
{
IIC_SCL_0();
I2C_delay();
IIC_RX_Data=IIC_RX_Data<<1; //
BitCnt--;
IIC_SCL_1();
I2C_delay();
if(SDA_READ())
IIC_RX_Data = IIC_RX_Data|0x01; //
else
IIC_RX_Data = IIC_RX_Data&0x0fe; //
}
while(BitCnt);
IIC_SCL_0();
return IIC_RX_Data;
}
void Delay_Ms(int16_t time)
{
time=time*1;
while(time>0)
{
I2C_delay();
time--;
}
}
void Waken(void)
{
I2C_Start();
SendData(IIC_Add);
Test_Ack();
Delay_Ms(2);
I2C_Stop();
}
static u8 WriteNByte(u8 sla,u8 *s,u8 n)
{
unsigned char i;
I2C_Start();
SendData(sla);
if(!Test_Ack())
{
WR_Flag = 1;
return(0);
}
for(i=0;i<n;i++)
{
SendData(*(s+i));
if(!Test_Ack())
{
WR_Flag = 1;
return(0);
}
}
I2C_Stop();
return(1);
}
static u8 ReadNByte(u8 Sal, u8 *p,u8 n)
{
unsigned char i;
I2C_Start();
SendData((Sal)| 0x01);
if(!Test_Ack())
{
WR_Flag = 1;
return(0);
}
I2C_delay();
I2C_delay();
I2C_delay();
for(i=0;i<n-1;i++)
{
*(p+i)=ReceiveData();
Ack();
}
*(p+n-1)=ReceiveData();
NoAck();
I2C_Stop();
return(1);
}
unsigned int CRC16(unsigned char *ptr, unsigned char len)
{
unsigned int crc=0xffff;
unsigned char i;
while(len--)
{
crc ^=*ptr++;
for(i=0;i<8;i++)
{
if(crc & 0x1)
{
crc>>=1;
crc^=0xa001;
}
else
{
crc>>=1;
}
}
}
return crc;
}
unsigned char CheckCRC(unsigned char *ptr,unsigned char len)
{
unsigned int crc;
crc=(unsigned int)CRC16(ptr,len-2);
if(ptr[len-1]==(crc>>8) && ptr[len-2]==(crc & 0x00ff))
{
return 0xff;
}
else
{
return 0x0;
}
}
extern int g_sys_runtime_counter;
uint8_t crc = 0;
void get_sht30(uint8_t *data)
{
float temp, humi;
int i;
WriteNByte(IIC_Add,(uint8_t *)IIC_TX_Buffer,2);
Delay_Ms(200);
ReadNByte(IIC_Add,iic_recv_buf,6);
Delay_Ms(200);
crc = sht30_calc_crc(iic_recv_buf, 2);
if(crc!=iic_recv_buf[2])
return ;
// 注意先转换为u16,uint8_t计算可能出现负数!!
u16 temp_h = iic_recv_buf[0] * 256;
u16 temp_l = iic_recv_buf[1];
temp = 175.00 * (temp_h + temp_l) / 65535.0 - 45;
printf("temp:%f\n", temp);
crc = sht30_calc_crc(iic_recv_buf + 3, 2);
if(crc != iic_recv_buf[5])
return ;
// 注意先转换为u16,uint8_t计算可能出现负数!!
u16 humi_h = iic_recv_buf[3] * 256;
u16 humi_l = iic_recv_buf[4];
humi = 100.00 * (humi_h + humi_l) / 65535.0;
printf("humi:%f\n", humi);
//humi = 100.00 * (iic_recv_buf[3] * 256 + iic_recv_buf[4]) / 65535.0;
if(temp > 0)
{
am2320_data_buf[2] = (uint16_t)(temp * 10) >> 8;
}else
{
am2320_data_buf[2] = (uint16_t)(temp * 10) | 0x80;
}
am2320_data_buf[0] = (uint16_t)(humi * 10) >> 8;
am2320_data_buf[1] = (uint16_t)(humi * 10) & 0xff;
am2320_data_buf[3] = (uint16_t)(temp * 10) & 0xff;
data[0] = am2320_data_buf[0];
data[1] = am2320_data_buf[1];
data[2] = am2320_data_buf[2];
data[3] = am2320_data_buf[3];
}
uint8_t sht30_calc_crc(uint8_t* data, uint8_t len)
{
uint8_t bit; // bit mask
uint8_t crc = 0xFF; // calculated checksum
uint8_t byteCtr; // byte counter
// calculates 8-Bit checksum with given polynomial
for(byteCtr = 0; byteCtr < len; byteCtr++)
{
crc ^= (data[byteCtr]);
for(bit = 8; bit > 0; --bit)
{
if(crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
return crc;
}