[MM32生态]Python,让嵌入式应用开发更便捷、更高效、更专注

2023-05-16

 前言

前面分享了基于PikaScript如何在MM32平台上部署Python开发环境的帖子,实现了Python基础开发环境的部署,可以通过串口终端软件在线编写Python,然后直接运行得到结果。

通过Python编程我们是想用来实现应用程序控制的,而非底层驱动程序的实现;基于开发板的底层驱动、以及对板载资源的外设驱动,是在开发板上部署Python开发环境的时候就需要实现的,相当于Python的基建;只有基建实现了,才能够搭建出上层建筑。

那如何实现基于开发板Python的应用编程呢?或者说,怎样才能做到通过Python编程实现对开发板、或者板载外设的控制?如何灵活的下载程序呢?

本文将一步步带你来完成Python在开发板上基建的部署,以及实现上层Python应用程序的开发例程。


 

串口下载Python脚本、运行程序

对于Python开发环境的部署本质还是在KEIL MDK或者IAR EWARM集成开发环境下通过C语言来开发的,编译后生成HEX执行文件,通过J-LINK或者CMSIS-DAP工具将执行文件下载到芯片当中去运行;那我们Python应用程序,是Python脚本源码文件,如何下载到芯片中去运行呢?

PikaScript提供了Python脚本源码解析的功能,它通过将Python脚本源码解析成Pika字节码,然后运行应用功能,所以我们只需要Python脚本源码传送给PikaScript解析运行即可;这样对于Python的存储方式就灵活很多了,你可以选择存放在MCU内部的FLASH空间、可以存放在外部SPI FLASH空间、也可以存放在TF/SD卡中,通过FatFs文件系统读取Python脚本源码给PikaScript解析运行。

我们这边的实现方式是通过串口的方式,将Python脚本源码存放在MCU内部的FLASH中,将串口接收到的Python脚本字符串完整写入到MCU内容FLASH即可。在启动时不再是直接使用pikaScriptInit()函数,而是通过定义的pikaMain根对象,使用obj_run(pikaMain, code)运行脚本功能。

要实现串口下载Python脚本,需要依据你使用的不同芯片进行相应的移植,参考如下几个步骤:

  • 配置串口参数、开启串口接收中断功能,将串口接收到的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();

}

接下来,我们来演示一下通过串口方式来下载Python应用程序,以及查看运行结果:

https://www.bilibili.com/video/BV1s94y1R74x/


 

PikaScript标准库

PikaScript提供了5个标准库,分别是PikaStdLib标准库、PikaStdDevice标准设备、PikaStdData数据结构、PikaStdTask多任务、PikaDebug调试器;基于除了PikaStdDevice标准设备是由我们用户定义和实现的外,其它的都是PikaScript已经完成的功能代码,我们不需要再做修改,直接使用就可以了。

为了使基于PikaScript的Python应用程序对不同平台设备的操作具有统一性,官方提出了PikaStdDevice标准设备库,其中定义了固定的对GPIO、TIM、PWM、ADC、I2C、SPI、UART等基本MCU外设的操作函数,我们只需要根据使用的MCU来进行适配就可以了。


 

PikaScript C模块开发

Python的上层应用程序开发是基于PikaScript这个基建的,而PikaScript C模块开发可以给上层的Python应用程序提供丰富的功能,你可以理解为应用程序调用底层驱动的API接口函数或者库。接下来,我们使用神舟 III号开发板(板载MCU为MM32F3270)在完成串口下载功能的工程模板上,可以根据下面的描述和步骤来操作……

在附件工程中Source\PikaScript文件夹下需要有4个基础文件文件:requestment.txt、pikaPackage.exe、pikaBeforBuild-keil.bat、rust-msc-latest-win10.exe,根据requestment.txt的版本要求,双击pikaPackage.exe获取PikaScript源码到当前目录;pikaBeforBuild-keil.bat文件是用来在KEIL MDK中编译前预处理的指令集合,通过调用rust-msc-latest-win10.exe来自动运行PikaScript预编译器,将Python文件在PC开发时就转换成字节码并打包成一个库,就像C一样,可以通过KEIL进行编译下载到MCU运行,给Python上层应用程序提供基建模块。所以KEIL中需要有如下配置:

