2025寒假练 - 基于带显示屏的RP2040调试平台设计同步脉冲信号发生器
该项目使用了Thonny软件、MicroPython语言,实现了带显示屏的RP2040调试平台的同步脉冲信号发生器的设计,它的主要功能为:使用PIO编程,实现与外部触发信号同步的多通道单脉冲信号发生器,包含1个输入源、8个输出源,且输出延迟能够分别单独调整。
标签
嵌入式系统
RP2040
MicroPython编程
2025寒假在家一起练
脉冲信号发生器
pei
更新2025-03-13
福州大学
12

项目需求

与外部触发信号同步的多通道单脉冲信号发生器

  • 1个输入源,8个输出源
  • 8个通道的输出延迟时间,需要能够单独分别调整,调整范围为100ns-1ms,调整分辨率为10ns
  • 输入信号的单次脉宽测试范围为:10us-500ms
  • 示意图:
    image.png

需求分析

  1. 同步脉冲延迟时间的调整精度为10ns,即频率为100MHz,常规GPIO方法难以满足,需要使用PIO。当PIO状态机频率设定为100MHz时,一条PIO汇编指令的时长为10ns,因此只需调整指令执行次数即可达到对脉冲延时精确控制的目的。
  2. 题目要求输出8路,考虑到RP2040共有两个PIO模块(PIO0、PIO1),且每个PIO模块有4个独立的状态机,正好满足8个输出端口输出延迟时间能够单独分别调整的需求。
  3. 人机交互方面,在LCD上显示的引脚示意图通过形象的字符组成,并利用彩色(颜色对应于端口导线颜色)显示增强可读性。

实现方式及代码说明

一、LCD显示

屏幕显示驱动部分使用板卡自带的st7789.py,以下对各部分进行说明:

  1. 彩色显示:屏幕采用565编码方式,可通过st7789驱动程序中的“color565”函数将红色,绿色和蓝色值(0~255)转换为16位565编码(在屏幕显示中加入彩色的目的是用颜色标记对应端口)
st7789.color565(225,0,255)   # 紫色
  1. 显示逻辑:在本项目中,被选中的参数使用反显(白底黑字,正常显示情况为黑底白字)突出光标位置,而可选位置通过“x“和”y“存储,当移动光标时,原先的光标位置通过”x_old“和”y_old“储存,恢复为正常显示状态,而新光标位置进行反显,大致逻辑如下:
x_old = x_pos
y_old = y_pos
display.text(font1, str((delays[y_pos] // 10**(5-x_pos)) % 10), x[x_pos], y[y_pos], BLACK, WHITE)
display.text(font1, str((delays[y_old] // 10**(5-x_old)) % 10), x[x_old], y[y_old], WHITE, BLACK)

二、按键交互

本项目按键交互采用中断方式实现。当选中了一个参数(某通道延时时间的某一位),对应位置会被高亮,此时按下左上方的按钮(A按钮),对应位数的数字加一;按下中间上方的按钮(B按钮),对应位数的数字减一;左右拨动右上方的按钮可在同一行左右移动,而居中按下可切换到下一个输出通道。同时,选中不同通道时,被选中的通道会在示意图中以叉表现出来(往右拨动按钮的代码逻辑示意如下,其他按钮对应代码的结构相同)。

if(x_pos == 5):
x_pos = 0
else:
x_pos = x_pos + 1

三、PIO实现

由PIO生成与外部触发信号同步的单脉冲信号主要由以下三个部分组成:

1、PIO汇编程序

完整PIO汇编程序如下:

## PIO程序
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def pulse_gen():
wrap_target()
wait(1, gpio, 20) # 等待GPIO20上升沿
mov(x, osr) # 加载延迟参数
label("delay_loop")
jmp(x_dec, "delay_loop") # 延时循环
set(pins, 1) [9] # 输出10ns脉冲
set(pins, 0) # 脉冲结束
wait(0, gpio, 20) # 结束流程,等待下一个上升沿
wrap()

首先,等待GPIO20端口(即CH0)给出输入脉冲的上升沿:

wait(1, gpio, 20)        # 等待GPIO20上升沿

接下来将OSR中的延时时长数据移动到X寄存器中(注意,这是一个复制过程,OSR中的数据不会消失):

mov(x, osr)              # 加载延迟参数

进入延时——通过”jmp“指令循环执行跳过预定的指令周期,”x_dec“表示对X寄存器中的数据自减:

jmp(x_dec, "delay_loop") # 延时循环

最后将对应引脚拉高后再拉低,此处设定脉冲宽度为10ns,并等待低电平以结束整个流程:

set(pins, 1) [9]         # 输出10ns脉冲
set(pins, 0) # 脉冲结束
wait(0, gpio, 20) # 结束流程,等待下一个上升沿

其中,”wait(1, gpio, 20)“指令实际上只是等待输入信号的高电平,需要配合最后的”wait(0, gpio, 20)”以达到效果上检测上升沿的目的。

2、状态机的初始化

完整代码如下:

# 初始化状态机
state_machines = []
for i, pin in enumerate(OUTPUT_PINS):
pio = rp2.PIO(0 if i < 4 else 1)
sm = pio.state_machine(
i % 4, # 分配PIO
pulse_gen,
freq=100_000_000, # 频率为100MHz
set_base=Pin(pin),
in_base=Pin(20) # 设置输入基准为GPIO20
)
sm.active(1)
state_machines.append(sm) # 便于sm管理

将2×4个状态机分配到八个输出端口,并利用Python的一些语法特性使管理便捷。

3、refill_fifo函数:更改延时

每次更改延时时间时,调用此函数,将新的时间放入FIFO并拉取:

# FIFO管理
def refill_fifo():
for i, sm in enumerate(state_machines):
#while sm.tx_fifo() == 0:
delaytime = delays[i] - 6
sm.put(delaytime)
sm.exec("pull()")

功能框图

如图所示:

效果展示

在本项目中,每个“CH”右侧是对应通道的延时,通过按键调整延时,通过另一块RP2040配合PulseView采集波形:

image.png

题目要求输入信号的单次脉宽测试范围为10us-500ms,故选用10us、1ms、500ms三种脉宽的输入信号进行测试,输出结果如下,可得本项目在各脉宽都能正常工作:

10us情况(第一个通道为输入,其余为输出):

image.png

image.png

1ms情况:

image.png

image.png

500ms情况(由于逻辑分析仪采样频率调低,适当增加了输出通道的脉宽):

image.png

image.png

延时时间可随意调整:

image.png

代码附件

见文末附件处(含所使用Micropython固件版本和代码工程文件)。

参考资料

  1. RaspberryPi官方MicroPython文档
  2. RaspberryPi官方数据手册
  3. 硬禾学堂板卡介绍+题目解析直播
  4. DigiKey:Shawn的RP2040教程
  5. Github上的官方MicroPython例程包
  6. 2024年寒假练 - PWM发生器


附件下载
RPI_PICO-20241129-v1.24.1.uf2
项目使用的MicroPython固件版本
PIO_Pulse.zip
工程文件
团队介绍
福州大学 电气工程及其自动化专业 何祥培
团队成员
pei
福州大学 电气工程及其自动化专业
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号