M61 读取 AHT20

[复制链接]
查看446 | 回复11 | 2024-6-13 15:39:41 | 显示全部楼层 |阅读模式

M61板子申请下来了

灯也点了

我却不知道干个啥

直到看到外设移植的活动

对我这种人简直神助

一来可以根据芯片手册懂芯片了

二来还不用看那种封装太多我看的头晕的代码

这次,就是 先读AHT20温湿度模块

源工程:

【外设移植】AHT20温湿度传感器M61开发板驱动 - DIY 经验分享 - 物联网开发者社区-安信可论坛 - Powered by Discuz! (ai-thinker.com)

先看手册:

image.png

简单总结,

先发送 0x71 读取状态字

如果bit[3] 为0,发送0xBE 初始化

如果bit[3] 为1,可以开始测量

发送0xAC 发送测量命令 等待80ms

直接读取状态字,如果bit[7] == 0 测量完成

开始读取7个字节的温湿度数据

image.png

image.png

读取数据后转换

image.png

代码实现

AHT20.h

#ifndef __AHT20_H__
#define __AHT20_H__

#include "bflb_i2c.h"
#include "bflb_gpio.h"
#include "bflb_mtimer.h"

#define AHT20_CMD_INIT 0xBE     /* 初始化AHT20芯片指令 */
#define AHT20_CMD_SOFT_RES 0xBA /* 软复位AHT20芯片指令 */
#define AHT20_CMD_START 0xAC    /* 启动AHT20芯片工作指令 */

#define AHT20_ADDR 0x38 /* AHT20芯片IIC地址*/

/* 芯片状态 */
typedef enum
{
    AHT20_STA_ERR = 0, /* 芯片忙和为校准 */
    AHT20_STA_READY,   /* 芯片空闲和已校准 */
    AHT20_STA_LAST,
} AHT20Sta;

/* 初始化结果 */
typedef enum
{
    AHT20_INIT_RES_ERR = 0, /* 芯片初始化失败 */
    AHT20_INIT_RES_OK,      /* 芯片初始化成功 */
    AHT20_INIT_RES_LAST,
} AHT20InitRes;

/**
 * @brief 温湿度数据读取结果
 *
 */
typedef enum
{
    AHT20_READ_ERR = 0, /* 读取失败 */
    AHT20_READ_OK,      /* 读取成功 */
    AHT20_READ_LAST,
} AHT20ReadRes;

/**
 * @brief AHT20 初始化
 *
 * @return AHT20InitRes
 */
AHT20InitRes AHT20_Init();

/**
 * @brief 读取温湿度数据
 *
 * @param _THVal 读取温湿度数据数组
 * @return AHT20ReadRes
 */
AHT20ReadRes AHT20_RecTempAndHumiVal(int32_t *_THVal);

/**
 * @brief 通过读取状态位,判断当前是不是空闲并已校准
 *          空闲 bit[7] = 0
 *          已校准 bit[3] = 1
 *
 * @return AHT20Sta
 */
AHT20Sta AHT20_ReadSta(void);
#endif

AHT20.c

#include "AHT20.h"

static struct bflb_device_s *i2c;
static struct bflb_i2c_msg_s msgs[2];
/**************************Local Function**************************/

/**
 * @brief IIC 引脚初始化
 *
 */
void IIC0_Init(void)
{
    struct bflb_device_s *gpio;

    gpio = bflb_device_get_by_name("gpio");
    /* I2C0_SCL */
    bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
    /* I2C0_SDA */
    bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);

    /* IIC初始化,速度为400K */
    i2c = bflb_device_get_by_name("i2c0");
    bflb_i2c_init(i2c, 400000);

    // printf("IIC0 Init over\r\n");
}

/**
 * @brief 发送IIC命令
 *
 * @param _Cmd    发送的指令
 * @param Sendbuf 继续发送的参数数组指针
 * @param _length 参数数组长度
 */
void AHT20_SenCmd(uint8_t _Cmd, uint8_t *Sendbuf, uint16_t _length)
{
    msgs[0].addr = AHT20_ADDR;
    msgs[0].flags = I2C_M_NOSTOP;
    msgs[0].buffer = &_Cmd;
    msgs[0].length = 1;

    if (_length != 0)
    {
        /* 有数据的发送 */
        msgs[1].addr = AHT20_ADDR;
        msgs[1].flags = 0;
        msgs[1].buffer = Sendbuf;
        msgs[1].length = _length;
        bflb_i2c_transfer(i2c, msgs, 2);
    }
    else
    {
        /* 只发一个字节的数据 */
        msgs[0].flags = 0;
        bflb_i2c_transfer(i2c, msgs, 1);
    }
}

