HaaS EDU K1是HaaS Education Kit1的缩写,是基于四核高性能MCU-HaaS1000芯片打造的、集颜值和内涵于一身的物联网教育开发板。
下面是HaaS EDU K1的简单介绍, 详细功能和参数可以参考HaaS EDU K1硬件介绍。
AliOS Things的开发环境准备, 点击查看开发环境安装 。
git clone https://github.com/alibaba/AliOS-Things.git -b dev_3.1.0_haas
对于国内用户,为避免从github下载速度较慢,可以从gitee上下载。
git clone https://gitee.com/alios-things/AliOS-Things.git -b dev_3.1.0_haas
进入代码的顶层目录如AliOS-Things进行编译,以开机自带的的edu_demo为例。
aos make clean & aos make distclean
aos make edu_demo@haaseduk1 -c config
aos make
给HaaS EDU K1上电,USB Type-C口插上usb线并连接到烧录主机,打开开机开关(电源正常的情况下板子右上角LED灯会亮),等待烧录主机发现新插入的usb设备并识别成串口。
当前提供命令行和GUI工具两种烧录方式,开发者可以根据自己的开发电脑平台来选择其一。
打开命令行工具,进入到代码顶层目录,然后输入命令aos upload,选择相应的串口即可开始烧录。
烧录成功后,显示“Firmware upload succeed“字样。
烧录成功后,也自动将串口信息保存在当前目录下的.aos_config_burn文件中。如果后续烧录时,串口号有变化,可以删除该文件,再使用aos upload命令烧录。
如果在烧录期间,提示“Please reboot the board manually“,请按复位键复位开发板。
若复位无效,还是一直打印“Please reboot the board manually“,则需要将板子完全断电,再上电,然后重新使用aos upload命令烧录。
在windows环境下编译成功后,进入platform/mcu/haas1000/release/write_flash_gui目录,双击运行haas1000_write_flash_main,出现烧录软件的主界面
如下所示:
使用串口工具如Putty/SecureCRT,设置串口波特率1500000。
Putty设置
设置串口波特率1500000,并关闭Parity 和 Flow control,并设置字符编码为UTF-8,否则打印会乱码。
SecureCRT设置
设置串口波特率1500000,并关闭Parity 和 Flow control, 并设置字符编码为UTF-8,否则打印会乱码。
启动log
设置好串口后, 重启设备就可以看到AliOS Things的启动log,版本号打印,以及最后homepage_task的打印了。
Welcome to AliOS Things
*****
image version = 1.0.0
hal_spi_init done
hardware_init START
hal_gpio_init done
curLevelMenuSize 10
menu info homepage 872419756
menu info humiture 872420196
menu info gyroscope 872419648
menu info shakeshake 872423864
menu info compass 872418508
menu info barometer 872418204
menu info lightmeter 872420668
pchildlist->MenuListSize
menu info musicbox 872423572
menu info greedySnake 872419112
menu info aircraftBattle 872415352
enter key_init:169
aos_task_new homepage_task
edu_demo是HaaS EDU K1出厂自带的官方应用,里面包含丰富的应用案例,学习代码以及产测模块等。
代码位于application/example/edu_demo,具体见下图:
HaaS EDU K1 整体的系统启动流程。
我们将应用目录抽象为如下格式:
k1_apps
├─app0
├─app1
├─app1.1
└─app1.2
对应这种多级目录的格式,我们将文件也按这个目录顺序进行管理,当前的目录结构为:
k1_apps
│ menu.c // 目录管理的所有逻辑
│ menu.h
├─gyroscope // app0
│ gyroscope.c
│ gyroscope.h
├─homepage // app1
│ homepage.c
│ homepage.h
...
如果开发者需要创建新的应用,只需要在对应目录中插入即可。例如想要创建新的应用helloworld,需要创建的目录就是helloworld。
typedef struct
{
int (*pMenuTaskInit)(void); //指向菜单任务初始化函数的指针 返回值0 成功 需要整个err_code啥的
int (*pMenuTaskEnd)(void); //指向菜单任务结束函数的指针 返回值0 成功
// user don't need to care
uint8_t MenuTaskIsRunning; //标注task是否在执行 不同MENU_COVER_TYP有不同行为
} MENU_TASK_TYP;
typedef enum
{
MENU_COVER_NONE,
MENU_COVER_TEXT,
MENU_COVER_IMG,
MENU_COVER_GIF
} MENU_COVER_MODE_ENU;
typedef struct
{
MENU_COVER_MODE_ENU MenuCoverMode; // 0 none 直接显示应用 1text 2img 3gif
char *text;
uint8_t **img;
uint8_t ***gif;
} MENU_COVER_TYP;
typedef struct
{
struct MenuTyp **pMenuList;
uint8_t MenuListSize;
} MENU_LIST_TYP;
typedef struct MenuTyp
{
char *MenuName; //菜单名称字符串
MENU_COVER_TYP *MenuCover; //封面
MENU_TASK_TYP *pMenuTask; //指向菜单任务的指针
void (*pTaskKeyDeal)(key_code_t key_code); //指向菜单任务按键处理函数的指针 让开发者自己处理按键定义事件
struct MENU_LIST_TYP *pChildrenList; //指向子菜单列表的指针
// user don't need to care
MENU_ID_TYP MenuID;
struct MenuTyp *pParent; //指向上层菜单的指针
struct MenuTyp *pChild; //指向子菜单的指针 这里是第一个child 即进入后显示的第一个目录项
struct MenuTyp *pRight; //指向右菜单的指针
struct MenuTyp *pLeft; //指向左菜单的指针
} MENU_TYP;
所有页面排序放在Menus中,默认按照顺序执行,如果添加了新的页面,需要将对应的页面指针添加到这里,并且添加MenuList的数值。
MENU_TYP *Menus[] = {
&homepage,
&humiture,
&gyroscope,
&shakeshake,
&compass,
&barometer,
&lightmeter,
&musicbox,
&greedySnake,
&aircraftBattle,
};
MENU_LIST_TYP MenuList = {
Menus,
10};
目前的按键事件处理如下:
驱动层 key.c 上报 key_code 不论是上升沿还是下降沿,没触发一次中断,就扫描全部的按键GPIO,转化成key_code上报,这样上层接收到的key_code一定是跟物理状态保持同步。
int key_init(key_cb key_func, key_code_cb key_code_func)
public_key_event_handle用于截获来自驱动层的所有 key code,并进行分流。对于公共的按键事件,例如KEY_CODE_BACK,只会在public_key_event_handle中直接相应。而其他按键事件,会交给另一个回调函数 app_key_code_cb 处理。
key_init(NULL, public_key_event_handle);
static void public_key_event_handle(key_code_t key_code);
key_code_cb app_key_code_cb = menu_key_event_handle;
app_key_code_cb = pCurMenu->pTaskKeyDeal;
当进入新的应用时,app_key_code_cb被指向每个应用自己的pTaskKeyDeal函数,由应用自己来定义和处理上报的按键事件。当退出应用时,app_key_code_cb重新指回menu_key_event_handle,来处理目录。
以helloworld显示到OLED屏幕上为例,我们来看一下如何创建一个新的页面。
首先参考humiture文件夹。并创建文件application/example/edu_demo/k1_apps/helloworld/helloworld.h
/*
* Copyright (C) 2015-2020 Alibaba Group Holding Limited
*/
#ifndef __HELLOWORRLD_H__
#define __HELLOWORRLD_H__
#include "../menu.h"
extern MENU_TYP helloworld;
int helloworld_init(void);
int helloworld_uninit(void);
void helloworld_task(void);
#endif
创建文件application/example/edu_demo/k1_apps/helloworld/helloworld.c
#include "../menu.h"
#include "helloworld.h"
MENU_COVER_TYP helloworld_cover = {MENU_COVER_NONE};
MENU_TASK_TYP helloworld_tasks = {
helloworld_init,
helloworld_uninit};
MENU_TYP helloworld = {
"helloworld",
&helloworld_cover,
&helloworld_tasks,
NULL,
NULL};
int helloworld_init(void)
{
printf("si7006_init begin\n");
si7006_init();
printf("si7006_init done\n");
OLED_Clear();
OLED_Refresh_GRAM();
aos_task_new("humiture_task", helloworld_task, NULL, 1000);
printf("aos_task_new helloworld task \n");
return 0;
}
void helloworld_task(void)
{
uint8_t temp_str[10];
unsigned char c = 0;
uint16_t index = 0;
while (1)
{
sprintf(temp_str, "hello world! %d", index);
OLED_Show_String(20, 26, temp_str, 12, 1); //显示到x主标20,y坐标26
index ++;
OLED_Refresh_GRAM(); //刷新显示缓冲区
aos_msleep(1000);
}
}
int helloworld_uninit(void)
{
aos_task_delete("helloworld_task");
printf("aos_task_delete helloworld_task \n");
return 0;
}
修改application/example/edu_demo/k1_apps/menu.c,将helloworld添加到首页显示。
MENU_TYP *Menus[] = {
&helloworld,
&homepage,
&humiture,
&gyroscope,
&shakeshake,
&compass,
&barometer,
&lightmeter,
&musicbox,
&greedySnake,
&aircraftBattle,
};
MENU_LIST_TYP MenuList = {
Menus,
11};
修改文件application/example/edu_demo/aos.mk,添加如下语句
$(NAME)_SOURCES += k1_apps/helloworld/helloworld.c
$(NAME)_INCLUDES += k1_apps/helloworld/
如下:
怎么样,是不是很简单?
此外,我们还提供了丰富的说明文档供大家学习,其中每个模块都有对应的详细的指导文档,有兴趣的小伙伴可以去看看HaaS EDU专栏。
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号
更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/