初步设想

之前买了一个早鸟唤醒的“光闹钟”,即使用灯光唤醒。但不知是哪里出了问题,尝试了几天闹钟既没能亮也没能响,遂火速退货。于是想着何不用树莓派自制一个呢?

材料清单

  • 树莓派3B+
  • 树莓派zero
  • 压电式蜂鸣器
  • LED小灯泡
  • 按钮式开关
  • 跳线若干

说明:

之所以我用了两个树莓派,是因为树莓派zero性能较差而树莓派3B+价格较高(我买的二手的,¥220)。又考虑到二者的GPIO几乎一样(见下两图),所以便使用树莓派3B+进行研发测试,而使用树莓派zero作为最终产品。

R-Pi-3-B-Pinout.png
RPI-Zero-Pinout.png

Raspbian的使用

参考:Raspberry Pi Basics: installing Raspbian and getting it up and running (howtoforge.com)

树莓派系统对时

参考:Debian/Ubuntu 时区和自动校时设置_debian时间校准-CSDN博客

所需Python包

1
2
3
4
import gpiozero
import time
import threading as thr
import smbus

设定时间的调节

电路连接

设定时间主要是通过两个按钮(一个设定小时,一个设定分钟)实现的。

设定时间的调节.jpg

代码实现

首先定义两个按钮

1
2
buttonH = gpiozero.Button(22)
buttonM = gpiozero.Button(15)

在项目目录下新建两个文件分别为minutehour用来存储我们的时间,并在里面先输入两个值作为初始值。

编写调节函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def format(num):
if num >= 10:
return str(num)
if num < 10:
return "0" + str(num)

def setMin():
with open("minute", "r") as minute_file:
minutes = int(minute_file.read())
print(minutes)
while True:
if buttonM.is_pressed:
if minutes - 60 >= -1:
minutes = minutes - 59
else:
minutes += 1
with open("minute", "w") as minute_file:
minute_file.write(str(minutes))
print(minutes)
time.sleep(0.2)


def setHour():
with open("hour", "r") as hour_file:
hours = int(hour_file.read())
print(hours)
while True:
if buttonH.is_pressed:
if hours - 24 >= -1:
hours = hours - 23
else:
hours += 1
with open("hour", "w") as hour_file:
hour_file.write(str(hours))
print(format(hours))
time.sleep(0.2)

上面的format()函数用于将个位数变为"0"+数字的形式,便于后续在LCD显示屏上显示。

设定时间和当前时间的显示

在这里,我们选用LCD显示屏。有关树莓派和LCD屏幕的更多信息,可以参考:树莓派通过 I2C 驱动 LCD1602 液晶屏 | 树莓派实验室 (nxez.com)

电路连接

连接LCD.jpg

所需库的写入

复制以下这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import time
import smbus
BUS = smbus.SMBus(1)
LCD_ADDR = 0x27
BLEN = 1 #turn on/off background light

def turn_light(key):
global BLEN
BLEN = key
if key ==1 :
BUS.write_byte(LCD_ADDR ,0x08)
else:
BUS.write_byte(LCD_ADDR ,0x00)

def write_word(addr, data):
global BLEN
temp = data
if BLEN == 1:
temp |= 0x08
else:
temp &= 0xF7
BUS.write_byte(addr ,temp)

def send_command(comm):
# Send bit7-4 firstly
buf = comm & 0xF0
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)

# Send bit3-0 secondly
buf = (comm & 0x0F) << 4
buf |= 0x04 # RS = 0, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)

def send_data(data):
# Send bit7-4 firstly
buf = data & 0xF0
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)

# Send bit3-0 secondly
buf = (data & 0x0F) << 4
buf |= 0x05 # RS = 1, RW = 0, EN = 1
write_word(LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
write_word(LCD_ADDR ,buf)

def init_lcd():
try:
send_command(0x33) # Must initialize to 8-line mode at first
time.sleep(0.005)
send_command(0x32) # Then initialize to 4-line mode
time.sleep(0.005)
send_command(0x28) # 2 Lines & 5*7 dots
time.sleep(0.005)
send_command(0x0C) # Enable display without cursor
time.sleep(0.005)
send_command(0x01) # Clear Screen
BUS.write_byte(LCD_ADDR ,0x08)
except:
return False
else:
return True

def clear_lcd():
send_command(0x01) # Clear Screen

def print_lcd(x, y, str):
if x < 0:
x = 0
if x > 15:
x = 15
if y <0:
y = 0
if y > 1:
y = 1

# Move cursor
addr = 0x80 + 0x40 * y + x
send_command(addr)

for chr in str:
send_data(ord(chr))

if __name__ == '__main__':
init_lcd()
print_lcd(0, 0, 'Hello, world!')

保存为LCD1602.py于项目目录下。

显示

编写函数,实现实时显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def screening():
while True:
t = time.localtime()
hour = t.tm_hour
minute = t.tm_min
lcd.print_lcd(0, 1, "NOW:")
lcd.print_lcd(0, 0, "ALARM AT:")
lcd.print_lcd(9, 1, format(hour) + ":" + format(minute))
with open("minute", "r") as minute_file:
minutes = int(minute_file.read())
print(minutes)
lcd.print_lcd(12, 0, format(minutes))
with open("hour", "r") as hour_file:
hours = int(hour_file.read())
print(hours)
lcd.print_lcd(9, 0, format(hours) + ":")
time.sleep(0.1)

注意,下面使用这个函数时需要先初始化LCD屏幕:

1
lcd.init_lcd()

声闹钟实现

电路连接

连接蜂鸣器.jpg

代码实现

定义蜂鸣器:

1
buzzer = gpiozero.Buzzer(26)

蜂鸣:

1
2
3
4
5
def buzzing():
buzzer.on()
time.sleep(0.5)
buzzer.off()
time.sleep(0.5)