软件I2C sht3x温湿度传感器 学习过程记录
sensirion_sw_i2c_implementation.c
#include
#include
#include "sensirion_arch_config.h"
#include "sensirion_i2c.h"
static I2C_InitTypeDef hi2c1;
static GPIO_InitTypeDef gpioinit;
static uint32_t I2Cx_TIMEOUT_UserCallback(char value);
#define I2Cx_FLAG_TIMEOUT ((uint32_t) 900)
#define I2Cx_LONG_TIMEOUT ((uint32_t)(300 * I2Cx_FLAG_TIMEOUT))
#define WAIT_FOR_FLAG(flag, value, timeout, errorcode) I2CTimeout = timeout;\
while(I2C_GetFlagStatus(I2C1, flag) != value){\
if((I2CTimeout--) == 0) return I2Cx_TIMEOUT_UserCallback(errorcode);\
}\
#define CLEAR_ADDR_BIT I2C_ReadRegister(I2C1, I2C_Register_SR1);\
I2C_ReadRegister(I2C1, I2C_Register_SR2);\
static uint32_t I2Cx_TIMEOUT_UserCallback(char value)
{
I2C_InitTypeDef hi2c1;
I2C_GenerateSTOP(I2C1, ENABLE);
I2C_SoftwareResetCmd(I2C1, ENABLE);
I2C_SoftwareResetCmd(I2C1, DISABLE);
I2C_DeInit(I2C1);
hi2c1.I2C_ClockSpeed = 100000;
hi2c1.I2C_Mode = I2C_Mode_I2C;
hi2c1.I2C_DutyCycle = I2C_DutyCycle_2;
hi2c1.I2C_OwnAddress1 = 0;
hi2c1.I2C_Ack = I2C_Ack_Enable;
hi2c1.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &hi2c1);
//Console::Instance()->printf("I2C1 Restarted. \n");
return 1;
}
s8 I2C_WriteBlock(uint8_t w_addr, const uint8_t* p_data, uint16_t len)
{
uint16_t i = 0;
__IO uint32_t I2CTimeout = I2Cx_LONG_TIMEOUT;
WAIT_FOR_FLAG(I2C_FLAG_BUSY,RESET,I2Cx_LONG_TIMEOUT,1);
I2C_GenerateSTART(I2C1, ENABLE);
WAIT_FOR_FLAG(I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 2);
I2C_Send7bitAddress(I2C1,(w_addr << 1), I2C_Direction_Transmitter);
WAIT_FOR_FLAG(I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 3);
CLEAR_ADDR_BIT;
while (i < len)
{
I2C_SendData(I2C1, *p_data);
WAIT_FOR_FLAG(I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 4);
i++; p_data++;
}
WAIT_FOR_FLAG(I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 5);
I2C_GenerateSTOP(I2C1, ENABLE);
return 0;
}
s8 I2C_ReadBlock(uint8_t r_addr, uint8_t* p_data, uint16_t len)
{
__IO uint32_t I2CTimeout = I2Cx_LONG_TIMEOUT;
WAIT_FOR_FLAG(I2C_FLAG_BUSY,RESET,I2Cx_LONG_TIMEOUT,6);
I2C_GenerateSTART(I2C1, ENABLE);
WAIT_FOR_FLAG(I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 7);
I2C_Send7bitAddress(I2C1, (r_addr << 1), I2C_Direction_Transmitter);
WAIT_FOR_FLAG(I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 8);
CLEAR_ADDR_BIT;
WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 9);
I2C_SendData(I2C1,r_addr);
WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 10);
I2C_GenerateSTART(I2C1, ENABLE);
WAIT_FOR_FLAG (I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 11);
I2C_Send7bitAddress(I2C1,(r_addr << 1), I2C_Direction_Receiver);
WAIT_FOR_FLAG (I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 12);
/*规定死就2个长度*/
while(len)
{
if (len == 1)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
}
if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
*p_data = I2C_ReceiveData(I2C1);
p_data++;
len--;
}
}
I2C_AcknowledgeConfig(I2C1, ENABLE);
return 0;
}
void sensirion_i2c_init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
gpioinit.GPIO_Mode = GPIO_Mode_OUT;
gpioinit.GPIO_OType = GPIO_OType_PP;
gpioinit.GPIO_PuPd = GPIO_PuPd_UP;
gpioinit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7;
gpioinit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpioinit);
GPIO_SetBits(GPIOB, GPIO_Pin_7);
GPIO_SetBits(GPIOB, GPIO_Pin_8);
I2C_SoftwareResetCmd(I2C1, ENABLE);
gpioinit.GPIO_Mode = GPIO_Mode_AF;
gpioinit.GPIO_OType = GPIO_OType_OD;
gpioinit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_7;
gpioinit.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpioinit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
GPIO_Init(GPIOB, &gpioinit);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
hi2c1.I2C_ClockSpeed = 100000;
hi2c1.I2C_Mode = I2C_Mode_I2C;
hi2c1.I2C_DutyCycle = I2C_DutyCycle_16_9;
hi2c1.I2C_OwnAddress1 = 0;
hi2c1.I2C_Ack = I2C_Ack_Enable;
hi2c1.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &hi2c1);
/* Enable the remapping of Pins 6/7 to 8/9 and the I2C clock before the initialization of the GPIO Pins*/
}
s8 sensirion_i2c_read(u8 address, u8 *data, u16 count)
{
return (s8) I2C_ReadBlock(address, data, count);
}
s8 sensirion_i2c_write(u8 address, const u8 *data, u16 count)
{
return (s8) I2C_WriteBlock(address,data, count);
}
/**
* Sleep for a given number of microseconds. The function should delay the
* execution for at least the given time, but may also sleep longer.
*
* @param useconds the sleep time in microseconds
*/
void sensirion_sleep_usec(u32 useconds) {
// 没用到
}
SDA、SCL引脚根据自己的实际情况配置,这里复用了一个管脚,硬件设计上只剩下这种管脚了。
sensirion_sleep_usec()
函数不需要用。I2Cx_TIMEOUT_UserCallback()
用来应对超时处理的,防止因为I2C总线出现的各种问题卡死在while中,一出问题就重新初始化I2C进行恢复。WAIT_FOR_FLAG()
用宏定义封装了超时处理及判断I2C中的EV等事件的发生。见stm32官方手册。I2C_ReadBlock()
读函数,规定死了2的bytes的长度,有想用的要自己改下。I2C_WriteBlock()
写函数,这个没有规定长度,可以任意发送,w_addr是写入设备的地址。
sht3x.c
#include "sensirion_arch_config.h"
#include "sensirion_common.h"
#include "sensirion_i2c.h"
#include "sht.h"
#include "sht_common.h"
/* all measurement commands return T (CRC) RH (CRC) */
#if USE_SENSIRION_CLOCK_STRETCHING
static const u8 CMD_MEASURE_HPM[] = { 0x2C, 0x06 };
static const u8 CMD_MEASURE_LPM[] = { 0x2C, 0x10 };
#else
static const u8 CMD_MEASURE_HPM[] = { 0x24, 0x00 };
static const u8 CMD_MEASURE_LPM[] = { 0x24, 0x16 };
#endif /* USE_SENSIRION_CLOCK_STRETCHING */
static const u8 CMD_READ_STATUS_REG[] = { 0xF3, 0x2D };
static const u8 COMMAND_SIZE = sizeof(CMD_MEASURE_HPM);
#ifdef SHT_ADDRESS
static const u8 SHT3X_ADDRESS = SHT_ADDRESS;
#else
static const u8 SHT3X_ADDRESS = 0x44;
#endif
static const u16 MEASUREMENT_DURATION_USEC = 15000;
static const u8 *cmd_measure = CMD_MEASURE_HPM;
s8 sht_measure_blocking_read(s32 *temperature, s32 *humidity)
{
s8 ret = sht_measure();
if (ret == STATUS_OK) {
sensirion_sleep_usec(MEASUREMENT_DURATION_USEC);
ret = sht_read(temperature, humidity);
}
return ret;
}
s8 sht_measure()
{
return sensirion_i2c_write(SHT3X_ADDRESS, CMD_MEASURE_HPM, COMMAND_SIZE);
}
s8 sht_read(s32 *temperature, s32 *humidity)
{
return sht_common_read_measurement(SHT3X_ADDRESS, temperature, humidity);
}
s8 sht_probe()
{
u8 data[3];
sensirion_i2c_init();
s8 ret = sensirion_i2c_write(SHT3X_ADDRESS, CMD_READ_STATUS_REG, COMMAND_SIZE);
if (ret)
return ret;
ret = sensirion_i2c_read(SHT3X_ADDRESS, data, sizeof(data));
if (ret)
return ret;
ret = sensirion_common_check_crc(data, 2, data[2]);
if (ret)
return ret;
return STATUS_OK;
}
s8 sht_disable_sleep(u8 disable_sleep)
{
return STATUS_FAIL; /* sleep mode not supported */
}
void sht_enable_low_power_mode(u8 enable_low_power_mode)
{
cmd_measure = enable_low_power_mode ? CMD_MEASURE_LPM : CMD_MEASURE_HPM;
}
//const char *sht_get_driver_version()
//{
// return SHT_DRV_VERSION_STR;
//}
u8 sht_get_configured_sht_address()
{
return SHT3X_ADDRESS;
}
const char *sht_get_driver_version()
需要注掉
,并没有定义驱动版本,你也可以自己定义,否则会报错。- 有很多封装好的函数可以调用,睡眠,低功耗模式等等(
其实鸟用也没用
,反正我没用)sht_probe()
探针,用来检测是不是正常的,主程序中会用到。- 还有一些开头定义的
命令数组及地址
等
mian.c
while (sht_probe() != STATUS_OK) {
LED_D2_D3(GPIO_Pin_6);
/* printf("SHT sensor probing failed\n"); */
}
GPIO_SetBits(GPIOA, GPIO_Pin_6);
LED_D2_D3(GPIO_Pin_7);
/*printf("SHT sensor probing successful\n"); */
while (1) {
s32 temperature, humidity;
/* Measure temperature and relative humidity and store into variables
* temperature, humidity (each output multiplied by 1000).
*/
s8 ret = sht_measure_blocking_read(&temperature, &humidity);
if (ret == STATUS_OK) {
/* printf("measured temperature: %0.2f degreeCelsius, "
"measured humidity: %0.2f percentRH\n",
temperature / 1000.0f,
humidity / 1000.0f); */
LED_D2_D3(GPIO_Pin_6);
} else {
//printf("error reading measurement\n");
LED_D2_D3(GPIO_Pin_7);
}
delay_ms(1000);
}
}
void LED_D2_D3(uint32_t GPIO_Pin_x)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIOInit;
GPIOInit.GPIO_Mode = GPIO_Mode_OUT;
GPIOInit.GPIO_OType = GPIO_OType_PP;
GPIOInit.GPIO_Pin = GPIO_Pin_x;
GPIOInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIOInit);
}
完整读取的时间:16ms(传感器自身测量占了15ms
见手册)