我们来进行两个探究。1. 模拟示波器显示方波脉冲。
2. 通过改变开发板姿态来移动屏幕中文字。
#####探究1:
我们知道,PWM意义为脉冲宽度调制,其原理为通过控制方波脉冲的占空比,来实现模拟连续的时域内的三角函数曲线波,以此实现对模拟物理量的表达,比如声音的振幅,LED的亮度。而ADC转换的意义为 模拟—数字 转换,如果在有ADC功能的引脚输入一个PWM调制后的信号,这个信号会被解调成原本的方波脉冲。我们通过PICO及其扩展板做一个实验来验证这一点。
首先,扩展板将PICO连接到了一个最高支持240X240像素的LCD屏上,使用3.3V电源使能屏幕光源(LED). 屏幕像素的控制是通过四根导线与Pico板的通信实现的,分别是:SCL(控制线), SDA(数据线), DC(直流电线),和RSTn(三项四线电源),其通信方式为I2C。
我们首先来看LCD屏显示的代码:
from machine import Pin, PWM
from time import sleep
import utime
import st7789
from fonts import vga1_16x32 as font2
st7789_res = 0
st7789_dc = 1
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=0, polarity=1, sck=spi_sck, mosi=spi_tx)
disp_width = 240
disp_height = 240
print(spi0)
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=120, rotation=0)
此代码定义了一个函数display, 其本体是等号右边的st7789库里面的ST7789类,调用display时可以使用此函数的其他形式。要实现屏幕的控制,首先需要加载运行这个库.以下为库的部分代码:
def pixel(self, x, y, color):
"""
Draw a pixel at the given location and color.
Args:
x (int): x coordinate
Y (int): y coordinate
color (int): 565 encoded color
"""
self.set_window(x, y, x, y)
self.write(None, _encode_pixel(color))
如注释所示,此函数为ST7789类内的一个行为,调用时可以在屏幕上的一个像素画点。
如果在模块一接上如下代码:
display.fill(st7789.BLACK)
display.text(font2, "text_content", x, y)
display.text(......)
#for i in range(5000):
# display.pixel(random.randint(0, disp_width),
# random.randint(0, disp_height),
#st7789.color565(random.getrandbits(8),random.getrandbits(8),random.getrandbits(8)))
就可以在屏幕上显示想要的内容,内容可在display.text中自定义。最后四行代码可以额外产生雪花般的效果,可以不加。
接下来,我们通过PWM来输出信号,代码如下:
from machine import Pin, PWM
from time import sleep
pwm=PWM(Pin(28))
pwm.freq(200000)
while True:
for duty in range(0,51200,+256):
pwm.duty_u16(duty)
从原理图可以看出,具有PWM功能的28号引脚可以通过跳线连接到蜂鸣器电路,或者连接到外部输出接口。如上图所示,用黄线两端连接三根柱的下面两根就可以控制蜂鸣器(与其他跳线无关)。蜂鸣器的声音大小和频率可以通过占空比(duty)和频率(freq)控制,但由于此函数过于简单实际效果不明显。
如果如图这样跳线,就将信号输出到了27号引脚上,其通过A-D转化后,就读到了原本的脉冲方波信号。将代码整合后,就制作出了简易的方波示波器:
from machine import Pin, PWM
from time import sleep
import utime
import st7789
from fonts import vga1_16x32 as font2
st7789_res = 0
st7789_dc = 1
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=0, polarity=1, sck=spi_sck, mosi=spi_tx)
disp_width = 240
disp_height = 240
print(spi0)
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=120, rotation=0)
spi = machine.SPI(0)
reset = machine.Pin(0)
dc = machine.Pin(1)
oled = st7789.ST7789(spi,240,240,reset,dc)
oled.fill(st7789.BLACK)
key = machine.Pin(6,machine.Pin.IN)
keyleft=machine.Pin(4,machine.Pin.IN)
keyright=machine.Pin(5,machine.Pin.IN)
pwm=PWM(Pin(28))
pwm.freq(200)
potentiometer = machine.ADC(27)
data1=0
mo=500
a=0
###中断函数###
def int_handler(pin):
keyleft.irq(handler=None)
global mo
global dif
if key.value()==1:
a=0
print("key=0")
elif key.value()==0:
a=1
print("key=1")
if keyleft.value() == 0:
if keyright.value() == 1:
print("顺时针")
if mo<1000:
mo=mo+100
if keyright.value() == 0:
print("逆时针")
if mo>100:
mo=mo-100
if keyleft.value() == 1:
if keyright.value() == 0:
print("顺时针")
if mo<1000:
mo=mo+100
if keyright.value() == 1:
print("逆时针")
if mo>100:
mo=mo-100
#oled.text(font2,mo,100,2)
oled.fill(st7789.BLACK)
if mo==100:
dif=80
oled.text(font2, "1000", 100, 2)
if mo==200:
dif=87
oled.text(font2, "900", 100, 2)
if mo==300:
dif=300
oled.text(font2, "800", 100, 2)
if mo==400:
dif=65
oled.text(font2, "700", 100, 2)
if mo==500:
dif=41
oled.text(font2, "600", 100, 2)
if mo==600:
dif=80
oled.text(font2, "500", 100, 2)
if mo==700:
dif=87
oled.text(font2, "400", 100, 2)
if mo==800:
dif=300
oled.text(font2, "300", 100, 2)
if mo==900:
dif=65
oled.text(font2, "200", 100, 2)
if mo==1000:
dif=41
oled.text(font2, "100", 100, 2)
keyleft.irq(handler=int_handler)
keyleft.irq(trigger=machine.Pin.IRQ_FALLING|machine.Pin.IRQ_RISING, handler=int_handler)
###中断实现###
while True:
pwm.duty_u16(60000)
data1 = potentiometer.read_u16()
for x in range (0,240):
data2=data1
data1=potentiometer.read_u16()
if data2>data1:
display.vline(x, data1//mo, (data2-data1)//mo, st7789.BLUE)
elif data1>data2:
display.vline(x, data2//mo, (data1-data2)//mo, st7789.BLUE)
else:
display.hline(x, data1//mo, (data1-data2)//mo, st7789.RED)
display.pixel(x, data1//mo, st7789.WHITE)
display.fill(st7789.BLACK)
其中,有中断注释的部分是为了实现旋钮控制振幅单位(V/div),在最后的while循环外能够产生中断,先跳到中断函数内执行对mo的操作改变这个全局变量的值,再在最后的while循环内代入计算。竖线是通过库函数display.vline实现,但横线hline画不好,暂时未解决。烧录后就可以实现视频的效果。通过改变pwm.freq和pwm.duty_u16的占空比可以展示不同的波形。
#####探究2:
MMA7660是一个三轴加速度传感器,在x,y,z三个方向移动开发板就会由于惯性而在芯片内部产生相应电容的变化,通过算法就可以解算出加速度。通过放大这个加速度,把它作为显示内容的横纵坐标的增量进行迭代,就可以在屏幕上“移动”显示的文字。
请看代码:
from machine import Pin,PWM, I2C, SPI
import st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import time
import struct
from time import sleep
from math import ceil
import utime
import uos
import random
# spi
SCK = Pin(2)
MOSI = Pin(3)
RST = Pin(0, Pin.OUT)
DC = Pin(1, Pin.OUT)
SCL = Pin(11)
SDA = Pin(10)
BUS = 1
width = 240
height = 240
# inititializing SPI and I2C
spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, sck=SCK,mosi=MOSI)
mma7660 = I2C(BUS,scl=SCL, sda=SDA, freq=40000000)
display = st7789.ST7789(spi0, width, height, reset=RST, dc=DC,xstart=0, ystart=0,rotation=0)
display.fill(st7789.color565(255,255,0))
time.sleep(2)
display.fill(st7789.BLACK)
display.text(font2,"Hello MMA7660", 10, 10)
address = mma7660.scan()
print("I2C address:%x", hex(address[1]))
display.text(font2,"I2C addr: %x" %address[1] , 10, 40)
print("激活 MMA7660")
# 向寄存器 0x07写入 1
mma7660.writeto_mem(76, 7, b'1')
key1=machine.Pin(21,machine.Pin.IN)
key2=machine.Pin(22,machine.Pin.IN)
key3=machine.Pin(20,machine.Pin.IN)
st7789_res = 0
st7789_dc = 1
xa=20
ya=20
def disp(xout,yout):
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=0, polarity=1, sck=spi_sck, mosi=spi_tx)
disp_width = 240
disp_height = 240
print(spi0)
global xa
global ya
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)
xa=xa+10*ceil(xout)
ya=ya+10*ceil(yout)
display.text(font2,"HELLO,PICO!",xa,ya,st7789.WHITE)
# The 6-bit measurement data is stored in the XOUT (0x00), YOUT (0x01), and ZOUT (0x02) registers
try:
while True:
x= mma7660.readfrom_mem(76, 0, 6)
y= mma7660.readfrom_mem(76, 1, 6)
z= mma7660.readfrom_mem(76, 2, 6)
xout = struct.unpack('>f', x)[0]
yout = struct.unpack('>f', y)[0]
zout = struct.unpack('>f', z)[0]
disp(xout,yout)
print('x:{:+.10f},y:{:+.10f},z:{:+.10f}'.format(xout,yout,zout))
except KeyboardInterrupt:
print("QUIT")
display.fill(st7789.color565(255,0,0))
display.text(font2, "GOOD BYE", 80, 120)
于是就实现了视频第二段的效果。存留的问题是:无法获得每个轴负向的加速度,导致图案只能往右下方移动。请后续开发者参照MMA7660官方的文档来完善。