前言

后悔,总之就是非常后悔,我当时到底是为啥才会猪油蒙心,选择了 EFR32 来学习 ZigBee 使用啊?

EFR32 这玩意看性能确实不错,但是资料太少了,EmberZnet SDK 也是用得一头雾水。能找到的教程和例子基本是都是控制一下LED ,配置入网啥的,具体的涉及常用的ADC,I2C什么的资料太难找了,SDK 里面也没有找到类似demo的东西,总之就是非常痛苦。

这里给大家分享一些好东西!EFR32和EFM32 非常全面的驱动示例 demo 这玩意救我狗命啊!国内不知道为啥都没有人分享这么好的玩意,找到了下载居然还要钱!这里就分享给大家吧。

https://github.com/SiliconLabs/peripheral_examples/tree/master/series2

超级实用的 EFR32 demo !


硬件准备

我使用的是画时科技的 ZDB-01 是 silicon EFR32MG21 的开发板。

传感器用了以前的 DFRobot 电容式土壤湿度传感器模块

因为第一次接触 ZigBee 我没有什么 ZigBee 的网关和上位机啥的,一开始我还蛮头疼,然后我发现精灵一号就有 ZigBee 网关功能,这玩意还真是方便啊,万万没想到之前买的精灵一号还能在这时候帮上忙。

但是笑死,官方又没有提供开发调试工具,还得自己写。

软件准备

EFR32 入网流程可以参考我上一篇文章《手把手带你使用ZigBee——通过爱智控制EFR32,以及 Simplicity Studio 使用过程中注意事项》这里就不赘述了。

土壤湿度传感器 的输出是模拟量所以需要在 Simplicity Studio 的 Defaultmode Peripherals 中添加并配置 IADC



不知道是我 IDE 问题还是啥,自动生成的 SDK 中生成的 IADC 库文件不全,缺少 IADC.c 文件,而且 IADC.h 有问题。需要我们自己添加一下 IADC.c 和 IADC.h 文件,这两个文件的下载地址:

https://github.com/ryankurte/efm32-base/blob/master/emlib/src/em_iadc.c

将下载下来的 IADC.c 放入项目文件夹的 emlib 文件夹下:



然后在 IDE 中 Refresh 一下:



而 IADC.h 虽然存在,但是有问题,无法通过编译,需要替换成新的 IADC.h ,网上大部分教程都建议不要修改 SDK

而选择 Make a Copy



但是经过我亲测,在这里我建议大家选择 Edit in SDK ,因为选择 Make a Copy 的话会报错(虽然不影响编译),提示某些符号无法解析,可能是出现了重复定义的情况,而且这个 SDK 中的文件就是有问题的,保留也没有意义,不如直接替换成新的文件。

代码分析

这个代码是基于官方 demo 基础上修改而来。

为了方便讲解逻辑,我会打乱代码的顺序可能还会进行裁剪,要是想直接拿代码跑的朋友可以直接去 灵感桌面的秘密宝库 获取代码,或者直接 clone:

https://gitee.com/inspiration-desktop/DEV-lib-arduino.git

头文件与初始化配置

#include "app/framework/include/af.h"
#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_iadc.h"
#include "em_gpio.h" // Set CLK_ADC to 10MHz
#define CLK_SRC_ADC_FREQ 20000000 // CLK_SRC_ADC
#define CLK_ADC_FREQ 10000000 // CLK_ADC - 10MHz max in normal mode /*
* Specify the IADC input using the IADC_PosInput_t typedef. This
* must be paired with a corresponding macro definition that allocates
* the corresponding ABUS to the IADC. These are...
*
* GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AEVEN0_ADC0
* GPIO->ABUSALLOC |= GPIO_ABUSALLOC_AODD0_ADC0
* GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BEVEN0_ADC0
* GPIO->BBUSALLOC |= GPIO_BBUSALLOC_BODD0_ADC0
* GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDEVEN0_ADC0
* GPIO->CDBUSALLOC |= GPIO_CDBUSALLOC_CDODD0_ADC0
*
* ...for port A, port B, and port C/D pins, even and odd, respectively.
*/
#define IADC_INPUT_0_PORT_PIN iadcPosInputPortBPin0; // 配置输入引脚
#define IADC_INPUT_1_PORT_PIN iadcNegInputPortBPin1; #define IADC_INPUT_0_BUS BBUSALLOC // 配置总线
#define IADC_INPUT_0_BUSALLOC GPIO_BBUSALLOC_BEVEN0_ADC0
#define IADC_INPUT_1_BUS BBUSALLOC
#define IADC_INPUT_1_BUSALLOC GPIO_BBUSALLOC_BODD0_ADC0 /*******************************************************************************
*************************** GLOBAL VARIABLES *******************************
******************************************************************************/ static volatile uint32_t sample;
const float AirValue = 465; // 初始化最大干燥 (传感器在空中的情况)这个数据每个传感器不一样,需要自己测试
const float WaterValue = 1177; // 初始化最大湿度 (传感器放入水中的情况) EmberEventControl AcoinfoAioReportEventControl; // 声明事件

