树莓派是大家喜闻乐见的arm嵌入式计算机,它既可以当作普通的个人计算机用也可以作为服务器,最重要的一点是它具有丰富的独特接口——除传统的USB、以太网、HDMI外的GPIO接口。可当作一套嵌入式设备的控制器,比如SPI和I2C读取传感器、GPIO控制LED和蜂鸣器、UATR与其他设备通讯,同时兼具强大的运算能力、图形显示能力和网络通讯能力,这是普通MCU不能相比的。所以,linux该咋用这玩意就咋用。
  下文用我的树莓派3B+做演示。
IMG_20210709_132742.jpg

GPIO是什么

  GPIO(General Purpose I/O Ports)意思是通用输入/输出端口,说白了就是一些引脚(上图左上角的两排针),它们可以输出高低电平与电路交互,实现程序控制电路的能力
  当然这些引脚也不是全都能被控制,而是有相关的定义方式

2018102716151630.png

  由图可看出,40个引脚中除了12个电源脚外,只有28个可用引脚,其中3、5、14、15、19、21、23、24、26、27、28脚不仅能做普通的GPIO,还有特殊的用途
定义引脚的方式有三种,BOARD编码、BCM编码、Wiring编码
也可以通过在终端输入pinoutgpio readall查看引脚
QQ截图20210709143347.png

面向GPIO编程

本文使用python3.7+VScode SSH作为测试环境
python的树莓派GPIO库有三套,功能和实现各有不同,先用最简单的RPi.GPIO

  • RPi.GPIO:如同Arduino一般控制方便,底层基于C实现
  • gpiozero:面向对象的GPIO编程
  • pigpio:基于TCP连接pigpio服务,可以远程控制

嵌入式的Hello World——点亮一个LED

首先用杜邦线将LED的正极连接到io引脚上(这里我用的是3脚),负极连接到GND上
python代码部分需要导入RPi.GPIO库,可参考官方文档

from RPi import GPIO

LED = 3

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED, GPIO.OUT)
GPIO.output(LED, True)

效果是这样的,就证明程序已经调试通过
IMG_20210709_162017.jpg

GPIO.setmode()用来设置GPIO的编码方式,它的参数可以是GPIO.BOARD也可以是GPIO.BCM
GPIO.setup()用来配置GPIO的模式,比如输入或者输出,上拉或下拉
GPIO.output()直接用bool值指定了GPIO的输出状态,False低电平、True高电平

但在运行时会产生一条Warring信息,这是因为重复指定了GPIO模式导致,所以需要在GPIO.setmode()之前加一行GPIO.setwarnings(False)用来关闭这个警告
QQ截图20210709165749.png

让它闪起来!

改变GPIO的输出状态对于程序部分就是调用一个函数这么简单,所以就能通过修改传入参数实现修改电路状态的功能
这里用了一个延时和循环,使得3端口每200ms改变一下输出状态

from RPi import GPIO
import time

LED = 3

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED, GPIO.OUT)
while True:
    GPIO.output(LED, True)
    time.sleep(0.2)
    GPIO.output(LED, False)
    time.sleep(0.2)

效果就像这样
动画 (0).gif

除了闪动之外,也可以使用PWM(脉宽调制)进行无极调光
使用GPIO.PWM()创建一个PWM控制对象,其中第一个参数是要控制的GPIO,第二个参数是PWM的频率
然后使用PWM.start()启动PWM输出,用PWM.ChangeDutyCycle()改变占空比,用PWM.ChangeFrequency()改变输出频率,最后再用PWM.stop()关闭PWM输出
下面这个程序里用了两个小循环将PWM输出的占空比从0%-100%以10ms的频率递增和递减,形成了一种呼吸灯的效果
这里要注意一点:每个PWM对象是一个独立的线程,如果整个Python脚本(进程)退出了,同时也会停止所有的线程,那么所有的PWM输出也会停止

from RPi import GPIO
import time

LED = 3

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED, GPIO.OUT)

pwm = GPIO.PWM(LED, 100)
pwm.start(0)
while True:
    for rate in range(0, 100):
        pwm.ChangeDutyCycle(rate)
        time.sleep(0.01)
    for rate in range(100, 0, -1):
        pwm.ChangeDutyCycle(rate)
        time.sleep(0.01)

动画 (1).gif

办完事记得打扫场地

  不论是写什么程序,在所需的功能执行完后,都需要去释放资源,这样才是一种好的编程习惯。比如C语言释放堆内存的free()如果不去理睬就会占用过多的系统资源
  同样,在使用完GPIO的API后,也记得要在末尾添加一行GPIO.cleanup(),使GPIO恢复到系统默认状态,释放相应的硬件资源同时也防止损坏其他设备

下期预告:输入和事件