Micro:bit系列教程25:自定义Micro:bit软件包

摘要: 当要使用Micro:bit驱动非板载外设时,制作专用软件包并添加到项目,可提高程序的重复利用率,同时提高开发效率。 本节将介绍如何制作Micro:bit扩展软件包 ... ...

当要使用Micro:bit驱动非板载外设时,制作专用软件包并添加到项目,可提高程序的重复利用率,同时提高开发效率。

本节将介绍如何制作Micro:bit扩展软件包:

  1.搭载环境

  1.1.安装node.js

下载地址:https://nodejs.org/en/,根据32位或64位系统下载不同版本,并安装,推荐安装官方推荐版本:


检查是否安装成功:打开Windows命令行,输入node -v,输出版本号则表明安装成功:


若未正常显示版本号,请将安装路径添加到系统环境变量,或重新安装node.js

1.2.安装pxt命令行工具

  打开Windows命令行,输入:

    npm install -g pxt

 打若出现以下提示,则成功安装:


1.3.安装Visual Studio Code

下载地址:https://code.visualstudio.com/,根据32位或64位系统选择不同的版本下载安装,该工具为官方推荐工具,编辑TypeScript脚本时有语法提示,错误检查等,推荐使用。

检查是否安装成功:打开Windows控制台,输入code -v,输出版本号则表明安装成功:


若未正常显示版本号,请将安装路径添加到系统环境变量,或重新安装Visual Studio Code

1.4.安装Git

下载地址:https://git-scm.com/根据32位或64位系统选择不同的版本下载安装,发布软件包的时候需要用到该软件。

1.5.加载工具链

新建文件夹,(注意:制作的软件包也需放至该文件夹的子文件夹下,本次操作是在E:\Program\Project\MicroBit_Project\Server路径建立microbit文件夹)
在microbit文件夹下加载Micro:bit工具链,打开Windows命令行进入该文件夹,输入:
1pxt target microbit

该过程可能持续几分钟,如果出现如下提示,则表明Micro:bit工具链加载成功:

此时输入:

1pxt help

可查看pxt的命令行帮助:


打开microbit文件夹,可见该文件夹下新增如下文件:


  2.生成软件包所需文件

在microbit文件夹下,建立projects文件夹,(注意,必须命名为projects,当执行pxt serve命令时,将会寻找projects文件夹)。
进入projects文件夹,新建文件夹,并以软件包名称命名(最终会将该文件夹下所有文件上传至Github,本次操作中,在projects文件夹下新建MCP23017文件夹),如下图所示:

打开Windows命令行,进入到新建的以软件包名称命名的文件夹 (本次进入到MCP23017文件夹),执行以下命令,生成软件包所需的部分文件:

1pxt init


此操作需输入相关信息,分别如下:

name:模块名称,为软件包名称,该名称将来也将显示到makecode界面中。

description:对软件包功能的描述,用makecode加载软件包时将展示。

license: 软件授权条款

输入相关信息后,MCP23017文件夹下新增了如下文件:


其中pxt.json则记录了模块名称,软件包描述,软件授权条款等信息,如下图所示:


数据以json键值对的形式存储,如果需要修改数据,修改键对应的值即可。

3.设计驱动代码及图形块

打开Windows命令行,进入到新建的以软件包名称命名的文件夹 (本次进入到MCP23017文件夹),输入以下命令,采用Visual Studio Code 打开该项目:

code .

输入回车后,VS Code打开了该项目(pxt init命令生成的就是一个VS Code项目)


由于是制作软件包,不需要main.ts文件,因此,将main.ts重命名为 mcp23017.ts,并在该文件下采用TypeScrip编写MCP23017的驱动代码,设计图形块(图形块与注释相关联,图形块设计请参考:

https://makecode.com/defining-blocks

),之后,将pxt.json文件中”file”:下的main.ts修改为MCP23017.ts,如下图所示:



MCP23017驱动及图形块代码如下图所示:

  cpp代码:

