一.项目介绍
本项目基于带显示屏的RP2040平台,实现了输出可调3路PWM波的功能。项目的具体要求如下
- 使用RP2040的PIO编程,生成3路最高重复频率为12MHz的PWM信号,每一路的重复频率和占空比都可独立调节
- 重复频率越高,占空比分辨率降低(主时钟120MHz为例),占空比的调节精度最高设定为1/1000
- 使用按键和拨轮组合调节输出输出频率、占空比,并由按键控制每一路PWM信号的输出
- 能在LCD上显示基础信息如当前使用引脚示意、引脚相应的PWM参数
二.平台介绍
RP2040具有9根GPIO,功能灵活,通过搭配不同程序可以做成各种调试器。RP2040芯片具有双Arm Cortex M0+内核,默认运行的125MHz时钟超频到200MHz也可稳定运行,搭载的PIO功能使其可以生成各种常用或者自定义的协议,开发语言可以选择MicroPython或C/C++且官方文档例程丰富,(本项目采用micropython)适用于初学者快速入门应用的同时也可开发出芯片极致性能。
此外,本开发板配备了一块240*240分辨率的LCD彩屏以及两个可程控按键和一个拨轮,丰富了人机交互功能,可应用信息观察、界面切换等使用方式。
三.实现思路
项目实现可控PWM,可应用micro自带的PWM类来选择管脚输出PWM,通过类属性控制占空比与频率。关键在于人机交互逻辑。项目的实现逻辑见下
- 显示逻辑
该项目需要显示三路PWM的的频率与占空比,考虑表头至少需要显示4*3的列表,同时还需要添加交互时的显示标注,如下图。
因此设置了两个偏移变量(横向偏移,纵向偏移)用以辅助显示与选择配置。此外,为简化显示逻辑并提高程序性能,仅当有按键按下时刷新屏幕,且仅刷新变化部分。如当调整通道时,将左侧标识清空并刷新到新位置;当通道配置变化时,将原有数值清空并刷新数值。
- 占空比处理
由于PWM占空比仅支持0-65535的整数赋值,无法以10倍的分辨度递进,因此采取了近似与倍增的的方式,将65535等分为1000份,则每份取证为65,每增加一个刻度,将占空比数值增加65。由此避免了无法整除以及产生小数的问题。
四.代码与实现效果
项目主要代码见下,实现逻辑可参照注释与视频讲解
import uos
import test.st7789 as st7789
from test.fonts import vga2_8x8 as font1
from test.fonts import vga1_16x32 as font2
import random
import framebuf
from machine import Pin, SPI, ADC,PWM
import time, math,array
from utime import sleep_ms
import struct
#将主频设为240M,由此可以产生120MHz的脉冲
machine.freq(240000000) # set the CPU frequency to 240 MHz
#配置显示器
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=Pin(2)
spi_tx=Pin(3)
spi0=SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
reset=machine.Pin(st7789_res, machine.Pin.OUT),
dc=machine.Pin(st7789_dc, machine.Pin.OUT),
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.text(font1, "select a channel", 10, 10)
display.text(font1, " no duty frq", 10, 40)
display.text(font1, " 1", 10, 70)
display.text(font1, " 2", 10, 100)
display.text(font1, " 3", 10, 130)
#配置按键
buttonM = Pin(5,Pin.IN, Pin.PULL_UP) #B
buttonS = Pin(6,Pin.IN, Pin.PULL_UP) #A
buttonL = Pin(7,Pin.IN, Pin.PULL_UP) #A
buttonR = Pin(9,Pin.IN, Pin.PULL_UP) #A
#初始化偏移量 no为当前通道 select为配置属性
no=0
select=0
#配置通道
pwm=[PWM(Pin(20)),PWM(Pin(21)),PWM(Pin(22))]
pwmattr=[1,1,1]
dutyattr=[500,500,500]
for i in pwm:
i.freq(120)
i.duty_u16(32768)
#6个频率挡位
freq=[120,1200,12000,120000,1200000,12000000]
#显示PWM信息
display.text(font1, str(pwm[0].freq()), 140, 70)
display.text(font1, str('{:.3f}'.format(pwm[0].duty_u16()/65535)), 60, 70)
display.text(font1, str(pwm[1].freq()), 140, 100)
display.text(font1, str('{:.3f}'.format(pwm[0].duty_u16()/65535)), 60, 100)
display.text(font1, str(pwm[2].freq()), 140, 130)
display.text(font1, str('{:.3f}'.format(pwm[0].duty_u16()/65535)), 60, 130)
#主循环
while True:
#按键信息归一化,若按下数值为1
buttonValueM = int(not(buttonM.value()))
buttonValueS = int(not(buttonS.value()))
buttonValueL = int(not(buttonL.value()))
buttonValueR = int(not(buttonR.value()))
#选择通道,有按键按下时才刷新通道选择
if buttonValueM or buttonValueS:
display.text(font1, " ", 10, 70)
display.text(font1, " ", 10, 100)
display.text(font1, " ", 10, 130)
display.text(font1, " ", 10, 30)
no=(no+buttonValueM)%3
select=(select+buttonValueS)%2
display.text(font1, " *", 10, 70+30*no)
display.text(font1, " *", 40+100*select, 30)
#选择属性,有按键按下时才刷新配置选择与配置
if buttonValueL or buttonValueR:
if select==1:
current_value=pwmattr[no]
if buttonValueL :
pwmattr[no]=max(current_value-1,0)
else :
pwmattr[no]=min(current_value+1,5)
pwm[no].freq(freq[pwmattr[no]])
display.text(font1, str(pwm[no].freq())+" ", 140, 70+30*no)
#打印当前通道与频率
print(no,pwm[no].freq())
else :
#占空比需要输入整型,为避免变量类型转换带来的精度误差,直接采用乘法与整型来计算占空比
offset=pow(10,max(pwmattr[no],3)-3)
if buttonValueL :
dutyattr[no]=max(dutyattr[no]-offset,0)
else:
dutyattr[no]=min(dutyattr[no]+offset,1000)
#由于占空比有效值为0-65535,若取1/1000的精度则最小刻度为65.535,取65
pwm[no].duty_u16(65*dutyattr[no])
display.text(font1, "0."+str(dutyattr[no]), 60, 70+30*no)
#打印当前通道与占空比
print(no,pwm[no].duty_u16())
#等待0.1s
time.sleep(0.1)
实际效果见下,展示了调节占空比与通道的效果
五.遇到的问题
本项目中的主要问题在于显示布局与PWM配置有些繁琐,遇到的技术问题阅读官方文档便可解决。
六.感想与体会
本项目中使用micropython开发嵌入式软件,简单易懂的书写方式可快速构建项目原型并迭代,是非常好用的开发工具。未来期望再次参加活动,了解并学习更多的知识,掌握更多的技能,开拓电子芯片在生活中运用的视野。