树莓派 GSM 语音短信报警
树莓派系统安装
1
2
3
4
5
6
7
8
9
101. 购买树莓派
2. 购买无线网卡,读卡器,内存卡,HDMI转VGA线,USB转RS232串口连接转换线,相应的电源线
3. 下载树莓派系统
4. 将系统安装到内存卡中
5. 接通电源,启动服务
6. 通过无线网卡,连接WIFI
7. 启动ssh服务
root@raspberrypi:~# /etc/init.d/ssh start
root@raspberrypi:~# update-rc.d ssh defaults
root@raspberrypi:~# update-rc.d -f ssh remove树莓派基本操作
1
2
3
4
5
6
7pi@raspberrypi:~ $ sudo su -
root@raspberrypi:~# apt-get update
root@raspberrypi:~# apt-get upgrade
root@raspberrypi:~# apt-get install vim ntpdate
root@raspberrypi:~# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
root@raspberrypi:~# raspi-config 初始化一些配置树莓派工具 密码:yb3k
树莓派 调用 GSM模块 发送短信 和 语音
给单个用户发送短信
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
56pi@raspberrypi:~/gsm $ cat send_sms.py
#!/usr/bin/env python3
#coding:utf8
import RPi.GPIO as GPIO
import serial
import time, sys
import datetime
import binascii
P_BUTTON = 24
def setup():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(P_BUTTON, GPIO.IN, GPIO.PUD_UP)
def Unicode2HexStr(Unicde_Str):
Hex_Str = ""
for i in range(0,len(Unicde_Str)):
Hex_Str += (hex(ord(Unicde_Str[i])).replace('0x','').zfill(4))
return Hex_Str
INFO = Unicode2HexStr('hi,刘朋')
AA = binascii.a2b_hex('1A')
SERIAL_PORT = "/dev/ttyUSB0"
ser = serial.Serial(SERIAL_PORT, baudrate = 9600, timeout = 5)
setup()
ser.write('AT+CMGDA="DEL ALL"\r'.encode())
print(ser.read(ser.inWaiting()))
time.sleep(1)
ser.write("AT+CMGF=1\r".encode())
print(ser.read(ser.inWaiting()))
time.sleep(1)
ser.write('AT+CSMP=17,167,2,25\r'.encode())
time.sleep(3)
print(ser.read(ser.inWaiting()))
ser.write('AT+CSCS="UCS2"\r'.encode())
time.sleep(3)
print(ser.read(ser.inWaiting()))
ser.write('AT+CMGS="00310035003200300031003600380034003200320033"\r'.encode())
time.sleep(2)
ser.write(INFO.encode())
time.sleep(1)
ser.write(AA)
print(ser.read(ser.inWaiting()))
time.sleep(1)
ser.close()给单个用户打电话,语音报警
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
62pi@raspberrypi:~/gsm $ cat send_gms.py
#!/usr/bin/env python3
#coding:utf8
import serial
import time, sys
import datetime
def Unicode2HexStr(Unicde_Str):
Hex_Str = ""
for i in range(0,len(Unicde_Str)):
Hex_Str += (hex(ord(Unicde_Str[i])).replace('0x','').zfill(4))
return Hex_Str
INFO = Unicode2HexStr('你在干什么!!! 我一直在盯着你!!! 你给我小心点!!!')
SEND_INFO = 'AT+CTTS=1,' + '"' + INFO + '"'
PHONE_NUM = 'ATD' + '{手机号}' + ';'
SERIAL_PORT = "/dev/ttyUSB0"
ser = serial.Serial(SERIAL_PORT, baudrate = 115200, timeout = 5)
time.sleep(1)
ser.write("ATE1;\r".encode())
time.sleep(1)
print(ser.read(ser.inWaiting()))
ser.write("AT+COLP=1\r".encode())
time.sleep(1)
print(ser.read(ser.inWaiting()))
ser.write("AT+CTTSRING=0\r".encode())
time.sleep(1)
print(ser.read(ser.inWaiting()))
ser.write("AT+CTTSPARAM=20,0,50,75,1\r".encode())
time.sleep(1)
print(ser.read(ser.inWaiting()))
ser.write((PHONE_NUM + '\r').encode())
time.sleep(1)
ABC = 0
CBA = 0
while ABC != 1:
AA = ser.read(ser.inWaiting())
BB = AA.decode()
if '+COLP' in BB and 'OK' in BB:
ser.write((SEND_INFO + '\r').encode())
time.sleep(10)
ser.write("AT+CTTS=0\r".encode())
time.sleep(1)
ABC = 1
CBA += 1
print(CBA)
if CBA == 50:
ABC = 1
time.sleep(1)
ser.write("ATH\r".encode())
ser.close()
树莓派 python 模块
pyserial
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
41Python中用于读串口的模块是"pySerial"
读取串口时首先导入包"import serial",其次设置读取哪一个口,波特率,数据位,停止位
例如:
class serial.Serial
__init__( port=None,
baudrate=9600,
bytesize=EIGHTBITS,
parity=PARITY_NONE,
stopbits=STOPBITS_ONE,
timeout=None,
xonxoff=False,
rtscts=False,
writeTimeout=None,
dsrdtr=False,
interCharTimeout=None )
baudrate:设置波特率
bytesize:数据位
stopbits:停止位
timeout:超时时间
timeout = None: 长时间等待
timeout = 0: 不阻塞形式 (读完之后就返回)
timeout = x: x秒后超时 (float allowed)
例2:
import serial //导入模块
ser = serial.Serial(0) //打开第一个串口
print ser.portstr //能看到第一个串口的标识,windows下是COM1
ser.write("hello") //往串口里面写数据
ser.close() //关闭ser表示的串口
ser.open() //打开这个串口
ser = serial.Serial('COM1', 115200) //来设置波特率,当然还有专门的函数
data = ser.read() //可以读1个字符
data = ser.read(20) //可以读20个字符
data = ser.readline() //是读一行,以/n结束,要是没有/n就一直读,阻塞
data = ser.readlines()和ser.xreadlines() //都需要设置超时时间
ser.baudrate = 9600 //设置波特率
ser //来查看当前串口的状态
ser.isOpen() //看看这个串口是否已经被打开RPi.GPIO
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
98
99
100GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平
用户可以通过GPIO口和硬件进行数据交互(如UART),控制硬件工作(如LED、蜂鸣器等),读取硬件的工作状态信号(如中断信号)等
掌握了GPIO,差不多相当于掌握了操作硬件的能力
例如:
import RPi.GPIO as GPIO //导入RPi.GPIO模块
或者:
try:
import RPi.GPIO as GPIO
except RuntimeError:
print("引入错误")
在RPi.GPIO中,同时支持树莓派上的两种GPIO引脚编号:
第一种编号是BOARD编号,这和树莓派电路板上的物理引脚编号相对应.使用这种编号的好处是,你的硬件将是一直可以使用的,不用担心树莓派的版本问题.因此,在电路板升级后,你不需要重写连接器或代码
第二种编号是BCM规则,是更底层的工作方式,它和Broadcom的片上系统中信道编号相对应.在使用一个引脚时,你需要查找信道号和物理引脚编号之间的对应规则.对于不同的树莓派版本,编写的脚本文件也可能是无法通用的
GPIO.setmode(GPIO.BOARD) //指定BOARD编号
或者
GPIO.setmode(GPIO.BCM) //指定BCM规则
mode = GPIO.getmode() //返回设置的引脚编号
GPIO.setwarnings(False) //禁用警告
GPIO.setup(channel, GPIO.IN) //将引脚设置为输入模式
GPIO.setup(channel, GPIO.OUT) //将引脚设置为输出模式
GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH) //为输出的引脚设置默认值
GPIO.cleanup() //释放脚本中的使用的引脚(注意,GPIO.cleanup()只会释放掉脚本中使用的GPIO引脚,并会清除设置的引脚编号规则)
GPIO.output(channel, state) //设置引脚的输出状态(状态可以设置为0,GPIO.LOW,False,1,GPIO.HIGH,True.如果编码规则为"GPIO.BOARD",那么channel就是对应引脚的数字)
一次性设置多个引脚:
chan_list = [11,12]
GPIO.output(chan_list, GPIO.LOW)
GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW))
你还可以使用Input()函数读取一个输出引脚的状态并将其作为输出值:
GPIO.output(12, not GPIO.input(12))
我们也常常需要读取引脚的输入状态,获取引脚输入状态如下代码:
GPIO.input(channel)
注意:低电平返回0,GPIO.LOW,False;高电平返回1,GPIO.HIGH.True
如果输入引脚处于悬空状态,引脚的值将是漂动的.换句话说,读取到的值是未知的,因为它并没有被连接到任何的信号上,直到按下一个按钮或开关.由于干扰的影响,输入的值可能会反复的变化.解决方法:
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
注意: 上面的读取代码只是获取当前一瞬间的引脚输入信号
如果需要实时监控引脚的状态变化,可以有两种办法:
最简单原始的方式是每隔一段时间检查输入的信号值,这种方式被称为轮询.如果你的程序读取的时机错误,则很可能会丢失输入信号.轮询是在循环中执行的,这种方式比较占用处理器资源.
另一种响应GPIO输入的方式是使用中断(边缘检测),这里的边缘是指信号从高到低的变换(下降沿)或从低到高的变换(上升沿)
轮询方式:
while GPIO.input(channel) == GPIO.LOW:
time.sleep(0.01) # wait 10 ms to give CPU chance to do other things
边缘检测:
边缘是指信号状态的改变,从低到高(上升沿)或从高到低(下降沿).通常情况下,我们更关心于输入状态的该边而不是输入信号的值.这种状态的该边被称为事件
先介绍两个函数:
* wait_for_edge() 函数
wait_for_edge()被用于阻止程序的继续执行,直到检测到一个边沿.也就是说,上文中等待按钮按下的实例可以改写为:
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
print('Timeout occurred')
else:
print('Edge detected on channel', channel)
* add_event_detect() 函数
该函数对一个引脚进行监听,一旦引脚输入状态发生了改变,调用event_detected()函数会返回true,如下代码:
GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channel
do_something()
// 下面的代码放在一个线程循环执行。
if GPIO.event_detected(channel):
print('Button pressed')
设置多个回调函数:
def my_callback_one(channel):
print('Callback one')
def my_callback_two(channel):
print('Callback two')
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)
注意:回调触发时,并不会同时执行回调函数,而是根据设置的顺序调用它们
例如: 点亮LED灯
import RPi.GPIO as GPIO //引入函数库
import time
RPi.GPIO.setmode(GPIO.BOARD) //设置引脚编号规则
RPi.GPIO.setup(11, RPi.GPIO.OUT) //将11号引脚设置成输出模式
while True
GPIO.output(channel, 1) //将引脚的状态设置为高电平,此时LED亮了
time.sleep(1) //程序休眠1秒钟,让LED亮1秒
GPIO.output(channel, 0) //将引脚状态设置为低电平,此时LED灭了
time.sleep(1) //程序休眠1秒钟,让LED灭1秒
GPIO.cleanup() //程序的最后别忘记清除所有资源
00310035003200300031003600380034003200320033
00480065006C006C006F002C5218670B