调试SHT30代码,工程使用
本文主要目标是学习IIC协议及传感器模块,旨在传到STM32单片机优化代码,亲测可用
一、环境搭建,
1、野火开发板
2、JLINK下载器(腾创电子家的,不得不说这个下载器是真的好用,店主推荐购买企业版就买了,把链接发出来,方便大家,JLINK店家地址)
二、首先搭建好iic驱动代码
三、编辑好SHT30初始化代码
四、写好SHT30读写温湿度代码
SHT30读取温度值有两种模式,1、状态查询模式2、数值查询模式,本文采用数值查询模式
iic.h
#define EEPROM_I2C_WR 0 /* 写控制bit */
#define EEPROM_I2C_RD 1 /* 读控制bit */
/* 定义IIC总线连接GPIO端口,用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define EEPROM_GPIO_PORT GPIOB /* GPIO端口 */
#define EEPROM_RCC_PORT RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define EEPROM_I2C_SCL_PIN GPIO_Pin_6 /* 连接SCL时钟线引脚 */
#define EEPROM_I2C_SDA_PIN GPIO_Pin_7 /* 连接SDA时钟线引脚 */
/* 定义读写SCL和SDA的宏,已增加的代码可移植性和可阅读性 */
#if 0 /*条件编译 1选择GPIO的库函数实现IO读写 */
#define EEPROM_I2C_SCL_1() GPIO_SetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SCL_PIN)
#define EEPROM_I2C_SCL_0() GPIO_ResetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SCL_PIN)
#define EEPROM_I2C_SDA_1() GPIO_SetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SDA_PIN)
#define EEPROM_I2C_SDA_0() GPIO_ResetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SDA_PIN)
#define EEPROM_I2C_SDA_READ() GPIO_ReadInputDataBit(EEPROM_GPIO_PORT,EEPROM_I2C_SDA_PIN)
#else /* 这个分支选择直接寄存器实现IO读写 */
/* 注意:如下写法:在IAR最高级优化时,会被编译器错误优化 */
#define EEPROM_I2C_SCL_1() GPIO_SetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SCL_PIN)
#define EEPROM_I2C_SCL_0() GPIO_ResetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SCL_PIN)
#define EEPROM_I2C_SDA_1() GPIO_SetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SDA_PIN)
#define EEPROM_I2C_SDA_0() GPIO_ResetBits(EEPROM_GPIO_PORT,EEPROM_I2C_SDA_PIN)
#define EEPROM_I2C_SDA_READ() ((EEPROM_GPIO_PORT->IDR & EEPROM_I2C_SDA_PIN) != 0)
#endif
iic.c
```c
static void i2c_cfGpio(void);
static void i2c_Delay(void);
/*
下面的时间是通过逻辑分析仪测试得到的
工作条件:CPU:72MHz,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205khz
循环次数为7时, SCL频率 = 347khz SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时, SCL频率 = 421khz,SCL高电平时间1.2us,SCL低电平时间2.37us
*/
static void i2c_Delay(void){
uint8_t i;
for(i=0; i<10; i++);
}
/**
* @brief CPU发起I2C总线启动信号
* @param 无
* @retval 无
*/
void i2c_Start(void){
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
EEPROM_I2C_SDA_1();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SDA_0();
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
}
/**
* @brief CPU发起I2C总线停止信号
* @param 无
* @retval 无
*/
void i2c_Stop(void){
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线停止信号 */
EEPROM_I2C_SDA_0();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SDA_1();
}
/**
* @brief CPU向I2C总线设备发送8bit数据
* @param ucByte -[in]等待发送的字节
* @retval 无
*/
void i2c_SendByte(uint8_t _ucByte){
uint8_t i;
/* 先发送字节的高bit7 */
for(i=0; i<8; i++){
if(_ucByte & 0x80){
EEPROM_I2C_SDA_1();
}
else{
EEPROM_I2C_SDA_0();
}
i2c_Delay();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SCL_0();
if(i==7){
EEPROM_I2C_SDA_1();
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/**
* @brief CPU从I2C总线设备 读取 8bit数据
* @param 无
* @retval 读到的数据
*/
uint8_t i2c_ReadByte(void){
uint8_t i;
uint8_t value;
value = 0;
/* 读取第1个bit为数据的bit7 */
for(i=0; i<8; i++){
// EEPROM_I2C_SCL_0();
// Delay_us(5);
// EEPROM_I2C_SCL_1();
value <<= 1;
EEPROM_I2C_SCL_1();
i2c_Delay();
if(EEPROM_I2C_SDA_READ()){
value++;
}
EEPROM_I2C_SCL_0();
i2c_Delay();
}
return value;
}
/**
* @brief CPU产生一个时钟,并读取器件的ack应答信号
* @param 无
* @retval 返回0表示正确应答,1表示无器件响应
*/
uint8_t i2c_WaitAck(void){
uint8_t re;
EEPROM_I2C_SDA_1(); /* 释放SDA总线 */
i2c_Delay();
EEPROM_I2C_SCL_1(); /* CPU驱动SCL = 1,此时器件会返回ack应答 */
i2c_Delay();
if(EEPROM_I2C_SDA_READ()){ /* CPU读取SDA口线状态*/
re = 1;
}else{
re = 0;
}
EEPROM_I2C_SCL_0();
i2c_Delay();
return re;
}
/**
* @brief CPU产生ack应答信号
* @param 无
* @retval 无
*/
void i2c_Ack(void){
EEPROM_I2C_SDA_0(); /* CPU驱动 SDA = 0*/
i2c_Delay();
EEPROM_I2C_SCL_1(); /* CPU产生一个时钟*/
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
EEPROM_I2C_SDA_1(); /* CPU释放SDA总线*/
}
/**
* @brief CPU产生1个nack应答信号
* @param 无
* @retval 无
*/
void i2c_NAck(void){
EEPROM_I2C_SDA_1();
i2c_Delay();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
}
/**
* @funct local function
* @brief 配置I2C总线GPIO,采用模拟IO的方式实现
* @param 无
* @retval 0无
*/
void i2c_cfGpio(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN | EEPROM_I2C_SDA_PIN;
GPIO_Init(EEPROM_GPIO_PORT,&GPIO_InitStructure);
/* 给一个停止信号,复位I2C总线上所有设备待机模式 */
i2c_Stop();
}
/**
* @brief 检测I2C总线设备,CPU向设备发送地址,然后读取该设备应答来判断该设备是否存在
* @param _Address -[in]设备的I2C总线地址
* @retval 0表示正确,返回1表示未探测到
*/
uint8_t i2c_CheakDevice(uint8_t _Address){
uint8_t ucAck;
i2c_cfGpio(); /* 配置GPIO端口 */
i2c_Start();
/* 发送该设备地址+读写控制bit (0 = w,1 = r)bit7先传 */
i2c_SendByte(_Address | EEPROM_I2C_WR);
ucAck = i2c_WaitAck(); /* 检测设备的ack应答信号 */
i2c_Stop();
return ucAck;
}
/**
* @brief 检测I2C总线设备,CPU向设备发送地址,然后读取该设备应答来判断该设备是否存在
* @param _Address -[in]设备的I2C总线地址
* @retval 0表示正确,返回1表示未探测到
*/
void Check(uint8_t _Address){
i2c_cfGpio();
}
sht30.c
```c
#include "./sht30/bsp_sht30.h"
#include "./iic/bsp_iic.h"
#include "./systick/bsp_systick.h"
#include "bsp_usart.h"
float humiture[4];
uint8_t humiture_buff1[20];
void SHT30_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;
GPIO_Init(EEPROM_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 推挽输出 */
GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN;
GPIO_Init(EEPROM_GPIO_PORT,&GPIO_InitStructure);
}
/**
* @brief 初始化SHT30的IO
* @param 无
* @retval 无
*/
void SHT30_Read_Value(uint8_t addr){
/* SHT30有两种读取数值得方法,分别是状态查询和数值查询,*/
uint16_t tem,hum;
u16 buff[6];
float Temperature = 0;
float Humidity = 0;
/* 发送指令 默认0x2c06 */
i2c_Start();
i2c_SendByte(addr<<1 |EEPROM_I2C_WR);
i2c_WaitAck();
i2c_SendByte(0x2c);
i2c_WaitAck();
i2c_SendByte(0x06);
i2c_WaitAck();
i2c_Stop();
Delay_ms(50);
i2c_Start();
i2c_SendByte(addr<<1 |EEPROM_I2C_RD);
if(i2c_WaitAck() == 0){
buff[0] = i2c_ReadByte();i2c_Ack(); //返回温度高8位
buff[1] = i2c_ReadByte();i2c_Ack(); //返回温度低8位
buff[2] = i2c_ReadByte();i2c_Ack(); //温度crc校验位
buff[3] = i2c_ReadByte();i2c_Ack(); //返回湿度高8位
buff[4] = i2c_ReadByte();i2c_Ack(); //返回湿度低8位
buff[5] = i2c_ReadByte(); //湿度crc校验位
i2c_NAck();
i2c_Stop();
}
tem = ((buff[0]<<8) | buff[1]); //取出温度数据 温度拼接
hum = ((buff[3]<<8) | buff[4]); //取出湿度数据 湿度拼接
/* 转换实际温湿度 */
Temperature = (175.0*(float)tem/65535.0 - 45.0);
Humidity = (100.0*(float)hum/65535.0);
if(addr == 0x44 || addr == 0x45){
/* 判断超范围语句 */
if((Temperature >= -20) && (Temperature <= 125) && ((Humidity >= 0)) && ((Humidity <= 100))){
humiture[0] = Temperature;
humiture[2] = Humidity;
printf("TEM and HUM %6.1f*C %6.1f*RH\r\n",Temperature,Humidity);
}else /* 数据错误 */
{
humiture[0] = 0;
humiture[2] = 0;
}
}
hum = 0;
tem = 0;
}