项目需求
具体要求:利用板上的电位计调节电压从0-3.3V之间变化,在OLED显示屏上显示电压值,可以以数字的方式,也可以以图形的方式来显示
一.硬件介绍:
2个按键输入
4个单色LED
12个WS2812B RGB三色灯
1个姿态传感器
1个128*64 OLED显示屏
1个蜂鸣器
1个可调电位计(用于电压表)
1路音频信号输入(用于示波器)
8位R-2R电阻网络构成的DAC(用于DDS信号发生器)
二.设计思路:
将电位器的电压读数通过ADC模块读取,并在OLED屏幕上显示出来。具体来说,它将电位器读数映射到OLED的0到55的范围上,并以这个范围为基础在OLED屏幕上绘制波形。还使用定时器中断函数,每隔一段时间将电压值在OLED屏幕的第56到第63行之间显示出来。
在代码实现上,首先通过导入相关模块和库文件初始化电位器的读数,设置OLED屏幕宽度并定义一个定时器中断函数。然后,在主程序中,它先将电位器的读数映射到OLED屏幕的0到55范围,并将每次读数加入到一个长度为128的数组中。接着,它在OLED屏幕上绘制波形,将读数值映射到y坐标,将数组中存储的历史读数映射到x坐标,使用oled.line()函数连接所有的坐标点。最后,使用OLED屏幕的show()函数显示波形,并使用sleep()函数设置每隔0.1秒更新一次屏幕。同时,通过定时器中断函数,每隔10毫秒在OLED屏幕上显示当前的电压值。流程图如下:
三.实现过程:
使用的硬件框图如下:
使用的硬件资源介绍:
1.ADC:
STEP Pico具有一些内置的硬件外设,其中包括两个12位精度的ADC(模数转换器),每个ADC有3个输入通道。这些ADC可用于将模拟信号转换为数字信号,以供微控制器进行处理。
Pico的ADC支持单端输入和差分输入,它的测量范围是0到3.3V,具有12位的精度,可以测量的电压分辨率为3.3V/2^12=0.0008V。由于Pico的输入电阻比较高,可以达到5兆欧,因此可以使用高阻抗的传感器直接连接到Pico的ADC输入端。
在Micropython中,可以通过 machine.ADC(pin) 方法来初始化ADC对象,其中pin是要读取的ADC通道的引脚号,一般使用 Pin 对象来表示。
本次项目中,要读取Pico的第二个ADC通道(GPIO28引脚)的电压值,可以使用以下代码:
from machine import ADC, Pin, Timer
dianweiqi = ADC(Pin(pin_cfg.pot))
voltage = dianweiqi.read_u16()
其中,read_u16() 方法用于读取ADC的原始值(0~65535),voltage 变量是通过将原始值转换为实际电压值计算得出的。
2.Timer:
本次项目中通过定时器中断实现了每10ms读取一次电位器的电压值,并将其转换为实际电压值并在OLED屏幕上显示。定时器中断是一种常见的编程技术,可以通过设置定时器周期和回调函数,让回调函数在每个周期中被自动调用。这种技术可以用于各种应用场景,比如周期性读取传感器数据、控制执行器、实现定时任务等等。
# 定义定时器中断函数
def on_timer(timer):
v = dianweiqi.read_u16()
oled.text("Voltage: %.2fV" % (v * 3.3 / 65535), 0, 56)
# 初始化定时器
tim = Timer(-1)
tim.init(period=10, mode=Timer.PERIODIC, callback=on_timer)
在这段代码中,使用Timer模块初始化一个定时器,并将回调函数on_timer注册为中断服务函数。在on_timer函数中,读取电位器的值并转换为实际电压值,并将其显示在OLED屏幕上的第56行。由于这个回调函数每10ms被调用一次,因此可以实时显示电压值,以便进行实时监测和调试。
3.OLED
7线SPI驱动的OLED(Organic Light Emitting Diode)屏幕是一种常见的显示设备,其显示效果好,视觉效果高。本项目中的OLED屏幕使用SPI总线进行通信。使用了micropython官方提供的spi驱动函数,并结合oled的控制命令及数据信号,向OLED屏幕发送需要显示的内容。通过定时器定时刷新电压值,保证屏幕内容的及时更新和显示。同时,还使用了ADC模块读取电位器端的电压值,并将其转化为对应的波形高度,并通过spi方式向OLED屏幕发送,达到实时显示的效果。
from oled import oled
#55 - 实现了3.3v在屏幕顶端,符合观感
Voltage_transfer = 55 - int(dianweiqi.read_u16() * 55.0 / 65535.0)
#将下一个读取的电位器值放到前一位实现波形的左移变化
for i in range(127):
oled_width[i] = oled_width[i + 1]
oled_width[127] = Voltage_transfer
#清空oled
oled.fill(0)
#描点成线
for i in range(128):
if i >= 1:
oled.line(i - 1, oled_width[i - 1], i, oled_width[i], 1)
#把buffer内容显示出来
oled.show()
sleep(0.1)
以下是一些用到的函数:
oled.fill(0):清除OLED屏幕上的所有内容,将屏幕的像素点设置为0。
oled.text(str, x, y):在OLED屏幕上指定的坐标(x,y)处显示字符串。
oled.line(x0, y0, x1, y1, color):在OLED屏幕上绘制一条直线。起点和终点坐标由(x0,y0)和(x1,y1)给出,color指定线条的颜色。
还有其他可用于控制OLED屏幕的函数,包括oled.pixel(),oled.hline(),oled.vline(),oled.rectangle()等,它们的功能各不相同。可以参考OLED屏幕的驱动文档来了解更多细节。
4.电位计
在本次项目中,电位计由一根可调的电阻组成,一端连接电源,一端接地,另一端连接测量电路。通过调整电位计的电阻值,可以改变电路中的电压和电流,从而实现对物理量的测量和调节。在代码中,通过ADC采集电位计的电压值,并将其转换为电位计的电压,从而实现OLED显示。
项目完成图示:
通过旋转电位计,波形和电压值都是会显示在OLED上,实现电压表的功能。
四.遇到问题
一开始并未用定时器中断读取ADC的值,这样在oled上的显示是一直跳变的,显示效果不好。后面是通过定时器中断读取,使用定时器中断显示电压值,可以将该任务交由硬件完成,不需要在主循环中反复查询电压,减少了CPU的负担,节省了系统资源。同时,使用定时器中断可以实现高精度的定时,不受主循环中其他代码的影响,可以更加精准地执行该任务。此外,由于定时器中断的优先级较高,因此即使在主循环中有其他中断产生,也不会对该任务的执行产生影响,可以保证电压值的实时性和准确性
五.展望未来
了解到扩展板上有8位R-2R电阻网络构成的DAC(用于DDS信号发生器),之后打算学习和使用这个DAC。用8位R-2R电阻网络构成的DAC可以用于生成精确的模拟信号。打算用这个DAC生成一个幅度为0到3.3V,频率为1kHz的三角波。首先,设置一个1kHz的定时器中断,每次中断时增加一个计数器变量。然后,将该计数器变量作为DAC的输入,即每次中断时通过DAC输出一个8位数字。将数字乘以3.3/256得到0到3.3V的模拟电压。每次中断结束后将计数器清零。如果将模拟输出连接到低通滤波器,输出的三角波将更加平滑。因此,使用R-2R DAC可以非常方便地生成任何幅度和频率的模拟信号。打算系统写完这个功能
六.致谢
感谢电子森林提供了这样一个学习机会。在这个过程中,我学习了很多新的技能和知识,这将对我的未来有很大的帮助。同时,我也很感激电子森林提供的友好客服,他们非常耐心地解答了我的问题,让我能够更好地理解学习内容。其次,我要感谢和我一起参与这个项目的群友。他们和我一样都是热爱学习和探索的人,我们相互帮助、分享经验,让学习过程更加愉快、高效。最后,我要说感谢这个项目让我交到了一些新朋友。他们来自不同的背景和领域,但是我们都对学习和技术充满热情,这让我感到非常开心。我相信我们会在未来的学习和工作中相互支持、共同成长。
这次经历让我收获了很多,感激不尽。我希望自己能够继续保持学习的热情和乐观的态度,不断提升自己的技能和能力,为自己和周围的人带来更多的价值。