/**
 * @brief IIC读取字节
 *
 * @param Recbuf 读取的保存的数组指针
 * @param _length 要读取的字节数
 */
void AHT20_RecData(uint8_t *Recbuf, uint16_t _length)
{
    msgs[0].addr = AHT20_ADDR;
    msgs[0].flags = I2C_M_READ;
    msgs[0].buffer = Recbuf;
    msgs[0].length = _length;
    bflb_i2c_transfer(i2c, msgs, 1);
}

/**
 * @brief 发送初始化命令  要发送0xBE命令(初始化)和命令参数
 *
 */
void AHT20_ChipInit(void)
{
    uint8_t SendDataBuff[2] = {0x08, 0x00};

    AHT20_SenCmd(AHT20_CMD_INIT, SendDataBuff, 2);

    // printf("Chip Init CMD send over\r\n");
}

/**
 * @brief 发送测量命令  要发送0xAC命令(测量)和命令参数
 *
 */
void AHT20_ChipStartWork(void)
{
    uint8_t SendDataBuff[2] = {0x33, 0x00};

    AHT20_SenCmd(AHT20_CMD_START, SendDataBuff, 2);

    // printf("Chip Start CMD send over\r\n");
}

/**
 * @brief 软复位命令
 *
 */
void AHT20_ChipSoftRes(void)
{
    AHT20_SenCmd(AHT20_CMD_SOFT_RES, 0, 0);

    // printf("Chip Soft Res CMD send over\r\n");
}

/**************************Global Function**************************/

/**
 * @brief 通过读取状态位,判断当前是不是空闲并已校准
 *          空闲 bit[7] = 0
 *          已校准 bit[3] = 1
 *
 * @return AHT20Sta
 */
AHT20Sta AHT20_ReadSta(void)
{
    uint8_t ReadStaVal = 0;
    AHT20_RecData(&ReadStaVal, 1); // 读取一个字节数据
    if ((ReadStaVal & 0x68) == 0x08)
    {
        // printf("Chip Sta is OK\r\n");
        return AHT20_STA_READY;
    }
    else
    {
        // printf("Chip State is Err !!!Receive State Value is %d\r\n", ReadStaVal);
        return AHT20_STA_ERR;
    }
}

/**
 * @brief AHT20 初始化
 *
 * @return AHT20InitRes
 */
AHT20InitRes AHT20_Init()
{
    uint8_t SoftResCount = 0; // 重试次数

    IIC0_Init(); // 初始化IO

    /* 延时40ms,等待传感器加载成功 */
    bflb_mtimer_delay_ms(40); // 如手册所说,延时40ms 等待初始化

    /* 初始化AHT20,然后等待10ms。
     */
    AHT20_ChipInit();

    /* 等待AHT20芯片初始化完成 */
    bflb_mtimer_delay_ms(500);

    while (AHT20_STA_ERR == AHT20_ReadSta()) /* 直至AHT20为空闲状态且验证校准 */
    {
        /* 软复位AHT20 */
        AHT20_ChipSoftRes();
        bflb_mtimer_delay_ms(200);

        AHT20_ChipInit(); // 初始化

        /* 等待AHT20芯片初始化完成 */
        bflb_mtimer_delay_ms(500);
        SoftResCount++;
        if (SoftResCount > 10)
        {
            /* 初始化10次失败 */
            return AHT20_INIT_RES_ERR;
        }
    }
    return AHT20_INIT_RES_OK;
}

/**
 * @brief 读取温湿度数据
 *
 * @param _THVal 读取温湿度数据数组
 * @return AHT20ReadRes
 */
