M61板子申请下来了
灯也点了
我却不知道干个啥
直到看到外设移植的活动
对我这种人简直神助
一来可以根据芯片手册懂芯片了
二来还不用看那种封装太多我看的头晕的代码
这次,就是 先读AHT20温湿度模块
源工程:
【外设移植】AHT20温湿度传感器M61开发板驱动 - DIY 经验分享 - 物联网开发者社区-安信可论坛 - Powered by Discuz! (ai-thinker.com)
先看手册:
简单总结,
先发送 0x71 读取状态字
如果bit[3] 为0,发送0xBE 初始化
如果bit[3] 为1,可以开始测量
发送0xAC 发送测量命令 等待80ms
直接读取状态字,如果bit[7] == 0 测量完成
开始读取7个字节的温湿度数据
读取数据后转换
代码实现
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);
}
}
根据大佬的外设移植帖子,我把代码变量,函数功能都加了注释,直接粘贴进去就可以好好读了,比如这样
鼠标放到函数上就可以看说明了
补充
最后说我刚看代码的疑问,以及解答 对向我这样的菜鸟有用
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
读取结果: