树莓派3B介绍
树莓派3B和树莓派4B参数比较
型号 | Raspberry Pi 4B | Raspberry Pi 3B |
CPU | 1.5GHz,Quad-Core Broadcom BCM2711(Cortex A-72) | 1.2GHz,Quad-Core Broadcom BCM2837 (Cortex A-53) |
RAM | 1GB/2GB/4GB LPDDR4(取决于型号) | 1G LPDDR2 |
GPU | 500 MHZ Broadcom VideoCore VI | 250MHZ Broadcom VideoCrore IV |
无线 | 802.11.b/g/n/ac(2.4/5GHz) 1.2Gbps Bluetooth 5.0 | 802.11.b/g/n(2.4/5GHz) 150Mbps Bluetooth 4.1 |
以太网 | Gigabit Ethernet | 10/100 Ethernet |
USB | 2个 USB 2.0 / 2个 USB 3.0 USB Type-c | 4 个 USB 2.0 Micro USB |
GPIO | 40个GPIO引脚 | 40个GPIO引脚 |
最大分辨率 | 2 x micro-HDMI ports, up to 4Kp60 supported | 1920x1080 |
电源 | 5V,3A DC | 5V,2.5A DC |
树莓派引脚对照表
TdoList:上图是树莓派2B的引脚图,目前看画的最好,找到个人官网,但发现已经关闭。后续看能不能找到树莓派3B和4B的引脚图。更详细引脚说明参考Raspberry Pi GPIO Pinout。仅有GPIO.1(物理引脚12)支持 PWM_OUTPUT 模式,仅有GPIO.7(物理引脚 7)支持 CLOCK 输出模式。
特性 | I2C | UART | SPI |
数据线数目 | 两根线:SDA(串行数据)和SCL(串行时钟) | 两根线:TXD(发送)和RXD(接收) | 四根线:MOSI(主机输出从机输入)、MISO(主机输入从机输出)、SCLK(时钟)、SS(片选) |
传输速率 | 最高可达3.4 Mbps | 通常情况下速率较低 | 速率高,可达数十Mbps |
通信方式 | 同步通信 | 异步通信 | 同步通信 |
设备地址 | 7位或10位设备地址 | 不需要地址 | 不需要地址 |
线长限制 | 通常不超过1米 | 通常不超过15米 | 通常不超过3米 |
多主机支持 | 支持多主机 | 不支持多主机 | 支持多主机 |
硬件成本 | 硬件成本低,只需要两个IO口 | 硬件成本低,只需要两个IO口 | 硬件成本较高,需要4个或更多IO口 |
适用场景 | 短距离通信 | 适用于点对点通信和低速数据传输 | 高速数据传输 |
常见应用 | I/O扩展器、EEPROM、温度传感器等 | 终端设备、调试设备等 | 存储器、显示屏、WiFi模块等 |
树莓派固定IP配置
sudo nano /etc/dhcpcd.conf
因此要改静态IP就要更改/etc/dhcpcd.conf文件。
在此文件后面添加
设置有线配置可以改成eth0(网卡用ifconfig来查询)
最后在shell中输入命令
sudo reboot now
修改软件更新源
sudo nano /etc/apt/sources.list
清华大学软件源stretch版本:
deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ bullseye main non-free contrib rpi
deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ bullseye main non-free contrib rpi
树莓派实验前期准备
接线准备
面包板
T型扩展板
彩虹排线(一般情况,彩虹线红色为电源线,黑色为地线。)
三者接线图如下(理论上T型板电源引脚与开发板电源对应。本次购买T型板,标红凸起朝向开发板,不要反接)
网络准备
把树莓派接入公司网络,物理网口连接。配置一个无人使用的静态IP。
打开浏览器,输入公司网页登录IP;打开浏览器开发者模式,选择网络-》保留日志
找到login.php,复制-》复制为cURL(bash);
找到有自己用户名的登陆脚本,例如查找"xuwt",找到类似这段的登陆脚本:
curl 'http://10.0.6.106/ac_portal/login.php' \
-H 'Accept: */*' \
-H 'Accept-Language: zh' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
-H 'Cookie: Sessionid=731386501-1' \
-H 'Origin: http://10.0.6.106' \
-H 'Referer: http://10.0.6.106/ac_portal/20200703125620/pc.html?template=20200703125620&tabs=pwd&vlanid=0&_ID_=0&switch_url=&url=http://10.0.6.106/homepage/index.html&controller_type=&mac=08-c0-21-04-9a-cb' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67' \
-H 'X-Requested-With: XMLHttpRequest' \
--data-raw 'opr=pwdLogin&userName=xuwt&pwd=dea07317bd6e11b9e0&auth_tag=1689129415144&rememberPwd=1' \
--compressed \
--insecure
curl 'http://10.0.6.106/ac_portal/login.php' \
-H 'Accept: */*' \
-H 'Accept-Language: zh-CN,zh;q=0.9' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
-H 'Origin: http://10.0.6.106' \
-H 'Referer: http://10.0.6.106/ac_portal/20200703125620/pc.html?template=20200703125620&tabs=pwd&vlanid=0&_ID_=0&switch_url=&url=http://10.0.6.106/homepage/index.html&controller_type=&mac=08-c0-21-04-9a-cb' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36' \
-H 'X-Requested-With: XMLHttpRequest' \
--data-raw 'opr=pwdLogin&userName=xuwt&pwd=510dbf5267f2d5bcafa047&auth_tag=1691130767238&rememberPwd=0' \
--compressed \
--insecure
编写一个启动脚本,需要联网时启动。或者把脚本路径写入到rc.local文件,实现树莓派启动后接入网络。有时可能联网失败,手动执行下脚本即可。
交叉编译准备:
参考【NFV落地】入网测试Kube5gNfvo总结
传感器实验测试
在树莓派基础实验中,主要利用的是wiringPi
库或者bcm2835
库。
wiringPi库:
Raspberry Pi | Wiring | Download & Install | Wiring Pi
WiringPi / WiringPi 镜像库 32位库
https://github.com/guation/WiringPi-arm64 64位库
目前网站已经不更新,但是参考文档较多。
WiringPi includes a software-driven PWM handler capable of outputting a PWM signal on any of the Raspberry Pi’s GPIO pins.(WiringPi包括一个软件驱动的PWM处理器,能够在Raspberry Pi的任何GPIO引脚上输出PWM信号。)
而wiringPi一般用于C++等平台
#include "wiringPi.h"
wiringPiSetup();
安装完wiringPi库后,输入gpio readall
可以查看树莓派详细引脚信息。
相关库函数:
硬件初始化函数原型 | 函数返回值 | 函数说明 |
int wiringPiSetup (void) | 返回:执行状态,-1表示失败 | 当使用这个函数初始化树莓派引脚时,程序使用的是wiringPi 引脚编号表。引脚的编号为 0~16需要root权限 |
int wiringPiSetupGpio (void) | 返回:执行状态,-1表示失败 | 当使用这个函数初始化树莓派引脚时,程序中使用的是BCM GPIO 引脚编号表。需要root权限 |
wiringPiSetupPhys(void) | 不常用,不做介绍 | / |
wiringPiSetupSys (void) ; | 不常用,不做介绍 | / |
通用GPIO控制函数原型 | 函数参数 | 函数说明 |
void pinMode (int pin, int mode) | pin:配置的引脚mode:指定引脚的IO模式可取的值:INPUT、OUTPUT、PWM_OUTPUT,GPIO_CLOCK | 作用:配置引脚的IO模式注:只有wiringPi 引脚编号下的1脚(BCM下的18脚) 支持PWM输出;只有wiringPi编号下的7(BCM下的4号)支持GPIO_CLOCK输出 |
void digitalWrite (int pin, int value) | pin:控制的引脚value:引脚输出的电平值。可取的值:HIGH,LOW分别代表高低电平 | 让对一个已经配置为输出模式的引脚,输出指定的电平信号 |
int digitalRead (int pin) | pin:读取的引脚返回:引脚上的电平,可以是LOW HIGH 之一 | 读取一个引脚的电平值 LOW HIGH ,返回 |
void analogWrite(int pin, int value) | pin:引脚 value:输出的模拟量 value - 占空比:0(始终断)到255(始终导通)之间。 | 模拟量输出。树莓派的引脚本身是不支持AD转换的,也就是不能使用模拟量的API,需要增加另外的模块 |
int analogRead (int pin) | pin:引脚返回:引脚上读取的模拟量 | 模拟量输入树莓派的引脚本身是不支持AD转换的,也就是不能使用模拟量的API,需要增加另外的模块 |
void pwmWrite (int pin, int value) | pin:引脚value:写入到PWM寄存器的值,范围在0~1024之间 | 输出一个值到PWM寄存器,控制PWM输出。pin只能是wiringPi 引脚编号下的1脚(BCM下的18脚) |
void pullUpDnControl (int pin, int pud) | pin:引脚pud:拉电阻模式可取的值:PUD_OFF 不启用任何拉电阻。关闭拉电阻PUD_DOWN 启用下拉电阻,引脚电平拉到GNDPUD_UP 启用上拉电阻,引脚电平拉到3.3v | 对一个设置IO模式为 INPUT 的输入引脚设置拉电阻模式。与Arduino不同的是,树莓派支持的拉电阻模式更丰富。树莓派内部的拉电阻达50K欧姆 |
软件模拟PWM函数原型 | 函数参数 | 函数说明 |
int softPwmCreate (int pin, int initialValue, int pwmRange) | pin:用来作为软件PWM输出的引脚initalValue:引脚输出的初始值pwmRange:PWM值的范围上限1-100建议100。返回值:0表示成功。 | 使用一个指定的pin引脚创建一个模拟的PWM输出引脚 其他IO口 |
void softPwmWrite (int pin, int value) | pin:通过softPwmCreate创建的引脚value:PWM引脚输出的值 | 更新引脚输出的PWM值 |
bcm2835库:
bcm2835: C library for Broadcom BCM 2835 as used in Raspberry Pi
bcm2835库更加简洁,它只有两个源文件bcm2835.c和bcm2835.h。在使用过程中我们可以选择将其安装到树莓派中来使用,也可以选择直接将两个文件包含到我们的应用代码中。
BCM编码一般都在python库中使用:
import RPi.GPIO as GPIO //引入RPi.GPIO库
GPIO.setmode(GPIO.BCM) //设置引脚编号为BCM编码方式;
实验分类:
- 高低电平:双色LED灯、有源蜂鸣器、开关电源
- PWM:LED(RGB 255,255,255)灯、电机控制、无源蜂鸣器
- 触发事件(数字):按键开关、继电器、光遮断模块、金属触摸
- 触发事件(模拟):声音检测模块、麦克风声音模块、光敏电阻
- 摄像头 :摄像、人脸识别(视频)、远程登陆查看摄像头
实验1:3mm红绿双色LED模块
树莓派 | 双色LED |
GPIO 1 | R(中间) |
GND | GND |
GPIO 2 | G(S) |
模块上面标-号的接地,中间的接物理引脚12(wiringPi编码1),第三个接物理引脚13(wiringPi编码2)。
使用WiringPi库代码示例:
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define Led_PinRed 1 // 红色LED 管脚
#define Led_PinGreen 2 // 绿色LED 管脚
// LED 初始化
void raspberry_led_Init(void)
{
pinMode(Led_PinRed, OUTPUT);
pinMode(Led_PinGreen, OUTPUT);
}
int main(void)
{
//初始化连接失败时,将消息打印到屏幕
if(wiringPiSetup() == -1){
printf("setup wiringPi failed !");
return -1;
}
raspberry_led_Init(); // LED 初始化
for(int i=0;i<5;i++)
{
printf("gpio out: %d\n", i);
digitalWrite(Led_PinRed, HIGH); //digital是数字,analog是模拟;
delay(1000);
digitalWrite(Led_PinRed, LOW);
delay(1000);
digitalWrite(Led_PinGreen, HIGH);
delay(1000);
digitalWrite(Led_PinGreen, LOW);
}
return 0;
}
#include <wiringPi.h>
#include <softPwm.h>
#include <stdio.h>
#define uchar unsigned char
#define Led_PinRed 1 // 红色LED 管脚
#define Led_PinGreen 2 // 绿色LED 管脚
// LED 初始化
void makerobo_led_Init(void)
{
softPwmCreate(Led_PinRed, 0, 100);
softPwmCreate(Led_PinGreen, 0, 100);
}
int main()
{
//初始化连接失败时,将消息打印到屏幕
if(wiringPiSetup() == -1){
printf("setup wiringPi failed !");
return 1;
}
makerobo_led_Init(); // LED 初始化
for(int i=0;i<5;i++)
{
printf("gpio out: %d\n", i);
softPwmWrite(Led_PinRed, 100);
delay(1000);
softPwmWrite(Led_PinRed, 0);
delay(1000);
softPwmWrite(Led_PinGreen, 100);
delay(1000);
softPwmWrite(Led_PinGreen, 0);
}
return 0;
}
编译参数:
gcc -Wall -o 1_mm_led 1_mm_led.c -lwiringPi //-Wall 是为了使能所有警告,以便发现程序中的问题
或者使用树莓派本地工具Geany打开后,选择"Build"->"Set Build Commands",编译和生成添加"-lwiringPi":
之后就可以选择图像界面进行编译和执行:
python代码接线方式:
树莓派 | 双色LED |
GPIO 18 | R |
GND | GND |
GPIO 27 | B |
使用bcm2835库测试示例:
import RPi.GPIO as GPIO
import time
# 设置GPIO模式为BCM
GPIO.setmode(GPIO.BCM)
# 定义LED所连接的GPIO引脚号
led_pinRed = 18
led_pinBlue = 27
# 设置GPIO引脚为输出模式
GPIO.setup(led_pinRed, GPIO.OUT)
GPIO.setup(led_pinBlue, GPIO.OUT)
# 控制LED灯的开关状态
def toggle_led(state):
GPIO.output(led_pinRed, state)
def toggle_ledblue(state):
GPIO.output(led_pinBlue, state)
# 测试LED灯
try:
while True:
toggle_led(GPIO.HIGH) #
toggle_ledblue(GPIO.LOW)
time.sleep(1) # 延时1秒
toggle_led(GPIO.LOW) # 关闭LED灯
toggle_ledblue(GPIO.HIGH)
time.sleep(1) # 延时1秒
except KeyboardInterrupt:
pass
GPIO.cleanup()
红绿灯切换示意图:
实验2:5mm红绿双色LED模块
代码同上实验1,测试图如下:
实验3:3色LED模块(RGB)模块
模块上面标-号的接地,R接物理引脚11(wiringPi编码0),G接接物理引脚12(wiringPi编码1),B接接物理引脚13(wiringPi编码2)。
树莓派 | 双色LED |
GPIO 17 | R |
GND | GND |
GPIO 18 | G |
GPIO 27 | B |
#!/usr/bin/env python #告诉Linux本文件是一个Python程序
import RPi.GPIO as GPIO # 导入控制GPIO的模块,RPi.GPIO
import time # 导入时间模块,提供延时、时钟和其它时间函数
colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF] # 颜色列表
R = 17 # 定义物理针脚号
G = 18
B = 27
def setup(Rpin, Gpin, Bpin):
global pins # 在函数内部声明被其修饰的变量是全局变量
global p_R, p_G, p_B
pins = {'pin_R': Rpin, 'pin_G': Gpin, 'pin_B': Bpin}
GPIO.setmode(GPIO.BCM) # 设置引脚编号模式为板载模式,即树莓派上的物理位置编号
for i in pins:
GPIO.setup(pins[i], GPIO.OUT) # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(pins[i], GPIO.LOW) # Set pins to low(0 V) to off led
p_R = GPIO.PWM(pins['pin_R'], 2000) # set Frequece to 2KHz
p_G = GPIO.PWM(pins['pin_G'], 1999)
p_B = GPIO.PWM(pins['pin_B'], 5000)
p_R.start(0)
p_G.start(0)
p_B.start(0)
def ledmap(x, in_min, in_max, out_min, out_max): # 将颜色的刺激量转换为占空比对应的值。
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
def off():
for i in pins:
GPIO.output(pins[i], GPIO.LOW) # Turn off all leds
def setColor(col): # For example : col = 0x112233
R_val = (col & 0xff0000) >> 16 # 先“与”运算只保留自己颜色所在位的值有效
G_val = (col & 0x00ff00) >> 8 # 再“右移”运算将自己颜色所在位的值提取出来
B_val = (col & 0x0000ff) >> 0
R_val = ledmap(R_val, 0, 255, 0, 100) # 将颜色的刺激量转换为占空比对应的值
G_val = ledmap(G_val, 0, 255, 0, 100)
B_val = ledmap(B_val, 0, 255, 0, 100)
p_R.ChangeDutyCycle(R_val) # 更改占空比,调整该颜色的亮度
p_G.ChangeDutyCycle(G_val)
p_B.ChangeDutyCycle(B_val)
def loop():
while True:
for col in colors:
setColor(col)
time.sleep(1)
def destroy():
p_R.stop() # Turn off PWM
p_G.stop()
p_B.stop()
off() # Turn off all leds
GPIO.cleanup() # 重置GPIO状态
if __name__ == "__main__":
try:
setup(R, G, B) # 调用初始化设置LED灯的函数
loop() # 调用循环函数
except KeyboardInterrupt: # 如果遇用户中断(control+C),则执行destroy()函数
destroy() # 调用清除LED状态的函数
实验4:摄像头模块
- 安装OpenCV库
首先需要安装OpenCV库。您可以使用pip3命令在终端中安装OpenCV库:
pip3 install opencv-python
- 测试摄像头打开实验:
import cv2
cap=cv2.VideoCapture(0)
i=0
while(1):
ret ,frame = cap.read()
k=cv2.waitKey(1)
if k==27: #按下ESC退出窗口
break
elif k==ord('s'): #按下s保存图片
cv2.imwrite('./'+str(i)+'.jpg',frame)
i+=1
cv2.imshow("capture", frame)
cap.release()
- 基于OpenCV的摄像头人脸识别实验,下载Haar Cascade分类器
Haar Cascade分类器是OpenCV中用于检测人脸的预训练模型。可以从OpenCV官方GitHub存储库中下载分类器文件。在终端中,输入以下命令下载分类器:
wget https://github.com/opencv/opencv/raw/master/data/haarcascades/haarcascade_frontalface_default.xml
haarcascade_frontalface_default.xml
- 编写Python脚本来打开摄像头并进行人脸检测。以下是一个示例脚本:
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('frame', frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
实验5:模拟温度模块
import RPi.GPIO as GPIO
import time
lm35_pin = 18
GPIO.setmode(GPIO.BCM) # 以BCM编码格式
GPIO.setup(lm35_pin, GPIO.IN)
def read_temperature():
# 读取模拟输入引脚的电压值
voltage = GPIO.input(lm35_pin)
# 转换为摄氏温度值
temperature = (voltage * 3.3) / 1024 * 100
return temperature
def main():
print("Raspberry Pi Temperature test program\n")
time.sleep(1) # 通电后前一秒状态不稳定,时延一秒
while True:
temperature = read_temperature()
print('Temperature: {0:.2f}°C'.format(temperature))
time.sleep(1)
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
不确定是否硬件问题,输出温度一直为0(后期有万用表再进行测试)。
实验6:DS18B20温度传感器
温度传感器DS18B20是一款常用的数字温度传感器,具有体积小,硬件成本低,抗干扰能力强,精度高的特点。数字温度传感器易于连接,采用1线总线,可直接输出温度数据。
树莓派 | T型转接板 | 温度传感器模块 |
GPIO4 | GPIO4 | OUT |
5V | 5V | VCC |
GND | GND | GND |
1、编辑/boot/config.text文件。在文件底部添加一行:dtoverlay=w1-gpio。
/boot/config.text文件
2、重启树莓派系统。
sudo reboot
3、安装设备驱动程序并确认设备是否有效。
sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices/
ls
4、查看设备数据,检查当前温度。
pi@raspberrypi:/sys/bus/w1/devices $ cd cd 28-20320c34abca
pi@raspberrypi:/sys/bus/w1/devices/cd 28-20320c34abca $ ls
driver hwmon id name power subsystem uevent w1_slave
pi@raspberrypi:/sys/bus/w1/devices/cd 28-20320c34abca $ cat w1_slave
a7 01 55 aa 7f ff 09 10 53 : crc=53 YES
a7 01 55 aa 7f ff 09 10 53 t=26437
字符段“t=26437”中的数字就是当前温度值。如果要将其转换为摄氏度,也可以除以1000,即当前温度为26437÷1000=26.437°C。
#include <OneWire.h>
OneWire ds(10); // 连接arduino10引脚
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
Serial.println("No more addresses.");
Serial.println();
ds.reset_search();
delay(250);
return;
}
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr[i], HEX);
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
Serial.println();
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
Serial.println(" Chip = DS18S20"); // or old DS1820
type_s = 1;
break;
case 0x28:
Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
Serial.println(" Chip = DS1822");
type_s = 0;
break;
default:
Serial.println("Device is not a DS18x20 family device.");
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
Serial.print(" Data = ");
Serial.print(present,HEX);
Serial.print(" ");
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.print(" CRC=");
Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
// convert the data to actual temperature
unsigned int raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// count remain gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
Serial.print(" Temperature = ");
Serial.print(celsius);
Serial.print(" Celsius, ");
Serial.print(fahrenheit);
Serial.println(" Fahrenheit");
}
实验7:温湿度传感器模块
DHT11用的是单总线协议,一次传送40位的数据。 注意了,看到这一句话,也就是说我们每次读取DHT11的数据时,都要一次性读取40次,也就是读取40位。并且数据前16位是与湿度相关的,中间16位是与温度相关的,最后八位是用来校验的,当我们校验成功后,证明这一次的温湿度结果正确的,树莓派就可以使用这个温湿度值;如果校验不通过,那么就代表我们这次读取出来的温湿度值,是错误的(也许是我们的时序错误了,也许是传感器的问题),我们不进行采样。
DHT11的总体通信流程: 第一步:主机(树莓派)先发送开始信号,从机(DHT11)会返回一个相应信号进行应答。 第二步:主机信号线拉高准备接收数据。 第三步:开始接收数据(一次接收40位)。
接线方式如下:
DHT Pin | Signal | Pi Pin |
1 | 3.3V | 1 |
2 | Data/Out | GPIO17 |
3 | Ground | GND |
import RPi.GPIO as GPIO
import numpy as np
import time
dhtpin = 17
GPIO.setmode(GPIO.BCM) # 以BCM编码格式
def read_dht11_dat():
GPIO.setup(dhtpin, GPIO.OUT)
GPIO.output(dhtpin, GPIO.LOW)
# 给信号提示传感器开始工作,并保持低电平18ms以上
time.sleep(0.02) # 这里保持20ms
GPIO.output(dhtpin, GPIO.HIGH) # 然后输出高电平
GPIO.setup(dhtpin, GPIO.IN)
# 发送完开始信号后得把输出模式换成输入模式,不然信号线上电平始终被拉高
while GPIO.input(dhtpin) == GPIO.LOW:
continue
# DHT11发出应答信号,输出 80 微秒的低电平
while GPIO.input(dhtpin) == GPIO.HIGH:
continue
# 紧接着输出 80 微秒的高电平通知外设准备接收数据
# 开始接收数据
j = 0 # 计数器
data = [] # 收到的二进制数据
kk = [] # 存放每次高电平结束后的k值的列表
while j < 40:
k = 0
while GPIO.input(dhtpin) == GPIO.LOW: # 先是 50 微秒的低电平
continue
while GPIO.input(dhtpin) == GPIO.HIGH: # 接着是26-28微秒的高电平,或者 70 微秒的高电平
k += 1
if k > 100:
break
kk.append(k)
if k < 8: # 26-28 微秒时高电平时通常k等于5或6
data.append(0) # 在数据列表后面添加一位新的二进制数据“0”
else: # 70 微秒时高电平时通常k等于17或18
data.append(1) # 在数据列表后面添加一位新的二进制数据“1”
j += 1
print("sensor is working.")
print("初始数据高低电平:%s,参数k的列表内容:%s\n" % (data, kk))
m = np.logspace(7, 0, 8, base=2, dtype=int) # logspace()函数用于创建一个于等比数列的数组
# 即[128 64 32 16 8 4 2 1],8位二进制数各位的权值
data_array = np.array(data) # 将data列表转换为数组
# dot()函数对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积)
humidity = m.dot(data_array[0:8]) # 用前8位二进制数据计算湿度的十进制值
humidity_point = m.dot(data_array[8:16])
temperature = m.dot(data_array[16:24])
temperature_point = m.dot(data_array[24:32])
check = m.dot(data_array[32:40])
print(humidity, humidity_point, temperature, temperature_point, check)
tmp = humidity + humidity_point + temperature + temperature_point
# 十进制的数据相加
if check == tmp: # 数据校验,相等则输出
return humidity, temperature
else: # 错误输出错误信息
return False
def main():
print("Raspberry Pi DHT11 Temperature test program\n")
time.sleep(1) # 通电后前一秒状态不稳定,时延一秒
while True:
result = read_dht11_dat()
if result:
humidity, temperature = result
print("humidity: %s %%, Temperature: %s ℃\n" % (humidity, temperature))
time.sleep(1)
if result == False:
print("Data are wrong,skip\n")
time.sleep(1)
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
实验8:麦克风声音模块
树莓派 | T型转接板 | PCF8591模块 |
* | * | AO |
GND | GND | G |
5V | 5V | + |
GPIO4 | GPIO4 | DO |
import RPi.GPIO as GPIO
import time
microphone_pin = 4
GPIO.setmode(GPIO.BCM) # 以BCM编码格式
GPIO.setup(microphone_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def read_voice():
# 读取模拟输入引脚的电压值
voltage = GPIO.input(microphone_pin)
return voltage
def main():
print("Raspberry Pi microphone test program\n")
time.sleep(1) # 通电后前一秒状态不稳定,时延一秒
while True:
voice = read_voice()
print('microphone voice: {0:.2f}'.format(voice))
time.sleep(1)
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
麦克风左侧灯常亮,传感器可能异常,可变电阻器被击穿,调节无效。
实验9:激光传感器
树莓派 | 激光传感器模块 |
GIPO17 | SIG(S) |
* | * |
GND | GND |
#!/usr/bin/env python
# DO NOT WATCH THE LASER DIRECTLY IN THE EYE!
import RPi.GPIO as GPIO
import time
LedPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(LedPin, GPIO.OUT) # Set LedPin's mode is output
GPIO.output(LedPin, GPIO.LOW) # Set LedPin LOW(0V) to off led
def loop():
while True:
print('...Laser off')
GPIO.output(LedPin, GPIO.LOW) # led off
time.sleep(0.5)
print('Laser on...')
GPIO.output(LedPin, GPIO.HIGH) # led on
time.sleep(0.5)
def destroy():
GPIO.output(LedPin, GPIO.LOW) # led off
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验10:按键开关模块
Python代码说明:
树莓派 | T型转接板 | 轻触开关 |
GPIO 17 | GPIO 17 | S |
3.3V | 3.3V | VCC(中间触点) |
GND | GND | GND |
树莓派 | T型转接板 | 双色LED |
GPIO 12 | GPIO 12 | R(红色端口) |
GND | GND | GND |
GPIO 13 | GPIO 13 | G(绿色端口) |
若按键没有按下则信号是高电平,GPIO.input(BtnPin)的值为1,即LED(x)中的x==1,红灯亮,打印显示“Button is up !”; 按下键后信号是低电平,GPIO.input(BtnPin)的值为0,即LED(x)中的x==0,绿灯亮,打印显示“Button is down !”。
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
Rpin = 12
Gpin = 13
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(Gpin, GPIO.OUT) # Set Green Led Pin mode to output
GPIO.setup(Rpin, GPIO.OUT) # Set Red Led Pin mode to output
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Led(x): # 控制双色LED灯闪烁的函数
if x == 0:
GPIO.output(Rpin, 1) # 红灯亮
GPIO.output(Gpin, 0) # 绿灯灭
if x == 1:
GPIO.output(Rpin, 0) # 红灯灭
GPIO.output(Gpin, 1) # 绿灯亮
def Print(x): # 打印按键是否按下的提示消息
if x == 0:
print(' * Button is down! *')
elif x == 1:
print(' * Button is up ! *')
def detect(chn):
Led(GPIO.input(BtnPin)) # 控制双色LED灯闪烁
Print(GPIO.input(BtnPin)) # 打印按键是否按下的提示消息
def loop():
while True:
pass # pass 不做任何事情,一般用做占位语句。
def destroy():
GPIO.output(Gpin, GPIO.LOW) # Green led off
GPIO.output(Rpin, GPIO.LOW) # Red led off
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验11:Arduino 继电器
树莓派 | T型转接板 | 继电器模块 |
GPIO 4 | GPIO 4 | SIG(IN) |
5V | 5V | VCC(DC+) |
GND | GND | GND(DC-) |
5V | 5V | COM |
双色LED模块 | T型转接板 | 继电器模块 |
R | * | 常开(NO) |
GND | GND | * |
G | * | 常闭(NC) |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
RelayPin = 4
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(RelayPin, GPIO.OUT)
GPIO.output(RelayPin, GPIO.LOW)
def loop():
while True:
print('...relay on')
GPIO.output(RelayPin, GPIO.LOW) # 低电平时,继电器为初始状态
time.sleep(1) # 常闭触点通电,绿灯亮
print('relay off...')
GPIO.output(RelayPin, GPIO.HIGH) # 高电平时,继电器为激活状态
time.sleep(1) # 常开触点通电,红灯亮
def destroy():
GPIO.output(RelayPin, GPIO.LOW)
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
测试灯将在红绿之间切换:
实验12:水银开关
树莓派 | T型转接板 | 磁簧开关 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印是否有打开开关
if x == 0:
print(' * Light! *')
elif x == 1:
print(' * No light! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验13:磁簧开关模块
磁簧开关(Reed Switch)是一个通过所施加的磁场操作的电开关。基本型式是将两片磁簧片密封在玻璃管内,两片虽重叠,但中间间隔有一小空隙。当外来磁场时将使两片磁簧片接触,进而导通。 一旦磁体被拉到远离开关,磁簧开关将返回到其原来的位置。可以用来计数或限制位置。
树莓派 | T型转接板 | 磁簧开关 |
GPIO 17 | GPIO 17 | SIG(DO) |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印检测到磁性物质
if x == 0:
print(' * Detected Magnetic Material! *')
elif x == 1:
print(' * Nothing happened! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
while True:
pass # pass 不做任何事情,一般用做占位语句。
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验14:光敏电阻
光敏电阻随着光强的变化而改变其电阻,光敏电阻阻值随光强变化,光线越强,阻值越小。
树莓派 | T型转接板 | 干簧管传感器 |
GPIO 17 | GPIO 17 | SIG(DO) |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印是否有光照
if x == 0:
print(' * Detected Magnetic Material! *')
elif x == 1:
print(' * Nothing happened! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验15:光遮断模块
接线、代码同14:光敏电阻。遮断操作如下:
实验16:红外避障传感器
树莓派 | T型转接板 | 红外避障传感器 |
GPIO17 | GPIO17 | OUT(SIG) |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
ObstaclePin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(ObstaclePin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def loop():
while True:
if 0 == GPIO.input(ObstaclePin): # 当检测到障碍物时,输出低电平信号
print("Detected Barrier!")
else:
print("****Nothing!******")
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验17:红外发射接收模块
一般情况下,发射和接收模块使用2块开发板进行测试,目前使用1块开发板可以验证该功能,后续深入了解可再进行优化。
发射模块:
树莓派 | T型转接板 | 红外发射 |
GPIO 17 | GPIO 17 | S |
GPIO 18 | GPIO 18 | 中间(未使用) |
GND | GND | GND |
import RPi.GPIO as GPIO
import time
led_pin = 17
GPIO.setmode(GPIO.BCM) # 以BCM编码格式
GPIO.setup(led_pin, GPIO.OUT)
# 控制LED灯的开关状态
def toggle_led(state):
GPIO.output(led_pin, state)
def main():
print("Raspberry Pi IR LED test program\n")
time.sleep(1) # 通电后前一秒状态不稳定,时延一秒
while True:
toggle_led(GPIO.HIGH) #
print('Set GPIO.HIGH')
time.sleep(1) # 延时1秒
toggle_led(GPIO.LOW) # 关闭LED灯
print('Set GPIO.LOW')
time.sleep(1) # 延时1秒
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
接收模块:
树莓派 | T型转接板 | 红外接收 |
GPIO 12 | GPIO 12 | S |
5V | 5V | VCC中间 |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 12
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印是否有光照
if x == 0:
print(' * Receive! *')
elif x == 1:
print(' * No Receive! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
print(' * Start IR Receive! *')
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
当接收到信号时,接收模块会红灯闪烁。
实验18:火焰模块
没有火。接线、代码同13:光敏电阻。
树莓派 | T型转接板 | 火焰模块 |
GPIO 17 | GPIO 17 | SIG(DO) |
3.3V | 3.3V | VCC |
GND | GND | GND |
实验19:霍尔磁力传感器模块
树莓派 | T型转接板 | 霍尔传感器 |
GPIO 17 | GPIO 17 | SIG(DO) |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印检测到磁性物质
if x == 0:
print(' * Detected Magnetic Material! *')
elif x == 1:
print(' * Nothing happened! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
print(' Start Hall Sensor! ')
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验20:金属触摸传感器
树莓派 | T型转接板 | PCF8591模块 |
* | * | AO |
GND | GND | G |
5V | 5V | + |
GPIO4 | GPIO4 | DO |
代码处理类似声音判断。
import RPi.GPIO as GPIO
import time
microphone_pin = 4
GPIO.setmode(GPIO.BCM) # 以BCM编码格式
GPIO.setup(microphone_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def read_voice():
# 读取模拟输入引脚的电压值
voltage = GPIO.input(microphone_pin)
return voltage
def main():
print("Raspberry Pi microphone test program\n")
time.sleep(1) # 通电后前一秒状态不稳定,时延一秒
while True:
voice = read_voice()
print('touch test: {0:.2f}'.format(voice))
time.sleep(1)
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
触摸后左侧灯亮,且收到输入信号。
实验21:魔术光杯模块
树莓派 | T型转接板 (BCM) | 旋转编码器模块 |
GPIO17 | GPIO17 | S |
GPIO18 | GPIO18 | L |
3.3V | 3.3V | VCC(+) |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
LedPin = 18
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
GPIO.setup(LedPin, GPIO.OUT) # 设置针脚模式为输出(或者输入GPIO.IN)
GPIO.output(LedPin, GPIO.LOW)
def Print(x): # 水银传感器震动后,灯亮
if x == 0:
print(' * Light! *')
GPIO.output(LedPin, GPIO.HIGH)
elif x == 1:
print(' * No light! *')
GPIO.output(LedPin, GPIO.LOW)
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验22:敲击传感器
树莓派 | T型转接板 | 振动开关 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
BtnPin = 17
tmp = 0
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input
def Print(x): # 打印是否有震动变化,只打印变化情况
global tmp
if x != tmp:
if x == 0:
print('* Shake On! *')
elif x == 1:
print('* Shake Off! *')
tmp = x
def loop():
while True:
state = GPIO.input(BtnPin)
if state != 1: # 每当振动产生时
print("state:%d\n" % state)
Print(state)
time.sleep(1)
else:
Print(state)
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
print('* Shake Code Start! *')
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验23:倾斜开关
树莓派 | T型转接板 | 振动开关 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
实验代码与敲击传感器相同;
实验24:手指侦测心跳模块
树莓派 | T型转接板 | 振动开关 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
BtnPin = 17
tmp = 0
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input
def Print(x): # 打印是否有心跳变化,只打印变化情况
global tmp
if x != tmp:
if x == 0:
print('* Off! *')
elif x == 1:
print('* On! *')
tmp = x
def loop():
while True:
state = GPIO.input(BtnPin)
if state == 1:
print("state:%d\n" % state)
Print(state)
time.sleep(1)
else:
Print(state)
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
print('* Heartbeat check start! *')
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验25:双轴XY摇杆
树莓派 | T型转接板 | 双轴XY摇杆 |
GPIO 17 | GPIO 17 | VRx |
GPIO 18 | GPIO 18 | VRy |
GPIO 27 | GPIO 27 | SW |
5V | 5V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPinX = 17
BtnPinY = 18
BtnPinPress = 27
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPinX, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BtnPinX, GPIO.BOTH, callback=directionX, bouncetime=200)
GPIO.setup(BtnPinY, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BtnPinY, GPIO.BOTH, callback=directionY, bouncetime=200)
GPIO.setup(BtnPinPress, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BtnPinPress, GPIO.BOTH, callback=directionPress, bouncetime=200)
def directionX(chx): # 获取X轴操纵杆方向结果
statex = GPIO.input(BtnPinX)
print("x state :%d" % statex)
def directionY(chy): # 获取Y轴操纵杆方向结果
statey = GPIO.input(BtnPinY)
print("y state :%d" % statey)
def directionPress(chp): # 获取操纵杆按下结果
statepress = GPIO.input(BtnPinPress)
print("Press state :%d" % statepress)
def loop():
print(' * Start Rocker Sensor! *')
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验26:有源蜂鸣器
- 有源蜂鸣器常用于发出单一的提示性报警声音,没有频率变化,内置振荡器;
有源蜂鸣器内部有一个简单的振荡电路,能将恒定的直流电转化成一定频率的脉冲信号,程序控制方便但频率固定,单片机一个高低电平就可以让其发出声音。
- 无源蜂鸣器的驱动方式为频率脉冲驱动,可以发出各种有频率的信号声音;
无源蜂鸣器和电磁扬声器一样没有内部驱动电路,需要接在音频输出电路中才能发声。如果给直流信号是不响的,因为磁路恒定,必须用2K-5K的方波去驱动它。
树莓派 | T型转接板 | 有源蜂鸣器 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
BuzzerPin = 17 # pin11
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BuzzerPin, GPIO.OUT)
GPIO.output(BuzzerPin, GPIO.HIGH)
def on():
GPIO.output(BuzzerPin, GPIO.LOW)
# 低电平是响
def off():
GPIO.output(BuzzerPin, GPIO.HIGH)
# 高电平是停止响
def beep(x): # 响3秒后停止3秒
print("buzzer start")
on()
time.sleep(x)
off()
time.sleep(x)
def loop():
print("loop start")
while True:
beep(3)
def destroy():
GPIO.output(BuzzerPin, GPIO.HIGH)
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验27:无源蜂鸣器
树莓派 | T型转接板 | 无源蜂鸣器 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
Buzzer = 17
CL = [0, 131, 147, 165, 175, 196, 211, 248]
CM = [0, 262, 294, 330, 350, 393, 441, 495]
CH = [0, 525, 589, 661, 700, 786, 882, 990]
song_0 = [CL[1], CL[2], CL[3], CL[4], CL[5], CL[6], CL[7],
CM[1], CM[2], CM[3], CM[4], CM[5], CM[6], CM[7],
CH[1], CH[2], CH[3], CH[4], CH[5], CH[6], CH[7]]
# song_0表示从低音do依次到高音si的音符列表
beat_0 = [2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2]
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(Buzzer, GPIO.OUT) # Set pins' mode is output
global Buzz # Assign a global variable to replace GPIO.PWM
Buzz = GPIO.PWM(Buzzer, 440) # 440 is initial frequency.
Buzz.start(50) # Start Buzzer pin with 50% duty ration
def loop():
while True:
# --------------------------------------------
print('\n\n Playing Low C notes...')
for i in range(0, 7): # Play song 0的C调低音音符
Buzz.ChangeFrequency(song_0[i])
# 根据歌曲的音符改变频率
time.sleep(beat_0[i] * 0.5)
# 根据节拍列表每个音符延迟1秒,2 beats*0.5s=1s
print('\n\n Playing Middle C notes...')
for i in range(7, 14): # Play song 0
Buzz.ChangeFrequency(song_0[i]) # Change the frequency along the song note
time.sleep(beat_0[i] * 0.5) # delay a note for beat * 0.5s
print('\n\n Playing High C notes...')
for i in range(14, 21): # Play song 0
Buzz.ChangeFrequency(song_0[i]) # Change the frequency along the song note
time.sleep(beat_0[i] * 0.5) # delay a note for beat * 0.5s
Buzz.ChangeFrequency(0.5) # 一首曲子结束,间隔3秒
time.sleep(3)
def destory():
Buzz.stop() # Stop the buzzer
GPIO.output(Buzzer, 1) # Set Buzzer pin to High
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destory()
实验28:旋转编码器模块
树莓派 | T型转接板 (BCM) | 旋转编码器模块 |
GPIO0 | GPIO17 | CLK |
GPIO1 | GPIO18 | DT |
GPIO2 | GPIO27 | SW |
3V | 3V | VCC(+) |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
RoAPin = 17 # CLK Pin
RoBPin = 18 # DT Pin
BtnPin = 27 # Button Pin
globalCounter = 0
flag = 0
Last_RoB_Status = 0
Current_RoB_Status = 0
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(RoAPin, GPIO.IN) # input mode
GPIO.setup(RoBPin, GPIO.IN)
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def rotarydeal():
global flag
global Last_RoB_Status
global Current_RoB_Status
global globalCounter
Last_RoB_Status = GPIO.input(RoBPin)
while not GPIO.input(RoAPin): # 未旋转时,GPIO.input(RoAPin)值为1,旋转时会变为0
Current_RoB_Status = GPIO.input(RoBPin) # 旋转时的当前值
flag = 1
if flag == 1:
flag = 0
if (Last_RoB_Status == 1) and (Current_RoB_Status == 0):
globalCounter = globalCounter + 1 # 顺时针旋转,角位移增大
if (Last_RoB_Status == 0) and (Current_RoB_Status == 1):
globalCounter = globalCounter - 1 # 逆时针旋转,数值减小
def btnisr(channel):
global globalCounter
globalCounter = 0
def loop():
global globalCounter
tmp = 0 # Rotary Temporary
GPIO.add_event_detect(BtnPin, GPIO.FALLING, callback=btnisr)
# 当按下按钮时,调用回调函数btnISR
while True:
rotarydeal()
if tmp != globalCounter:
print("globalCounter = %d\n" % globalCounter)
tmp = globalCounter
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
实验29:循迹模块
树莓派 | T型转接板 | 无源蜂鸣器 |
GPIO 17 | GPIO 17 | SIG |
3.3V | 3.3V | VCC |
GND | GND | GND |
#!/usr/bin/env python
import RPi.GPIO as GPIO
BtnPin = 17
def setup():
GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical location
GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode is input, and pull up to high level(3.3V)
GPIO.add_event_detect(BtnPin, GPIO.BOTH, callback=detect, bouncetime=200)
def Print(x): # 打印检测黑线或白线
if x == 0:
print(' * black line! *')
elif x == 1:
print(' * white line! *')
def detect(chn):
Print(GPIO.input(BtnPin)) # 验证GPIO.input(ReedPin)的值
def loop():
while True:
pass
def destroy():
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
当
实验30:在 Raspberry Pi 上运行 TensorFlow Lite 对象检测模型
- 如何在 Raspberry Pi 上设置和运行 TensorFlow Lite 对象检测模型
遗留问题
- 32bit和64bit之间如何切换?
【答】OS的不同,重新烧录系统
- 树莓派的内存怎么看?
在芯片上可以看,应该是被散热片挡住了。
- 树莓派上有ntp吗?
可以搭建ntp服务器。
树莓派服务端:
timedatectl set-timezone Asia/Shanghai
apt-get install ntp
systemctl start ntp
客户端:
timedatectl set-timezone Asia/Shanghai
apt-get install ntpdate
ntpdate ntp.server.ip #ntp服务器ip地址
vim /etc/crontab #设置客户端定时更新
30 10 * * * root /usr/sbin/ntpdate ntp.server.ip #表示每天10:30自动执行ntpdate指令,与NTP服务器时间同步
crontab -e 立即生效
- http网页登陆查看摄像头,出现摄像头打开失败情况。
- 疑问:对softPwmWrite函数的参数设置都是大于100的,而且如果想混色,是需要遵循标准RGB表进行设置。如红色设置为(255,0,0),超过100就是没用的?猜测精度是否不够?
参考资料:
Raspberry Pi | Wiring | Download & Install | Wiring Pi
树莓派wiringPi库详解
Raspberry Pi | Wiring | Download & Install | Wiring Pi
WiringPi / WiringPi 镜像库 32位库
https://github.com/guation/WiringPi-arm64 64位库
bcm2835: C library for Broadcom BCM 2835 as used in Raspberry Pi
(Works on all versions up to and including RPI 4. Works with all versions of Debian up to and including Debian Buster 10. bcm2835库更加简洁,它只有两个源文件bcm2835.c和bcm2835.h。在使用过程中我们可以选择将其安装到树莓派中来使用,也可以选择直接将两个文件包含到我们的应用代码中。bcm2835库本身就只有两个源文件,添加到应用层代码很简单而且方便查看源码。wring目前资料较多,与Arduino代码类似。)
树莓派使用C/C++基于Bcm2835操作GPIO学习记录_c++ 树莓派 io 口 操作 cannot find -lbcm2835_假的程序猿LC的博客-CSDN博客bcm2835源码说明
超简单教你在树莓派上安装opencv(二)_树莓派安装opencv_流 浪 猫的博客-CSDN博客
暂时找到32位,python3.9.2版本安装流程,测试通过。64位还需要测试(找文档注意系统和python版本);
树莓派基础实验_慕雪华年的博客-CSDN博客
热门内容和标签 | 树莓派实验室