AHT20ReadRes AHT20_RecTempAndHumiVal(int32_t *_THVal)
{
    uint8_t RecBuff[10] = {0};
    uint8_t WorkSta = 0;
    uint8_t ReadCount = 0;
    uint32_t RecDateTemp = 0;

    /* 启动芯片开始工作 */
    AHT20_ChipStartWork();

    /* 等到测试完成 */
    bflb_mtimer_delay_ms(80);

    /* 获取芯片状态 */
    AHT20_RecData(&WorkSta, 1);

    /* 检验芯片是否为空闲状态 */
    while ((WorkSta & 0x80) == 0x80)
    {
        bflb_mtimer_delay_ms(10);
        ReadCount++;
        if (ReadCount > 100)
        {
            /* 等待1S芯片依然处于忙的状态 */
            return AHT20_READ_ERR;
        }
        /* 重新读取状态 */
        AHT20_RecData(&WorkSta, 1);
    }

    /* 获取温湿度数据 */
    AHT20_RecData(RecBuff, 7);

    /* 湿度 */
    RecDateTemp = 0;
    RecDateTemp = (RecDateTemp | RecBuff[1]) << 8;
    RecDateTemp = (RecDateTemp | RecBuff[2]) << 8;
    RecDateTemp = RecDateTemp | RecBuff[3];
    RecDateTemp = RecDateTemp >> 4;
    /* 数据转换,转换结果保留小数点后一位且放大10倍 */
    *_THVal++ = RecDateTemp * 1000 / 1024 / 1024;

    /* 温度 */
    RecDateTemp = 0;
    RecDateTemp = (RecDateTemp | RecBuff[3]) << 8;
    RecDateTemp = (RecDateTemp | RecBuff[4]) << 8;
    RecDateTemp = RecDateTemp | RecBuff[5];
    RecDateTemp = RecDateTemp & 0xFFFFF;
    /* 数据转换,转换结果保留小数点后一位且放大10倍 */
    *_THVal = RecDateTemp * 200 * 10 / 1024 / 1024 - 500;

    return AHT20_READ_OK;
}

main.h

#include "board.h"
#include "AHT20.h"
#include "bflb_gpio.h"

struct bflb_device_s *gpio;

int main(void)
{
    int32_t AHT20ReadTempAndHumi[2] = {0}; // 温湿度数据数组

    board_init(); /* 板卡初始化 */
    if (AHT20_INIT_RES_OK == AHT20_Init())
    {
        /* AHT20初始化成功 */
        printf("AHT20 Init OK\r\n");
    }
    else
    {
        /* AHT20初始化失败 */
        printf("AHT20 Init Err!!!\r\n");
    }
    while (1)
    {
        /* 读取 ATH20 传感器状态 */
        while (AHT20_STA_ERR == AHT20_ReadSta())
        {
            /* 重新初始化AHT20 */
            AHT20_Init();
            bflb_mtimer_delay_ms(30);
        }
        /* 获取温湿度数据 */
        if (AHT20_READ_OK == AHT20_RecTempAndHumiVal(AHT20ReadTempAndHumi))
        {
            /* 获取成功 */
            printf("AHT20 Read Temperature is:%.1f,Humidity is %.1f\r\n", (float)AHT20ReadTempAndHumi[1] / 10, (float)AHT20ReadTempAndHumi[0] / 10);
        }
        else
        {
            /* 获取失败 */
            printf("Read Err!!!\r\n");
        }
        bflb_mtimer_delay_ms(1000);
    }
}

根据大佬的外设移植帖子,我把代码变量,函数功能都加了注释,直接粘贴进去就可以好好读了,比如这样

鼠标放到函数上就可以看说明了

image.png

补充

最后说我刚看代码的疑问,以及解答 对向我这样的菜鸟有用

01 IIC初始化

gpio = bflb_device_get_by_name("gpio");
/* I2C0_SCL */
bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
/* I2C0_SDA */
bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);

这两个IIC 引脚初始化一样,怎么确定是 SCL 还是 SDA

解答:

数据手册有详细描述:docs.ai-thinker.com/_media/bl616_bl618_ds_zh_cn_1.4.pdf

image.png

读取结果:

image.png

回复

使用道具 举报

爱笑 | 2024-6-13 16:08:11 | 显示全部楼层
不错不错!
用心做好保姆工作
回复

使用道具 举报

lovzx | 2024-6-13 16:29:15 | 显示全部楼层

学习

回复 支持 反对

使用道具 举报

爱笑 | 2024-6-13 16:37:44 | 显示全部楼层

打卡学习

用心做好保姆工作
回复 支持 反对

使用道具 举报

bzhou830 | 2024-6-13 17:20:27 | 显示全部楼层

打卡学习

选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

1084504793 | 2024-6-13 17:28:31 | 显示全部楼层
回复

使用道具 举报

iiv | 2024-6-13 23:04:27 | 显示全部楼层
打卡学习
回复

使用道具 举报

lazy | 2024-6-14 11:27:26 | 显示全部楼层
打卡学习
回复

使用道具 举报

jkernet | 2024-6-14 21:51:48 | 显示全部楼层
打卡学习
回复

使用道具 举报

Francisliu | 2024-6-17 12:39:45 | 显示全部楼层
还是不错的
回复 支持 反对

使用道具 举报

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

本版积分规则