通过模拟I2c对DHT8x传感器进行温度和湿度的读取。
/**************************************************.h文件**************************************************/
#ifndef __BSP_DTH8x_H
#define __BSP_DTH8x_H
#include "stm32f10x.h"
#define DTH8x_CH_MAX 16
enum __type
{
TEM=0,
HUM,
TEM_AND_HUM
};
//commond //adr commond r/w
#define WRITE_STATUS_REG 0x06 //000 0011 0
#define READ_STATUS_REG 0x07 //000 0011 1
#define TEM_MEASURE 0x03 //000 0001 1
#define HUM_MEASURE 0x05 //000 0010 1
#define RESET 0x1e //000 1111 0
//config
typedef struct
{
unsigned char sck_port;
unsigned char sck_pin;
unsigned char data_port;
unsigned char data_pin;
}DTH8x_config_t;
//data
typedef struct
{
float tem;
float hum;
}DTH8x_Data_t;
typedef struct
{
unsigned char isUsed;
DTH8x_config_t config;
DTH8x_Data_t state;
}DTH8x_t;
int DTH8x_setConfig(unsigned char ch, DTH8x_config_t config);
int DTH8x_GetConfig(unsigned char ch, DTH8x_config_t* config);
int DTH8x_Measure(unsigned char ch, enum __type type, unsigned char ischeckCrc);
int DTH8x_GetData(unsigned char ch, DTH8x_Data_t* value);
#endif
/**************************************************.c文件**************************************************/
#include "bsp_DTH8x.h"
#include <stdio.h>
DTH8x_t DTH8x[DTH8x_CH_MAX] = {0};
//SCK
#define SCK_OUTPUT_H(port,pin) GPIO_SetBits(port, pin)
#define SCK_OUTPUT_L(port,pin) GPIO_ResetBits(port, pin)
//DATA
#define DATA_OUTPUT_H(port,pin) GPIO_SetBits(port, pin)
#define DATA_OUTPUT_L(port,pin) GPIO_ResetBits(port, pin)
#define DATA_INPUT_READ(port,pin) GPIO_ReadInputDataBit(port, pin)
//ACK
enum __ack
{
NACK=0,
ACK
};
//tem cal
enum __tem_d1_cal
{
TEM_5V=0,
TEM_4V,
TEM_3_5V,
TEM_3V,
TEM_2_5V,
TEM_D1_ALL
};
typedef struct
{
float d1_C;
float d1_F;
}temD1_t;
temD1_t const temCal_d1[TEM_D1_ALL] = {
{-40.1, -40.2},
{-39.8, -39.6},
{-39.7, -39.5},
{-39.6, -39.3},
{-39.4, -38.9}
};
enum __tem_d2_cal
{
TEM_14BIT=0,
TEM_12BIT,
TEM_D2_ALL
};
typedef struct
{
float d2_C;
float d2_F;
}temD2_t;
temD2_t const temCal_d2[TEM_D2_ALL] = {
{0.01, 0.018},
{0.04, 0.072}
};
//hum cal
enum __hum_cal
{
HUM_12BIT=0,
HUM_8BIT,
HUM_ALL
};
typedef struct
{
float c1;
float c2;
float c3;
}humCal_t;
humCal_t const humCal[HUM_ALL] = {
{-2.0468, 0.0367, -0.0000015955},
{-2.0468, 0.5872, -0.00040845}
};
typedef struct
{
float t1;
float t2;
}humCmpe_t;
humCmpe_t const humCmp[HUM_ALL] = {
{0.01, 0.00008},
{0.01, 0.00128}
};
//cal
#define HUM_RH_LINEAR(c1,c2,c3,H) ( c1 + (c2*H) + (c3*H*H) ) //相对湿度
#define TEM_TC(d1,d2,T) ( d1 + (d2*T) ) //实际温度
#define HUM_RH_TRUE(t1,t2,H,RH_LINEAR,TC) ( ( (TC-25)*(t1+(t2*H)) ) + RH_LINEAR ) //实际湿度
//void delay_nus(unsigned long n)
//{
// unsigned long j = 0;
//
// while(n--)
// {
// j = 12;
// while(j--);
// }
//}
static GPIO_TypeDef* getPortIdx(INT8U port)
{
INT8U PortIdx = port;
GPIO_TypeDef* GPIOx = NULL;
switch(PortIdx)
{
case 0: GPIOx = GPIOA; break;
case 1: GPIOx = GPIOB; break;
case 2: GPIOx = GPIOC; break;
case 3: GPIOx = GPIOD; break;
case 4: GPIOx = GPIOE; break;
case 5: GPIOx = GPIOF; break;
case 6: GPIOx = GPIOG; break;
default:break;
}
return GPIOx;
}
static unsigned short getPinIdx(INT8U pin)
{
return (unsigned short)(1<<pin);
}
int DTH8x_DATA_GpioModeSet(unsigned char ch, GPIOMode_TypeDef gpioMode)
{
int err = 0;
GPIO_InitTypeDef GPIO_InitStructure;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
err = -2;
//端口速度
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//端口模式,此为输出推挽模式
GPIO_InitStructure.GPIO_Mode = gpioMode;
//DATA_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(DTH8x[ch].config.data_pin);
//DATA_PORT初始化端口
GPIO_Init(getPortIdx(DTH8x[ch].config.data_port), &GPIO_InitStructure);
return err;
}
int DTH8x_transferStart(unsigned char ch)
{
int err = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//init state
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
return err;
}
int DTH8x_connectionReset(unsigned char ch)
{
int err = 0;
unsigned char i = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//init state
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
for(i = 0; i < 9; i++)
{
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
err = DTH8x_transferStart(ch);
return err;
}
int DTH8x_writeByte(unsigned char ch, unsigned char value)
{
int err = 0;
int ack = 0;
unsigned char i = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//write
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
for(i = 0x80; i > 0; i/=2)
{
if(i&value)
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
else
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
//release DATA-line
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
//clk #9 for ack
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
//check ack
ack = DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
//release DATA-line
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
if(ack)
return err = -3;
return err;
}
unsigned char DTH8x_readByte(unsigned char ch, unsigned char ack, int* errCode)
{
unsigned char value = 0;
unsigned char i = 0;
if((ch >= DTH8x_CH_MAX) || (errCode == 0))
{
*errCode = -1;
return value;
}
if(!DTH8x[ch].isUsed)
{
*errCode = -2;
return value;
}
//read
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
for(i = 0x80; i > 0; i/=2)
{
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
if(DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
value = value | i;
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
if(ack)
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
else
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
*errCode = 0;
return value;
}
//-----------------------------------------------
// crc caculate
//-----------------------------------------------
char DTH8x_crc8(char byte,char crc8)
{
char i;
char temp;
crc8^=byte;
for(i=0;i<8;i++)
{
temp=crc8;
crc8<<=1;
if((temp&0x80)!=0)
crc8^=0x31;
}
return crc8;
}
//-----------------------------------------------
// swap crc byte
//-----------------------------------------------
char DTH8x_swapcrc(char byte)
{
unsigned char i;
char temp=0;
for (i=0x80;i>0;i/=2)
{
if((byte&i)!=0)
temp|=0x80;
if(i==0x01)
break;
temp>>=1;
temp&=0x7f;
}
return temp;
}
int DTH8x_CRC8_check(unsigned char commond,unsigned char adValueH,unsigned char adValueL,unsigned char checksum)
{
int isOk = 0;
unsigned char crcvalue = 0;
crcvalue = DTH8x_crc8(commond,crcvalue); //first byte ,commond
crcvalue = DTH8x_crc8(adValueH,crcvalue);//second byte,adValueH
crcvalue = DTH8x_crc8(adValueL,crcvalue);//thrid byte,adValueL
crcvalue = DTH8x_swapcrc(crcvalue); //swap high and low bit
if(crcvalue==checksum) //checksum == crcvalue
isOk=1;
return isOk;
}
static int DTH8x_getAd(unsigned char ch, enum __type type, unsigned char isCheckCrc, unsigned short* value)
{
int err = 0;
unsigned char commond = 0;
unsigned char adValueH = 0;
unsigned char adValueL = 0;
unsigned short adValue = 0;
unsigned char checkSum = 0;
unsigned long int i = 0;
if((ch >= DTH8x_CH_MAX) || (value == 0))
err = -1;
if(!DTH8x[ch].isUsed)
err = -2;
//开始读取
{
//连接测量
err = DTH8x_transferStart(ch);
if(!err)
{
switch(type)
{
case TEM: commond = TEM_MEASURE; break;
case HUM: commond = HUM_MEASURE; break;
default: err = -1; break;
}
}
if(!err)
{
//send commond
err = DTH8x_writeByte(ch,commond);
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
//等待ACK,超时500ms
#ifdef RTOS_UCOS
for(i = 0; i < 100; i++)
{
if(!DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
break;
OSTimeDly(OSmsToTick(5));
}
#else
for(i = 0; i < SystemCoreClock/72; i++) //时钟为72M
{
if(!DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
break;
}
#endif
if(DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
err = -4;
}
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
if(!err)
adValueH = DTH8x_readByte(ch,ACK,&err);//MSB
if(!err)
{
adValueL = DTH8x_readByte(ch,ACK,&err);
adValue = (unsigned short)(adValueH<<8) + adValueL;
}
if(!err)
checkSum = DTH8x_readByte(ch,NACK,&err);//check sum
// printf("***%s***: adValueH = 0x%02x, adValueL = 0x%02x, checkSum = 0x%02x, adValue = 0x%02x\r\n", \
// (type==TEM?"TEM":"HUM"), adValueH, adValueL, checkSum, adValue);
if((!err) && (isCheckCrc))
{
if(!DTH8x_CRC8_check(commond,adValueH,adValueL,checkSum))
err = -5;
}
if(!err)
*value = adValue;
}
return err;
}
int DTH8x_Measure(unsigned char ch, enum __type type, unsigned char ischeckCrc)
{
int err = 0;
unsigned short temValue = 0;
unsigned short humValue = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -2;
//计算真实值
switch(type)
{
case TEM:
{
err = DTH8x_getAd(ch, TEM, ischeckCrc, &temValue);
if(err == 0)
{
float d1 = temCal_d1[TEM_3_5V].d1_C;
float d2 = temCal_d2[TEM_14BIT].d2_C;
DTH8x[ch].state.tem = TEM_TC(d1,d2,temValue);
}
}
break;
case HUM:
{
err = DTH8x_getAd(ch, HUM, ischeckCrc, &humValue);
if(err == 0)
{
float c1 = humCal[HUM_12BIT].c1;
float c2 = humCal[HUM_12BIT].c2;
float c3 = humCal[HUM_12BIT].c3;
float RH_linear = HUM_RH_LINEAR(c1,c2,c3,humValue);
float t1 = humCmp[HUM_12BIT].t1;
float t2 = humCmp[HUM_12BIT].t2;
DTH8x[ch].state.hum = HUM_RH_TRUE(t1,t2,humValue,RH_linear,DTH8x[ch].state.tem);
}
}
break;
case TEM_AND_HUM:
{
err = DTH8x_getAd(ch, TEM, ischeckCrc, &temValue);
if(err == 0)
{
float d1 = temCal_d1[TEM_3_5V].d1_C;
float d2 = temCal_d2[TEM_14BIT].d2_C;
DTH8x[ch].state.tem = TEM_TC(d1,d2,temValue);
}
if(!err)
err = DTH8x_getAd(ch, HUM, ischeckCrc, &humValue);
if(err == 0)
{
float c1 = humCal[HUM_12BIT].c1;
float c2 = humCal[HUM_12BIT].c2;
float c3 = humCal[HUM_12BIT].c3;
float RH_linear = HUM_RH_LINEAR(c1,c2,c3,humValue);
float t1 = humCmp[HUM_12BIT].t1;
float t2 = humCmp[HUM_12BIT].t2;
DTH8x[ch].state.hum = HUM_RH_TRUE(t1,t2,humValue,RH_linear,DTH8x[ch].state.tem);
}
}
break;
default: err = -1;
break;
}
//异常复位
if(err)
{
printf("DTH8x_Measure, ch = %d, err = %d\r\n", ch, err);
DTH8x_connectionReset(ch);
}
else
{
//printf("ch = %d, tem = %.2fC, hum=%.2f%%\r\n", ch,DTH8x[ch].state.tem,DTH8x[ch].state.hum);
}
return err;
}
int DTH8x_setConfig(unsigned char ch, DTH8x_config_t config)
{
int err = 0;
GPIO_InitTypeDef GPIO_InitStructure;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if((getPortIdx(config.data_port) == 0) || (getPortIdx(config.sck_port) == 0)
|| (getPinIdx(config.data_pin) > GPIO_Pin_All) || (getPinIdx(config.sck_pin) > GPIO_Pin_All))
return err = -1;
if((getPortIdx(config.data_port) == GPIOA)||(getPortIdx(config.sck_port) == GPIOA))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
else if((getPortIdx(config.data_port) == GPIOB)||(getPortIdx(config.sck_port) == GPIOB))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
else if((getPortIdx(config.data_port) == GPIOC)||(getPortIdx(config.sck_port) == GPIOC))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
else if((getPortIdx(config.data_port) == GPIOD)||(getPortIdx(config.sck_port) == GPIOD))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
else if((getPortIdx(config.data_port) == GPIOE)||(getPortIdx(config.sck_port) == GPIOE))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
else if((getPortIdx(config.data_port) == GPIOF)||(getPortIdx(config.sck_port) == GPIOF))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);
else if((getPortIdx(config.data_port) == GPIOG)||(getPortIdx(config.sck_port) == GPIOG))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
else
return err = -1;
//端口速度
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//端口模式,此为输出推挽模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//SCK_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(config.sck_pin);
//SCK_PORT初始化端口
GPIO_Init(getPortIdx(config.sck_port), &GPIO_InitStructure);
//DATA_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(config.data_pin);
//DATA_PORT初始化端口
GPIO_Init(getPortIdx(config.data_port), &GPIO_InitStructure);
//初始化参数
DTH8x[ch].isUsed = 1;
DTH8x[ch].config = config;
DTH8x[ch].state.hum = 0.0;
DTH8x[ch].state.tem = 0.0;
err = DTH8x_connectionReset(ch);
return err;
}
int DTH8x_GetConfig(unsigned char ch, DTH8x_config_t* config)
{
int err = 0;
if((ch >= DTH8x_CH_MAX) || (config == 0))
return err = -1;
if(DTH8x[ch].isUsed)
*config = DTH8x[ch].config;
else
return err = -2;
return err;
}
int DTH8x_GetData(unsigned char ch, DTH8x_Data_t* value)
{
int err = 0;
if((ch >= DTH8x_CH_MAX) || (value == 0))
return err = -1;
if(DTH8x[ch].isUsed)
*value = DTH8x[ch].state;
else
return err = -2;
return err;
}
/**************************************************.h文件**************************************************/
#ifndef __BSP_DTH8x_H
#define __BSP_DTH8x_H
#include "stm32f10x.h"
#define DTH8x_CH_MAX 16
enum __type
{
TEM=0,
HUM,
TEM_AND_HUM
};
//commond //adr commond r/w
#define WRITE_STATUS_REG 0x06 //000 0011 0
#define READ_STATUS_REG 0x07 //000 0011 1
#define TEM_MEASURE 0x03 //000 0001 1
#define HUM_MEASURE 0x05 //000 0010 1
#define RESET 0x1e //000 1111 0
//config
typedef struct
{
unsigned char sck_port;
unsigned char sck_pin;
unsigned char data_port;
unsigned char data_pin;
}DTH8x_config_t;
//data
typedef struct
{
float tem;
float hum;
}DTH8x_Data_t;
typedef struct
{
unsigned char isUsed;
DTH8x_config_t config;
DTH8x_Data_t state;
}DTH8x_t;
int DTH8x_setConfig(unsigned char ch, DTH8x_config_t config);
int DTH8x_GetConfig(unsigned char ch, DTH8x_config_t* config);
int DTH8x_Measure(unsigned char ch, enum __type type, unsigned char ischeckCrc);
int DTH8x_GetData(unsigned char ch, DTH8x_Data_t* value);
#endif
/**************************************************.c文件**************************************************/
#include "bsp_DTH8x.h"
#include <stdio.h>
DTH8x_t DTH8x[DTH8x_CH_MAX] = {0};
//SCK
#define SCK_OUTPUT_H(port,pin) GPIO_SetBits(port, pin)
#define SCK_OUTPUT_L(port,pin) GPIO_ResetBits(port, pin)
//DATA
#define DATA_OUTPUT_H(port,pin) GPIO_SetBits(port, pin)
#define DATA_OUTPUT_L(port,pin) GPIO_ResetBits(port, pin)
#define DATA_INPUT_READ(port,pin) GPIO_ReadInputDataBit(port, pin)
//ACK
enum __ack
{
NACK=0,
ACK
};
//tem cal
enum __tem_d1_cal
{
TEM_5V=0,
TEM_4V,
TEM_3_5V,
TEM_3V,
TEM_2_5V,
TEM_D1_ALL
};
typedef struct
{
float d1_C;
float d1_F;
}temD1_t;
temD1_t const temCal_d1[TEM_D1_ALL] = {
{-40.1, -40.2},
{-39.8, -39.6},
{-39.7, -39.5},
{-39.6, -39.3},
{-39.4, -38.9}
};
enum __tem_d2_cal
{
TEM_14BIT=0,
TEM_12BIT,
TEM_D2_ALL
};
typedef struct
{
float d2_C;
float d2_F;
}temD2_t;
temD2_t const temCal_d2[TEM_D2_ALL] = {
{0.01, 0.018},
{0.04, 0.072}
};
//hum cal
enum __hum_cal
{
HUM_12BIT=0,
HUM_8BIT,
HUM_ALL
};
typedef struct
{
float c1;
float c2;
float c3;
}humCal_t;
humCal_t const humCal[HUM_ALL] = {
{-2.0468, 0.0367, -0.0000015955},
{-2.0468, 0.5872, -0.00040845}
};
typedef struct
{
float t1;
float t2;
}humCmpe_t;
humCmpe_t const humCmp[HUM_ALL] = {
{0.01, 0.00008},
{0.01, 0.00128}
};
//cal
#define HUM_RH_LINEAR(c1,c2,c3,H) ( c1 + (c2*H) + (c3*H*H) ) //相对湿度
#define TEM_TC(d1,d2,T) ( d1 + (d2*T) ) //实际温度
#define HUM_RH_TRUE(t1,t2,H,RH_LINEAR,TC) ( ( (TC-25)*(t1+(t2*H)) ) + RH_LINEAR ) //实际湿度
//void delay_nus(unsigned long n)
//{
// unsigned long j = 0;
//
// while(n--)
// {
// j = 12;
// while(j--);
// }
//}
static GPIO_TypeDef* getPortIdx(INT8U port)
{
INT8U PortIdx = port;
GPIO_TypeDef* GPIOx = NULL;
switch(PortIdx)
{
case 0: GPIOx = GPIOA; break;
case 1: GPIOx = GPIOB; break;
case 2: GPIOx = GPIOC; break;
case 3: GPIOx = GPIOD; break;
case 4: GPIOx = GPIOE; break;
case 5: GPIOx = GPIOF; break;
case 6: GPIOx = GPIOG; break;
default:break;
}
return GPIOx;
}
static unsigned short getPinIdx(INT8U pin)
{
return (unsigned short)(1<<pin);
}
int DTH8x_DATA_GpioModeSet(unsigned char ch, GPIOMode_TypeDef gpioMode)
{
int err = 0;
GPIO_InitTypeDef GPIO_InitStructure;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
err = -2;
//端口速度
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//端口模式,此为输出推挽模式
GPIO_InitStructure.GPIO_Mode = gpioMode;
//DATA_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(DTH8x[ch].config.data_pin);
//DATA_PORT初始化端口
GPIO_Init(getPortIdx(DTH8x[ch].config.data_port), &GPIO_InitStructure);
return err;
}
int DTH8x_transferStart(unsigned char ch)
{
int err = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//init state
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
return err;
}
int DTH8x_connectionReset(unsigned char ch)
{
int err = 0;
unsigned char i = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//init state
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
for(i = 0; i < 9; i++)
{
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
err = DTH8x_transferStart(ch);
return err;
}
int DTH8x_writeByte(unsigned char ch, unsigned char value)
{
int err = 0;
int ack = 0;
unsigned char i = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -1;
//write
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
for(i = 0x80; i > 0; i/=2)
{
if(i&value)
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
else
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
//release DATA-line
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
//clk #9 for ack
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
//check ack
ack = DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
//release DATA-line
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
if(ack)
return err = -3;
return err;
}
unsigned char DTH8x_readByte(unsigned char ch, unsigned char ack, int* errCode)
{
unsigned char value = 0;
unsigned char i = 0;
if((ch >= DTH8x_CH_MAX) || (errCode == 0))
{
*errCode = -1;
return value;
}
if(!DTH8x[ch].isUsed)
{
*errCode = -2;
return value;
}
//read
{
#ifdef RTOS_UCOS
OS_CPU_SR_DEF();
OS_ENTER_CRITICAL();//进入临界区
#endif
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
for(i = 0x80; i > 0; i/=2)
{
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
if(DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
value = value | i;
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
}
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
if(ack)
DATA_OUTPUT_L (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
else
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
__nop();__nop();__nop();
SCK_OUTPUT_H (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
SCK_OUTPUT_L (getPortIdx(DTH8x[ch].config.sck_port), getPinIdx(DTH8x[ch].config.sck_pin));
__nop();__nop();__nop();
DATA_OUTPUT_H (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin));
#ifdef RTOS_UCOS
OS_EXIT_CRITICAL();//退出临界区
#endif
}
*errCode = 0;
return value;
}
//-----------------------------------------------
// crc caculate
//-----------------------------------------------
char DTH8x_crc8(char byte,char crc8)
{
char i;
char temp;
crc8^=byte;
for(i=0;i<8;i++)
{
temp=crc8;
crc8<<=1;
if((temp&0x80)!=0)
crc8^=0x31;
}
return crc8;
}
//-----------------------------------------------
// swap crc byte
//-----------------------------------------------
char DTH8x_swapcrc(char byte)
{
unsigned char i;
char temp=0;
for (i=0x80;i>0;i/=2)
{
if((byte&i)!=0)
temp|=0x80;
if(i==0x01)
break;
temp>>=1;
temp&=0x7f;
}
return temp;
}
int DTH8x_CRC8_check(unsigned char commond,unsigned char adValueH,unsigned char adValueL,unsigned char checksum)
{
int isOk = 0;
unsigned char crcvalue = 0;
crcvalue = DTH8x_crc8(commond,crcvalue); //first byte ,commond
crcvalue = DTH8x_crc8(adValueH,crcvalue);//second byte,adValueH
crcvalue = DTH8x_crc8(adValueL,crcvalue);//thrid byte,adValueL
crcvalue = DTH8x_swapcrc(crcvalue); //swap high and low bit
if(crcvalue==checksum) //checksum == crcvalue
isOk=1;
return isOk;
}
static int DTH8x_getAd(unsigned char ch, enum __type type, unsigned char isCheckCrc, unsigned short* value)
{
int err = 0;
unsigned char commond = 0;
unsigned char adValueH = 0;
unsigned char adValueL = 0;
unsigned short adValue = 0;
unsigned char checkSum = 0;
unsigned long int i = 0;
if((ch >= DTH8x_CH_MAX) || (value == 0))
err = -1;
if(!DTH8x[ch].isUsed)
err = -2;
//开始读取
{
//连接测量
err = DTH8x_transferStart(ch);
if(!err)
{
switch(type)
{
case TEM: commond = TEM_MEASURE; break;
case HUM: commond = HUM_MEASURE; break;
default: err = -1; break;
}
}
if(!err)
{
//send commond
err = DTH8x_writeByte(ch,commond);
//data-line gpio set input
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_IPU);
//等待ACK,超时500ms
#ifdef RTOS_UCOS
for(i = 0; i < 100; i++)
{
if(!DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
break;
OSTimeDly(OSmsToTick(5));
}
#else
for(i = 0; i < SystemCoreClock/72; i++) //时钟为72M
{
if(!DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
break;
}
#endif
if(DATA_INPUT_READ (getPortIdx(DTH8x[ch].config.data_port), getPinIdx(DTH8x[ch].config.data_pin)))
err = -4;
}
//data-line gpio set output
DTH8x_DATA_GpioModeSet(ch,GPIO_Mode_Out_PP);
if(!err)
adValueH = DTH8x_readByte(ch,ACK,&err);//MSB
if(!err)
{
adValueL = DTH8x_readByte(ch,ACK,&err);
adValue = (unsigned short)(adValueH<<8) + adValueL;
}
if(!err)
checkSum = DTH8x_readByte(ch,NACK,&err);//check sum
// printf("***%s***: adValueH = 0x%02x, adValueL = 0x%02x, checkSum = 0x%02x, adValue = 0x%02x\r\n", \
// (type==TEM?"TEM":"HUM"), adValueH, adValueL, checkSum, adValue);
if((!err) && (isCheckCrc))
{
if(!DTH8x_CRC8_check(commond,adValueH,adValueL,checkSum))
err = -5;
}
if(!err)
*value = adValue;
}
return err;
}
int DTH8x_Measure(unsigned char ch, enum __type type, unsigned char ischeckCrc)
{
int err = 0;
unsigned short temValue = 0;
unsigned short humValue = 0;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if(!DTH8x[ch].isUsed)
return err = -2;
//计算真实值
switch(type)
{
case TEM:
{
err = DTH8x_getAd(ch, TEM, ischeckCrc, &temValue);
if(err == 0)
{
float d1 = temCal_d1[TEM_3_5V].d1_C;
float d2 = temCal_d2[TEM_14BIT].d2_C;
DTH8x[ch].state.tem = TEM_TC(d1,d2,temValue);
}
}
break;
case HUM:
{
err = DTH8x_getAd(ch, HUM, ischeckCrc, &humValue);
if(err == 0)
{
float c1 = humCal[HUM_12BIT].c1;
float c2 = humCal[HUM_12BIT].c2;
float c3 = humCal[HUM_12BIT].c3;
float RH_linear = HUM_RH_LINEAR(c1,c2,c3,humValue);
float t1 = humCmp[HUM_12BIT].t1;
float t2 = humCmp[HUM_12BIT].t2;
DTH8x[ch].state.hum = HUM_RH_TRUE(t1,t2,humValue,RH_linear,DTH8x[ch].state.tem);
}
}
break;
case TEM_AND_HUM:
{
err = DTH8x_getAd(ch, TEM, ischeckCrc, &temValue);
if(err == 0)
{
float d1 = temCal_d1[TEM_3_5V].d1_C;
float d2 = temCal_d2[TEM_14BIT].d2_C;
DTH8x[ch].state.tem = TEM_TC(d1,d2,temValue);
}
if(!err)
err = DTH8x_getAd(ch, HUM, ischeckCrc, &humValue);
if(err == 0)
{
float c1 = humCal[HUM_12BIT].c1;
float c2 = humCal[HUM_12BIT].c2;
float c3 = humCal[HUM_12BIT].c3;
float RH_linear = HUM_RH_LINEAR(c1,c2,c3,humValue);
float t1 = humCmp[HUM_12BIT].t1;
float t2 = humCmp[HUM_12BIT].t2;
DTH8x[ch].state.hum = HUM_RH_TRUE(t1,t2,humValue,RH_linear,DTH8x[ch].state.tem);
}
}
break;
default: err = -1;
break;
}
//异常复位
if(err)
{
printf("DTH8x_Measure, ch = %d, err = %d\r\n", ch, err);
DTH8x_connectionReset(ch);
}
else
{
//printf("ch = %d, tem = %.2fC, hum=%.2f%%\r\n", ch,DTH8x[ch].state.tem,DTH8x[ch].state.hum);
}
return err;
}
int DTH8x_setConfig(unsigned char ch, DTH8x_config_t config)
{
int err = 0;
GPIO_InitTypeDef GPIO_InitStructure;
if(ch >= DTH8x_CH_MAX)
return err = -1;
if((getPortIdx(config.data_port) == 0) || (getPortIdx(config.sck_port) == 0)
|| (getPinIdx(config.data_pin) > GPIO_Pin_All) || (getPinIdx(config.sck_pin) > GPIO_Pin_All))
return err = -1;
if((getPortIdx(config.data_port) == GPIOA)||(getPortIdx(config.sck_port) == GPIOA))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
else if((getPortIdx(config.data_port) == GPIOB)||(getPortIdx(config.sck_port) == GPIOB))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
else if((getPortIdx(config.data_port) == GPIOC)||(getPortIdx(config.sck_port) == GPIOC))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
else if((getPortIdx(config.data_port) == GPIOD)||(getPortIdx(config.sck_port) == GPIOD))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
else if((getPortIdx(config.data_port) == GPIOE)||(getPortIdx(config.sck_port) == GPIOE))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
else if((getPortIdx(config.data_port) == GPIOF)||(getPortIdx(config.sck_port) == GPIOF))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);
else if((getPortIdx(config.data_port) == GPIOG)||(getPortIdx(config.sck_port) == GPIOG))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
else
return err = -1;
//端口速度
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//端口模式,此为输出推挽模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//SCK_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(config.sck_pin);
//SCK_PORT初始化端口
GPIO_Init(getPortIdx(config.sck_port), &GPIO_InitStructure);
//DATA_PIN引脚设置
GPIO_InitStructure.GPIO_Pin = getPinIdx(config.data_pin);
//DATA_PORT初始化端口
GPIO_Init(getPortIdx(config.data_port), &GPIO_InitStructure);
//初始化参数
DTH8x[ch].isUsed = 1;
DTH8x[ch].config = config;
DTH8x[ch].state.hum = 0.0;
DTH8x[ch].state.tem = 0.0;
err = DTH8x_connectionReset(ch);
return err;
}
int DTH8x_GetConfig(unsigned char ch, DTH8x_config_t* config)
{
int err = 0;
if((ch >= DTH8x_CH_MAX) || (config == 0))
return err = -1;
if(DTH8x[ch].isUsed)
*config = DTH8x[ch].config;
else
return err = -2;
return err;
}
int DTH8x_GetData(unsigned char ch, DTH8x_Data_t* value)
{
int err = 0;
if((ch >= DTH8x_CH_MAX) || (value == 0))
return err = -1;
if(DTH8x[ch].isUsed)
*value = DTH8x[ch].state;
else
return err = -2;
return err;
}