OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3167|回复: 6

SHT20温湿度传感器数据读取异常

[复制链接]

23

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
350
金钱
350
注册时间
2015-7-14
在线时间
76 小时
发表于 2019-9-9 13:19:49 | 显示全部楼层 |阅读模式
1金钱
使用SHT20温湿度传感器,用模拟IIC通信,不能正确的读取数据。现象有3个
第一,读取温度的低8位始终是0xFF。
第二,读取温度的高8位的数值会从0x00随着温度上升不断增加,增加至0xFF后,继续变为0x00后再增加。实验过程中发现从20摄氏度室温升高至90摄氏度的过程中,多次出现该情况。
第三,读取温度的高8位,取反后进行计算,在46.85摄氏度以内的温度变化是准确的。

最佳答案

查看完整内容[请看2#楼]

问题解决了。wait ack函数内,应答超时后会发送stop。但是sht20需等待传感器测量完成之后才能返回应答,所以需要等待的时间会略多一些,仅250次计数不够。而函数内250次计数后将发送stop,结束本次交互。因此解决办法有两种,第一个是屏蔽wait ack函数中的stop命令,但是对于多设备总线时会有一定影响。第二是改变wait ack中超时计数变量的类型,将uint8_t该为uint16_t,并增加超时判断。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

23

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
350
金钱
350
注册时间
2015-7-14
在线时间
76 小时
 楼主| 发表于 2019-9-9 13:19:50 | 显示全部楼层
问题解决了。wait ack函数内,应答超时后会发送stop。但是sht20需等待传感器测量完成之后才能返回应答,所以需要等待的时间会略多一些,仅250次计数不够。而函数内250次计数后将发送stop,结束本次交互。因此解决办法有两种,第一个是屏蔽wait ack函数中的stop命令,但是对于多设备总线时会有一定影响。第二是改变wait ack中超时计数变量的类型,将uint8_t该为uint16_t,并增加超时判断。
回复

使用道具 举报

23

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
350
金钱
350
注册时间
2015-7-14
在线时间
76 小时
 楼主| 发表于 2019-9-9 13:27:54 | 显示全部楼层
void BSP_IIC_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_IIC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = PIN_IIC_SCL | PIN_IIC_SDA;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
        GPIO_Init(PORT_IIC, &GPIO_InitStructure);
}

void IIC_SCL_IN(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_IIC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = PIN_IIC_SCL;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        GPIO_Init(PORT_IIC, &GPIO_InitStructure);
}

void IIC_SDA_IN(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_IIC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = PIN_IIC_SDA;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        GPIO_Init(PORT_IIC, &GPIO_InitStructure);
}

void IIC_SCL_OUT(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_IIC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = PIN_IIC_SCL;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
        GPIO_Init(PORT_IIC, &GPIO_InitStructure);
}

void IIC_SDA_OUT(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_IIC_PORT, ENABLE);

        GPIO_InitStructure.GPIO_Pin = PIN_IIC_SDA;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
        GPIO_Init(PORT_IIC, &GPIO_InitStructure);
}

void IIC_Delay_10uS(uint16_t us)
{
        uint16_t cnt;
        for (cnt = 0; cnt < 20 * us; cnt++);
}

void IIC_Start(void)
{
        IIC_SDA_OUT();

        IIC_SDA_HIGH();
        IIC_SCL_HIGH();
        IIC_Delay_10uS(1);
        IIC_SDA_LOW();
        IIC_Delay_10uS(1);
        IIC_SCL_LOW();
        IIC_Delay_10uS(1);
}

void IIC_Stop(void)
{
        IIC_SDA_OUT();

        IIC_SDA_LOW();
        IIC_SCL_LOW();
        IIC_Delay_10uS(1);
        IIC_SCL_HIGH();
        IIC_Delay_10uS(1);
        IIC_SDA_HIGH();
        IIC_Delay_10uS(1);
}