001/**
002 * 使用此文件来定义自定义函数和图形块。
003 * 想了解更详细的信息,请前往 https://makecode.microbit.org/blocks/custom
004 */
005 
006/**
007 * 自定义图形块
008 */
009 
010enum REGISTER {
011    IODIRA = 0x00,
012    IODIRB = 0x01,
013    IPOLA = 0x02,
014    IPOLB = 0x03,
015    GPINTENA = 0x04,
016    GPINTENB = 0x05,
017    DEFVALA = 0x06,
018    DEFVALB = 0x07,
019    INTCONA = 0x08,
020    INTCONB = 0x09,
021    IOCONA = 0x0A,
022    IOCONB = 0x0B,
023    GPPUA = 0x0C,
024    GPPUB = 0x0D,
025    INTFA = 0x0E,
026    INTFB = 0x0F,
027    INTCAPA = 0x10,
028    INTCAPB = 0x11,
029    GPIOA = 0x12,
030    GPIOB = 0x13,
031    OLATA = 0x14,
032    OLATB = 0x15
033}
034 
035enum PIN {
036    A = 0,
037    B = 1
038}
039 
040//% weight=5 color=#9900CC icon="\uf53b"
041namespace MCP23017 {
042    const MCP23017_ADDRESS = 0x20
043 
044    const MCP23017_IODIRA = 0x00
045    const MCP23017_IPOLA = 0x02
046    const MCP23017_GPINTENA = 0x04
047    const MCP23017_DEFVALA = 0x06
048    const MCP23017_INTCONA = 0x08
049    const MCP23017_IOCONA = 0x0A
050    const MCP23017_GPPUA = 0x0C
051    const MCP23017_INTFA = 0x0E
052    const MCP23017_INTCAPA = 0x10
053    const MCP23017_GPIOA = 0x12
054    const MCP23017_OLATA = 0x14
055 
056    const MCP23017_IODIRB = 0x01
057    const MCP23017_IPOLB = 0x03
058    const MCP23017_GPINTENB = 0x05
059    const MCP23017_DEFVALB = 0x07
060    const MCP23017_INTCONB = 0x09
061    const MCP23017_IOCONB = 0x0B
062    const MCP23017_GPPUB = 0x0D
063    const MCP23017_INTFB = 0x0F
064    const MCP23017_INTCAPB = 0x11
065    const MCP23017_GPIOB = 0x13
066    const MCP23017_OLATB = 0x15
067 
068    let initialized = false
069 
070    function i2cwrite(addr: number, reg: number, value: number): void {
071        let buf = pins.createBuffer(2);
072        buf[0] = reg;
073        buf[1] = value;
074        pins.i2cWriteBuffer(addr, buf);
075    }
076 
077    function i2cread(addr: number, reg: number): number {
078        pins.i2cWriteNumber(addr, reg, NumberFormat.UInt8BE);
079        let val = pins.i2cReadNumber(addr, NumberFormat.UInt8BE);
080        return val;
081    }
082 
083    function initMCP23017(): void {
084        for (let regAddr = 0; regAddr < 22; regAddr++) {
085            if (regAddr == 0 || regAddr == 1) {
086                i2cwrite(MCP23017_ADDRESS, regAddr, 0xFF);
087            }
088            else {
089                i2cwrite(MCP23017_ADDRESS, regAddr, 0x00);
090            }
091        }
092 
093        //configue all PinA output
094        i2cwrite(MCP23017_ADDRESS, MCP23017_IODIRA, 0x00);
095 
096        //configue all PinB input
097        i2cwrite(MCP23017_ADDRESS, MCP23017_IODIRB, 0xFF);
098        //configue all PinB pullUP
099        i2cwrite(MCP23017_ADDRESS, MCP23017_GPPUB, 0xFF);
100 
101        initialized = true;
102    }
103 
104 
105    /**
106     *Read data from the register
107     * @param reg [0-21] register of mcp23017; eg: 0, 15, 23
108    */
109    //% blockId=ReadReg block="Read register |%reg| data"
110    //% weight=65
111    export function ReadReg(reg: REGISTER): number {
112        let val = i2cread(MCP23017_ADDRESS, reg);
113        return val;
114    }
115 
116 
117    /**
118     * WriteData to PinA or PinB
119     * @param pin [0-1] choose PinA or PinB; eg: 0, 1
120     * @param value [0-255] pulse of servo; eg: 128, 0, 255
121    */
122    //% blockId=WritePin block="Set P |%pin| value |%value|"
123    //% weight=75
124    //% value.min=0 value.max=255
125    export function WritePin(pin: PIN, value: number): void {
126        if (!initialized) {
127            initMCP23017();
128        }
129        if (pin == 0) {
130            i2cwrite(MCP23017_ADDRESS, MCP23017_GPIOA, value);
131        }
132        else {
133            i2cwrite(MCP23017_ADDRESS, MCP23017_GPIOB, value);
134        }
135    }
136 
137    /**
138     *ReadData From PinA or PinB
139     * @param pin [0-1] choose PinA or PinB; eg: 0, 1
140    */
141    //% blockId=ReadPin block="Read data from |%pin|"
142    //% weight=85
143    export function ReadPin(pin: PIN): number {
144        if (!initialized) {
145            initMCP23017();
146        }
147        if (pin == 0) {
148            let val = i2cread(MCP23017_ADDRESS, MCP23017_GPIOA);
149            return val;
150        }
151        else {
152            let val = i2cread(MCP23017_ADDRESS, MCP23017_GPIOB);
153            return val;
154        }
155    }
156}