设置上电打印与上电初始化 IADC

void emberAfMainInitCallback(void)
{
emberAfCorePrintln("---------------灵感桌面---------------");
// 初始化 IADC
initIADC();
}

设置按按钮入网

void emberAfHalButtonIsrCallback(uint8_t button, uint8_t state)
{
if (state == BUTTON_RELEASED) {
emberAfPluginNetworkSteeringStart();
}
}

初始化 IADC ,我比较奇怪的一点,在上面 Defaultmode Peripherals 的时候就已经配置过 IADC 了,为什么在这里还需要配置?之前尝试 LED 的时候就不需要。(我试过了,不重新初始化 IADC 是不能用的)

void initIADC (void)
{
// 初始化结构体声明
IADC_Init_t init = IADC_INIT_DEFAULT;
IADC_AllConfigs_t initAllConfigs = IADC_ALLCONFIGS_DEFAULT;
IADC_InitSingle_t initSingle = IADC_INITSINGLE_DEFAULT;
IADC_SingleInput_t initSingleInput = IADC_SINGLEINPUT_DEFAULT; // 重置IADC以重置配置,以防它已被其他代码修改
IADC_reset(IADC0); // 为IADC选择时钟
CMU_ClockSelectSet(cmuClock_IADCCLK, cmuSelect_FSRCO); // FSRCO - 20MHz // 修改init结构体并初始化此处设置HFSCLK预设值
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, CLK_SRC_ADC_FREQ, 0);
//
// // 默认情况下,扫描和单个转换都使用配置0。使用无缓冲AVDD(供电电压为mV)作为参考
initAllConfigs.configs[0].reference = iadcCfgReferenceVddx;
initAllConfigs.configs[0].vRef = 3300;
//
// // 除以CLK_SRC_ADC,设置CLK_ADC频率
initAllConfigs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
CLK_ADC_FREQ,
0,
iadcCfgModeNormal,
init.srcClkPrescale);
//
// // 将引脚分配到差分模式下的正输入
initSingleInput.posInput = IADC_INPUT_0_PORT_PIN;
// 负输入
initSingleInput.negInput = IADC_INPUT_1_PORT_PIN;
//
// // 初始化 IADC
IADC_init(IADC0, &init, &initAllConfigs);
//
// // 初始化Single转换输入
IADC_initSingle(IADC0, &initSingle, &initSingleInput); // 为ADC0输入分配模拟总线
GPIO->IADC_INPUT_0_BUS |= IADC_INPUT_0_BUSALLOC;
GPIO->IADC_INPUT_1_BUS |= IADC_INPUT_1_BUSALLOC;
}

我尝试通过 aio 命令触发 aio 回调函数从而获取 aio 输出,但是失败了,不知道为什么我报文发过去,板子也收到了,但是就是没办法触发 aio 的回调函数,但是 dio 命令的回调却是正常的,于是我在这取了个巧,通过 EFR32 的事件机制规避了这个问题。

通过发送 dio 命令触发 dio 函数的回调函数,然后在dio 回调函数中激活事件,调用事件函数获取 传感器数据然后通过 aio通道发送给精灵一号。

这是 dio 函数的回调函数,在这激活事件


