文章目录

  • 前言
  • 硬件准备
  • 软件准备
  • 代码分析
  • 总结

前言

后悔,总之就是非常后悔,我当时到底是为啥才会猪油蒙心,选择了 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("---------------灵感桌面---------------");// 初始化 IADCinitIADC();
}

设置按按钮入网

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;
//
//    // 初始化 IADCIADC_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);
//
//    // 开始转换 IADCIADC_command(IADC0,iadcCmdStartSingle);// Wait for conversion to be completewhile((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 respectivelysample = 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. 读取24位ad的值_实践案例丨利用小熊派开发板获取土壤湿度传感器的ADC值

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

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

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

  4. arduino 土壤温湿度传感器_怎样将Arduino与土壤湿度传感器FC-28连接起来

    步骤1:在模拟模式下连接传感器 模拟模式 - 连接土壤湿度传感器和Arduino 要在模拟模式下连接传感器,我们需要使用传感器的模拟输出.从土壤湿度传感器FC-28获取模拟输出时,传感器给出的值为0- ...

  5. STM32的串口打印土壤湿度传感器(YL-69)数据

    最近在弄课设,需要使用土壤传感器来读取数据,用来测量土壤或其他的湿度数据,我选择使用串口打印数据. 用的控制器是STM32F103C8T6,在网上找了好多代码,各种问题,都没有用,或许的要实现的功能不 ...

  6. 手把手带你玩转Spark机器学习-使用Spark进行数据处理和数据转换

    系列文章目录 手把手带你玩转Spark机器学习-专栏介绍 手把手带你玩转Spark机器学习-问题汇总 手把手带你玩转Spark机器学习-Spark的安装及使用 手把手带你玩转Spark机器学习-使用S ...

  7. 存活扫描_如何使用土壤湿度传感器使植物存活

    存活扫描 Every good plant mom (or dad) knows there are two important things to keep your indoor plants a ...

  8. Arduino UNO驱动土壤湿度传感器检测

    Arduino UNO驱动土壤湿度传感器检测 简介 运行要求 Arduino UNO与传感器接线 程序展示 实践效果 总结 简介 本次使用到是这个新款土壤湿度传感器! 这款电容式土壤湿度传感器区别于市 ...

  9. arduino 土壤温湿度传感器_如何将土壤湿度传感器与Arduino接口

    简介 如果您有家庭花园或者是带草皮的后院,那么你可能知道我们需要花多少时间浇灌植物和草皮. 花园洒水器是浇水的常用选择之一.草坪和植物,嗯,唯一的选择,最好的选择是手动浇水. 但是如果你打算制造一个自 ...

最新文章

  1. 从表到里学习JVM实现
  2. 批量kill掉包含某个nginx的进程
  3. jquery.MultiFile 实现自动删掉上传列表
  4. Asp.Net Core部署:早知道,还是docker!以及一点碎碎念
  5. html参考文献_毕业设计参考文献格式(要求与范例)
  6. python(源码包安装 基本使用 循环)
  7. python随机森林库_随机森林库:R和Python中的不同结果
  8. wdcp 开启某个Mysql数据库远程访问
  9. Lua开发学习2-数据类型
  10. 人工智能 一种现代方法 第7章 逻辑Agent(命题逻辑)
  11. python画立体温度分布图_Origin绘制3D立体温度分布图的方法
  12. 芯烨打印机WEB API 调用HEX的模式DEMO
  13. flash小黄油安卓_从Android 1到10 一起回顾伴随我们成长的安卓系统
  14. 象棋马走日全球变暖——(bfs例题)
  15. IB中文诗歌手法分析
  16. 怎么用大众都懂的语言解释黎曼空间?
  17. 增量式编码器与绝对值编码器的区别
  18. eclipse运行java总显示上一个程序的运行结果(解决方案)
  19. 再见PanDownload ,下一个已经来了。
  20. 【IDEA】如何用IDEA测试接口

热门文章

  1. SDNUOJ 1665-1668(树状数组的应用)
  2. Install SysBench support MySQL and PostgreSQL
  3. linux g 使用教程,linux下的gedit命令使用方法与技巧
  4. Unity 拖动UI物体(干货)
  5. WPF中使用PS导出的SVG矢量图
  6. Linux tar命令总结:Linux下对文件进行打包、压缩并分割成指定大小
  7. Carla在Windows上的安装与运行
  8. learn2reg-配准介绍
  9. 微机原理与接口技术:并行接口
  10. TIA WinCC Professional入门经典(2) 创建画面与联合仿真