4.编写测试代码

  在采用pxt init 生成的文件中,test.ts文件为测试文件,当作为软件包添加到其它项目中时,该文件不会被编译,而作为开发流程中的功能测试时,该文件将会被编译,且单独执行。

  现编写测试代码,对输出功能进行测试:


  在该测试代码中,其操作为对MCP23017A引脚的输出寄存器写入十进制数值:85,其二进制为:01010101,对应PA0PA7的电平状态分别为:高低高低高低高低。

  此次测试代码为:

  cpp代码:

1/* tests go here; this will not be compiled when this package is used as a library*/
2basic.forever(() => {
3    MCP23017.WritePin(0,85);
4})

5.编译检查,测试

  先进行语法检查,如果有语法出错,VS code 会进行提示,及时在VS Code中改正即可:


  打开Windows命令行,进入到新建的以软件包名称命名的文件夹 (本次进入到MCP23017文件夹),进行以下操作:

  编译:(可选在命令行输入:pxt build,该步骤主要方便检查语法错误,实际中,VS Code能够提示语法错误,可先在VS Code中修改语法错误。

  编译并下载:(可选)在命令行输入:pxt deploy,该步骤为先编译,编译成功后直接下载,实际中,通过makecode进行下载更便捷。

打开makecode进行编辑并下载:(推荐)

  在命令行进入到microbit路径(该路径下包含projects文件夹,运行pxt serve将寻找projects文件夹,若找不到,则将自动创建新项目,因此必须先进入到含有projects子文件夹的microbit文件夹),如下所示:


  在此基础上,在命令行输入:pxt serve,运行makecode 服务器,自动打开makecode网页:


此时,软件包已经加载到左侧,可预览软件包的颜色及图标,并可对图形块进行移动,如下图所示:


但是,在test.ts文件中,仅能以JavaScript代码的形式进行显示。

连接microbit,点击左下角的download,程序将下载到microbit中,运行的是test.ts文件中的代码。

下载后,将MCP23017PA0-PA7连接至8LED(低电平亮),观察得,PA0-PA7连接的LED分别为灭亮灭亮灭亮灭亮,软件包测试通过。

6.发布

    软件包测试通过后,将其发布到Github,此次发布的本地仓库为MCP23017文件夹,具体发布流程请参考廖雪峰的Git教程:

https://www.liaoxuefeng.com/

最后,打开Windows命令行进入到MCP23017文件夹,输入pxt bump命令,修改版本号(修改pxt.json文件中version键对应的值)

    将软件包发布后,即可根据Github仓库链接找到软件包,可在makecode中自由扩展该软件包到项目中了。


参考链接

搭建环境,及Github的使用:

https://makecode.com/cli

https://makecode.com/packages/getting-started

https://makecode.com/packages/getting-started/vscode

图形块定义

https://makecode.com/defining-blocks

Github教程

https://www.liaoxuefeng.com/