1. 项目描述
1.1 项目介绍
利用基于树莓派Pico的嵌入式系统学习平台,通过MicroPython编程来学习嵌入式系统的工作原理和应用,最终开发一个交通灯控制器,具体需要实现以下功能:仿真马路上的交通灯的工作状态切换,利用班上的红、黄、绿三种颜色的LED显示道路状态的切换,即普通的交通灯。另外,结合日常生活中的需求,加入人性化设计,行人需要通行时,加入手动控制,延长红灯时间方便行人通行。
1.2 设计思路
利用版上的三个不同颜色的LED模拟交通灯的三种状态,设计程序轮流切换灯的明暗状态,完成普通交通灯,并根据按键的输入情况(开启线程)来调整交通灯的切换状态。
1.3 流程图
2. 硬件介绍
2.1 硬件内容
2个按键输入、4个单色LED、12个WS2812B RGB三色灯、1个姿态传感器、1个128*64 OLED显示屏、1个蜂鸣器、1个可调电位计(用于电压表)、1路音频信号输入(用于示波器)、8位R-2R电阻网络构成的DAC(用于DDS信号发生器)
2.2 功能及管脚映射表
2.3 STEPPico核心模块原理图
3. 实现的功能及图片展示
3.1 运行程序
三色LED灯按顺序切换红、黄、绿三种颜色。
3.2 当按下按键K1
当前灯不发生变化,下一轮的红灯时间会延长,并且延长期间内,会伴随蜂鸣器的哔哔声。
4. 代码段说明介绍
4.1 配置管脚属性
led_red = machine.Pin(26, machine.Pin.OUT)
led_yellow = machine.Pin(20, machine.Pin.OUT)
led_green = machine.Pin(22, machine.Pin.OUT)
button = machine.Pin(12, machine.Pin.IN, machine.Pin.PULL_UP)
buzzer = machine.Pin(19, machine.Pin.OUT)
这些代码设置引脚GP26、GP20、GP22作为输出,每个管脚都给了一个描述性的名称,以'led'开始,这样可读性更好,一眼就知道哪个管脚控制一个led,以及该led的颜色。设置引脚GP12上的按钮用作行人的按键输入,引脚GP22上的蜂鸣器作为声音输出。因为树莓派Pico有内置的可编程输入电阻,我们将其设置为上拉模式。这意味着引脚的电压被拉到3.3V(它的逻辑电平是1),除非它连接到GND(在这种情况下,它的逻辑电平将是0)。
4.2 交通灯循环
实际的交通灯不会一闪而过就停下来,即便没有交通堵塞,没有人通行,它们也会一直运行着。需要建立一个无限循环:
while True:
led_red.value(1)
utime.sleep(5)
led_red.value(0)
led_yellow.value(1)
utime.sleep(2)
led_yellow.value(0)
led_green.value(1)
utime.sleep(5)
led_green.value(0)
led_yellow.value(1)
utime.sleep(2)
led_yellow.value(0)
LED的状态变化如下:
1、首先红色的LED会亮起来,意味着禁止通行;
2、接下来,黄色的LED灯会亮起来,红灯关闭,意味着等待时间;
3、黄灯关闭,绿色LED亮起来,意味着可以通行了;
4、然后绿色的LED灯熄灭,黄色的灯亮起来,意味着交通灯又要变了;
5、最后,黄色的LED熄灭,循环重新开始,红色的LED亮起。
该模式将一直无限循环下去,直到按下停止按钮。它是基于国内现实世界交通控制系统中使用的交通灯模式,在这个模拟试验中,我们只是将状态转换做了加速,最长的通行时间只有5秒钟。
4.3 行人对交通灯的控制
global button_pressed
button_pressed = False
这将button_pressed设置为一个全局变量,并给它一个默认值False, 意思是当程序开始时,按钮还没有被按下。
将控制灯光循环的视为程序的主线程,同时使用_thread库可以创建一个同时运行的附加线程。
def button_reader_thread():
global button_pressed
while True:
if button.value() == 0:
button_pressed = True
utime.sleep(0.01)
第一行定义了线程并给它起了一个描述性的名字, 它是一个读取按钮输入的线程,条件语句用于检查按键的值是否为1,当按键没有按下时,读取值为1,附加线程不运行,读取值为零时,程序其他部分知道按键按下。
_thread.start_new_thread(button_reader_thread, ())
这告诉_thread库启动前面定义的线程。
if button_pressed == True:
led_red.value(1)
for i in range(10):
buzzer.value(1)
utime.sleep(1)
buzzer.value(0)
utime.sleep(0.2)
global button_pressed
button_pressed = False
这段代码检查button_pressed全局变量,以查看自循环最后一次运行以来,按键是否在任何时候被按下。如果有,就像我们之前做的按键阅读线程报告的那样,它开始运行一段代码,首先打开红色的LED灯来停止交通,然后按下蜂鸣器十次,让行人知道时间到了可以过马路了。最后两行将button_pressed变量重置为False, 所以下一次环路运行它不会触发行人通行规则,除非再次按下按钮。
5. 难题及解决办法
本任务的难题在于人为对交通灯的变化加以干预,以方便行人的同行
我采取的方法是建立附加线程,对控制按钮是否按下进行实时检查,若控制按钮按下,则三色LED颜色的切换加入新的流程,在循环前加入一段新的红灯时常,并且加入蜂鸣器的声音,提醒行人通过,从而控制红绿灯。
6. 未来的计划
本次任务,还有许多可以完善和改进的地方,比如可以增设控制按钮,让马路双方的人都可以控制交通灯,另外我计划了解不同国家的交通灯的变换形式,重新编程交通灯进行匹配。利用板子上的显示屏,来模拟行人过马路,增加项目的可视性等等,希望可以更深层次的学习和练习嵌入式开发。