快速开发上手视频
点击查看完整版:Mind+自定义用户库视频教程
1-开发教程简介
MindPlus-用户库扩展-开发者文档
Mind+是一款拥有自主知识产权的国产青少年编程软件,支持Arduino、micro:bit、掌控板等各种开源硬件,兼容Scratch3.0,支持AI与IoT功能,只需要拖动图形化程序块即可完成编程,还可以使用Python/C/C++等高级编程语言,让大家轻松体验创造的乐趣。
-
Mind+支持三大主流开源硬件平台(Arduino,micro:bit,掌控板esp32),均可以使用基于arduino C的库,因此只需要编写一个arduino的库即可达到三平台兼容。
-
Mind+已经支持几十种常用的扩展小模块库,为方便更多用户的使用,从V1.6.2版本开始开放用户自定义库功能,你可以根据自己的需要编写或移植现有的arduino库,自己设计图形模块(block)的外观及形状,自己设计对应生成的代码。
-
支持通过网络加载Github的用户库或直接本地加载(config.json或.mpext文件)。
提示:尽管用户库增加非常简单,但依然建议有一定代码基础的用户进行操作,若有需要增加的模块而不懂代码,依然可以给官方反馈需要增加的模块。
使用用户库请先升级Mind+到V1.6.2 RC2.0及以上版本。
-
样例库: https://gitee.com/dfrobot/ext-oled12864.git
----------
2-用户库文件结构
└─newExtensions // 项目名称
│ config.json // 本用户库的配置文件
│ LICENSE.TXT // 许可证说明
│ README.md // 文档说明
│
└─arduinoC // arduino模式用户库根目录
│ main.ts // 图形块描述文件
│
├─libraries // arduino库文件,列出本扩展库所有需要引用的.c或.h或.cpp文件
│ └─oled12864
│ oled12864.cpp
│ oled12864.h
│ qrcode.c
│ qrcode.h
│
├─_images // 图片文件
│ featured.png // MindPlus扩展库展示图片
│ icon.svg // MindPlus中图形块上的图标文件
│
├─_locales // 翻译文件,支持多国语言
│ zh-cn.json
│ en.json
│
└─_menus // 下拉菜单参数,每个板子可以独立设置
leonardo.json
uno.json
nano.json
mega2560.json
microbit.json
mpython.json
----------
3-文件说明
3.1-config.json配置文件
{
"name": {
"zh-cn": "OLED-12864显示屏(测试)",
"en": "OLED-12864 screen(Test)"
},
"description": {
"zh-cn": "小体积显示屏,可用于智能穿戴设备的显示器",
"en": "I2C OLED-2864 Display Module"
},
"author": "DFRobot",
"email": "MindPlus@dfrobot.com",
"license": "MIT",
"isTest": false,"备注":"此字段已删除,自动判断,不需要"
"isBoard": false,
"id": "oled12864",
"platform": ["win", "mac", "web"],
"version": "0.0.1","备注":"整个扩展库的版本号,缺少会报错"
"asset": {
"arduinoC": {
"dir": "arduinoC/",
"version": "0.0.1",
"board": ["microbit", "esp32"],
"main": "main.ts",
"files": ["备注":"此字段自动生成,调试时不需要填写"
"_locales/zh-cn.json","备注":"此字段自动生成,不需要"
"_images/icon.svg","备注":"此字段自动生成,不需要"
"libraries/oled12864/oled12864.cpp","备注":"此字段自动生成,不需要"
"libraries/oled12864/oled12864.h","备注":"此字段自动生成,不需要"
"libraries/oled12864/qrcode.c","备注":"此字段自动生成,不需要"
"libraries/oled12864/qrcode.h""备注":"此字段自动生成,不需要"
]
}
}
}
详细说明:
- name: 名称。模块显示在扩展库中的标题名称。
- description: 描述。模块显示在扩展库中的描述。
- author: 作者名。请使用英文字母表示。
- email: 邮箱。当版本更新需要修改用户库或用户反馈,将通过邮件通知开发者(预留功能)
- license: 许可证类型。参考链接
isTest: 调试模式。True打开测试模式:每次编译都会重新构建静态文件(用于调试);False关闭测试模式:只会在第一次编译才会构建静态文件。建议开发者在调试过程中设置为True,在导出发布时设置为False。注:从1.6.2RC2.0开始删除此字段,根据加载库方法自动判断模式(从本地解压导入config.json为调试模式则有调试标志及刷新按钮,以zip或从网络加载为非调试模式则无标志及按钮)。
- isBoard: 主控。当前扩展是否为主控(预留功能,统一为false)
- id: 模块区分号。同一作者的不同模块需要设置不同的id,建议使用英文和数字符号命名。
- platform: 支持平台。有三个选项:"win", "mac", "web",分别表示Mind的windows桌面版,mac桌面版,网页版,当前仅支持win。
- asset: 各模式配置。当前仅支持上传模式的arduino C模式。
- dir: 指定模式路径。
/
不能遗漏,例如:"dir": "arduinoC/"
,不建议修改。 - version: 版本信息。三个数字,从小到大,例如:
"0.0.1"
,建议每次发布都增加一位小数,依次从小到大增加(版本控制功能预留)。 - board: 指定支持的主控,主控对应字段见下文“主控列表”。请确认测试通过后添加对应支持主控。若当前主控板不支持或模式不支持,则用户库右上角会显示“不可用”
- main: block描述文件的文件名。需要是ts后缀文件,名称自定义,需要在对应路径下,例如:
main.ts
。 files: 包含所需文件的路径,以便加载。注:从1.6.2RC2.0开始删除此字段,编译和导出库时自动添加相关文件。
主控列表
主控 | 类型 | 名称 |
---|---|---|
UNO | 主控 | arduino |
Nano | 主控 | arduinonano |
Leonardo | 主控 | leonardo |
Micro:Bit | 主控 | microbit |
掌控 | 主控 | esp32 |
Mega2560 | 主控 | mega2560 |
Vortex | 套件 | vortex |
Romeo | 套件 | romeo |
UNOR3 | 套件 | arduinounor3 |
Max:Bot | 套件 | maxbot |
麦昆 | 套件 | maqueen |
Max | 套件 | max |
RoboMaster TT | 主控 | telloesp32 |
FireBeetle ESP32 | 主控 | firebeetleesp32 |
FireBeetle ESP32-E | 主控 | firebeetleesp32e |
Maixduino | 主控 | maixduino |
**注:**主控对应的board名可选择对应主控,然后加载一个任意扩展,则会提示无法加载的时候显示当前主板对应的名称,如下图可知"FireBeetle ESP8266"对应的board名为"esp8266"
----------
3.2-main.ts描述文件总述
- 图形块描述文件中通过//%后面的内容可以定义图形块外观
- 通过function定义block对应的生成代码以及位置
文件内容结构
enum xxxx {
//% 引脚描述内容定义,需要翻译的菜单项需要定义到menu文件中
//% 引脚生成代码定义
}
//% color="#xxxx" 整个扩展block的外观定义,通过 //% 后的描述内容定义
namespace xxxx {
//% block="xxx [xxx]" blockType="xxx" 第一个block的外观定义描述内容
//% block其他描述内容
export function xxxx(parameter: any, block: any) { //单个block的生成代码定义,通过函数描述生成代码的位置及内容
//生成的代码位置及内容描述
}
//% block="xxx [xxx]" blockType="xxx" 第二个block的外观定义描述内容
//% block其他描述内容
export function xxxx(parameter: any, block: any) {
//生成的代码位置及内容描述
}
//% block="xxx [xxx]" blockType="xxx" 第N个block的外观定义描述内容
//% block其他描述内容
export function xxxx(parameter: any, block: any) {
//生成的代码位置及内容描述
}
}
以一个block的定义为例说明
main.ts中的代码如下:
//% block="when press [BUTTON]" blockType="hat"
//% BUTTON.shadow="dropdown" BUTTON.options="BTN" BUTTON.defl="BTN.A"
export function myBlock(parameter: any, block: any) {
let button = parameter.BUTTON.code;
Generator.addInclude('Mylibraray', '#include <Mylibraray.h>');
Generator.addObject(`libraray`, `MY_Libraray`, `libraray;`);
Generator.addEvent("functionName", "String", "functionName", "String message, int8_t error", true);
Generator.addSetup("libraray.begin", `libraray.begin(${button});`);
Generator.addSetup(`libraray.callback`, `libraray.callback(functionName);`);
Generator.addCode('libraray.start();')
}
- //% 后面的内容确定了block的外观以及输入值的绑定。
- export fuction中通过Generator确定不同的代码生成的位置和内容。
效果:
- 生成的block:
- 生成的代码:
/*!
* MindPlus
* microbit
*
*/
#include <Mylibraray.h>
// 函数声明
String functionName(String message, int8_t error);
// 创建对象
MY_Libraray libraray;
// 主程序开始
void setup() {
libraray.begin(A);
libraray.callback(functionName);
libraray.start();
}
void loop() {
}
// 事件回调函数
String functionName(String message, int8_t error) {
}
3.2.1-block外观定义
描述规则
描述命令必须包含在
//%
描述符后。
命令 | 含义 | 作用位置 | 可选参数 |
---|---|---|---|
color | 设置颜色 | namespace及block | 24位真彩色 |
iconWidth | icon图标宽度 | namespace | 默认40 |
iconHeight | icon图标高度 | namespace | 默认40 |
board | 指定当前图形块支持的主控,当选择的主控不在此参数后面则当前积木隐藏不显示 多个用逗号隔开 |
block | arduino、leonardo、microbit、esp32等(参考3.1节主控列表中的参数) |
block | block描述 | block | 自定义 例如:xxx[A]xxx |
blockType | block类型 | block | hat:帽子形 command:方形 reporter:圆形 boolean:菱形 |
shadow | 输入框类型 | 输入框 | string:文本 dropdown:下拉不可拖入 dropdownRound:下拉可拖入 boolean:布尔 range:范围 number:数字 |
defl | 设置默认值 | 输入框 | 自定义 |
params.min | 设置最小值 | range型输入框 | 自定义 |
params.max | 设置最大值 | range型输入框 | 自定义 |
options | 指定下拉菜单内容 | 菜单型输入框 | 自定义 |
描述内容限制
- block的描述中有些是必选的,有些是可选的参数描述,详情参考下表:
● 表示必需有此参数
⭕ 表示此参数为可选
\ 表示此无需此参数
参数字段 | namespace 命名空间 |
block 积木定义 |
string 文本输入框 |
number 数字输入框 |
range 数字范围输入框 |
boolean 布尔输入框 |
dropdown 下拉菜单 |
dropdownRound 可拖入下拉菜单 |
normal 原始输出无类型 |
---|---|---|---|---|---|---|---|---|---|
color | ⭕ | \ | \ | \ | \ | \ | \ | \ | \ |
iconWidth | ⭕ | \ | \ | \ | \ | \ | \ | \ | \ |
iconHeight | ⭕ | \ | \ | \ | \ | \ | \ | \ | \ |
block | \ | ● | \ | \ | \ | \ | \ | \ | \ |
blockType | \ | ⭕ | \ | \ | \ | \ | \ | \ | \ |
shadow | \ | \ | ● | ● | ● | ● | ● | ● | ● |
defl | \ | \ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ |
params.min | \ | \ | \ | \ | ⭕ | \ | \ | \ | \ |
params.max | \ | \ | \ | \ | ⭕ | \ | \ | \ | \ |
options | \ | \ | \ | \ | \ | \ | ● | ● | \ |
block | \ | ⭕ | \ | \ | \ | \ | \ | \ | \ |
namespace命名空间
在namespace前面的描述词可以指定整个用户库的颜色和icon信息,所有的block定义都需要在namespace大括号中。
//% color="#AA278D" iconWidth=50 iconHeight=40
namespace module {
...
}
创建一个TypeScript命名空间,所有的图形块都写在里面,还可以设置模块的整体颜色以及icon的尺寸,对于图形风格设置应该包含在//%
描述符中。所有的风格设置不是必须的,如果没有设置这些参数,系统将会按照默认的风格展示,//%
所包含的内容可以写在一行或多行。
- color: 设置图形块颜色,RGB24位真彩。
- iconWidth: 设置icon显示宽度。
- iconHeight: 设置icon显示高度,icon要求svg格式,图片应该放在
_images
文件夹根目录。
blockType
积木类型
通过blockType关键词可以设置block的整体外观。
//% block="set the line width to [WIDTH] pixels" blockType="command"
export function setBrightness(parameter: any, block: any) {
...
}
定义一个方形的图形块,//%
所包含的内容可以写在一行或多行。
- block: 一个图形块的完整描述,也是这个图形块的默认显示语言,
[]
所包含的内容为输入框的名称。 - blockType: 设置外观形状,可选参数有
hat,command,boolean,reporter
| block外观 | blockType值 | 外观 |
| ------------ | ------------ | ------------ |
| | hat | 帽子型 |
| | command | 方形 |
| | reporter| 圆形 |
| | boolean | 菱形 |
修饰功能
二级标签文字
1.8.0 RC3.0及以上版本新增功能
- block="标签文字内容" blockType="tag" ,blockType为tag,block内容为显示的文字
- 函数名不能跟其他函数重名,函数内容留空即可。
//% block="标签测试" blockType="tag"
export function tagtest() {}
空行
- block="---" ,固定格式,block内容为三个-,无需blockType参数
- 函数名不能跟其他函数重名,函数内容留空即可。
//% block="---"
export function noteSep() {}
shadow输入框
- 输入框由shadow关键词定义,总共有8种类型:normal:原始输出 string:文本 dropdown:下拉不可拖入 dropdownRound:下拉可拖入 boolean:布尔 range:范围 number:数字
- 如下代码使用一个block展示所有输入类型。
- defl关键词指定默认显示的参数。
- options关键词指定下拉菜单选项,在ts文件中定义一个枚举,如果需要区分主控,则需要将引脚定义放在_menus文件夹的根目录。
- 在range型输入框种可指定 params.min: 最小值 和 params.max: 最大值。
//% block="所有输入库类型测试:原始输出:[NM] 文本型:[SS] 数字型 [SN] 布尔型:[SB] 范围型 [SR] 下拉不可拖入型:[SD] 下拉可拖入型:[SDR] " blockType="command"
//% NM.shadow="normal" NM.defl="obj"
//% SS.shadow="string" SS.defl="mind+"
//% SN.shadow="number" SN.defl="123"
//% SB.shadow="boolean"
//% SR.shadow="range" SR.params.min=0 SR.params.max=10 SR.defl=5
//% SD.shadow="dropdown" SD.options="BTN" SD.defl="BTN.B"
//% SDR.shadow="dropdownRound" SDR.options="LINE" SDR.defl="LINE.1"
export function myBlock(parameter: any, block: any) {
}
字符引号 string
- STR.shadow="string"
角度控件 angle
- edge:1或-1 1表示0~180,-1表示-180~180
//% block="设置角度 [VALUE]" blockType="command"
//% VALUE.shadow="angle" VALUE.params.edge=1
export function setAngle(parameter: any, block: any) {
}
点阵控件 matrix
- row:行数,默认5最大16
- column:列数,默认5最大32
- split:中间分隔,true或false
- builtinFunc:定义内置图片,可以不定义,有函数名则必须有对应回调函数,点阵列表1表示点亮0熄灭。
//% extenralFunc
export function getBuiltinFunc_() {
return [
{matrix: "0101011111111110111000100"},
{matrix: "0000001010011100010000000"},
{matrix: "0010001110101010010000100"},
{matrix: "0010000100101010111000100"},
{matrix: "0010001000111110100000100"}
]
}
//% block="设置点阵 [MT]" blockType="command"
//% MT.shadow="matrix" MT.params.row=5 MT.params.column=5 MT.defl="0101011111111110111000100"
//% MT.params.builtinFunc="getBuiltinFunc_"
export function setMatrix(parameter: any, block: any) {
}
色盘控件 colorPalette
- column:表示将颜色数组用多少列排列。
- colorsFunc:颜色回调函数,必须存在。
注:色盘控件传入16进制颜色值,如需拆分成RGB三个10进制值,可查看本文最后常见问题中的方法。
//% externalFunc
export function getColorsFunc_() {
return [
"#fff", "#f00", "#0f0", "#00f", "#ff0", "#0ff", "#f0f", "#000"
]
}
//% block="设置颜色2 [COLOR]" blockType="command"
//% COLOR.shadow="colorPalette" COLOR.params.column=5
//% COLOR.params.colorsFunc="getColorsFunc_"
export function setColor2(parameter: any, block: any) {
}
- 注: 不定义columns和colorsFunc,则显示默认的7x10色盘。
//% block="设置颜色2 [COLOR]" blockType="command"
//% COLOR.shadow="colorPalette"
export function setColor3(parameter: any, block: any) {
}
调色控件 colorSlider
- 控件固定,可以设置默认值。
//% block="设置颜色1 [COLOR]" blockType="command"
//% COLOR.shadow="colorSlider" COLOR.defl="#f0f"
export function setColor(parameter: any, block: any) {
}
钢琴音符 note
- 控件固定,可以设置默认值。
//% block="show [STR] at x [X] y [Y]" blockType="command"
//% STR.shadow="note" STR.defl=247
//% X.shadow="range" X.params.min=0 X.params.max=127 X.defl=0
//% Y.shadow="range" Y.params.min=0 Y.params.max=63 Y.defl=0
export function print(parameter: any, block: any) {
let str = parameter.STR.code
let x = parameter.X.code
let y = parameter.Y.code
Generator.addInclude('oled12864', '#include <oled12864.h>');
Generator.addObject(`myoled`, `OLED_12864`, `myoled;`);
Generator.addSetup(`myoled.begin`, `myoled.begin();`);
Generator.addCode(`myoled.setCursor(${x}, ${y});\n\tmyoled.print(${str});`);
}
输入限制
- validateFunc:定义输入限制的函数,不定义则不限制,定义则必须存在回调函数。
- 输入限制函数:采用正则表达式进行判断。
//% externalFunc
export function validateStr_(str) {
let regx: RegExp = /^[a-z0-9]{1,8}\.[a-z0-9]{1,3}$/;
if (!regx.test(str)) {
return null;
}
return str;
}
//% block="show [STR] on the [LINE] line" blockType="hat"
//% STR.shadow="string" STR.defl="hellomm" STR.params.validateFunc="validateStr_"
//% LINE.shadow="dropdown" LINE.options="LINE" LINE.defl="LINE.1"
export function println(parameter: any, block: any) {
let str = parameter.STR.code
let line = parameter.LINE.code
Generator.addInclude('oled12864', '#include <oled12864.h>');
Generator.addObject(`myoled`, `OLED_12864`, `myoled;`);
Generator.addSetup(`myoled.begin`, `myoled.begin();`);
Generator.addCode(`myoled.setCursorLine(${line});\n\tmyoled.printLinemm(${str});`);
}
3.2.2-Generator代码定义
Generator是提供生成代码的工具,它被内置在mindplus解释器中,通过Generator.
来调用以控制生成代码的规范。
Generator.addInclude(id, code, cover)
在全局区添加include.
- id: 标识符,
- code: 代码
- cover: 是否覆盖具有相同id的代码, 默认值为False(仅第一条block生成代码,如需要生成多条代码可查看常见问题中的案例)。此参数可以实现多个block之间的联动,例如串口输出没有使用初始化block会默认生成波特率9600的代码,当使用了初始化波特率为115200时block会生成波特率115200的代码.
例如:
- main.ts:
Generator.addInclude("includeMylibraray", "#include <Mylibraray.h>", True);
- arduino.ino:
#include <Mylibraray.h>"
Generator.addDefine(code1, code2)
注意:172RC2.0以下版本不支持。
添加#define代码。
- code1: 宏名
- code2: 字符串
例如:
- main.ts:
Generator.addDefine("ledPin", "3");
- arduino.ino:
#define ledPin 3
Generator.addObject(id, type, code, cover)
在全局区添加对象
- id: 标识符
- type: class名称
- code: 对象名称
- cover: 是否覆盖具有相同id的代码, 默认值为false
例如:
- main.ts代码:
Generator.addObject(`libraray`, `MY_Libraray`, `libraray;`);
- arduino.ino代码:
MY_Libraray ibraray;
Generator.addSetup(id, code, cover)
在setup中添加代码。
特别注意:使用此函数生成的代码只会生成在setup中,并会生成在其他语句前,且无法生成在函数或其他事件程序中,若非必须,请使用addCode生成代码
- id: 标识符
- code: 代码
- cover: 是否覆盖具有相同id的代码, 默认值为false
Generator.addCode(code)
在setup或者loop中添加代码,没有返回值的代码添加(一般为方形,帽子形)。
- code: 代码。
Generator.addCode([code, level])
在setup或者loop中添加代码,有返回值的代码添加(一般为圆形,菱形)。
- code:需要注册的代码。
- level:运算符优先级,为代码添加括号。建议默认设置为Generator.ORDER_UNARY_POSTFIX。
例如:
Generator.addCode(["libraray.read()", Generator.ORDER_UNARY_POSTFIX]);
Generator.addEvent(id, type, nam, args, cover)
全局区定义一个回调函数
- id: 标识符
- type: 返回值类型,遵从C++语言规范。
- name: 函数名,遵从C++语言规范。
- args: 函数参数,遵从C++语言规范。
- cover: 是否覆盖具有相同id的代码, 默认值为false
例如:
Generator.addEvent("addEvent", "void", "function", "int x,int y");
运算符优先级
命令 | 级别 | 适用范围 |
---|---|---|
Generator.ORDER_UNARY_POSTFIX | 1 | expr++ expr-- () [] . |
Generator.ORDER_UNARY_PREFIX | 2 | -expr !expr ~expr ++expr --expr |
Generator.ORDER_MULTIPLICATIVE | 3 | * / % ~/ |
Generator.ORDER_ADDITIVE | 4 | + - |
Generator.ORDER_SHIFT | 5 | << >> |
Generator.ORDER_RELATIONAL | 6 | >= > <= < |
Generator.ORDER_EQUALITY | 7 | == != === !== |
Generator.ORDER_BITWISE_AND | 8 | & |
Generator.ORDER_BITWISE_XOR | 9 | ^ |
Generator.ORDER_BITWISE_OR | 10 | | |
Generator.ORDER_LOGICAL_AND | 11 | && |
Generator.ORDER_LOGICAL_OR | 12 | || |
Generator.ORDER_CONDITIONAL | 13 | expr ? expr : expr |
Generator.ORDER_ASSIGNMENT | 14 | = *= /= ~/= %= += -= <<= >>= &= ^= |
- 数字越小级别越高
Generator.board
此代码可以返回当前选择的主控板型号,根据此可以实现同一block在不同主控板生成不同代码。
注:如果要在某些主板下屏蔽某积木,只需要在block外观定义阶段增加board参数即可,详情见3.2.1-block外观定义
例如:
if(Generator.board === 'arduino'){//如果是arduinouno板,生成如下代码
Generator.addSetup("GTSerialSetup",`${ser}.begin(9600);`);
}else if(Generator.board === 'esp32'){//如果是掌控板,生成如下代码
Generator.addSetup("GTSerialSetup",`${ser}.begin(9600,${rx}, ${tx});`);
}
主控列表
参考3.1节主控列表
3.2.3-parameter传入参数
parameter是shadow传入参数,它被内置在mindplus解释器中,通过parameter.
来调用获取shadow动态传入的参数。
例如:
//% block="show [STR] on the [LINE] line" blockType="command"
//% STR.shadow="string" STR.defl=hello
//% LINE.shadow="dropdownRound" LINE.options="LINE" LINE.defl="LINE.1"
export function println(parameter: any, block: any) {
let str = parameter.STR.code
let line = parameter.LINE.code
Generator.addInclude('oled12864', '#include <oled12864.h>');
Generator.addObject(`myoled`, `OLED_12864`, `myoled;`);
Generator.addSetup(`myoled.begin`, `myoled.begin();`);
Generator.addCode(`myoled.setCursorLine(${line});\n\tmyoled.printLine(${str});`);
}
其中,parameter.STR.code即可获取STR这个输入框输入的内容。
目前parameter有四个输入参数可选,根据此4个参数,可以灵活调整生成的代码。
- code : 生成的代码
- parType : 传入参数类型
- codeType : 生成代码的数据类型
- checkType : 拖入参数类型限制
----------
3.3-资源文件夹
3.3.1-_images
此文件可放置图片类的资源文件。
- featured.png
扩展库界面图片,名称不可修改,600*372分辨率的png图片。
- icon.svg
block上显示的图标文件,名称不可修改,svg格式矢量图,内容尽量精简,推荐白色icon。
建议使用inkscape或AI等软件制作,也可从阿里巴巴矢量图标库iconfont等现成的图标库下载。
3.3.1-_locales
- 根据文件名对应不同的语言,若没有对应语言的翻译文件则以main.ts中block描述代码中的内容直接显示。
"files": [
"_locales/zh-cn.json",
"_images/icon.svg",
"libraries/oled12864/oled12864.cpp",
"libraries/oled12864/oled12864.h",
"libraries/oled12864/qrcode.c",
"libraries/oled12864/qrcode.h"
]
- block及menu都可以定义。
- json格式,每一行格式为:
"用户库名称.函数名|block":"翻译内容[菜单项]",
或菜单项则为:
"用户库名称.菜单名.菜单项|menu":"翻译内容",
- 以下为OLED12864示例库中的zh-cn.json内容:
{
"oled12864.buttonPress|block": "当 [BUTTON] 按钮按下",
"oled12864.qrcode|block": "在坐标x [X] y [Y] 绘制二维码[STR] 尺寸 [SIZE]",
"oled12864.println|block": "在第 [LINE] 显示 [STR]",
"oled12864.print|block": "在坐标x [X] y [Y] 显示 [STR]",
"oled12864.setLineWidth|block": "设置线宽为 [WIDTH] 像素",
"oled12864.getLineWidth|block": "获取线宽",
"oled12864.buttonIsPressed|block": "按钮 [BUTTON] 被按下?",
"oled12864.notTrue|block": "非 [Flag]",
"oled12864.SIZE.1|menu": "29*29(1)",
"oled12864.SIZE.2|menu": "58*58(2)"
}
- 语言列表如下(其他语言列表见翻译文件):
语言文件名 | 对应语言 |
---|---|
zh-cn.json | 简体中文 |
es-419.json | 西班牙文(南美) |
fr.json | 法文 |
ko.json | 韩文 |
th.json | 泰文 |
tr.json | 土耳其文 |
mn.json | 蒙文 |
zh-tw.json | 繁体中文 |
3.3.1-_menus
- 此文件夹中放置各种不同板子对应的下拉菜单内容。
"files": [
"_locales/zh-cn.json",
"_images/icon.svg",
"libraries/oled12864/oled12864.cpp",
"libraries/oled12864/oled12864.h",
"libraries/oled12864/qrcode.c",
"libraries/oled12864/qrcode.h"
]
- 每个主控板一个json文件,文件名以板子命名,不可修改,格式为json格式。**注:**在官方示例中有所有板子主要引脚文件可直接取用。
- menu字段对应菜单项:["下拉block中显示的内容","生成代码获得的内容"]
- default_函数名_下拉字段名称 可以设置默认下拉引脚
- 以下为OLED12864示例库中的microbit.json内容:
{
"PINX": {
"menu": [["P0", "0"], ["P1", "1"], ["P2", "2"]],
"default_setBrightness_TXPIN": "1",
"default_setBrightness_RXPIN": "2"
},
"MENU": {
"menu": [["A", "0"], ["B", "1"], ["C", "2"]],
"default_setMenu_MENU":"2",
}
}
3.3.1-libraries
- 此文件放置生成代码需要调用的arduino库文件,如果不需要库文件,需要将libraries文件夹删除。
此文件夹下需要用到的文件路径需要在config.json中的file字段下填写注:从1.6.2RC2.0开始删除files字段,编译和导出库时自动添加相关文件,可以无需手动添加。
"files": [
"_locales/zh-cn.json",
"_images/icon.svg",
"libraries/oled12864/oled12864.cpp",
"libraries/oled12864/oled12864.h",
"libraries/oled12864/qrcode.c",
"libraries/oled12864/qrcode.h"
]
- 以下为OLED12864示例库中的libraries内容:
├─libraries
│ └─oled12864
│ oled12864.cpp
│ oled12864.h
│ qrcode.c
│ qrcode.h
----------
4-第一个用户库示例
目标
完成一个OLED显示库,实现高级功能。
准备
- 文本编辑器:推荐VS Code。
- libraris:如果需要用到库则需要准备。
- block设计:根据功能先预想block应该如何呈现。
- 图片设计:准备一张600*372像素的png图片。
- icon设计: 可以去网上搜索免费的icon,也可以使用inkscape或AI等软件自行设计。
步骤
(详情内容参考示例库: https://gitee.com/dfrobot/ext-oled12864.git )
- 编辑config.json配置文件。配置扩展库信息。参考本文档的“3.1-config.json配置文件”部分进行配置。
- 编辑main.ts描述文件。配置block外观。参考本文档的“3.2.1-block外观定义”部分进行配置。
- 编辑main.ts描述文件。配置block生成的代码。参考本文档的“3.2.2-Generator代码定义”部分进行配置。
- 根据main.ts的需要编辑_menus、_locales菜单文件。参考本文档的“3.2.1-block外观定义”部分进行配置。
- 将对应文件放入_images,librires文件。参考本文档的“3.2.1-block外观定义”部分进行配置。
测试
- 功能测试(通过本地加载config.json可以更新库),查看生成的block是否符合预期,查看生成的代码是否符合预期,查看编译是否通过。
- 调整config.json的主板支持类型,测试不同主控板下的适应性(注意需要编译通过)。
导出用户库
- 调试完成后,编写README.md文件(以markdown格式编辑本扩展库的教程)。
- 右键扩展库导出用户库为.mpext文件,如果上传git,文件名不要修改否则会出错。
- 分享(推荐分享到 Mind+社区):
- **本地加载:**直接分享给其他用户加载.mpext(
注意不要解压从本地上传,否则是调试模式,从本地应该直接选择.mpext加载打开
)。 - **网络加载:**将.mpext文件导出到与config.json同级目录下,通过git将整个文件夹上传到github或者gitee(码云) (gith教程),将git链接分享给其他用户加载。
**注:**如果要通过如下图所示直接搜索关键词加载,则可以申请加入官方推荐列表,点击查看加入方法
----------
5-常见问题
常见问题 | |
---|---|
问题描述: | 用户库显示“不可用” : |
解决办法: | 说明当前用户库不支持当前所在的模式(上传/实时)、代码(arduinoC/micropython),或主控板。 |
常见问题 | |
---|---|
问题描述: | 下拉菜单切换,生成代码无法切换是为何? |
解决办法: | 使用**字符串拼接符号与${}**符号实现下拉菜单生成代码的切换。 |
常见问题 | |
---|---|
问题描述: | 需要控制一个函数代码生成在setup中,参数根据用户选择的下拉可以生成多条,但是setup同一个id只能生成一条代码? |
解决办法: | 可以将下拉菜单的输入项作为id,这样选择不同的下拉就是不同的id,实现生成多条代码。 |
常见问题 | |
---|---|
问题描述: | 如何实现两个下拉框的联动? |
解决办法: | 用户库中不支持下拉框之间的联动,请尝试使用多个积木。 |
常见问题 | |
---|---|
问题描述: | 积木中自动生成了/或者"等输入符号如何处理? |
解决办法1: | 可以在TS代码中使用字符串查找分割等功能去除。 |
解决办法2: | 也可以在TS代码中使用字符串替换等功能去除。 |
常见问题 | |
---|---|
问题描述: | 使用dropdownRound输入框,如何判断输入值是下拉菜单还是插入的变量? |
解决办法: | 可以在TS代码中使用parType参数判断输入值是否为下拉框 |
常见问题 | |
---|---|
问题描述: | main.ts的block没有错误,导入之后输入框阴影无法输入。 |
解决办法: | 检查namespace命名是否与config中模块id相同,尝试删除用户库,再重新导入。 |
常见问题 | |
---|---|
问题描述: | main.ts的block没有错误,导入之后输入框阴影无法输入。 |
解决办法: | 检查namespace是否与config用户id相同,尝试删除用户库,再重新导入。 |
常见问题 | |
---|---|
问题描述: | Arduino的Cpp库中如何根据microbit、掌控板、arduino区分生成代码? |
解决办法: | 使用宏定义区分,如下: |
#if defined(NRF5)
//主控板选择microbit V1时编译器编译的代码
#elif defined (NRF52833)
//主控板选择microbit V2时编译器编译的代码
#elif defined (ESP_PLATFORM)
//主控板选择掌控板时编译器编译的代码
#else
//主控板为其他板时编译器编译的代码
#endif
常见问题 | |
---|---|
问题描述: | 如何让某些积木在指定主控板下隐藏? |
解决办法: | 在定义积木外观时增加描述命令board参数,参考3.2.1节 |
//例:如下代码对应的myBlock积木仅当主控板为uno和micro:bit时才会显示,选择其他主控板时则不会显示
//% board="arduino,microbit"
//% block="when press [BUTTON]" blockType="hat"
//% BUTTON.shadow="dropdown" BUTTON.options="BTN" BUTTON.defl="BTN.A"
export function myBlock(parameter: any, block: any) {
}
常见问题 | |
---|---|
问题描述: | 如何在软件中让micro:bit板重启? |
解决办法: | 调用语句: NVIC_SystemReset(); |
常见问题 | |
---|---|
问题描述: | colorPalette如何拆成RGB三个值? |
解决办法: | 将16进制颜色值使用字符串分别截取RGB的16进制然后进行转换即可。 |
//% block="set color [COLOR]" blockType="command"
//% COLOR.shadow="colorPalette"
export function devsetcolor(parameter: any, block: any) {
let color=parameter.COLOR.code; //获取传进来的值
var r = 0;
var g = 0;
var b = 0;
try {
if ( color.length == 8 ) {//分别截取RGB值然后转换为数字值
r = parseInt(color.substring(2, 4), 16);
g = parseInt(color.substring(4, 6), 16);
b = parseInt(color.substring(6, 8), 16);
}
} catch(e) {
return '';
}
Generator.addCode(`bulb.set_rgb(${r},${g},${b})`);//使用RGB颜色生成代码
}
如有问题,可以加入我们的官方QQ群或通过论坛、邮件反馈问题。