GetTextBuf(szString, sizeof(szString) - 1);MessageBeep(0);SendChar(0x5, PORT1); // Send CTRL+Aint nLength = strlen(szString);int i;for(i = 0; i < nL..._micropython作用">
赞
踩
简 介: 对于给定的MicroPython移植版本进行了初步的测试。对比之下,MCU中还有很多的模块尚未支持。这些工作需要近期尽快补充测试完毕。
关键词
: MM32,MicroPython
为了能够在第十七届 全国大学生智能车竞赛 中引入基于 MicroPython 开发模式,适合非电子专业背景的同学能够参与智能车竞赛的锻炼。实际上在之前比赛中,基于NXP的OpenMV,OpenART模块都以及采用了MicroPython开发模式,只是这些模块还无法提供更多的端口来满足智能车竞赛车模作品的开发。
下面是逐飞科技提供的基于灵动单片机MM32F3277的开发模块,其中已经初步抑制了MicroPython的环境。
在 调试来自于逐飞的MM32F3277移植有MicroPython开发板 介绍了该开发板的相关信息,并建立了通过REPL进行交互式开发的工具链。
▲ 图1.1.1 逐飞寄送过来的基本模块
利用 STM32 Bootloader 软件组成MicroPython的REPL交互式界面,并可以将剪切板上的MicroPython程序下载到MM32进行直接。同时可以将REPL输出的信息进行显示。
下面是逐飞科技发送过来关于开发版硬件操作说明。
连接正常的主板一块,寄过去的板子已接上屏幕并插入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版本。
基于附带的示例py文件,可以尝试运行显示效果
▲ 图1.2.6 运行LCD180.help()后的结果
运行以上语句,对应会电量LCD屏幕刷新为全屏红色并显示SEEKFREE字样。
原理可以如下链接下载: MM32F3277主板原理图
▲ 图1.2.7 核心主板管脚定义
▲ 图1.2.8 背板接口定义
▲ 图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 部分接口管脚定义
如下是MM32F3277中已经移植好的MicroPython功能。本文对于这些功能进行初步的测试。
▲ 图1.3.1 现在已经移植好的MicroPython辅助功能
from seekfree import GPIO
pinpg1 = GPIO(0x67, 1, 1)
print("Test GPIO .")
while True:
pinpg1.low()
pinpg1.high()
使用示波器测量MM32模块的G7管脚波形。
▲ 图2.1.1 使用示波器测量MM32模块的G7管脚波形
▲ 图2.1.2 G7端口输出的波形
通过上述测试,可以看到MicroPython下对于端口操作的周期大约为:22.28 μ s \mu s μs。
由于上述代码最终是一个死循环,所以需要通过MM32复位才能够从死循环中调出。
为了能够从软件上控制MM32复位,在原来调试端口增加NRST控制线。
▲ 图2.1.3 修改调试端口,增加RST控制端口
对于STM32的MPDLD命令中增加了MM32复位过程。
if(strncmp(szString, "MPDLD", 5) == 0) { // MicroPython Dlownload char 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+B Sleep(100); } SendChar(0x5, PORT1); // Send CTRL+A Sleep(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+B return; }
修改完之后,对于循环程序,也可以很方便自动下载程序了。
from seekfree import GPIO
pinpg1 = GPIO(0x67, 1, 1)
print("Test GPIO .")
while True:
pinpg1.toggle()
▲ 图2.1.4 toggle()函数对应的输出波形
从上述波形来看, toggle( )运行时间稍微比low(), high()慢一些。
现在模块中居然没有time模块,这个模块可以提供延时操作。因此,只能够通过软件延时来实现间隔。
将无线串口HEADER中的C6,C7,GND,+5V引出,测试GPIO输出控制LED。
from seekfree import GPIO led1 = GPIO(0x26, 1, 1) led2 = GPIO(0x27, 1, 0) print('Test LED.') while True: def delay(loop): for _ in range(loop): pass led1.high() led2.low() delay(20000) led1.low() led2.high() delay(20000)
▲ 图2.1.5 LED延时闪烁
▲ 图2.1.6 电路板上的按键与开关
根据前面硬件电路图所示,电路板上集成了四个按键:G0,G1,G2,G3。它们对应的端口为:GPIOG0, G1,G2,G3。
▲ 图2.1.7 开发板上的四个按键
from seekfree import GPIO led1 = 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): pass while True: print([btn1.value(), btn2.value(), btn3.value(), btn4.value()]) delay(50000)
电路板上还有两个拨码开关,分别对应的D14,D15。通过GPIO可以读出它们的状态。测试的方式与上面按键相同。
from seekfree import GPIO print('Test LED.') def delay(loop=50000): for _ in range(loop): pass led1 = 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 测量按键与拨码开关
▲ 图2.2.1 ADC.help() 显示信息
将电磁模块接口的引到面包板上,利用电位器获得不同的电压,发送到A4。
▲ 图2.2.2 采集到1024 个ADC数值
数据的方差: 5。
由于MicroPython不支持浮点运算。所以需要采用整形数完成相关的计算。
from seekfree import ADC,GPIO adc = ADC(0) adc.channel_init(adc.A4) print('Test ADC.') def delay(loop=50000): for _ in range(loop): pass def sqrt(x): left = 0 right = x//2+1 while left < right: middle = left + (right-left+1)//2 square = middle * middle if square > x: right = middle-1 else: left = middle return left SAMPLE_NUM = 1024 adcdim = [0]*SAMPLE_NUM for i in range(SAMPLE_NUM): adcdim[i] = adc.value(adc.A4) print(adcdim) count = 0 for s in adcdim: count += s average = count//SAMPLE_NUM sigma = 0 for s in adcdim: ss = s - average sigma += ss**2 print(sqrt(sigma//SAMPLE_NUM))
测试版上的PWM分别通过A0,A1,A2,A3输出。
from seekfree import PWM,GPIO
pwm = PWM(16000)
pwm.channel_init(pwm.A0, 5000)
print("Test PWM")
▲ 图2.3.1 A0输出PWM波形
▲ 图2.3.2 A0输出PWM波形
from seekfree import PWM,GPIO,ADC pwm = PWM(16000) pwm.channel_init(pwm.A0, 500) adc = ADC(0) adc.channel_init(adc.A4) def delay(loop=50000): for _ in range(loop): pass print('Test PWM...') while True: adcvalue = adc.value(adc.A4) pwmvalue = adcvalue*10000//0x1000 print(adcvalue, pwmvalue) pwm.duty(pwm.A0, pwmvalue) delay(10000)
▲ 图2.3.3 抖动的PWM
通过对采集到ADC进行平均之后,在控制PWM,波形就非常稳定了。
from seekfree import PWM,GPIO,ADC pwm = PWM(16000) pwm.channel_init(pwm.A0, 5000) adc = ADC(0) adc.channel_init(adc.A4) def delay(loop=50000): for _ in range(loop): pass print('Test PWM...') while True: sigma = 0 for i in range(256): sigma += adc.value(adc.A4) adcvalue = sigma//256 pwmvalue = adcvalue*10000//0x1000 pwm.duty(pwm.A0, pwmvalue) delay(1000)
▲ 图2.3.4 通过ADC改变PWM占空比
设置定时器的回调函数。
from seekfree import TIMER,GPIO
led1 = 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移植版本进行了初步的测试。也能够看到这个版本的移植工作还需要一定的丰富。
上述功能需要通过后期的补充进一步改善。
■ 相关文献链接:
● 相关图表链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。