3.1. PIKA - WIRELESS 开发板

我们骄傲地推出PIKA 派 - WIRELESS开发板,这是PikaPython官方首次推出的全流程、手把手教程的开发板。

在这个信息爆炸的新时代,嵌入式编程与Python结合,创造出了前所未有的应用可能性。而PikaPython,作为嵌入式Python的领军力量,成为了许多创新项目的核心动力。

为了培养与帮助下一代的开发者掌握这一创新技术,我们荣誉推出专为技术爱好者与新世代研发者设计的“PIKA 派 - WIRELESS”开发学习板。

“PIKA 派 - WIRELESS”的核心采用了业界知名、学习友好的ESP32S3。该芯片性能卓越、功能多样,绝对能满足您对嵌入式Python的所有探索与实验需求。这块开发板集成了大量的硬件资源(8M的Flash、WIFI与4G通信、众多传感器),并且提供了许多扩展接口,为您在各种项目中展翅翱翔创造了条件。配合此开发学习板,您将得以深度体验PikaPython的魅力,锻炼自己的编程能力,并为未来的技术挑战做好万全的准备。

img

🛠 技术参数一览:

  • 主控:ESP32S3

  • 存储:FLASH 8M, PSRAM 8M, nand FLASH 128MB

  • 通信:WIFI、4G、RS485 接口

  • 显示:LCD 屏幕

  • 传感器:板载温湿度传感器、光敏电阻

  • 其他:蜂鸣器、继电器、12V供电、WS2812

此款开发板完整覆盖了内核移植、驱动适配、模块开发、事件驱动、应用开发到最佳实践的全流程。它旨在帮助开发者快速并深入地学习PikaPython在项目实战中的各种技术,并迅速掌握实战开发能力。

📚 课程亮点:

  1. PikaPython基础移植与脚本启动模式深入讲解

  2. ESP32实战系列,包括驱动适配、事件驱动等核心技术

  3. 深入嵌入式驱动框架设计与应用

  4. 嵌入式编程思想与最佳实践

    image-20230909174529904

我们精心准备的课程不仅确保您能在此开发板上掌握PikaPython的核心技能,还设计了许多案例和实战,确保您可以举一反三,轻松拓展到任何新的平台上。

探索、学习,然后再创新。这不仅是我们的信念,更是我们希望与大家共同实现的目标。期待与您共同探索PikaPython的无限可能!💡

购买链接:https://m.tb.cn/h.5eu8O7B?tk=AgpWdB6P4Op

下面是程住气大佬结合开发板和课程的内容编写的课程笔记,非常值得一读!

3.1.1. CMAKE 内核编译和应用

教程中的 makefile 和 CMake 工程可以在 Win 上运行,这样可以快速进行测试和进行仿真运行,后面可以移植到你的实际硬件平台上(例如 STM32、ESP32等)。

3.1.1.1. 官网

https://pikapython.com/

3.1.1.2. 先下载包管理器:用于拉取pikapython的源码

http://pikapython.com/doc//%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8%E4%B8%8E%E6%A8%A1%E5%9D%97%E7%AE%A1%E7%90%86.html

image

3.1.1.3. 拉取内核源码

新建记事本requestment.txt,输入下面内容。

(不过即使没有这步,包管理器也会自动新建requestment.txt)

pikascript-core
PikaStdLib

其他可用版本查看:https://gitee.com/Lyon1998/pikascript/blob/master/packages.toml

然后执行包管理器,进行拉取代码。

运行预编译rust-msc-latest-win10.exe,它会将python文件预编译到pikascript-api中的C文件中去

image2

3.1.1.4. 编写应用主程序

新建main.c文件,代码如下:

#include<stdio.h>
#include"pikascript.h"

int main(int argc,char **argv)
{
	printf("hello world\r\n");
    //固件启动,需要编译
    PikaObj* pikaMain = pikaScriptInit();
}

3.1.1.5. 内核编译

官方视频是用 visual studio 来做的,这个软件太大了,家里网速慢,同时电脑有现成的 vscode,所以将分别采用 WIN 环境下 makefile 和 CMAKE 来编译。(其实是后续的 ESP32 视频,编译用的是 CMAKE,看不懂所以回头学了 CMAKE + makefile)

下载和安装MinGW32

下载地址: https://www.onlinedown.net/soft/10056269.htm

解压后,添加环境变量后:

95b7f3d6abb74a7212c67620e8db5aa

img

image-20231202162719952

makefile:

1.新建makefile文件,代码如下