void emberAfOnOffClusterServerAttributeChangedCallback(int8u endpoint,
EmberAfAttributeId attributeId)
{
EmberAfStatus status;
uint8_t data[1];
emberAfCorePrintln("---------------LED---------------");
emberAfCorePrintln("attributeId:%x",attributeId); status = emAfReadAttribute(endpoint,
ZCL_ON_OFF_CLUSTER_ID,
attributeId,
0x40,
0x0000,
data,
1,
NULL);
if (status == EMBER_ZCL_STATUS_SUCCESS) {
if(attributeId == ZCL_ACOINFO_ZB_DIO_ATTR_1_ATTRIBUTE_ID){
//激活事件
emberEventControlSetActive(AcoinfoAioReportEventControl);
}
}
}

这是事件处理函数,在这里获取到 IADC 数据,并且发送到精灵一号

void AcoinfoAioReportEventHandler(void)
{
// 在下次使用之前禁用该事件
emberEventControlSetInactive(AcoinfoAioReportEventControl);
//
// // 开始转换 IADC
IADC_command(IADC0,iadcCmdStartSingle); // Wait for conversion to be complete
while((IADC0->STATUS & (_IADC_STATUS_CONVERTING_MASK
| _IADC_STATUS_SINGLEFIFODV_MASK)) != IADC_STATUS_SINGLEFIFODV); //while combined status bits 8 & 6 don't equal 1 and 0 respectively sample = IADC_pullSingleFifoResult(IADC0).data; emberAfCorePrintln("sample:%d",sample);
float data = 100 - (((sample - AirValue)/(WaterValue - AirValue))*100);
if(data > 100)
{
data = 100;
} else if(data < 0)
{
data = 0;
}
emberAfCorePrintln("data:%d",data); uint8_t * p_data = (uint8_t *)&data;
uint8_t buf[7] = {0};
buf[0] = ZCL_ACOINFO_ZB_AIO_ATTR_1_ATTRIBUTE_ID && 0xFF;
buf[1] = ZCL_ACOINFO_ZB_AIO_ATTR_1_ATTRIBUTE_ID >> 8;
buf[2] = ZCL_FLOAT_SINGLE_ATTRIBUTE_TYPE;
for(int i=0;i<4;i++){
buf[3+i] = *p_data++;
}
emberAfFillCommandGlobalServerToClientReportAttributes(ZCL_ACOINFO_ZB_AIO_CLUSTER_ID,
(uint8_t *)buf, 7);
emberAfSetCommandEndpoints(1, 1);
emberAfSendCommandUnicast(EMBER_OUTGOING_DIRECT, 0x0000); // 延迟 5 秒后重新触发事件
// emberEventControlSetDelayMS(AcoinfoAioReportEventControl, 5000);
// // 结尾处重置回未激活状态
emberEventControlSetInactive(AcoinfoAioReportEventControl);
}

总结

土壤湿度传感器的 ZigBee 版本就完成了,不过不知道什么原因,这块 EFR32 板子和精灵一号的相性极差,设备非常容易掉线,而且重连很慢,板子断电后想要重新连上也是非常困难的事情。不知道是什么情况。但是好歹是成功了

