基于STEP Pico制作一个定时报警的时钟
制作一个定时报警的时钟,功能包含板上的12个彩色LED灯来指示时间,蜂鸣器在整点以播放音乐的方式报时,和用板上的按键设置报时时间
标签
嵌入式系统
2023寒假在家练
STEP Pico
时钟制作
整点报时
霖霖霖
更新2023-03-28
哈尔滨工业大学
518

1.项目介绍

制作一个时钟,可以通过板上的12个彩色LED灯来指示时间,并通过蜂鸣器在整点以播放音乐的方式报时,板上的按键可以设置时间。

实现方式为程序通过定时器计数的方式来生成时、分、秒信号,并根据这些信号来改变12个彩色LED灯的亮灭,产生PWM信号驱动蜂鸣器播放定时长度的音乐。

2.设计思路

在Thonny平台上,首先用RTC将实时的时间传输到程序中,再在程序中分别设计出OLED屏显示年月和小人,12个LED灯显示时分秒,整点报时,状态机等程序。

3.简单的硬件介绍

该项目运用到的硬件包括了STEP Pico、树莓派Pico扩展板和Type-C 数据线。其中,STEP Pico是一块RP2040微控制芯片,搭载了ARM Cortex MO+处理器,内置了264kb SRAM和2MB闪存,同时有Type-C接口;树莓派Pico扩展板包含了12个WS2812B RGB三色灯,1个蜂鸣器,2个按键输入,8位R-2R电阻网络构成的DAC等。

4.完成的功能和达到的性能

4.1时间指示

在运行程序后,会默认在OLED显示屏上出现年、月和一个螺旋斜向上的小人,其中年、月显示在OLED屏的右侧,小人显示在OLED屏的左侧。同时,12个WS2812B RGB三色灯会亮起三个,其中红色表示时,绿色表示分,蓝色表示秒。

IMG_20230310_212431

4.2报时时长设置

按一下按键输入k1,OLED屏就会切换到整点报时时长设置界面,在屏幕中心会显示报时的时长,范围为0-55秒。

进入设置界面后,初始会默认设置报时时长为0s,之后可通过按键输入k2来改变报时时长,按一下k2能增加5s的报时时长。另外当报时时长到达55s时,再按一下k2会使报时时长恢复初始化至0s。

IMG_20230310_212536IMG_20230310_212517

4.3整点报时

报时时长设置完成后,按一下按键设置k1,OLED屏就会切换回正常时间的显示,并且会进行整点报时,即当切回正常时间显示后,每经过一定时间后,就会发生整点报时,蜂鸣器就会歌曲《我和我的祖国》的旋律。

5.实现过程

5.1程序流程图

未命名文件

5.2用RTC传输时间

在程序中用函数RTC()将实时的时间数据传输到STEP Pico的程序中,并将时间的数据以元组储存,然后再用函数oled_time.show_date(),ws2812_time.show_time(),分别将时间中的年月显示在OLED屏上,将时分秒用12个WS2812B RGB三色灯显示,具体代码为:

rtc = RTC()

while True:

oled.fill(0)

dt_tuple = rtc.datetime()

year = dt_tuple[0]

month = dt_tuple[1]

h = dt_tuple[4]

m = dt_tuple[5]

s = dt_tuple[6]

5.3OLED屏上显示年月和小人

在程序中定义类“OledTime()”,来在OLED屏上显示年月和小人。其中,又主要定义了函数show_date、draw,分别起显示年月、绘制动态小人的作用,具体如下:

class OledTime():

def __init__(self, oled, frames):

self.oled = oled

self.frames = frames

self.oled.fill(0)

self.i = len(frames) - 1

self.wri = Writer(oled, freesans20)

def show_date(self, year, month):

self.y = year

self.m = month

def draw(self):

if self.i == 0:

self.i = len(frames) - 1

else:

self.i = self.i - 1

fb=framebuf.FrameBuffer(self.frames[self.i],64,64,framebuf.MONO_HLSB)

self.oled.blit(fb, 0, 0, 0)

self.wri.set_textpos(oled, 10, 70)

self.wri.printstring(str(self.y))

self.wri.set_textpos(oled, 30, 85)

self.wri.printstring(str(self.m))

5.4用LED灯显示时、分、秒

在程序中定义类“PixelDisplay()”和“Ws2812Time()”来用12个WS2812B RGB三色灯指示时间。其中,前者其调用12个WS2812B RGB三色灯的作用,后者主要起计算时间的作用,具体如下:

class PixelDisplay():

def __init__(self, wb):

self.pixel_array = array.array("I", [0 for _ in range(12)])

def set_color(self, n, color):

self.pixel_array[(n - 1) % 12] = (color[1]<<16) + (color[0]<<8) + color[2]