在获取/更新完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);

}



参考SHENZHOU3_LED的实现方法,结合SHENZHOU3_KEY-api和SHENZHOU3_LCD-api的所需要实现的接口函数,就可以轻松完善整个工程代码啦……

Python应用示例

通过编写Python应用程序,在神舟III号开发板上实现一个贪吃蛇的小程序功能示例:

复制

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所有,任何人未经允许禁止转载。 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[MM32生态]Python,让嵌入式应用开发更便捷、更高效、更专注 的相关文章

  • 通过 Python 与 Windows 控制台应用程序交互

    我在 Windows 上使用 python 2 5 我希望通过 Popen 与控制台进程交互 我目前有一小段代码 p Popen console app exe stdin PIPE stdout PIPE issue command 1
  • 使用 Flask SQLAlchemy 进行表(模型)继承

    我遵循了这个建议question https stackoverflow com questions 1337095 sqlalchemy inheritance但我仍然收到此错误 sqlalchemy exc NoForeignKeysE
  • Python中#和"""注释的区别

    开始用 Python 编程 我看到一些带有注释的脚本 and comments 这两种评论方式有什么区别 最好的事情就是阅读PEP 8 Python 代码风格指南 https www python org dev peps pep 0008
  • 使用 python 通过搜索端点从 Spotify API 获取曲目

    因此 我尝试使用 API 的搜索端点进行搜索 从而从 Spotify API 获取曲目 请参阅文档 https developer spotify com documentation web api reference search sea
  • 运行源代码中包含 Unicode 字符的 Python 2.7 代码

    我想运行一个在源代码中包含 unicode utf 8 字符的 Python 源文件 我知道这可以通过添加评论来完成 coding utf 8 在一开始的时候 但是 我希望不使用这种方法来做到这一点 我能想到的一种方法是以转义形式编写 un
  • 用于打印 C/C++ 文件的所有函数定义的 Python 脚本

    我想要一个 python 脚本来打印 C C 文件中定义的所有函数的列表 e g abc c定义两个函数为 void func1 int func2 int i printf d i return 1 我只想搜索文件 abc c 并打印其中
  • 代理阻止网络套接字?如何绕行

    我有一个用 Python 编写的正在运行的 websocket 服务器 来自https github com opiate SimpleWebSocketServer https github com opiate SimpleWebSoc
  • Python3模拟用另一个函数替换函数

    如何使用 python 中的另一个函数来模拟一个函数 该函数也将提供一个模拟对象 我有类似以下操作的代码 def foo arg1 arg2 r bar arg1 does interesting things 我想替换的实现bar函数 让
  • 打印一个 Jupyter 单元中定义的所有变量

    有没有一种更简单的方法来以漂亮的方式显示单个单元格中定义的所有变量的名称和值 我现在做的方式是这样的 但是当有30个或更多变量时我浪费了很多时间 您可以使用whos http ipython readthedocs io en stable
  • 检查对象数组中的多个属性匹配

    我有一个对象数组 它们都是相同的对象类型 并且它们有多个属性 有没有办法返回一个较小的对象数组 其中所有属性都与测试用例 字符串匹配 无论该属性类型是什么 使用列表理解all http docs python org 3 library f
  • Selenium 网页抓取与动态内容和隐藏数据表上的美丽汤

    真的需要这个社区的帮助 我正在使用 Selenium 和 Beautiful Soup 对 Python 中的动态内容进行网页抓取 问题是定价数据表无法解析为 Python 即使使用以下代码 html browser execute scr
  • Python将csv数据导出到文件中

    我有以下运行良好的代码 但我无法修剪数据并将其存储在数据文件中 import nltk tweets love this car this view amazing not looking forward the concert def g
  • Scrapy - 不会爬行

    我正在尝试运行递归爬行 由于我编写的爬行不能正常工作 因此我从网络上提取了一个示例并进行了尝试 我真的不知道问题出在哪里 但是爬行没有显示任何错误 谁能帮我这个 另外 是否有任何逐步调试工具可以帮助理解蜘蛛的爬行流程 非常感谢任何与此相关的
  • 如何从c++调用python

    我是Python新手 我尝试像这样从 C 调用 python 脚本 在 Raspberry Pi 中 std string pythonCommand python Callee py a b int res system pythonCo
  • 写入 UDP 套接字会被阻塞吗?

    如果是的话 在什么条件下 或者 换句话说 在twisted 中运行此代码是否安全 class StatsdClient AbstractStatsdClient def init self host port super StatsdCli
  • tweepy 流到 sqlite 数据库 - 语法错误[重复]

    这个问题在这里已经有答案了 可能的重复 tweepy 流到 sqlite 数据库 语法无效 https stackoverflow com questions 9434205 tweepy stream to sqlite database
  • 对 pandas 数据框中的每一列应用函数

    我如何以更多的熊猫方式编写以下函数 def calculate df columns mean self df means for column in df columns columns tolist cleaned data self
  • 在没有numpy的情况下在python中分配变量NaN

    大多数语言都有一个 NaN 常量 您可以使用它为变量分配值 NaN python 可以在不使用 numpy 的情况下做到这一点吗 是的 使用math nan https docs python org 3 library math html
  • Elastic Beanstalk 上的 Django + MySQL - 查询 MySQL 时出错

    当我在 Elastic beanstalk 上托管的 Django 应用程序上查询 MySQL 时 出现错误 错误说 admin login 处出现操作错误 1045 用户 adminDB 172 30 23 5 的访问被拒绝 使用密码 Y
  • 使用Python的timeit获取“全局名称'foo'未定义”

    我想知道执行一条Python语句需要多少时间 所以我上网查了一下 发现标准库提供了一个名为timeit http docs python org library timeit html旨在做到这一点 import timeit def fo