手把手带你使用EFR32 -- 土壤湿度传感器变身第二形态,以 ZigBee 形态出击的更多相关文章

  1. 从零开始的DIY智能家居 - 基于 ESP32 的土壤湿度传感器

    前言 自从上次做了那个 甲醛传感器 和 水浊度传感器 之后开始尝到智能家居的甜头了,这两东西有没有用我不知道,但是没事的时候掏出手机瞄两眼,看着就让人很安心( ̄︶ ̄). 于是懒惰的我开始琢磨把给植物浇 ...

  2. 在树莓派上读取土壤湿度传感器读书-python代码实现及常见问题(全面简单易懂)

    本篇文章简单介绍了如何在树莓派上配置土壤湿度传感器以读取土壤湿度(以百分比的形式出现)及代码实现. 主要包含有以下4个模块: 一.土壤湿度传感器常见类型及介绍 二.实验所需设备 三.设备连线方式与代码 ...

  3. 实践案例丨利用小熊派开发板获取土壤湿度传感器的ADC值

    摘要:一文带你用小熊派开发板动手做土壤湿度传感器. 一.实验准备 1.实验环境 一块stm32开发板(推荐使用小熊派),以及数据线 已经安装STM32CubeMX 已经安装KeilMDK,并导入stm ...

  4. [.Net] 手把手带你将自己打造的类库丢到 NuGet 上

    手把手带你将自己打造的类库丢到 NuGet 上 序 我们习惯了对项目右键点击“引用”,选择“管理NuGet 程序包”来下载第三方的类库,可曾想过有一天将自己的打造的类库放到 NuGet 上,让第三者下 ...

  5. 手把手带你做一个超炫酷loading成功动画view Android自定义view

    写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...

  6. Android性能优化:手把手带你全面实现内存优化

      前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录   1. 定义 优化处理 应用程序的内存使用.空间占用 2. 作用 避免因不正确使用内 ...

  7. Android:手把手带你深入剖析 Retrofit 2.0 源码

    前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将手把手带你深入剖析Retrofit v2.0的源码,希望你们会喜 ...

  8. 树莓派dht11,土壤湿度传感器,继电器的使用。树莓派云灌溉(二)

    关于传感器的一些说明 我的想法是这样的 我尽量用易于理解的语言去说我的想法 首先,土壤湿度传感器和dh11会获取数据,然后树莓派会处理这些数据,读出土壤温湿度和空气温湿度,并将这些数据上传到云服务器, ...

  9. [转帖]从零开始入门 K8s | 手把手带你理解 etcd

    从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...

随机推荐

  1. NPM 错误、问题等汇总

    一. npm的作用就是对Node.js依赖的包进行管理,也可以理解为用来安装/卸载Node.js需要装的东西 二. 1. 修改npm配置为淘宝的源下载: npm install -g cnpm --r ...

  2. suse 12 二进制部署 Kubernetets 1.19.7 - 第02章 - 部署etcd集群

    文章目录 1.2.部署etcd集群 1.2.0.下载etcd二进制文件 1.2.1.创建etcd证书和私钥 1.2.2.生成etcd证书和私钥 1.2.3.配置etcd为systemctl管理 1.2 ...

  3. MySQL架构原理之存储引擎InnoDB_Redo Log和BinLog

    Redo Log和Binlog是MySQL日志系统中非常重要的两种机制,有很多相似之处同时也有差别,本文探究两者细节和区别. 一.Redo Log 1.Redo Log介绍 Redo:顾名思义就是重做 ...

  4. CentOS8系统上Zookeeper安装启动

    下载Zookeeper安装包,下载地址为:https://zookeeper.apache.org/releases.html.注意选择bin的gz包,否则安装不成功,提示找不到相应的类. 一.单机模 ...

  5. FreeHttp2.3升级说明

    一.升级方法 下载新版本插件 https://files.cnblogs.com/files/lulianqi/FreeHttp2.3.0zip  或 http://lulianqi.com/file ...

  6. 从菜鸟到高手, HMS Core图像分割服务教你如何在复杂背景里精细抠图

    2021年以来,自动驾驶赛道进入爆发期,该行业成为大厂以及初创企业的必争之地.其中众多公司都采用了计算机视觉作为自动驾驶的技术底座,通过图像分割技术,汽车才能够有效理解道路场景,分清楚哪里是路,哪里是 ...

  7. R数据分析:样本量计算的底层逻辑与实操,pwr包

    样本量问题真的是好多人的老大难,是很多同学科研入门第一个拦路虎,今天给本科同学改大创标书又遇到这个问题,我想想不止是本科生对这个问题不会,很多同学从上研究生到最后脱离科研估计也没能把这个问题弄得很明白 ...

  8. 【c#新手学习 练习 案例】 阶段项目一:开发团队调度软件

    案例是模仿java https://blog.csdn.net/bjfu170203101/article/details/109322590 改用C#:开发环境   vs2022/vscode .n ...

  9. shell脚本编写自动启动服务方法

    shell脚本编写自动启动服务方法 前言 ln :创建连接文件 默认创建的是硬连接,好比复制 ,但是两个文件会同步命令:ln ./java/android/aa.txt aaa s :创建的是软连接变 ...

  10. yum报错 , yum相关配置信息,yum重装

    docker源的问题 yum有很多错,比如网络问题,dns问题,timeout 错,还有不知道什么错误 网上有很多,网络问题,dns问题,但是我ping www.baidu.com通,所以不是这个问题 ...