2.执行make

TAR = pikapython
# 添加头文件搜索路径
INC = -I ./ -I ./pikascript-core -I ./pikascript-api -I ./pikascript-lib/PikaStdLib

# 寻找源文件.c
SOURCES = $(wildcard *.c ./pikascript-api/*.c ./pikascript-core/*.c ./pikascript-lib/PikaStdLib/*.c)
OBJ = $(patsubst %.c,%.o,$(SOURCES))

# test:
# 	@echo $(SOURCES)
$(TAR):$(OBJ)
	gcc $^ -o $@  $(INC)

%.o:%.c
	gcc -c $^ -o $@ $(INC)

clean:
	rm -rf *.o ./**/*.o ./**/**/*.o $(TAR)

_images/image-20231202154030572-1712804613733-9.png

CMAKE:

CMAKE环境搭建:下载地址:https://cmake.org/download/

img

img

img

img

img

CMAKE开始:

	1.新建CMakeLists.txt文件,代码如下.

    2.新建build文件夹,然后进入build文件,

    3.cmake .. 

	4.make 

  (2.3的步骤是为了简洁工程,cmake会生成一堆中间文件,这样中间文件全部在build文件夹里了)
# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告
cmake_minimum_required(VERSION 3.10)

# 生成工程名字
project(pikapython)

# GLOB查找.c文件
file(GLOB API_SRC ${CMAKE_CURRENT_SOURCE_DIR}/pikascript-api/*.c)
file(GLOB CORE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/pikascript-core/*.c)
file(GLOB LIB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/pikascript-lib/PikaStdLib/*.c)


# 将所有的源文件组合在一起
set(SOURCE_FILES ${API_SRC} ${CORE_SRC} ${LIB_SRC} main.c)
# message("所有的.c文件:",${SOURCE_FILES})

# 添加头文件搜索路径
include_directories(${CMAKE_SOURCE_DIR}/pikascript-core)
include_directories(${CMAKE_SOURCE_DIR}/pikascript-api)
include_directories(${CMAKE_SOURCE_DIR}/pikascript-lib/PikaStdLib)

# 定义工程会生成一个可执行程序
add_executable(pikapython ${SOURCE_FILES})

image-20231202155152260

image-20231202155056347

3.1.1.6. 应用入门

修改main.py文件,加一句print(’hello world!’)

运行预编译rust-msc-latest-win10.exe

编译内核makefile/cmake

执行

_images/image-20231202160754059-1712804613733-17.png

3.1.2. ESP32 入门体验

3.1.2.1. 安装

3.1.2.1.1. 官方入门指南:入门指南

3.1.2.1.2. 下载地址:ESP-IDF下载地址

image-20240215152317535

这里选择 v5.1 版本,【一定一定一定】 要选 v5.1,v5.1.1不行!,v5.1.2也不行,后面会导致奇怪的问题!!!

(后面的截图中可能出现了 v5.1.2,这是当初使用 v5.1.2 的时候的截图,v5.1.2 已经掉坑里了!换回 v5.1 了! 一切以 v5.1 为准!)

下载完,一路next就行 2

3.1.2.2. 新建工程、编译、下载

# 打开esp-idf,切目录(这个目录后续用于插件,创建使用模板)
cd esample/get-start

# 新建工程
idf.py create-project hello

# 设置芯片
idf.py set-target esp32s3

# 编写代码hello.c
#include <stdio.h>
void app_main(void)
{
    printf("hello world,god bless you");
}

# 编译
idf.py build

# 下载代码并开启监听(串口的查看,参看下图)
idf.py flash -p COM8 monitor

# 退出监听,键盘快捷键
ctrl+]

3

4

3.1.2.3. vscode插件

之前的操作都是使用命令行,使用vscode+esp32插件,快乐加倍

3.1.2.4. vscode插件复制

5

打开命令面板:ctrl+shift+p 6

7

8

9

3.1.2.5. 点灯

插件新建工程

10

11

12

原理图 13

插件按钮 14

#include <stdio.h>
#include "driver/gpio.h"
#include "FreeRTOS/freertos.h"
#include "FreeRTOS/task.h"

#define LED2_PIN 4
#define LED1_PIN 7

void led_init(int index)
{
    gpio_config_t led_pin_config;
    led_pin_config.pin_bit_mask = 1<<index;
    led_pin_config.mode = GPIO_MODE_OUTPUT;
    led_pin_config.intr_type = GPIO_INTR_DISABLE;
    led_pin_config.pull_up_en = GPIO_PULLUP_DISABLE;
    led_pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&led_pin_config);
}

void led_on(int index)
{    
    gpio_set_level(index, 1);
    
}

void led_off(int index)
{
    gpio_set_level(index, 0);
}

void app_main(void)
{
    printf("hello gogogo");
    led_init(LED1_PIN);
    led_init(LED2_PIN);
    while(1)
    {
        led_on(LED1_PIN);
        led_off(LED2_PIN);
        vTaskDelay(50);
        led_off(LED1_PIN);
        led_on(LED2_PIN);
        vTaskDelay(50);
    }
    
}

3.1.2.6. 组件开发

在ESP32的开发中,我们经常需要使用一些特定的功能模块,比如OLED显示屏、温湿度传感器、红外遥控器等等。为了方便使用这些模块,我们可以将它们封装成自定义组件,以便在不同的项目中重复使用。pikapython也是以组件形式来做的,可以方便让你移植pika,事半功倍。(我当时不懂组件,移植都是懵的)

本文将介绍如何在ESP32中创建自定义组件。

3.1.2.6.1. 创建组件目录

首先,我们需要在ESP32的工程目录下创建一个名为components的目录,用于存放自定义组件。

在components目录下,我们可以创建一个名为test的子目录,用于存放自定义组件的代码和头文件。

3.1.2.6.2. 创建组件代码

在test目录下,我们可以创建一个名为test.c的文件,用于实现自定义组件的功能。

例如,我们可以在test.c中实现一个名为my_function的函数,用于打印一条消息:

// test.c:
#include "test.h"

#include "stdio.h"

void my_function(void)
{
    printf("test component!\n");
}

3.1.2.6.3. 创建组件头文件

在test目录下,我们还需要创建一个名为test.h的头文件,用于声明自定义组件的接口。

例如,我们可以在test.h中声明my_function函数:

// test.h:
#ifndef test_H

#define test_H

void my_function(void);

#endif

3.1.2.6.4. 在工程中使用自定义组件

现在,我们已经创建了一个名为test的自定义组件。接下来,我们需要在工程中使用它。

首先,我们需要在工程的CMakeLists.txt文件中添加以下代码,以便告诉ESP32编译器在编译时包含test目录:

idf_component_register(SRCS "test.c"
                    INCLUDE_DIRS ".")

然后,我们可以在工程的主代码中包含test.h头文件,并调用my_function函数:

// hello.c:
#include "test.h"

void app_main(void)
{
    my_function();
}

3.1.2.6.5. 编译和运行工程

如果一切正常,你应该能够在终端中看到”Hello, world!”这条消息。

3.1.2.6.6. 更改组件名字,需要在主cmake中修改:

!15

16

3.1.2.7. 总结

在ESP32的开发中,自定义组件是一个非常有用的工具,可以帮助我们更好地组织和重用代码。在本文中,我们介绍了如何创建和使用自定义组件,希望对你有所帮助。

3.1.3. ESP32 移植 PikaPython

3.1.3.1. 近况

有点惭愧,鸽了将近三个月!年中公司在裁员,年底了项目没减,人却少了,工作996二个月,年底不好找工作忍了(万恶的资本)!

等忙完工作,好不容易抽出身。然后就是咳嗽、甲乙丙各种流,低烧、咳嗽、鼻涕将近一个月。肺都要咳出来,我太难了~

3.1.3.2. 下载pika包

pikapython下载包

1

3.1.3.3. 新建工程

参考第二遍教程,新建工程。

3.1.3.4. pikapython作为组件

  1. 新建文件夹components/pikapyhon

  2. 将pika包放入pikapyhon文件夹中

  3. 运行pikaPackage.exe

3.1.3.5. 修改CMAKE

  1. 新建CMakeLists.txt文件,这个跟esp32组件开发有关,每个组件都是由一个CMake来编译

  2. 编写CMake,需要懂CMake知识,

# 匹配所有.c的文件,并赋值给SOURCES变量
file(GLOB_RECURSE SOURCES *.c)

# 组件注册 
# SRCS ${SOURCES} 编译SOURCES变量下的文件
# INCLUDE_DIRS ... 头文件包含
idf_component_register(SRCS ${SOURCES}
                    INCLUDE_DIRS 
                    "pikascript-api"
                    "pikascript-core"
                    "pikascript-lib/PikaStdLib"
                    )

3.1.3.6. 编写主函数

#include <stdio.h>
#include "pikascript.h"

void app_main(void)
{
    printf("aaaa");
    PikaObj* pikaMain = pikaScriptInit();
}

2

3.1.3.7. 心得

移植这个还是挺简单的,跟pikapython内核编译差不多。

主要需要熟悉gcc、CMake、freertos、esp32开发的知识,不然真的无法下手。 如果对上面不是很了解,建议先熟悉上面的知识点,磨刀不误砍柴工。

3.1.4. 串口通信

3.1.4.1. 通过串口进行交互,先熟悉下ESP32的串口代码。下面esp32s3的串口通信代码,实验结果为uart回传。

_images/1-1712804613733-37.png

串口通信代码
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "string.h"
#include "driver/usb_serial_jtag.h"

void app_main(void)
{
    printf("uart test/r/n");
    usb_serial_jtag_driver_config_t usb_cdc = {
        .rx_buffer_size = 65, //环形buf应大于64
        .tx_buffer_size = 65  //环形buf应大于64
    };
    ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usb_cdc)); //安装usb_serial驱动
    // usb_serial_jtag_driver_uninstall(); //卸载usb_serial驱动
    while(1)
    {
        char buf[1] = {0};
        if(usb_serial_jtag_read_bytes(buf, 1, portMAX_DELAY) >0) //阻塞当前任务,直到接收数据
        {
            usb_serial_jtag_write_bytes(buf, 1, portMAX_DELAY);
        }
        vTaskDelay(10/portTICK_PERIOD_MS);
    }
}

3.1.5. 交互运行

3.1.5.1. 交互式运行环境

  • 为了实现在目标平台上的交互式运行,我们需要提供getchar、putchar接口来重载。 getchar从标准输入字符,putchar从标准输出字符,查看pika平台的代码。

  • PIKA_WEAK 就是弱函数,弱函数可以应用到几个模块之间的交互接口,在项目中并行开发多个存在交互模块时,本模块代码需要使用到外部模块接口,但其他模块并未开发完成,此处可以使用弱函数解决,编译链接报错问题。 _images/2-1712804613733-38.png _images/3-1712804613733-39.png _images/4-1712804613733-40.png

//添加重载函数
char pika_platform_getchar() {
  while (1) {
    char buff[1] = {0};
    if (usb_serial_jtag_read_bytes(buff, 1,portMAX_DELAY) > 0) {
      return buff[0];
    }
    return  buff[1];
  }
}

int pika_platform_putchar(char ch) {
  usb_serial_jtag_write_bytes(&ch, 1, portMAX_DELAY);
  return 0;
}
    //在主函数中,增加shell代码
    //必须使用宏PRIu32,否则putchar会卡死,系统不工作。目前还没找到原因,后续有空再来查查
    uint32_t a =5;
    printf("Minimum free heap size: %" PRIu32 " bytes\n",a);
    PikaObj* pikaMain = pikaScriptInit();
    pikaScriptShell(pikaMain);

_images/5-1712804613733-41.png

3.1.5.2. 移植好的shell代码

增加shell的代码gitee地址

3.1.6. 文件系统

3.1.6.1. 文件系统适配

文件系统的适配使 PikaPython 能够从文件加载脚本,进行存储、检索和执行操作。 这可能包括对FLASH存储或SD卡等外部存储介质的支持,以及实现或利用现有文件系统 API。 常见文件系统:选择一个常用文件系统,来提供文件系统的适配,如 fatfs、LittleFS等。

3.1.6.2. 原理图 NAND FLASH

_images/imagasde-1712804613733-42.png

3.1.6.3. 新建sd_fatfs.c sd_fatfs.h文件、修改CMAKE

//sd_fatfs.c
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "driver/gpio.h"
#include "driver/sdspi_host.h"
#include "driver/uart.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "hal/spi_types.h"
#include "sdmmc_cmd.h"

#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_ota_ops.h"
#include "esp_wifi.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "pikaScript.h"
#include "sd_fatfs.h"

static sdmmc_card_t* card;
static bool is_sd_mounted = false;

int sd_fatfs_init(void) {
    esp_err_t ret;
    const char mount_point[] = MOUNT_POINT;

    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = 16 * 1024,
    };

    // Use settings defined above to initialize SD card and mount FAT
    // filesystem. Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience
    // functions. Please check its source code and implement error recovery when
    // developing production applications.

    sdmmc_host_t host = SDSPI_HOST_DEFAULT();
    host.slot = SPI3_HOST;
    spi_bus_config_t bus_cfg = {
        .mosi_io_num = SDSPI_MOSI,
        .miso_io_num = SDSPI_MISO,
        .sclk_io_num = SDSPI_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4000,
    };
    ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
    if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) {
        printf("Failed to initialize SPI bus.\r\n");
        return -1;
    }

    // This initializes the slot without card detect (CD) and write protect (WP)
    // signals. Modify slot_config.gpio_cd and slot_config.gpio_wp if your board
    // has these signals.
    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    slot_config.gpio_cs = SDSPI_CS;
    slot_config.host_id = host.slot;

    printf("Mounting filesystem...\r\n");
    ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config,
                                  &mount_config, &card);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            printf(
                "Failed to mount filesystem. "
                "If you want the card to be formatted, set the "
                "CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.\r\n");
        } else {
            printf(
                "Failed to initialize the card (%s). "
                "Make sure SD card lines have pull-up resistors in place.\r\n",
                esp_err_to_name(ret));
        }
        return -1;
    } else {
        printf("Filesystem mounted\r\n");
        is_sd_mounted = true;
        sdmmc_card_print_info(stdout, card);
    }
    return 0;
}
//sd_fatfs.h
#ifndef SD_FATFS_H
#define SD_FATFS_H

#define MOUNT_POINT "/sd"
#define SDSPI_CS (GPIO_NUM_47)
#define SDSPI_CLK (GPIO_NUM_21)
#define SDSPI_MISO (GPIO_NUM_14)
#define SDSPI_MOSI (GPIO_NUM_13)

int sd_fatfs_init(void);
#endif

3.1.6.4. 在main.c主函数中,初始化文件和添加操作文件的重载函数

//main.c文件 主函数添加
    sd_fatfs_init();
//main.c文件,添加文件重载函数
FILE *pika_platform_fopen(const char *filename, const char *modes)
{
    return fopen(filename, modes);
}

int pika_platform_fclose(FILE *fp) { return fclose(fp); }

int pika_platform_fseek(FILE *fp, long offset, int whence)
{
    return fseek(fp, offset, whence);
}

long pika_platform_ftell(FILE *fp) { return ftell(fp); }

size_t pika_platform_fread(void *ptr, size_t size, size_t count, FILE *fp)
{
    return fread(ptr, size, count, fp);
}

size_t pika_platform_fwrite(const void *ptr, size_t size, size_t count,
                            FILE *fp)
{
    return fwrite(ptr, size, count, fp);
}

3.1.6.5. 在cmake上需要添加编译 SRCS “sd_fatfs.c”


file(GLOB_RECURSE SOURCES *.c)

idf_component_register(SRCS "hello.c"
                    SRCS "sd_fatfs.c"
                    INCLUDE_DIRS ".")

idf_build_set_property(
    COMPILE_DEFINITIONS "-DPIKA_CONFIG_ENABLE" APPEND)

_images/image-1-1712804613733-45.png

3.1.7. os模块引入

os 模块提供了非常丰富的方法用来处理文件和目录,举个栗子:

import os

# 路径的拼接
folder_path = os.path.join("file","user")
print(folder_path) # file\user

# 查看sd文件夹里的文件
os.listdir('/sd')

3.1.7.1. 增加os模块

在requestment.txt增加os,增加完还需要运行pikaPackage.exe包来进行下载,然后执行rust-msc-latest-win10.exe,打包进去

_images/image-10-1712804613733-43.png _images/image-2-1712804613733-44.png

  • 这个特别注意下,参考下图,视频os当时是v0.1.1来做的,现在os版本是v0.1.4了(2024.2.27日),编译报错。其实在报错的时候,有错误提示在最后一个报错提示的,需要v1.12.7以上才可以,而我习惯看错误从一个错误开始看起,以为漏了那个宏定义的步骤。各种找问题,后面看到需要升级版本到v1.12.7,编译通过了,在执行os.listdir(’/sd’)的时候,由于内核PikaPlatform.c改了,需要重载pika_platform_listdir才行,我也是哭死了,为什么这么折磨我,后面对比固件代码,跟固件代码版本一致。成功了,从晚上十点折磨到凌晨4点,一口老血喷出。所以以后务必指明版本,我也没想到版本差别这么大。 _images/image-12-1712804613733-46.png

3.1.7.2. 修改pikapython中的CMAKE

增加os模块编译

_images/image-3-1712804613733-47.png

因为os模块很多代码使用的是linux环境下,所以我们需要把pikapython也设置为linux环境下,在main文件夹下修改CMAKE _images/image-4-1712804613733-48.png

3.1.7.3. 在main文件夹下添加pika_config.h文件

//pika_config.h
#define PIKA_LINUX_COMPATIBLE 1

3.1.7.4. 在py文件引入os

// main.py 更改后记得执行rust-msc-latest-win10.exe
import os
print('hello pikapython!')

3.1.7.5. 修改esp32配置

支持文件系统的长名字和大小写区分

命令:idf.py menuconfig _images/image-5-1712804613733-50.png _images/image-6-1712804613733-49.png _images/image-7-1712804613733-51.png _images/image-8-1712804613733-52.png

  • S为保存,保存后,idf.py fullclean,重新编译下 _images/image-14-1712804613734-53.png

3.1.7.6. 代码

文件系统gitee代码

3.1.8. 串口烧录脚本

回顾上一章的内容,实现了交互和文件系统,这次从串口发送脚本文件保存,并将这个脚本文件启动,实现串口烧录

3.1.8.1. 串口下载python脚本

  • 串口下载 Python 脚本和交互式运行非常类似,仍然是使用 obj_run 内核 API 进行脚本的运行。和交互式运行不同的是,下载 Python 脚本还需要对python脚本进行 存储。

  • obj_run 支持运行字符串形式的 Python 脚本,因此无论以哪种方式存储,只要最后给 obj_run 传入 Python 脚本的字符串即可。所以可以的存储方式有:flash 直接存储、文件系统、外部存储器等。

3.1.8.2. 存储python脚本

  • 存储 Python 源码很简单,将串口接收到的 Python 脚本字符串完整写入 Flash 即可。启动时不使用 pikaScriptInit() 函数,而是手动创建 pikaMain 根对象,再使用 obj_run(pikaMain, code) 运行脚本,code 代表的是存储好的 python 源码。

3.1.8.3. 运行脚本

  • 首先用pikastudio软件通过串口发送的.a文件,然后保存会保存到app.pika 20240325113029 20240325112553

  • 读取脚本

    PikaObj *root= NULL;
    //判断是否文件
    FILE *fp = fopen(PIKA_SHELL_SAVE_APP_PATH, "rb");
    if(fp!=NULL){
        fclose(fp);
        printf("[Info] load app from sd card\n");
        root = newRootObj("pikaMain", New_PikaMain);
        obj_linkLibraryFile(root,PIKA_SHELL_SAVE_APP_PATH);
        obj_runModule(root,"main");
    } else {
      printf("[Info] load app from firmware\n");
      root = pikaPythonInit();

    }
     pikaScriptShell(root);
  • 重启脚本,需要重载函数

void pika_platform_reboot(void){
  // esp_restart();
  abort();
}

3.1.8.4. 擦除脚本

  • 当写脚本的时候,不小心写了死循环,那么将无法通过串口再次烧录了,这时候需要先擦除,再来烧录

  • 擦除脚本

    remove(PIKA_SHELL_SAVE_APP_PATH);
    esp_restart();//擦除之后,需要重启
  • 新建一个任务,用来判断是否擦除脚本

// 创建动态任务
xTaskCreate(eriase_task, "Dynamic Task", 2048, (void *)5, 5, &task_handle);
vTaskDelay(3000/portTICK_PERIOD_MS);

/*IO 操作*/
#define BOOT_GPIO_PIN GPIO_NUM_0
#define BOOT gpio_get_level(BOOT_GPIO_PIN)

void key_init(void)
{
    gpio_config_t gpio_init_struct;
    gpio_init_struct.intr_type = GPIO_INTR_DISABLE; /* 失能引脚中断 */
    gpio_init_struct.mode = GPIO_MODE_INPUT; /* 输入模式 */
    gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 使能上拉 */
    gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 失能下拉 */
    gpio_init_struct.pin_bit_mask = 1ull << BOOT_GPIO_PIN; /* BOOT 按键引脚 */
    gpio_config(&gpio_init_struct); /* 配置使能 */
}

void eriase_task(void *pvParameters) {
  while(1){
    if(BOOT == 0)
      {
        vTaskDelay(10/portTICK_PERIOD_MS); /* 去抖动 */
        if(BOOT == 0)
        {
          //擦除
          printf("remove");
          remove(PIKA_SHELL_SAVE_APP_PATH);
          esp_restart();
        }
      }
       vTaskDelay(10/portTICK_PERIOD_MS);
  }

}

3.1.8.5. 源码地址

串口烧录源码