APM32F427, Python, PikaPython, Python, PikaPython, Python, PikaPython, Python, PikaPython, Python, PikaPython, Python, PikaPython, Python, PikaPython, Python, PikaPytho
本帖最后由 wangqy_ic 于 2026-1-22 16:59 编辑
#申请原创#
《在 APM32F427 上运行 Python》https://bbs.21ic.com/icview-3501089-1-1.html
介绍了移植 PikaPython 到 APM32F427 的基础功能,本文介绍 GPIO 驱动移植,目标:点灯。
引入新的必要的包
上一篇文章中,我们在 pikapython\requestment.txt 加入了当时必须的两个包(或者称之为”模块“)。在运行包管理器后,内容被追加了版本信息,变成:
- pikascript-core==v1.13.4
- PikaStdLib==v1.13.4
为了实现点灯,我们增加两个新的包: PikaStdDevice 和 time,内容变更为:
- pikascript-core==v1.13.4
- PikaStdLib==v1.13.4
- PikaStdDevice
- time
再次运行包管理器 pikaPackage.exe,完成后也是会追加合适的版本信息,内容为:
- pikascript-core==v1.13.4
- PikaStdLib==v1.13.4
- PikaStdDevice==v2.4.6
- time==v0.2.2
这4个包是点灯必须的。下面将会增加针对 APM32F427 的自定义包。
加入针对 APM32F427 的模块
新建文本文件 pikapython\apm32f4_pika.pyi,内容:
- # apm32f4_pika.pyi
- from PikaObj import *
- import PikaStdDevice
- class GPIO(PikaStdDevice.GPIO):
- ...
- class UART(PikaStdDevice.UART):
- ...
这是声明了两个类:GPIO 和 UART。
稍后编写 py 脚本的时候,是可以直接使用 apm32f4_pika.GPIO 实例化相应的类。
修改 pikapython\requestment.txt,把 apm32f4_pika 追加到文件末尾:
- pikascript-core==v1.13.4
- PikaStdLib==v1.13.4
- PikaStdDevice==v2.4.6
- time==v0.2.2
- apm32f4_pika
运行 rust-msc-latest-win10.exe,生成必要的内容,可以看到程序的输出类似:
红色框出可以看到有5个包,与 requestment.txt 的内容一一对应。
在 pikascript-api 文件夹下新增了3个文件:
- apm32f4_pika.h
- apm32f4_pika_GPIO.h
- apm32f4_pika_UART.h
这几个文件的内容不用关系,它们是自动生成的,也不需要编辑修改。下面开始编写驱动。
编写驱动
在 pikascript-lib 文件夹下,创建 apm32f4_pika 文件夹,GPIO/UART 的驱动就放在这个文件夹下。简单起见,我们先把全部驱动的代码放在 pikapython\pikascript-lib\apm32f4_pika\apm32f4_pika.c 这个源文件里:
- #include "BaseObj.h"
- #include "dataStrs.h"
- #include "pika_hal.h"
- #include "board.h"
- #include "apm32f427xx.h"
- #include <stdint.h>
- #include <string.h>
- struct platform_data_GPIO
- {
- int port;
- int pin;
- };
- static GPIO_T *const gpios[] = {
- GPIOA,
- GPIOB,
- GPIOC,
- GPIOD,
- GPIOE,
- GPIOF,
- GPIOG,
- GPIOH,
- };
- // 把字符串类型的 Pin 脚名称解析为 port/pin 编号
- static int get_io_port_and_pin(const char *name, int *port, int *pin)
- {
- char ch = 0;
- if (name[0] != 'P' && name[0] != 'p')
- {
- return -1;
- }
- int res = sscanf(name + 1, "%c%d", &ch, pin);
- if (res != 2)
- {
- return -1;
- }
- if (ch >= 'A' && ch <= 'Z')
- {
- *port = ch - 'A';
- }
- else if (ch >= 'a' && ch <= 'z')
- {
- *port = ch - 'a';
- }
- else
- {
- return -1;
- }
- if (*port < 0 || *port > 7 || *pin < 0 || *pin > 15)
- {
- return -1;
- }
- return 0;
- }
- // 打开 GPIO 设备
- int pika_hal_platform_GPIO_open(pika_dev *dev, char *name)
- {
- int port, pin;
- int res = get_io_port_and_pin(name, &port, &pin);
- if (res != 0)
- {
- return -1;
- }
- // 申请一个 GPIO 数据结构体
- struct platform_data_GPIO *data = pikaMalloc(sizeof(struct platform_data_GPIO));
- data->pin = pin;
- data->port = port;
- // 驱动数据指向生成的 GPIO 数据结构体
- dev->platform_data = data;
- return 0;
- }
- // 关闭 GPIO 设备
- int pika_hal_platform_GPIO_close(pika_dev *dev)
- {
- if (NULL != dev->platform_data)
- {
- pikaFree(dev->platform_data, sizeof(struct platform_data_GPIO));
- dev->platform_data = NULL;
- }
- return 0;
- }
- // 读取 GPIO
- int pika_hal_platform_GPIO_read(pika_dev *dev, void *buf, size_t count)
- {
- struct platform_data_GPIO *gpio_data = dev->platform_data;
- uint32_t level = (gpios[gpio_data->port]->IDATA >> gpio_data->pin) & 1;
- memcpy(buf, &level, count);
- return 0;
- }
- // 设置 GPIO
- int pika_hal_platform_GPIO_write(pika_dev *dev, void *buf, size_t count)
- {
- struct platform_data_GPIO *gpio_data = dev->platform_data;
- uint32_t level = 0;
- memcpy(&level, buf, count);
- if (level == 0)
- {
- gpios[gpio_data->port]->BSCL |= (1 << gpio_data->pin);
- }
- else
- {
- gpios[gpio_data->port]->BSCH |= (1 << gpio_data->pin);
- }
- return 0;
- }
- // 使能 GPIO 设备,暂时保持空
- int pika_hal_platform_GPIO_ioctl_enable(pika_dev *dev)
- {
- (void)dev;
- return 0;
- }
- // 禁用 GPIO 设备,暂时保持空
- int pika_hal_platform_GPIO_ioctl_disable(pika_dev *dev)
- {
- (void)dev;
- return 0;
- }
- // 配置 GPIO 设备
- int pika_hal_platform_GPIO_ioctl_config(pika_dev *dev,
- pika_hal_GPIO_config *cfg)
- {
- struct platform_data_GPIO *gpio_data = dev->platform_data;
- if (cfg->dir == PIKA_HAL_GPIO_DIR_OUT)
- {
- // 配置为 输出
- gpios[gpio_data->port]->MODE = (gpios[gpio_data->port]->MODE & (~(3 << (gpio_data->pin * 2)))) | (1 << (gpio_data->pin * 2));
- }
- else
- {
- // 否则为 输出
- gpios[gpio_data->port]->MODE = gpios[gpio_data->port]->MODE & (~(3 << (gpio_data->pin * 2)));
- }
- gpios[gpio_data->port]->PUPD = gpios[gpio_data->port]->PUPD & (~(3 << (gpio_data->pin * 2)));
- switch (cfg->pull)
- {
- case PIKA_HAL_GPIO_PULL_UP: // 上拉
- gpios[gpio_data->port]->PUPD |= (1 << (gpio_data->pin * 2));
- break;
- case PIKA_HAL_GPIO_PULL_DOWN: // 下拉
- gpios[gpio_data->port]->PUPD |= (2 << (gpio_data->pin * 2));
- break;
-
- default:
- break;
- }
- return 0;
- }
- // 提供 ms 延时
- void pika_platform_sleep_ms(uint32_t ms)
- {
- ms_delay(ms);
- }
驱动写完了,把它加入 keil 工程。
需要注意的是,pikascript-lib 目录下因为我们新增的两个包 PikaStdDevice 和 time 都自动生成了相应的源文件,也都需要加入到 keil 工程一起编译。
运行
编译成功,下载程序到开发板。
为了测试新增的包,编写一个测试程序,让 LED2 闪烁 50 次:
- import PikaStdLib
- import PikaStdDevice
- import apm32f4_pika
- import time
- mem = PikaStdLib.MemChecker()
- print('mem.max :')
- mem.max()
- print('mem.now :')
- mem.now()
- led2 = apm32f4_pika.GPIO()
- led2.setPin('PF0')
- led2.setMode('out')
- led2.enable()
- led2.low()
- for i in range(0,50):
- print(i)
- led2.low()
- time.sleep_ms(500)
- led2.high()
- time.sleep_ms(500)
-
- print('over')
因为目前的工程尚未集成文件系统,所以我们不能直接运行这个脚本。好在 PikaPython 项目提供了 pikaStudio 这个工具,可以通过串口发送并执行脚本。下载连接:https://gitee.com/Lyon1998/pikapython/attach_files/1285327/download
下载并执行这个程序:
在红色框处选择串口,波特率并打开。复位一次设备,就能在终端看到串口输出的内容:
勾选红色框处的复选框,把刚才准备好的 py 脚本拖进去~
从图可以看到执行期间串口输出的计数值。下面放一个视频,看看闪灯的效果:
https://bbs.21ic.com/forum.php?mod=attachment&aid=MjQ1NDY4OHxhNDI1ZDE0Y3wxNzg4NTkyMTY4fDB8
小结
PikaPython 提供了统一的驱动模式,只需要在 .pyi 文件声明支持的类,运行 **rust-msc-latest-win10.exe** 后就可以生成相应的程序框架。开发工程师就只需要完成具体的驱动开发就可以达成目标。总体来说还是很方便的。
APM32F427 大存储、高主频的特性,也给 PikaPython 提供了一个非常合适的运行平台, 大家快来试试呀~
@21小跑堂
|
-
打赏榜单
21小跑堂 打赏了 30.00 元 2026-01-28 理由:恭喜通过原创审核!期待您更多的原创作品~~
评论
|