def get_color(self, n):

v = self.pixel_array[(n - 1) % 12]

return ((v >> 8) & 0xff, (v >> 16) & 0xff, v & 0xff)

def fill(self, c):

a = self.pixel_array

for i in range(12):

a[i] = c

def pixels_show(self, brightness_input=1):

for ii,cc in enumerate(self.pixel_array):

r = int(((cc >> 8) & 0xFF) * brightness_input)

g = int(((cc >> 16) & 0xFF) * brightness_input)

b = int((cc & 0xFF) * brightness_input)

self.pixel_array[ii] = (g<<16) + (r<<8) + b

def render(self):

wb.state_mach.put(self.pixel_array, 8)

class Ws2812Time():

def __init__(self, pd):

self.pd = pd

self.h = 0

self.m = 0

self.s = 0

def show_time(self, h, m, s):

h_tmp = h

m_tmp = m

s_tmp = s

self.h = (h_tmp - 1) % 12 + 1

self.m = (int(m_tmp / 5) - 1) % 12 + 1

self.s = (int(s_tmp / 5) - 1) % 12 + 1

def draw(self):

pd.fill(0)

pd.set_color(self.h, (0xff, 0, 0))

pd.set_color(self.m, (0, 0xff, 0))

pd.set_color(self.s, (0, 0, 0xff))

5.5状态机/按k1切换状态

在程序中定义类“StateMachine”作为状态机。首先设定设置报时时间界面和显示标准时间界面分别为0,1。然后定义了函数update、showCurrentTime、settingAlarmTime,分别为传输状态机状态、切换到当前时间、切换到设置整点报时时长,具体如下:

class StateMachine():

SettingAlarmTime = 0

ShowCurrentTime = 1

def __init__(self, alarmTime):

self.state = StateMachine.ShowCurrentTime

self.old_state = self.state

self.alarmTime = alarmTime

def update(self, k1, k2, s):

self.old_state = self.state

if self.state == StateMachine.ShowCurrentTime:

self.showCurrentTime(k1)

elif self.state == StateMachine.SettingAlarmTime:

self.settingAlarmTime(k1, k2, s)

print(self.state)

def showCurrentTime(self, k1):

if k1 == False:

pass

elif k1 == True:

self.alarmTime.on = False

self.state = StateMachine.SettingAlarmTime

def settingAlarmTime(self, k1, k2, s):

if k1 == False:

if k2:

self.alarmTime.s = (self.alarmTime.s + 5) % 60

pass

if k1 == True:

self.alarmTime.ss = (s + self.alarmTime.s + 1) % 60

self.alarmTime.on = True

self.state = StateMachine.ShowCurrentTime

5.6整点报时

在程序中定义类“AlarmTime”,用来整点报时。其中,又定义了函数render、update、draw,分别用作调用音乐、传输数据和判定报时条件、OLED屏显示的作用,具体如下:

class AlarmTime:

def __init__(self, oled):

self.oled = oled

self.s = 0

self.ss = 0

self.on = False

self.wri = Writer(oled, freesans20)

def render(self):

if self.on and mymusic is not None:

mymusic.tick()

def update(self, s):

if (s - 10 - self.ss) % 60 == 10:

self.on = False

print(self.ss, s)

if self.on and self.ss < s:

music_toggle(True)

elif not self.on:

music_toggle(False)

def draw(self):

self.oled.fill(0)

self.wri.set_textpos(oled, 32, 64)

self.wri.printstring(str(self.s))

5.7调用音乐

在程序中定义函数“music_toggle()”调用音乐,具体如下:

def music_toggle(on):

global music_on, mymusic

if music_on and not on:

mymusic.stop()

music_on = False

elif not music_on and on:

mymusic = music(song, tempo = 1)

gc.collect()

mymusic.beat = 200

music_on = True

6.遇到的主要难题及解决方法

6.1整点报时的判定

在该项目中,整点报时的困难主要是报时开始和结束的判定。

目前,为判定报时开始,代码中加入了报警绝对时间ss的辅助量,其中ss等于当前设定的报时时长,加上设定后按下k1切换回指示时间界面的时间的秒数s。且当s等于ss+3时,即会发生报时。

在该项目中,当ss与s满足关系:s-10-ss对60取余等于10时,整点报时结束,音乐停止播放。

7.未来的计划建议

该项目已经成功实现了制作一个能够指示时间和整点报时的时钟,并达到了预期指标。然而该项目还有许多可以提升与扩展的地方:

(1)OLED屏上未显示时间中的时分秒,无法直观的指示时间;

(2)整点报时的时长只能以5秒为单位增加;

(3)该时钟只能完成单次整点报时,无法完成2次及以上次数的整点报时。

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