简 介: 对于给定的MicroPython移植版本进行了初步的测试。对比之下,MCU中还有很多的模块尚未支持。这些工作需要近期尽快补充测试完毕。
关键词
:MM32,MicroPython
§01MicroPython开发
一、背景介绍
为了能够在第十七届全国大学生智能车竞赛中引入基于MicroPython开发模式,适合非电子专业背景的同学能够参与智能车竞赛的锻炼。实际上在之前比赛中,基于NXP的OpenMV,OpenART模块都以及采用了MicroPython开发模式,只是这些模块还无法提供更多的端口来满足智能车竞赛车模作品的开发。
1、硬件模块
下面是逐飞科技提供的基于灵动单片机MM32F3277的开发模块,其中已经初步抑制了MicroPython的环境。
在调试来自于逐飞的MM32F3277移植有MicroPython开发板介绍了该开发板的相关信息,并建立了通过REPL进行交互式开发的工具链。
▲ 图1.1.1 逐飞寄送过来的基本模块
2、开发模式
利用STM32 Bootloader软件组成MicroPython的REPL交互式界面,并可以将剪切板上的MicroPython程序下载到MM32进行直接。同时可以将REPL输出的信息进行显示。
二、开发板硬件
1、实验板操作说明
下面是逐飞科技发送过来关于开发版硬件操作说明。
测试准备:
连接正常的主板一块,寄过去的板子已接上屏幕并插入SD卡;
▲ 图1.2.1 开发板硬件正面
请使用电池或稳压源从电源线供电,电压为推荐8V(超过6V即可)。
或者可以使用黑色核心板上Type-C进行供电,但仅使用Type-C进行供电时不可以接入舵机。
▲ 图1.2.2 开发版背后的SD卡槽
背面是SD卡插座,已接入SD卡,上电默认运行卡内main.py,现象是黑色核心板上LED闪烁。
连接与环境设置:
▲ 图1.2.3 开发板调试端口下载界面
串口连接黑色核心板的下载调试接口的串口,波特率为115200,上电后通过这里进行RPEL交互,需要注意的是,如果SD卡内已有main.py那么会优先运行main.py:
▲ 图1.2.4 串口终端PuTTY界面
此时运行的是SD卡内的main.py文件,我们附带的SD卡中该Python程序不设置退出,所以无法进入RPEL。
需要将SD卡中main.py删除或者将文件内循环删除,这里我们选择将文件删除,重新插卡并复位:
▲ 图1.2.5 进入REPL进行调试状态
此时进入RPEL,并输出了MicroPython版本。
尝试进行Python语句执行:
基于附带的示例py文件,可以尝试运行显示效果
▲ 图1.2.6 运行LCD180.help()后的结果
运行以上语句,对应会电量LCD屏幕刷新为全屏红色并显示SEEKFREE字样。
2、实验板原理图
原理可以如下链接下载:MM32F3277主板原理图
(1)核心主板
▲ 图1.2.7 核心主板管脚定义
(2)背板功能定义
▲ 图1.2.8 背板接口定义
(3)背板分电路图
▲ 图1.2.9 5V 电源原理图
电路板上有3个3.3V电源分别提供通用3.3V,摄像头,运放的电源。
▲ 图1.2.10 摄像头3.3V电源
▲ 图1.2.11 舵机电源
▲ 图1.2.12 部分接口管脚定义
▲ 图1.2.13 部分接口管脚定义
▲ 图1.2.14 部分接口管脚定义
三、MicroPython功能
如下是MM32F3277中已经移植好的MicroPython功能。本文对于这些功能进行初步的测试。
▲ 图1.3.1 现在已经移植好的MicroPython辅助功能
§02功能测试
一、GPIO测试
1、GPIO输出
(1)测试代码
from seekfreeimport GPIOpinpg1 = GPIO(0x67, 1, 1)print("Test GPIO .")while True:pinpg1.low()pinpg1.high()
(2)测试结果
使用示波器测量MM32模块的G7管脚波形。
▲ 图2.1.1 使用示波器测量MM32模块的G7管脚波形
▲ 图2.1.2 G7端口输出的波形
通过上述测试,可以看到MicroPython下对于端口操作的周期大约为:22.28μs\mu sμs。
由于上述代码最终是一个死循环,所以需要通过MM32复位才能够从死循环中调出。
(3)修改调试端口
为了能够从软件上控制MM32复位,在原来调试端口增加NRST控制线。
▲ 图2.1.3 修改调试端口,增加RST控制端口
对于STM32的MPDLD命令中增加了MM32复位过程。
if(strncmp(szString, "MPDLD", 5) == 0) {// MicroPython Dlownloadchar szString[0x8000];strcpy(szString, "");Clipboard()->GetTextBuf(szString, sizeof(szString) - 1);ClearInfor();ShowInfor("Reset MicroPython...");RTSEnable(1, PORT1);Sleep(100);ClearPort(PORT1);RTSEnable(0, PORT1);ShowInfor("Wait for MicroPython comeback...");double lfStart = GetDosTime();int nGreatCount = 0;int nGreatFlag = 0;for(;;) {if(GetDosTime() - lfStart > 2) break;char c;if(ReceChar(&c, PORT1) == 0) {if(c == '>') nGreatCount ++;if(c == ' ') {if(nGreatCount >= 3) {nGreatFlag = 1;break;}}}}int nLength = strlen(szString);int i;int nLine = 0;for(i = 0; i < nLength; i ++) {if(szString[i] == '\r') nLine ++;}char szTemp[512];sprintf(szTemp, "Download MicroPython : %d lines/%d characters.", nLine, nLength);ShowInfor(szTemp);ShowInfor("Begin to download programm...");Sleep(200);if(nGreatFlag == 0) {MessageBeep(0);SendChar(0x2, PORT1); // Send CTRL+BSleep(100);}SendChar(0x5, PORT1); // Send CTRL+ASleep(100);for(i = 0; i < nLength; i ++) {ProgressBar1->Position = (i + 1) * 100 / nLength;SendChar(szString[i], PORT1);}for(;;) {char c;if(ReceCharL(&c, PORT1, 20) > 0) break;}ShowInfor("-------------------------------------------------------------------------");SendChar(0x4, PORT1);// Send CTRL+Breturn;}
修改完之后,对于循环程序,也可以很方便自动下载程序了。
(4)测试toggle
from seekfreeimport GPIOpinpg1 = GPIO(0x67, 1, 1)print("Test GPIO .")while True:pinpg1.toggle()
▲ 图2.1.4 toggle()函数对应的输出波形
从上述波形来看, toggle( )运行时间稍微比low(), high()慢一些。
2、LED
现在模块中居然没有time模块,这个模块可以提供延时操作。因此,只能够通过软件延时来实现间隔。
将无线串口HEADER中的C6,C7,GND,+5V引出,测试GPIO输出控制LED。
from seekfreeimport GPIOled1 = GPIO(0x26, 1, 1)led2 = GPIO(0x27, 1, 0)print('Test LED.')while True:def delay(loop):for _ in range(loop):passled1.high()led2.low()delay(20000)led1.low()led2.high()delay(20000)
▲ 图2.1.5 LED延时闪烁
3、测试按钮
▲ 图2.1.6 电路板上的按键与开关
(1)硬件
根据前面硬件电路图所示,电路板上集成了四个按键:G0,G1,G2,G3。它们对应的端口为:GPIOG0, G1,G2,G3。
▲ 图2.1.7 开发板上的四个按键
(2)测试软件
from seekfreeimport GPIOled1 = GPIO(0x26, 1, 1)led2 = GPIO(0x27, 1, 0)btn1 = GPIO(0x60, 0, 1)btn2 = GPIO(0x61, 0, 1)btn3 = GPIO(0x62, 0, 1)btn4 = GPIO(0x63, 0, 1)print('Test LED.')def delay(loop=50000):for _ in range(loop):passwhile True:print([btn1.value(), btn2.value(), btn3.value(), btn4.value()])delay(50000)
4、测试拨码开关
电路板上还有两个拨码开关,分别对应的D14,D15。通过GPIO可以读出它们的状态。测试的方式与上面按键相同。
from seekfreeimport GPIOprint('Test LED.')def delay(loop=50000):for _ in range(loop):passled1 = GPIO(0x26, 1, 1)led2 = GPIO(0x27, 1, 0)btn1 = GPIO(0x60, 0, 1)btn2 = GPIO(0x61, 0, 1)btn3 = GPIO(0x62, 0, 1)btn4 = GPIO(0x63, 0, 1)sw1 = GPIO(0x3e, 0, 1)sw2 = GPIO(0x3f, 0, 1)while True:print([btn1.value(), btn2.value(), btn3.value(), btn4.value(), sw1.value(), sw2.value()])delay(50000)
▲ 图2.1.8 测量按键与拨码开关
二、ADC测试
1、ADC.help()
▲ 图2.2.1 ADC.help() 显示信息
2、adc.value()
将电磁模块接口的引到面包板上,利用电位器获得不同的电压,发送到A4。
▲ 图2.2.2 采集到1024 个ADC数值
数据的方差: 5。
由于MicroPython不支持浮点运算。所以需要采用整形数完成相关的计算。
from seekfreeimport ADC,GPIOadc = ADC(0)adc.channel_init(adc.A4)print('Test ADC.')def delay(loop=50000):for _ in range(loop):passdef sqrt(x):left = 0right = x//2+1while left < right:middle = left + (right-left+1)//2square = middle * middleif square > x:right = middle-1else: left = middlereturn leftSAMPLE_NUM = 1024adcdim = [0]*SAMPLE_NUMfor i in range(SAMPLE_NUM):adcdim[i] = adc.value(adc.A4)print(adcdim)count = 0for s in adcdim:count += saverage = count//SAMPLE_NUMsigma = 0for s in adcdim:ss = s - averagesigma += ss**2print(sqrt(sigma//SAMPLE_NUM))
三、PWM测试
测试版上的PWM分别通过A0,A1,A2,A3输出。
1、基本测试
from seekfreeimport PWM,GPIOpwm = PWM(16000)pwm.channel_init(pwm.A0, 5000)print("Test PWM")
duty = 5000
▲ 图2.3.1 A0输出PWM波形
duty = 500▲ 图2.3.2 A0输出PWM波形
2、利用ADC改变PWM
from seekfreeimport PWM,GPIO,ADCpwm = PWM(16000)pwm.channel_init(pwm.A0, 500)adc = ADC(0)adc.channel_init(adc.A4)def delay(loop=50000):for _ in range(loop):passprint('Test PWM...')while True:adcvalue = adc.value(adc.A4)pwmvalue = adcvalue*10000//0x1000print(adcvalue, pwmvalue)pwm.duty(pwm.A0, pwmvalue)delay(10000)
▲ 图2.3.3 抖动的PWM
通过对采集到ADC进行平均之后,在控制PWM,波形就非常稳定了。
from seekfreeimport PWM,GPIO,ADCpwm = PWM(16000)pwm.channel_init(pwm.A0, 5000)adc = ADC(0)adc.channel_init(adc.A4)def delay(loop=50000):for _ in range(loop):passprint('Test PWM...')while True:sigma = 0for i in range(256):sigma += adc.value(adc.A4)adcvalue = sigma//256pwmvalue = adcvalue*10000//0x1000pwm.duty(pwm.A0, pwmvalue)delay(1000)
▲ 图2.3.4 通过ADC改变PWM占空比
四、Timer测试
1、基本测试
设置定时器的回调函数。
from seekfreeimport TIMER,GPIOled1 = GPIO(0x26, 1, 1)led2 = GPIO(0x27, 1, 0)def timer_callback(s):led1.toggle()print(s.count())tim = TIMER(200)tim.callback(timer_callback)while True:pass
※ 测试总结 ※
对于MM32的MicroPython移植版本进行了初步的测试。也能够看到这个版本的移植工作还需要一定的丰富。
缺少对于SPI, I2C,CAN总线的支持。缺少对于浮点数运算的支持;缺少对于SD卡文件访问支持;
上述功能需要通过后期的补充进一步改善。
■ 相关文献链接:
智能车竞赛相关的教高司公函:公函[]201号文、教高司[]13号MicroPython调试来自于逐飞的MM32F3277移植有MicroPython开发板STM32 BootloaderMM32F3277主板原理图
● 相关图表链接:
图1.1.1 逐飞寄送过来的基本模块图1.2.1 开发板硬件正面图1.2.2 开发版背后的SD卡槽图1.2.3 开发板调试端口下载界面图1.2.4 串口终端PuTTY界面图1.2.5 进入REPL进行调试状态图1.2.6 运行LCD180.help()后的结果图1.2.7 核心主板管脚定义图1.2.8 背板接口定义图1.2.9 5V 电源原理图图1.2.10 摄像头3.3V电源图1.2.11 舵机电源图1.2.12 部分接口管脚定义图1.2.13 部分接口管脚定义图1.2.14 部分接口管脚定义图1.3.1 现在已经移植好的MicroPython辅助功能图2.1.1 使用示波器测量MM32模块的G7管脚波形图2.1.2 G7端口输出的波形图2.1.3 修改调试端口,增加RST控制端口图2.1.4 toggle()函数对应的输出波形图2.1.5 LED延时闪烁图2.1.6 电路板上的按键与开关图2.1.7 开发板上的四个按键图2.1.8 测量按键与拨码开关图2.2.1 ADC.help() 显示信息图2.2.2 采集到1024 个ADC数值图2.3.1 A0输出PWM波形图2.3.2 A0输出PWM波形图2.3.3 抖动的PWM图2.3.4 通过ADC改变PWM占空比