void IIC_SendByte(uint8_t _ucByte)
{
        uint8_t cnt;
       
        IIC_SCL_LOW();
        IIC_SDA_OUT();
       
        /* 先发送字节的高位bit7 */
        for (cnt = 0; cnt < 8; cnt++)
        {
                if (_ucByte & 0x80)
                {
                        IIC_SDA_HIGH();
                }
                else
                {
                        IIC_SDA_LOW();
                }
               
                _ucByte <<= 1;        /* 左移一个bit */
                IIC_Delay_10uS(1);
                IIC_SCL_HIGH();
                IIC_Delay_10uS(1);
                IIC_SCL_LOW();
                IIC_Delay_10uS(1);
        }
}

uint8_t IIC_ReadByte(void)
{
        uint8_t cnt;
        uint8_t value = 0;
       
        IIC_SDA_IN();
       
        /* 读到第1个bit为数据的bit7 */
        for (cnt = 0; cnt < 8; cnt++)
        {
                IIC_SCL_LOW();
                IIC_Delay_10uS(1);
                IIC_SCL_HIGH();
                value <<= 1;
               
                if (IIC_SDA_READ())
                {
                        value |= 0x01;
                }
                else
                {
                        value &= 0xFE;
                }
               
                IIC_Delay_10uS(1);
        }
       
        return value;
}

uint8_t IIC_WaitACK(void)
{
        uint8_t err_cnt;
       
        IIC_SDA_OUT();

        IIC_SDA_HIGH();        /* CPU释放SDA  总线 */
        IIC_Delay_10uS(1);
        IIC_SCL_HIGH();        /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
        IIC_Delay_10uS(1);
       
        IIC_SDA_IN();

        while(IIC_SDA_READ())
        {
                err_cnt++;
                if (err_cnt > 250)        /* CPU读取SDA口线状态 */
                {
                        IIC_Stop();
                        return 1;
                }
        }
       
        IIC_SCL_LOW();
        IIC_Delay_10uS(1);

        return 0;
}

void IIC_ACK(void)
{
        IIC_SCL_LOW();
        IIC_SDA_OUT();
        IIC_SDA_LOW();        /* CPU驱动SDA = 0 */
        IIC_Delay_10uS(1);
        IIC_SCL_HIGH();        /* CPU产生1个时钟 */
        IIC_Delay_10uS(1);
        IIC_SCL_LOW();
}

void IIC_NACK(void)
{
        IIC_SCL_LOW();
        IIC_SDA_OUT();
        IIC_SDA_HIGH();        /* CPU驱动SDA = 1 */
        IIC_Delay_10uS(1);
        IIC_SCL_HIGH();        /* CPU产生1个时钟 */
        IIC_Delay_10uS(1);
        IIC_SCL_LOW();
}

float BSP_SHT20_GetTemperature(void)
{
        uint8_t datah, datal;
        float temp = 0;
       
        IIC_Start();
        IIC_SendByte(IIC_ADR_W);
        IIC_WaitACK();
        IIC_SendByte(TRIG_T_MEASUREMENT_POLL);      
        IIC_WaitACK();
        IIC_Delay_10uS(1);
       
wait:       
        IIC_Start();       
        IIC_SendByte(IIC_ADR_R);
        IIC_WaitACK();
        if(IIC_WaitACK())
        {
                printf("ACK is FALSE!\n\r");
                goto wait;
        }
        else printf("ACK is TURE!\n\r");

        datah = IIC_ReadByte();
        IIC_ACK();                
        datal = IIC_ReadByte();
        IIC_NACK();               
        IIC_Stop();
       
        temp = (float)((datah << 8 | datal) & 0xFFFC) * 175.72 / 65536 - 46.85;
       
        return temp;
}


回复

使用道具 举报

23

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
350
金钱
350
注册时间
2015-7-14
在线时间
76 小时
 楼主| 发表于 2019-9-9 13:32:36 | 显示全部楼层
#define RCC_IIC_PORT   RCC_AHBPeriph_GPIOB // GPIO端口时钟
#define PORT_IIC          GPIOB

