上章节介绍了如何搭建环境,环境搭建好了,接下来就简单了,不会点灯的工程师不是“人类高质量开发者”,今天就来唠唠涂鸦SOC如何点灯。来吧,兄弟们,淦!
涂鸦三明治 Wi-Fi&BLE SoC NANO主控板(BK7231N)是方便开发者快速实现各种智能硬件产品原型的一款开发板。您可通过涂鸦三明治 Wi-Fi&BLE SoC NANO主控板(BK7231N),搭配其他功能电路模组或电路板,实现对应的功能。
I/O 口及各接口功能定义
1:MICROUSB(CN1) :即是 5V DC 输入口,也扩展了 2 个串口功能。
2:拨码开关(S1):拨码切到 ON 方向导通,通断 USB 转串口芯片的双串口和芯片串口之间的链路。
3:指示灯(D3):3.3V 电源指示灯。
4:按键(S2):通过 P9 检测,初始化高电平,按下为低电平。
5:指示灯(D2):通过 P16 控制,低电平点亮。
6:按键(RST):复位按键,按下后芯片复位。
原理图:
烧录授权接线方式:
将拨码开关(S2)的 1、2 路都拨至 ON 方向,BK7231N 的串口 UART1 与上位机链路导通。
注意:若出现“获取RF标志位失败”的情况,可在授权阶段,将串口2的RXD引脚(P01引脚)和GND短接。
上位机查看WiFi工作日志的接线方式
用户串口与上位机通信的接线方式:
将拨码开关(S2)的 1、2 路都拨至 ON 方向,BK7231N 的串口 UART1 与上位机链路导通。
芯片的两个UART口都做普通IO口使用的接线方式:
将拨码开关(S2)的 1、2、3、4 路都拨至 数字丝印方向,BK7231N 的串口 UART1 和 UART2 与 USB 芯片的链路断开。
更详细的介绍可以查看:这里
涂鸦Wi-Fi模组和涂鸦Wi-Fi&Bluetooth LE双模模组进行产品开发主要有三种不同的方式进行开发:
在开发前,需要先在涂鸦IoT平台上创建对应的产品,选择相关功能、面板和使用的模组,拿到功能点ID(DP ID)和产品ID (PID)后才能对涂鸦SDK进行二次开发,那么就先来了解下如何在涂鸦平台创建产品。
1、注册涂鸦
进入涂鸦IOT平台,注册成为新用户,注册之前,可以先联系小飞哥或者涂鸦的运营,他们有新用户注册福利可以领取。如何注册就不说了哈,都是文化人,一看就懂...
2、创建产品
注册完成之后,进入到首页,可以看到创建产品和进入产品研发,如果你是新开发的产品,创建产品即可,如果你是开发、修改之前已有的,就直接计入产品开发即可,可以看到小飞哥是已经创建了几个产品了
点击创建产品之后,可以看到种类还是非常繁多的,基本上室内常用的家装都有,忍住不想搞智能家居...
既然是点灯,那咱们就选个照明相关的项目,点击进去...乱花渐欲迷人眼,这琳琅满目的灯,见过的,没见过的,听过的,没听过的,应有尽有...
可以看到,有两个选项,零代码开发,自定义方案,零代码开发,只会硬件开发的兄弟们的福利来啦,不会写代码不要紧,画画板子就能出产品...
既然零代码的这么好,那咱们这章节主要讲讲自定义方案的,哈哈哈...说实话,这是留给了开发者无限的开发想象,就两类...
方案详情,包含了很多的功能
产品名称,自己取个,争取狂diao炸xuan,通讯方式,根据自己的需要选择,本次选择WiFi+BLE
有点遗憾,这样的名字不能取...
接下来进入到产品界面,按照第一行的几个开发选项,一步步进行,添加功能等
本着多多益善的原则,可以多添加一些
已有的功能没有自己想要的,没关系,涂鸦还支持自己配置,有点东西...
接下来是面板开发,说是开发有点心虚,面板选择好点,有公版面板、SDK面板、其他类型面板,别说还挺丰富多彩的
为了省事,小飞哥就算了个公版面板,欧式风格的哟,对审美要求比较高的,自己可以配配色,修改修改什么的
然后进入到硬件开发界面,有MCU SDK 和tuya os可以选择,MCU SDK就是使用涂鸦的模组和其他的MCU对接,作为一个模组使用,tuyaos就是二次开发的SDK,也是本次咱们要介绍的,选择框框中的模组
关于自定义固件,参考文章
接下来就可以下载SDK啦
用到的硬件S2-GPIO_9,D2-GPIO16(LED灯)
S2: GPIO_9 按键引脚,按下为低电平。涂鸦封装的引脚名称为TY_GPIOA_9。
D2: GPIO_16 LED引脚,低电平点亮。涂鸦封装的引脚名称为TY_GPIOA_16。
这里我们直接 下载涂鸦的的demo,在上一章节环境搭建我们已经下载了一个SDK,现在在上一章节的基础上,下载本次点灯的demo程序
示例Demo的GitHub仓库地址:
https://github.com/Tuya-Community/bk7231n_light1_io_xx
我们在SDK的APPS目录下下载下来,可以看到已经下载OK了,该文件夹名称就是工程名,也是上传固件时使用的固件标识名。所以大家在创建的时候文件夹名称应改成不同的名字,不然在编译生成固件后,上传到云平台时会因为已经有了该固件标识名导致固件上传失败。
在bk7231n_light1_io_xx文件夹中新建include和src两个文件夹,include文件夹用来放工程中用到的头文件,src文件夹用来放工程中用到的源文件(可以在include和src文件夹中创建新的文件夹对不同功能的.c和.h文件进行分类管理)。
在开始编写代码前,我们还需要对涂鸦SDK中常用头文件有一个了解。
可以用VSCOde或者其他的软件打开demo代码
在tuya_device.c中,按键初始化函数的实现:
#include "uni_log.h"
#include "tuya_iot_wifi_api.h"
#include "tuya_hal_system.h"
#include "tuya_iot_com_api.h"
#include "tuya_error_code.h"
#include "gw_intf.h"
#include "tuya_gpio.h"
#include "tuya_key.h"
#include "base_event_info.h"
#include "tuya_device.h"
#include "light_system.h"
#include "dp_process.h"
/***********************************************************
*************************micro define***********************
***********************************************************/
#define APP_RAW_PRINT_DEBUG 1
/* wifi config */
#define WIFI_WORK_MODE_SEL GWCM_OLD_PROD /* select Wi-Fi work mode */
#define WIFI_CONNECT_OVERTIME_S 180 /* connect network timeout time, uint: s */
/* reset key config */
#define WIFI_KEY_PIN TY_GPIOA_9 /* reset button pin */
#define WIFI_KEY_TIMER_MS 100 /* key scan poll time, default 100ms */
#define WIFI_KEY_LONG_PRESS_MS 3000 /* long press time */
#define WIFI_KEY_SEQ_PRESS_MS 400
#define WIFI_KEY_LOW_LEVEL_ENABLE TRUE
/**
* @brief initiation reset key
*
* @param[in] none
* @return none
*/
STATIC VOID_T wifi_key_init(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
KEY_USER_DEF_S key_def;
op_ret = key_init(NULL, 0, WIFI_KEY_TIMER_MS);
if (op_ret != OPRT_OK) {
PR_ERR("key_init err:%d", op_ret);
return;
}
/* config key parameter */
memset(&key_def, 0, SIZEOF(key_def));
key_def.port = WIFI_KEY_PIN;
key_def.long_key_time = WIFI_KEY_LONG_PRESS_MS;
key_def.low_level_detect = WIFI_KEY_LOW_LEVEL_ENABLE;
key_def.lp_tp = LP_ONCE_TRIG;
key_def.call_back = wifi_key_process;
key_def.seq_key_detect_time = WIFI_KEY_SEQ_PRESS_MS;
/* register key */
op_ret = reg_proc_key(&key_def);
if (op_ret != OPRT_OK) {
PR_ERR("reg_proc_key err:%d", op_ret);
}
}
在tuya_device.c中,按键被按下后回调函数的实现:
/**
* @brief button is pressed, call the function to process
*
* @param[in] port: button pin
* @param[in] type: button press type
* @param[in] cnt: press count
* @return none
* @Others: long press enter connect network mode, normal press toggle led
*/
STATIC VOID_T wifi_key_process(TY_GPIO_PORT_E port, PUSH_KEY_TYPE_E type, INT_T cnt)
{
OPERATE_RET op_ret = OPRT_OK;
PR_DEBUG("port:%d, type:%d, cnt:%d", port, type, cnt);
if (port = WIFI_KEY_PIN) {
if (LONG_KEY == type) { /* long press enter connect network mode */
op_ret = tuya_iot_wf_gw_unactive();
if (op_ret != OPRT_OK) {
PR_ERR("long press tuya_iot_wf_gw_unactive error, %d", op_ret);
return;
}
} else if (NORMAL_KEY == type) {
#if 1 /* turn on or off the button to control the light function */
if (get_light_status() == LIGHT_OFF) {
op_ret = set_light_status(LIGHT_ON); /* light turn on */
if (op_ret != OPRT_OK) {
PR_ERR("dp process set light status error, %d", op_ret);
return;
}
} else {
op_ret = set_light_status(LIGHT_OFF); /* light turn off */
if (op_ret != OPRT_OK) {
PR_ERR("dp process set light status error, %d", op_ret);
return;
}
}
/* update device current status to cloud */
update_all_dp();
#endif
} else {
PR_NOTICE("key type is no deal");
}
}
}
LED灯初始化函数:
light_system.h文件:
#include "tuya_cloud_types.h"
#include "tuya_gpio.h"
#define LIGHT_PIN TY_GPIOA_16
light_system.c文件:
#include "light_system.h"
#include "uni_log.h"
STATIC LED_STATUS_E cur_light_status = LIGHT_ON;
/**
* @brief need quick start tasks
* @return none
*/
VOID_T fast_boot(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
op_ret = light_init();
if (op_ret != OPRT_OK) {
PR_ERR("fast boot light init error, %d", op_ret);
return;
}
}
/**
* @brief light gpio init
*
* @return none
*/
OPERATE_RET light_init(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
/* light pin set output */
op_ret = tuya_gpio_inout_set(LIGHT_PIN, FALSE);
if (op_ret != OPRT_OK) {
PR_ERR("light init gpio set inout error!");
return op_ret;
}
/* light pin mode set pullup */
op_ret = tuya_gpio_mode_set(LIGHT_PIN, TY_GPIO_PULLUP);
if (op_ret != OPRT_OK) {
PR_ERR("light init gpio mode set error!");
return op_ret;
}
/* light on */
op_ret = set_light_status(LIGHT_ON);
if (op_ret != OPRT_OK) {
PR_ERR("light init light on error!");
return op_ret;
}
return op_ret;
}
灯控制函数:
light_system.h文件:
typedef LED_STATUS_E LED_STATUS_E;
#define LIGHT_OFF 0
#define LIGHT_ON 1
light_system.c文件:
/**
* @brief light on
*
* @return none
*/
STATIC OPERATE_RET light_on(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
/* pin set low level, light on */
op_ret = tuya_gpio_write(LIGHT_PIN, FALSE);
if (op_ret != OPRT_OK) {
PR_ERR("light on error!");
return op_ret;
}
cur_light_status = LIGHT_ON;
return op_ret;
}
/**
* @brief light off
*
* @return none
*/
STATIC OPERATE_RET light_off(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
/* pin set high level, light off */
op_ret = tuya_gpio_write(LIGHT_PIN, TRUE);
if (op_ret != OPRT_OK) {
PR_ERR("light off error!");
return op_ret;
}
cur_light_status = LIGHT_OFF;
return op_ret;
}
/**
* @brief set light status
*
* @param[in] status: LIGHT_ON or LIGHT_OFF
* @return none
*/
OPERATE_RET set_light_status(LED_STATUS_E status)
{
OPERATE_RET op_ret = OPRT_OK;
if (status == LIGHT_ON) {
op_ret = light_on();
if (op_ret != OPRT_OK) {
return op_ret;
}
} else {
light_off();
if (op_ret != OPRT_OK) {
return op_ret;
}
}
return op_ret;
}
获取灯状态函数:
/**
* @brief get light status
*
* @return light status: LIGHT_ON or LIGHT_OFF
*/
LED_STATUS_E get_light_status(VOID_T)
{
return cur_light_status;
}
修改代码:
可以根据下面的提示将PID信息改为你创建的产品的PID信息,也可以不对代码进行任何更改,跳过该步骤直接进入下一步编译生成固件继续操作。
将/apps/bk7231n_light1_io_xx/include目录下的tuya_device.h中的PRODECT_ID修改为你创建得到的PID。
#ifndef __TUYA_DEVICE_H__
#define __TUYA_DEVICE_H__
/* Includes ------------------------------------------------------------------*/
#include "tuya_cloud_types.h"
#include "tuya_cloud_com_defs.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef _TUYA_DEVICE_GLOBAL
#define _TUYA_DEVICE_EXT
#else
#define _TUYA_DEVICE_EXT extern
#endif /* _TUYA_DEVICE_GLOBAL */
// device information define
#define DEV_SW_VERSION USER_SW_VER
#define PRODECT_ID "fnrwpglflmbhjvvh" /* 将这里双引号内的PID更改为你创建产品得到PID */
/* Exported functions ------------------------------------------------------- */
_TUYA_DEVICE_EXT \
OPERATE_RET device_init(VOID_T);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __TUYA_DEVICE_H__ */
cd tuya-iotos-embeded-sdk-wifi-ble-bk7231n/
sh build_app.sh ./apps/bk7231n_light1_io_xx bk7231n_light1_io_xx 1.0.0
编译成功
在编译完成后,会将生成的固件按照不同版本放在所编译的工程目录下output文件夹内。
编译后的产物如上图所示,这里主要关注的bk7231n_light1_io_xx_QIO_1.0.0.bin、bk7231n_light1_io_xx_UA_1.0.0.bin和bk7231n_light1_io_xx_UG_1.0.0.bin这三个文件。
自定义开发固件不上传到云平台,直接将UA文件烧录到已授权的模组中,会导致配网一直无法成功。
1.进入涂鸦IoT平台,在开发的产品中找到“硬件开发”,按照下图指示点击“新增自定义固件”,填写相关固件信息。
“固件标识名”必须和你编译时的apps下的工程文件夹的名称一致。
“Flash大小”为16Mbit也就是2M大小。不同模组的flash大小可以在涂鸦的文档中心中查看相关模组的flash大小。
“固件版本”需要和编译时输入的版本号对应一致。“生产固件”上传包含QIO的bin文件,“用户区”上传包含UA的bin文件,“升级固件”上传包含UG的bin文件。运行模式选择QIO。点击保存。
注意:该顺序不一定固定,在后续固件管理中就不是按照“生产固件”,“用户区固件”和“升级固件”的顺序来排序,所以一定要看清楚是什么类型的固件在进行上传。
点击“进行固件上架”。
选择“不限范围”,点击“确认上架”。
注意:这里选择不限范围是为了方便个人开发。如果是公司将要量产的产品,请严格限定固件的使用范围。
获取生产凭证
PMS账号、云模组烧录授权工具的获取,烧录授权中常见问题都可以通过阅读 烧录授权 章节获取到答案。
将我们编译生成的固件上传到涂鸦IoT云平台,成功上架后,就可以免费领取激活码,通过「云模组烧录授权平台」工具进行烧录授权。
点击“免费领取10个激活码”
交付方式选择“生产凭证”,点击“提交订单”
点击“去订单列表页看看”
根据PID信息找到要烧录授权的设备,点击箭头②的“下载生产凭证”
.解压下载好的“生产凭证”,打开Token_information.txt文件,复制“生产凭证”。在「云模组烧录授权平台」工具中输入生产凭证,选择工位“烧录授权”
这里可能会出现获取token失败,没有操作权限的错误,解决办法如下:
出现该错误需要在PMS系统中,按照下图指示,依次点击“生产管理->工单管理->生产凭证确认”,然后输入刚刚没有操作权限的“生产凭证”点击“确认”。再回到「云模组烧录授权平台」工具中输入该生产凭证点击确认即可开始烧录授权操作。
生产凭证输入完成后,会如下图显示。会在“基础信息”一栏中显示固件的相关信息
烧录授权
在「云模组烧录授权平台」根据按照箭头的指引,输入生产凭证,选择工位为“烧录授权”,点击”确认“
CBU的三明治SOC开发板自带了CH304串口芯片。在点击运行后,按下CBU的三明治SOC开发板上USB口旁的复位按键即可重启芯片,开始烧录授权。
如果在烧录授权过程中出现进入产测失败的错误,可能原因是因为这个开发板在上一次烧录授权后已经累计连接到网络超过了15分钟了。设备此时关闭了产测功能,导致无法进入产测出现了授权失败的情况。解决办法参考 烧录授权 的内容进行解决。
至此,我们的固件开发、编译、下载就完成了,通过板子上的S2按键就可以控制LED的亮灭啦
除此之外,我们还是设计了APP的,也可以通过APP点灯,下章节再介绍...