- 配置串口参数、开启串口接收中断功能,将串口接收到的Python脚本字符存放在缓存中:
void MCU_InitUART(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
UART_InitTypeDef UART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_UART1, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
UART_StructInit(&UART_InitStructure);
UART_InitStructure.UART_BaudRate = 115200;
UART_InitStructure.UART_WordLength = UART_WordLength_8b;
UART_InitStructure.UART_StopBits = UART_StopBits_1;
UART_InitStructure.UART_Parity = UART_Parity_No;
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
UART_Init(UART1, &UART_InitStructure);
UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);
UART_Cmd(UART1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void UART1_IRQHandler(void)
{
if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)
{
pikaScript_RxData = UART_ReceiveData(UART1);
pikaScript_RxFlag = 1;
UART_ClearITPendingBit(UART1,UART_IT_RXIEN);
if(UART1_RxLength > sizeof(UART1_RxBuffer))
{
UART1_RxLength = 0;
memset(UART1_RxBuffer, 0, sizeof(UART1_RxBuffer));
}
UART1_RxBuffer[UART1_RxLength++] = pikaScript_RxData;
if(pikaScript_RxData == '\n')
{
if(pikaScript_ASM_ReceiveHandler(UART1_RxBuffer, UART1_RxLength))
{
goto line_exit;
}
memcpy(pikaScript_ShellBuffer, UART1_RxBuffer, sizeof(pikaScript_ShellBuffer));
pikaScript_ShellReady = 1;
line_exit:
UART1_RxLength = 0;
memset(UART1_RxBuffer, 0, sizeof(UART1_RxBuffer));
}
}
}
uint8_t pikaScript_ASM_ReceiveHandler(char *RxData, uint32_t RxSize)
{
char buff[64] = {0};
if(0 == codeHeap.ena)
{
uint8_t is_launch_code_recive = 0;
char *strLine = strGetLastLine(buff, RxData);
/* auto erase mode, send python file directly */
if(strIsStartWith(strLine, "import "))
{
is_launch_code_recive = 1;
codeHeap.auto_erase = 1;
codeHeap.content = pikaMalloc(codeHeap.size + 1);
}
/* manual erase mode, send "import" to erase first,
then send the python file.
*/
if(strEqu(strLine, "import\r\n"))
{
is_launch_code_recive = 1;
codeHeap.auto_erase = 0;
codeHeap.wait = 2;
__disable_irq();
obj_deinit(__pikaMain);
codeHeap.content = malloc(pikaScript_ASM_FINIS_ADDRESS - pikaScript_ASM_START_ADDRESS);
if(codeHeap.content == NULL)
{
printf("[error] no enough code buff, please reset the device.\r\n");
while(1);
}
__enable_irq();
printf("[info] in download mode, send python please.\r\n");
}
/* launch the code reciver */
if(is_launch_code_recive)
{
codeHeap.reciveTime = SysTick_Tick;
codeHeap.ena = 1;
RxData = strLine;
}
}
if(1 == codeHeap.ena)
{
if(!pikaScript_MomoryLocked)
{
pikaScript_MomoryLocked = 1;
}
if(codeHeap.wait > 0)
{
codeHeap.wait--;
}
codeHeap.reciveTime = SysTick_Tick;
codeHeap.oldSize = codeHeap.size;
codeHeap.size += RxSize;
/* write to heap buff */
if(codeHeap.auto_erase)
{
codeHeap.content = realloc(codeHeap.content, codeHeap.size + 1);
}
memcpy(codeHeap.content + codeHeap.oldSize, RxData, RxSize);
codeHeap.content[codeHeap.size] = 0;
return 1;
}
/* not work */
return 0;
}
- 实现对MCU内部FLASH的读写操作,定义存储空间区域,用于存放Python脚本源码:
uint32_t pikaScript_FLASH_GetPageNumber(uint32_t Address)
{
return (Address - MM32F327xG_FLASH_START_ADDRESS) / MM32F327xG_FLASH_PAGE_SIZE;
}
void pikaScript_FLASH_EraseUserZone(void)
{
uint32_t StartPage = 0, NumberOfPages = 0;
printf("[info]: erising flash...\r\n");
pikaScript_WriteAddress = 0;
pikaScript_FlashOffset = 0;
memset(pikaScript_FlashBuffer, 0, sizeof(pikaScript_FlashBuffer));
StartPage = pikaScript_FLASH_GetPageNumber(pikaScript_ASM_START_ADDRESS);
NumberOfPages = pikaScript_FLASH_GetPageNumber(pikaScript_ASM_FINIS_ADDRESS) - StartPage + 1;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
while(NumberOfPages--)
{
FLASH_ErasePage(MM32F327xG_FLASH_PAGE_SIZE * StartPage);
FLASH_ClearFlag(FLASH_FLAG_EOP); StartPage++;
}
FLASH_Lock();
printf("[ OK ]: erising flash ok!\r\n");
}
uint32_t pikaScript_FLASH_ProgramWord(uint32_t BaseAddress, uint32_t FlashAddress, char ch)
{
uint32_t pikaScript_FlashData = 0;
if(pikaScript_FlashOffset > 3)
{
pikaScript_FlashOffset = 0;
for(int i = 3; i >= 0; i--)
{
pikaScript_FlashData = pikaScript_FlashData << 8;
pikaScript_FlashData += pikaScript_FlashBuffer[i];
}
__platform_disable_irq_handle();
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_ProgramWord(BaseAddress + FlashAddress, pikaScript_FlashData);
FLASH_ClearFlag(FLASH_FLAG_EOP);
FLASH_Lock();
__platform_enable_irq_handle();
FlashAddress = FlashAddress + 4;
}
pikaScript_FlashBuffer[pikaScript_FlashOffset++] = ch;
return FlashAddress;
}
void pikaScript_FLASH_WriteASM(char *ptr, uint32_t StartAddress, uint32_t FinisAddress, uint32_t Size)
{
for(uint32_t i = 0; i < Size; i++)
{
pikaScript_WriteAddress = pikaScript_FLASH_ProgramWord(StartAddress, pikaScript_WriteAddress, ptr[i]);
}
}
void pikaScript_FLASH_WriteEOF(void)
{
uint32_t StartAddress = pikaScript_ASM_START_ADDRESS;
for(uint8_t i = 0; i < 16; i++)
{
pikaScript_WriteAddress = pikaScript_FLASH_ProgramWord(StartAddress, pikaScript_WriteAddress, '\0');
}
}
void pikaScript_FLASH_SaveString(char *str, uint32_t StartAddress, uint32_t FinisAddress)
{
pikaScript_FLASH_WriteASM(str, StartAddress, FinisAddress, strGetSize(str));
}
- 在定时器中对Python下载进行处理,用于判断是否完成接收,接收完成后存储Python脚本源码:
void pikaScript_ASM_ProgramHandler(void)
{
if(!codeHeap.ena)
{
/* recive not activate */
return;
}
if(codeHeap.wait)
{
/* still waiting */
return;
}
if(SysTick_Tick - codeHeap.reciveTime < 200)
{
/* still reciving */
return;
}
printf("==============[Programer]==============\r\n");
/* transmite is finished */
printf("[info]: recieved size: %d\r\n", codeHeap.size);
/* write to flash from buff (heap.content) */
pikaScript_FLASH_EraseUserZone();
printf("[info]: Writing flash... \r\n");
FLASH_Unlock();
/* write to flash */
pikaScript_FLASH_WriteASM(codeHeap.content,
pikaScript_ASM_START_ADDRESS,
pikaScript_ASM_FINIS_ADDRESS,
codeHeap.size);
/* write EOF */
pikaScript_FLASH_WriteASM("\n\n",
pikaScript_ASM_START_ADDRESS,
pikaScript_ASM_FINIS_ADDRESS,
0x02);
pikaScript_FLASH_WriteEOF();
FLASH_Lock();
printf("[ OK ]: Write flash ok! \r\n");
char *codeInFlash = (char *)pikaScript_ASM_START_ADDRESS;
printf("\r\n");
printf("----[code in flash]-----\r\n");
for(int i = 0; i < strGetSize(codeInFlash); i++)
{
if('\n' == codeInFlash[i])
{
if(codeInFlash[i - 1] != '\r')
{
fputc('\r', (FILE*)!NULL);
}
}
fputc(codeInFlash[i], (FILE*)!NULL);
}
printf("----[code in flash]-----\r\n");
printf("\r\n");
printf("[ OK ]: Programing ok! \r\n");
printf("[info]: Restarting... \r\n");
printf("==============[Programer]==============\r\n");
printf("\r\n");
NVIC_SystemReset();
}
- 系统上电启动后对Python脚本源码进行解析、然后跳转运行:
int main(void)
{
SysTick_Init();
MCU_InitUART();
printf("\r\nPikaScript SZ-III(MM32F3277G9P) %s %s", __DATE__, __TIME__);
pikaScriptInfo();
pikaScript_ASM_Init();
/* boot pikaScript */
char *code = (char *)pikaScript_ASM_START_ADDRESS;
if(((uint8_t)(code[0]) != 0xFF) && ((uint8_t)(code[1]) != 0xFF))
{
/* boot from flash */
pikaMain = newRootObj("pikaMain", New_PikaMain);
__pikaMain = pikaMain;
if(code[0] == 'i')
{
printf("[info]: compiling the python script...\r\n");
main_codeBuff = arg_setStr(NULL, "", code);
pikaCompile("", arg_getStr(main_codeBuff));
NVIC_SystemReset();
}
else
{
pikaVM_runByteCode(pikaMain, (uint8_t *)code);
goto main_loop;
}
}
else
{
/* boot from firmware */
printf("[info]: boot from firmware.\r\n");
pikaMain = pikaScriptInit();
goto main_loop;
}
main_loop:
pikaScriptShell(pikaMain);
/* after exit() from pika shell */
NVIC_SystemReset();
}
在获取/更新完PikaScript源码后,接着在Source\PikaScript文件夹下添加main.py、PikaStdDevice.pyi、MM32F3270.pyi、SHENZHOU3.pyi这4个文件:标准的设备驱动由PikaStdDevice结合MM32F3270来实现的,PikaStdDevice是一个抽象的设备驱动模块,定义了所有的用户API,各个平台的驱动模块只要从PikaStdDevice继承,就能名获得一模一样的用户API,而PikaStdDevice内部会间接调用平台驱动,通过多态特性重写底层的平台驱动,就可以在不同的平台工作了。如果是特定的开发板,你也可以选择不去实现PikaStdDevice也是可行的,通过MM32F3270和SHENZHOU3这两个文件来实现就可以了……
当前没有去实现标准设备库,只是通过MM32F3270.pyi基于SysTick实现了Task功能,这样在Python应用程序的时候,就可以使用Task来创建任务,进行任务调试;如下所示:
#include <stdint.h>
#include "BaseObj.h"
#include "config.h"
#include "dataStrs.h"
extern uint32_t SysTick_Tick;
void MM32F3270_Task_platformGetTick(PikaObj* self)
{
obj_setInt(self, "tick", SysTick_Tick);
}
如果对Task任务调试的时序要求比较高的话,可以将PikaScript的优化配置将原来的PIKA_OPTIMIZE_SIZE切换到PIKA_OPTIMIZE_SPEED,优化后的结果就是在运行速度和代码占用空间这两者之间做了个平衡和取舍。
每一个PikaScript C模块都是由模块接口和模块实现两部分组成,其中SHENZHOU3.pyi实现了一个模块接口,在模块接口中我们可以根据板载的资源去定义不同的类(比如LED、KEY、LCD等等),每个类中再根据功能需求定义不同的调用/实现方法;将SHENZHOU3.pyi添加到KEIL工程进行编译(会报错缺少文件哦),此时会由PikaScript预编译会生成对应的API文件,即相应的模块实现,这是根据模块接口中的类定义来自动生成的,分别对应了多个模块实现(SHENZHOU3_LED-api.c、SHENZHOU3_KEY-api.c、SHENZHOU3_LCD-api.c等等):
将这些模块实现添加到KEIL工程中来,再编译一下,这个时候会报警,有很多函数没有定义:
这时我们就需要新建文件(SHENZHOU3_LED.c、SHENZHOU3_KEY.c、SHENZHOU3_LCD.c),来实现这些调用接口函数,在实现了这些功能之后,我们的Python基建就完成了。
下面看一下SHENZHOU3_LED的具体实现,是不是很简单,其它就是实现PikaScript自动生成的SHENZHOU3_LED-api的接口函数,完成对底层板载LED灯的操作:
#include "SHENZHOU3_LED.h"
#include <stdint.h>
#include "BaseObj.h"
#include "dataStrs.h"
#include "config.h"
void SHENZHOU3_LED_Init(PikaObj* self)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOF, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_WriteBit(GPIOF, GPIO_Pin_6, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_7, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_8, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_9, Bit_SET);
}
void SHENZHOU3_LED_Toggle(PikaObj* self)
{
if(!obj_isArgExist(self, "ledState"))
{
obj_setInt(self, "ledState", 0);
}
int ledState = obj_getInt(self, "ledState");
if(0 == ledState)
{
GPIO_WriteBit(GPIOF, GPIO_Pin_6, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_7, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_8, Bit_SET);
GPIO_WriteBit(GPIOF, GPIO_Pin_9, Bit_SET);
}
else
{
GPIO_WriteBit(GPIOF, GPIO_Pin_6, Bit_RESET);
GPIO_WriteBit(GPIOF, GPIO_Pin_7, Bit_RESET);
GPIO_WriteBit(GPIOF, GPIO_Pin_8, Bit_RESET);
GPIO_WriteBit(GPIOF, GPIO_Pin_9, Bit_RESET);
}
obj_setInt(self, "ledState", (ledState + 1) % 2);
}
import PikaStdLib
import MM32F3270
import SHENZHOU3
snake_sx = 200
snake_sy = 50
snake_ex = 210
snake_ey = 60
snake_size = 10
snake_dir = 1
food_idx = 0
food_sx = [100, 20, 80, 160, 70, 200, 120, 180, 60, 220]
food_sy = [100, 300, 80, 160, 230, 50, 140, 270, 200, 190]
food_ex = [110, 30, 90, 170, 80, 210, 130, 190, 70, 230]
food_ey = [110, 310, 90, 170, 240, 60, 150, 280, 210, 200]
lcd = SHENZHOU3.LCD()
led = SHENZHOU3.LED()
key = SHENZHOU3.KEY()
lcd.Init()
led.Init()
key.Init()
mem = PikaStdLib.MemChecker()
print('Hello PikaScript ^_^')
print('memory used max : ')
mem.max()
lcd.Clear(0)
lcd.ShowText(0, 0, 'SZ-III(MM32):Hello PikaScript!')
lcd.FillArea( 8, 18, 232, 19, 0x07E0)
lcd.FillArea( 8, 18, 9, 312, 0x07E0)
lcd.FillArea(231, 18, 232, 312, 0x07E0)
lcd.FillArea( 8, 311, 232, 312, 0x07E0)
lcd.FillArea(100, 100, 110, 110, 0x07E0)
def led_Task():
led.Toggle()
return
def key_Task():
global snake_dir
keyState = key.Read()
if keyState == 0:
snake_dir = 1
print('KEY WAKEUP : UP')
elif keyState == 1:
snake_dir = 2
print('KEY TAMPER : DOWN')
elif keyState == 2:
snake_dir = 3
print('KEY USER1 : LEFT')
elif keyState == 3:
snake_dir = 4
print('KEY USER2 : RIGHT')
return
def food_Run():
global snake_sx
global snake_sy
global snake_ex
global snake_ey
global snake_dir
global food_sx
global food_sy
global food_ex
global food_ey
global food_idx
sx = food_sx[food_idx]
sy = food_sy[food_idx]
ex = food_ex[food_idx]
ey = food_ey[food_idx]
food_eat = 0
if snake_dir == 1:
if snake_sx == sx:
if snake_sy == ey:
lcd.FillArea(sx, sy, ex, ey, 0xF800)
food_eat = 1
food_idx = food_idx + 1
elif snake_dir == 2:
if snake_sx == sx:
if snake_ey == sy:
lcd.FillArea(sx, sy, ex, ey, 0xF800)
food_eat = 1
food_idx = food_idx + 1
elif snake_dir == 3:
if snake_sy == sy:
if snake_sx == ex:
lcd.FillArea(sx, sy, ex, ey, 0xF800)
food_eat = 1
food_idx = food_idx + 1
elif snake_dir == 4:
if snake_sy == sy:
if snake_ex == sx:
lcd.FillArea(sx, sy, ex, ey, 0xF800)
food_eat = 1
food_idx = food_idx + 1
if food_idx == 10:
food_idx = 0
if food_eat == 1:
sx = food_sx[food_idx]
sy = food_sy[food_idx]
ex = food_ex[food_idx]
ey = food_ey[food_idx]
lcd.FillArea(sx, sy, ex, ey, 0x07E0)
return
def snake_Run():
global snake_sx
global snake_sy
global snake_ex
global snake_ey
global snake_size
global snake_dir
sx = snake_sx
sy = snake_sy
ex = snake_ex
ey = snake_ey
lcd.FillArea(sx, sy, ex, ey, 0x0000)
if snake_dir == 1:
if snake_sy > 20:
snake_sy = snake_sy - snake_size
else:
snake_dir = 4
snake_sx = snake_sx + snake_size
elif snake_dir == 2:
if snake_sy < 310 - snake_size:
snake_sy = snake_sy + snake_size
else:
snake_dir = 3
snake_sx = snake_sx - snake_size
elif snake_dir == 3:
if snake_sx > 10:
snake_sx = snake_sx - snake_size
else:
snake_dir = 1
snake_sy = snake_sy - snake_size
elif snake_dir == 4:
if snake_sx < 230 - snake_size:
snake_sx = snake_sx + snake_size
else:
snake_dir = 2
snake_sy = snake_sy + snake_size
else:
snake_dir = 0
if snake_sx < 10:
snake_sx = 10
if snake_sy < 20:
snake_sy = 20
if snake_sx > 230 - snake_size:
snake_sx = 230 - snake_size
if snake_sy > 310 - snake_size:
snake_sy = 310 - snake_size
snake_ex = snake_sx + snake_size
snake_ey = snake_sy + snake_size
sx = snake_sx
sy = snake_sy
ex = snake_ex
ey = snake_ey
food_Run()
lcd.FillArea(sx, sy, ex, ey, 0xF800)
return
task = MM32F3270.Task()
task.call_period_ms(led_Task, 250)
task.call_period_ms(key_Task, 50 )
task.call_period_ms(snake_Run, 500)
print('Task Running...')
task.run_forever()
---------------------
作者:xld0932
链接:https://bbs.21ic.com/icview-3236202-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。