#define PIN_IIC_SCL    GPIO_Pin_6          // GPIO引脚
#define PIN_IIC_SDA   GPIO_Pin_7          // GPIO引脚

#define IIC_SCL_HIGH()    GPIO_SetBits(PORT_IIC,PIN_IIC_SCL)   // SCL = 1
#define IIC_SCL_LOW()     GPIO_ResetBits(PORT_IIC,PIN_IIC_SCL) // SCL = 0

#define IIC_SDA_HIGH()    GPIO_SetBits(PORT_IIC,PIN_IIC_SDA)   // SDA = 1
#define IIC_SDA_LOW()     GPIO_ResetBits(PORT_IIC,PIN_IIC_SDA) // SDA = 0

#define IIC_SDA_READ() GPIO_ReadInputDataBit(PORT_IIC,PIN_IIC_SDA)!=0 // 读SDA口线状态
#define IIC_SCL_READ()  GPIO_ReadInputDataBit(PORT_IIC,PIN_IIC_SCL)!=0 // 读SCL口线状态

typedef enum{
  TRIG_T_MEASUREMENT_HM    = 0xE3, // command trig. temp meas. hold master
  TRIG_RH_MEASUREMENT_HM   = 0xE5, // command trig. humidity meas. hold master
  TRIG_T_MEASUREMENT_POLL  = 0xF3, // command trig. temp meas. no hold master
  TRIG_RH_MEASUREMENT_POLL = 0xF5, // command trig. humidity meas. no hold master
  USER_REG_W               = 0xE6, // command writing user register
  USER_REG_R               = 0xE7, // command reading user register
  SOFT_RESET               = 0xFE  // command soft reset
}SHT20Command;

typedef enum {
  SHT20_RES_12_14BIT       = 0x00, // RH=12bit, T=14bit
  SHT20_RES_8_12BIT        = 0x01, // RH= 8bit, T=12bit
  SHT20_RES_10_13BIT       = 0x80, // RH=10bit, T=13bit
  SHT20_RES_11_11BIT       = 0x81, // RH=11bit, T=11bit
  SHT20_RES_MASK           = 0x81  // Mask for res. bits (7,0) in user reg.
} SHT20Resolution;

typedef enum {
  SHT20_EOB_ON             = 0x40, // end of battery
  SHT20_EOB_MASK           = 0x40, // Mask for EOB bit(6) in user reg.
} SHT20Eob;

typedef enum {
  SHT20_HEATER_ON          = 0x04, // heater on
  SHT20_HEATER_OFF         = 0x00, // heater off
  SHT20_HEATER_MASK        = 0x04, // Mask for Heater bit(2) in user reg.
} SHT20Heater;


typedef enum{
  HUMIDITY,
  TEMP
}SHT20MeasureType;

typedef enum{
  IIC_ADR_W                = 0x80,   // sensor IIC address + write bit
  IIC_ADR_R                = 0x81    // sensor IIC address + read bit
}IICHeader;


回复

使用道具 举报

4

主题

231

帖子

0

精华

高级会员

Rank: 4

积分
755
金钱
755
注册时间
2018-12-7
在线时间
131 小时
发表于 2019-9-9 17:25:25 | 显示全部楼层
帮顶   
回复

使用道具 举报

23

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
350
金钱
350
注册时间
2015-7-14
在线时间
76 小时
 楼主| 发表于 2019-9-9 17:26:53 | 显示全部楼层
因为wait ack超时了,所以读到的数据经观察,实际上可能是传感器温度数据的低8位或者是CRC校验,因此会出现自增并溢出的现象,读取的“第二”个字节也始终是0xFF,温度数值不准确也是理所当然的。
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2019-9-17
在线时间
4 小时
发表于 2020-4-28 20:16:12 | 显示全部楼层
Azer 发表于 2019-9-9 13:27
void BSP_IIC_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

谢谢分享!让我少走弯路
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-26 08:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表