随机推荐

  • 机器人定位误差标定模型

    概述 以工业机器人为基础 xff0c 构建柔性制造单元或柔性生产线 xff0c 实现产品自动化 柔性化 智能化生产必将成为现代制造发展的重点 新型产业环境下 xff0c 工业机器人的应用范围将越来越广泛 作业任务也将越来越精细复杂 xff0
  • 觉得C/C++难懂的、面临找工作面试笔试的,速来看这本书!

    如果你是C C 43 43 的初学者 xff0c 请看这本书 xff0c 因为其他的书也许你看了还不如不看 xff0c 一定要选一本好书 xff1b 如果你正准备求职 xff0c 那么请认真看这本书 xff0c 因为这本书会教会你工作中必备
  • rosdep update错误失败一直timeout解决方法

    更新rosdep 终端输入 rosdep update 失败1 The read operation timed out xff08 包括ERROR unable to process source xff0c ERROR error lo
  • bat, shell脚本ssh自动输入密码

    我电脑是win11 xff0c 并且自带ubuntu系统 xff0c 打开cmd xff0c 然后输入ubuntu xff0c 可以直接进入ubuntu系统 xff0c 然后执行简单的linux命令 我在两个系统下都写了自动连接远程服务的脚
  • FreeRtos 文件结构

    最核心的三个文件 1 xff09 tasks c 2 xff09 list c 3 xff09 queue c tasks c 任务相关 list c 为一个双向链表 queue c 队列 xff0c 信号量用于任务间通讯 4 xff09
  • 论文超详细精读:SMPL: A Skinned Multi-Person Linear Model

    文章目录 前言总览一 Introduction二 Related WorkBlend Skinning xff08 混合蒙皮 xff09 Blend shapes xff08 混合变形 xff09 Learning pose and sha
  • 1、列表推导式、字典推导式

    34 34 34 1 列表推导式 xff1a 作用 快速生成列表 需求1 xff1a 如何快速生成一个 34 data0 34 34 data1 34 34 data99 34 的列表 语法 xff1a y for x in xxx 实现
  • pwm超详细解读,大佬细说pwm的控制方式

    pwm xff0c 也就是常说的脉冲宽度调制脉冲宽度调制技术 目前 xff0c pwm技术的应用是非常多的 为了增进大家对pwm的认识 xff0c 本文将对pwm 的几种控制方法进行详细的阐述 xff0c 保证大家彻底理解 如果你对pwm
  • WiFi信号覆盖面积小?如何扩大Wifi信号覆盖范围?

    WiFi已是现代生活不可缺少的组成之一 xff0c 在WiFi的帮助下 xff0c 一个家庭网络或办公网络 xff0c 能够通过无线的方法连接诸多设备 为增进大家对WiFi的认识 xff0c 本文将对WiFi以及扩大WiFi信号覆盖范围的方
  • 数据存储方式有哪些?这3种数据存储方式了解吗?

    数据存储具有很强的现实意义 xff0c 只有采取合理的数据存储方式 xff0c 才能够有利于数据的管理 检索等 为增进大家对数据存储方式的认识 xff0c 本文将对三种数据存储方式予以介绍 如果你对数据存储方式具有兴趣 xff0c 不妨继续
  • 这里带你了解IR2104驱动电路

    Ir2014驱动电路及自举电容的应用 以前做智能车的时候用H桥驱动电路 xff0c 驱动芯片就是用的IR2104 xff0c MOS管用的IR7843 xff0c 想把以前的知识总结一下 1 为什么需要H桥电路 因为驱动电机正反转 xff0
  • 什么是神经网络模型,常见神经网络模型有哪些?

    神经网络模型是机器学习 深度学习的核心 xff0c 针对不同的问题 xff0c 我们需要搭建不同的神经网络模型 为增进大家对神经网络模型的认识 xff0c 本文将对常见的神经网络模型予以介绍 如果你对神经网络模型具有兴趣 xff0c 不妨继
  • STM32L431使用TencentOS tiny操作系统连接腾讯物联网开发平台

    去年腾讯为了宣传自己针对物联网的开源操作系统TencentOS tiny xff0c 举办了一场试用活动 xff0c 当时幸运获得一块 板子实物就这样 xff0c 没啥好介绍的 xff0c 都是基础的外设 xff0c 如今闲来无事 xff0
  • [总线技术]汽车ECU网络传输-诊断协议测试-基于Canoe软件CAPL脚本编写

    一 xff0e 汽车电子电控结构 先介绍一下汽车电子电控的结构 xff0c 汽车并不像电脑一样 xff0c 只有一个CPU xff0c 而是分为多个 CPU 独立工作 xff0c 就是由很多很多个控制器组成的 xff0c 比如 xff1a
  • [STM32F1]关于STM32F103芯片按钮机制串口发送程序

    就是目前遇到一个项目 xff0c 是监视各个按钮状态并将各个按钮的状态发送至上位机 xff0c 上位机进行整体程序逻辑动作 一般情况下串口发送可以直接一直发送给上位机 xff0c 通过解析不同数据位0和1的状态可以知道具体哪个按钮按下 xf
  • [uCOS/RTOS]freertos——创建任务(一)

    FreeRTOS操作系统学习 前言 FreeRTOS操作系统的学习正式开始 一 了解FreeRTOS FreeRTOS共有32个优先级 xff08 0 31 xff09 使用时0和31不使用 优先级规则 xff1a 数字越大优先级越高 任务
  • 基于FreeRTOS的UART空闲中断框架设计

    设计背景 xff1a 针对大部分国产低端MCU ARM CortexM0 来说 xff0c 并没有空闲中断 xff0c 此时就需要一个定时器Timer配合来完成此任务 对于UART接受不定长数据 xff0c 空闲中断还是非常实用的 xff0
  • 2、可迭代对象与迭代器

    1 Iterable 可迭代对象 概念 xff1a python中能够使用for循环遍历的都是可迭代对象 1 常见的可迭代对象 1 1 序列如 xff1a list str tuple range 1 2 非序列 xff1a dict se
  • 帮你分清嵌入式与单片机

    从事计算机和或电子行业相关领域工作的朋友 xff0c 一般都听说过单片机和嵌入式 但是要问单片机和嵌入式两者之间有什么联系 xff0c 大多数人都不能很好的解释清楚 想要弄清楚嵌入式和单片机有什么联系 xff0c 首先就要弄明白什么是嵌入式
  • [MM32生态]Python,让嵌入式应用开发更便捷、更高效、更专注

    前言 前面分享了基于PikaScript如何在MM32平台上部署Python开发环境的帖子 xff0c 实现了Python基础开发环境的部署 xff0c 可以通过串口终端软件在线编写Python xff0c 然后直接运行得到结果 通过Pyt