2024年“寒假在家一起练”——RP2040可调PWM
该项目使用了带显示屏的RP2040开发套件,实现了三路可调PWM的设计,它的主要功能为:通过按键与拨轮选择通道与属性,调整输出PWM的周期与占空比。
标签
嵌入式系统
开发板
在家一起练
张伟伟
更新2024-03-29
1020

一.项目介绍

本项目基于带显示屏的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彩屏以及两个可程控按键和一个拨轮,丰富了人机交互功能,可应用信息观察、界面切换等使用方式。

图片.png图片.png

三.实现思路

项目实现可控PWM,可应用micro自带的PWM类来选择管脚输出PWM,通过类属性控制占空比与频率。关键在于人机交互逻辑。项目的实现逻辑见下

图片.png

  • 显示逻辑

该项目需要显示三路PWM的的频率与占空比,考虑表头至少需要显示4*3的列表,同时还需要添加交互时的显示标注,如下图。

图片.png

因此设置了两个偏移变量(横向偏移,纵向偏移)用以辅助显示与选择配置。此外,为简化显示逻辑并提高程序性能,仅当有按键按下时刷新屏幕,且仅刷新变化部分。如当调整通道时,将左侧标识清空并刷新到新位置;当通道配置变化时,将原有数值清空并刷新数值。

  • 占空比处理

由于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开发嵌入式软件,简单易懂的书写方式可快速构建项目原型并迭代,是非常好用的开发工具。未来期望再次参加活动,了解并学习更多的知识,掌握更多的技能,开拓电子芯片在生活中运用的视野。

附件下载
main.py
团队介绍
某不知名工程师
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号