树莓派 ·

树莓派Zero W GPIO控制

0.  概述

本文介绍树莓派 Zero W的GPIO控制,并用LED看效果。

0.1 树莓派GPIO编号方式

1.  准备

1.1 硬件

  • 树莓派Pi Zero W
  • LED(3mm或5mm)
  • 1KΩ电阻
  • 杜邦线3根
  • 电脑(我用Windows 7)

GPIO功能树莓派Zero W GPIO控制 树莓派 第1张

树莓派提供了40个PIN口,大致的定义如下。其中黄色的GPIO PIN口有26个。 其余的是供电接口和接地口。每个GPIO接口都可以用作输入和输出,可以根据需要进行使用。 每个GPIO针脚都有编号,但是编号不是线性的。 

树莓派Zero W GPIO控制 树莓派 第2张

 

针脚电压

 

2个红色的针口提供了5V的输出电压,2个橘色的针口提供3.3V输出电压。 而8个黑色针口作为接地为0V。 其他的接口可以提供输入输出功能。所以作输出时可以提供3.3V电压,而作为输入时能承受3.3V电压。

 

输入/输出

 

对于GPIO接口来说,最重要的就是输入和输出功能。对于计算机来说能识别的只有0和1,而对于数字电路来说通过高低电平来表示输出的值是0还是1。 因为树莓派GPIO接口的电压是3.3V。所以用3.3V表示高电平,也就是1,而用0V表示低电平,也就是0。一般来说高低电平会是一个电压范围。

在买外设的时候发现,有些设备是5V高电平,有些是3.3V。了解到单片机分为3.3V和5V,就是指的是GPIO接口的电压。如果用GPIO口产生一个3.3V的高电平给一个5V的设备,可能会被认为是低电平,如果直接接上一个5V设备作为输入电平,可能会导致树莓派烧坏。所以使用外设是要注意这个外设的电压是5V还是3.3V。

当GPIO用做输入时,会有高电平、低电平、高阻态三个状态。高阻态,指的是电路的一种输出状态,既不是高电平也不是低电平,这个时候因为状态不确定,读取GPIO时可能会导致数据不正确。所以引入了上拉和下拉电阻的概念。

  • 上拉电阻:电阻一端接VCC,一端接逻辑电平接入引脚(如单片机引脚)
  • 下拉电阻:电阻一端接GND,一端接逻辑电平接入引脚(如单片机引脚)

A GPIO pin designated as an input pin can be read as high (3V3) or low (0V). This is made easier with the use of internal pull-up or pull-down resistors. Pins GPIO2 and GPIO3 have fixed pull-up resistors, but for other pins this can be configured in software.

从官网文档看,树莓派每个GPIO接口都有上拉和下拉电阻,大部分是可以通过软件的方式来设置。所以树莓派在连接外设时可以不需要外部的上拉或下拉电阻。而是初始化时设置一下就可以了。

 

更多上下拉电阻的概念可以参考:

Pull-up and pull-down Resistors

上拉电阻与下拉电阻有什么作用

GPIO电路图以及上拉电阻的作用

上拉电阻和下拉电阻

电阻(4)之上拉电阻与下拉电阻详解

 

 

GPIO数据传输

 

和外设之间进行通信主要通过GOIP接口进行输入和输出。GPIO接口提供了可编程的方式从外设读取或向外设发送状态数据。通过控制控制高低电平可以输出不同状态,所以用做开关控制是非常简单有效的。作为输入时可以读取数值或者是状态。虽然每次只能传递0和1这样的数据,但是多次连续传递0和1组合起来,就可以传递复杂的数据。 比如温度传感器就是用GPIO口通过单总线协议进行数据交换。 通过GPIO可以进行各种协议的通信。

 

 

PWM

 

脉冲宽度调制(PWM),是英文“Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。比如伺服电机使用输入PWM信号的脉冲宽度来确定它们的旋转角度,LCD显示器基于PWM信号的平均值来控制它们的亮度。PWM是根据频率占空比进行震荡的数字信号(方波)

  • 周期(Period):脉冲信号从一个上升沿到下一个上升沿的时间
  • 频率(Frequency):描述1秒钟内脉冲周期发生的次数
  • 占空比(Duty): 一个周期中高电平时间占整个周期时间的百分比

树莓派Zero W GPIO控制 树莓派 第3张

所以我们可以通过设置不同的占空比来控制脉冲宽度或者信号的平均值 ,从而达到控制外部设备的目的。下图是占空比为0,25%和100%。

 

树莓派Zero W GPIO控制 树莓派 第4张

PWM有硬件和软件两种输出方式:

  • 软件方法:将普通GPIO引脚作为PWM输出引脚,依据实际需求,配置好计时器,在指定计时周期翻转GPIO引脚电平,实现PWM功能。通过终端方式实现,占用CPU,精度差,控制复杂
  • 硬件方法:在原理图设计时,将支持硬件PWM的引脚作为PWM输出引脚,这样就可以直接通过配置寄存器,采用硬件实现PWM功能了。通过事件方式实现,不占用CPU。

 

在树莓派上,所有GPIO接口都支持软件方式输出PWMi信号,GPIO12、GPIO13、GPIO18、GPIO19支持硬件方式输出信号。

PWM (pulse-width modulation)

  • Software PWM available on all pins
  • Hardware PWM available on GPIO12, GPIO13, GPIO18, GPIO19

 

 

I2C

 

I2C (Inter-Integrated Circuit)是一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主要用来和一些简单的外设进行小数据的传输。一般连接一些传感器或驱动器,比如速度传感器、温度传感器、LCD显示器或电动马达。

树莓派Zero W GPIO控制 树莓派 第5张

I2C是一个同步串行(synchronous serial )接口。使用3条总线进行连接。分为主从设备,主从设备可以进行通信。

  • Shared clock signal (SCL): 因为I2C是串行的,所以需要SCL时钟总线发出信号来同步主从设备间的数据传输,发出时钟信号的设备为Master,而连接的设备为Slave。
  • Shared data line (SDA):主从设备间通过SDA总线进行数据传输,因为只有一根数据线,所以I2C接口是半双工
  • Common ground reference (GND) : 接地

 

I2C接口支持多个设备连接在同一个总线上。每个设备都有自己的地址,但是这个地址是软件实现的,这个地址用7bit表示,所以理论上I2C最多可以连接128个设备。而因为通信协议中带上了设备地址, 所以同时只能和一个设备通信,设备只会响应传递给自己地址的数据。I2C接口传输速率有Master的时钟频率决定。树莓派上默认是100KHZ。这个需要根据外设来进行设置。

 

树莓派上提供了2组I2C接口,分别是GPIO2、GPIO3和GPIO0、GPIO1。但是GPIO0和GPIO1是作为EEPROM,这个主要是用来刷主板上的ROM,所以不用来和外设进行通信。

I2C

  • Data: (GPIO2); Clock (GPIO3)
  • EEPROM Data: (GPIO0); EEPROM Clock (GPIO1)

 

SPI

 

SPI是串行外设接口(Serial Peripheral Interface)的缩写。是一种高速的,全双工,同步的通信总线。SPI有比较高的传输速度,所以适合用看来进行带宽要求比较高的数据传输,比如图像的传输。很多传感器都支持SPI和I2C接口。

树莓派Zero W GPIO控制 树莓派 第6张

SPI是一个同步串行(synchronous serial )接口。使用5条总线进行连接。分为主从设备,主从设备可以进行通信。

  • Master Out Slave In (MOSI)  数据总线,用于master向slave发送数据
  • Master In Slave Out (MISO) 数据总线,用于master接收slave发来的数据
  • Shared clock signal (CLK) 时钟总线,因为SPI是一个同步接口,所以也需要时钟总线来同步传输
  • Common ground reference (GND) 接地
  • CS 片选信号线,如果只有一个设备不需要

因为SPI使用了两条数据线传输数据,所以是全双工模式。 SPI同样支持多个设别连接,但是和I2C不同的是,SPI Slave设备地址是用硬件方式实现的,所以每个设备有一个CS总线和Master设备想了。这样Master可以同时和多个Slave设备进行通信。 SPI的传输熟虑也是由Master是时钟触发频率决定的,一般为16MHz 到 25MHz, 相比I2C要快了很多。

 

树莓派提供了2组SPI接口,其中SPI0提供了2个片选接口,SPI1提供了3个片选接口,所以树莓派最多应该可以连接5个SPI设备

SPI

  • SPI0: MOSI (GPIO10); MISO (GPIO9); SCLK (GPIO11); CE0 (GPIO8), CE1 (GPIO7)
  • SPI1: MOSI (GPIO20); MISO (GPIO19); SCLK (GPIO21); CE0 (GPIO18); CE1 (GPIO17); CE2 (GPIO16)

 

UART

 

通用异步收发传输器( Universal Asynchronous Receiver Transmitter), 一般也简称为串口(serial ports)。我们在使用电脑时也经常通说串口,比如老的COM口、现在的USB口。所以大家说串口一般是一个总称,而单片机上一般书串口指的是UART,它使用TTL电平(2.6V-5V为1,0为0-0.4V),而电脑上的COM口使用RS232电平 (逻辑1=-3V~-15V逻辑0=+3~+15V) 。COMTTLRS232RS485

树莓派Zero W GPIO控制 树莓派 第7张

UART接口是异步接口,所以不需要时钟总线。设备之间的传输速率是可以协商的,所以是通用接口。 设备直接通过RX和TX两个数据总线连接,所以是全双工模式。UART接收到的数据会放到一个FIFO队列中,直到设备读取。UART支持3线和5线两种连接方式:

  • 3-Wire ports include data receive (RX), data transmit (TX), and ground reference (GND) signals.
  • 5-Wire ports add request to send (RTS) and clear to send (CTS) signals used for hardware flow control. Flow control allows the receiving device to indicate that its FIFO buffer is temporarily full and the transmitting device should wait before sending any more data.

树莓派Zero W GPIO控制 树莓派 第8张

5线相比3线多了RTS和CTS两条控制总线。作用就是当FIFO队列满了的时候通知设备暂时不要传递数据。和I2C以及SPI不同的是,UART是点对点通信。速度比I2C块,但是可能要比SPI慢。

 

树莓派在GPIO14和GPIO15 接口提供了UART功能,但是没有提供RTS和CTS总线,所以只能以3线的方式连接。

  • Serial
    • TX (GPIO14); RX (GPIO15)

 

小结

 

之前对GPIO的理解有点偏差,认为普通GPIO口只能发送0,1作为开关,而其他I2C,SPI等接口可以发送负责的数据。 后来发现一些外设就是通过普通GPIO口来进行了单总线通信。 所以GPIO确实只能产生高低电平,但是如果连续产生,就可以连续的发送数据给设备。 而I2C, SPI这些总线本质也都是发送电平,不同的是他们是按指定的协议方式发送。 而实际外设中有很多是自定义协议,所以理论上无论是自定义协议,还是标准的I2C,SPI这些协议,都是可以用任意的GPIO口来通信的。

只是PI上定义了I2C, SPI这样的接口,如果不使用这些接口,而用普通GPIO接口就需要自己来实现这个协议,而不能使用已有的I2C,SPI的库来通信。对于自定义协议也是一样。其实设备的针脚是可以任意GPIO的、只是如果使用了已有的库文件,需要修改对应的针脚设置。所以GPIO功能是非常强大的,你可以使用GPIO来和任意协议的设备通信,可以用GPIO来模拟USB通信,设置你可以模拟硬盘IDE接口和硬盘通信。当然在速度上可能会有限制。

编程针脚

 

使用不同的库在编程时候对应的针脚的编号是不一样的,所以要根据库来设置针脚的编号。网上的图感觉标注的都不是很清楚,所以自己重新画了一个

树莓派Zero W GPIO控制 树莓派 第9张

 

1.2 GPIO接口

 

树莓派Zero W GPIO控制 树莓派 第10张

1.3 接线

首先我们把LED和树莓派连接。LED的正极串联一个1KΩ电阻接树莓派的GPIO18(pin12),负极接地。(注意,下面借用了别人一张图,图中LED正极接在pin11上,我们是接在pin12上)

树莓派Zero W GPIO控制 树莓派 第11张

2.  测试

2.1 连接电脑和Pi Zero W

用putty连接电脑和Pi Zero W,看本文最后的参考文档。Host Name填raspberrypi.local,端口22,用户名pi,密码raspberry。

注意:boot分区有一个名为ssh的空文本文件,这个ssh文件容易丢失,如果ssh不能登录了,先检查ssh是否丢失。

2.2 用Shell命令直接控制GPIO

  • 使GPIO18从内核空间暴露到用户空间中

pi@raspberrypi:~ $ sudo echo 18 > /sys/class/gpio/export

> 是IO重定向符号,IO重定向是指改变linux标准输入和输出的默认设备,指向一个用户定义的设备。echo 18 > export就是把18写入到export文件中。

执行该操作之后,/sys/class/gpio目录下会增加一个gpio18文件夹。

  • 查看GPIO18引脚(在Liunx中设备都以文件的形式,引脚也是设备)

pi@raspberrypi:~ $ cd /sys/class/gpio/gpio18

pi@raspberrypi:/sys/class/gpio/gpio18 $ ls

树莓派Zero W GPIO控制 树莓派 第12张

  • 设置GPIO18为输出模式

pi@raspberrypi:/sys/class/gpio/gpio18 $ sudo echo out > direction

  • 向value文件中输入1,GPIO输出高电平,LED点亮

pi@raspberrypi:/sys/class/gpio/gpio18 $ sudo echo 1 > value

  • 向value文件中输入0,GPIO输出低电平,LED熄灭

pi@raspberrypi:/sys/class/gpio/gpio18 $ sudo echo 0 > value

  • 返回家目录

pi@raspberrypi:/sys/class/gpio $ cd ~

  • 注销GPIO18接口

pi@raspberrypi:~ $ sudo echo 18 > /sys/class/gpio/unexport

 

2.3 用Shell脚本控制GPIO

  • 新建一个名为ledonoff.sh的脚本。

pi@raspberrypi:~ $ sudo nano ledonoff.sh

脚本写下面的内容:

echo $1 > /sys/class/gpio/export

echo out > /sys/class/gpio/gpio$1/direction

echo 1 > /sys/class/gpio/gpio$1/value

sleep 5   #延时5秒

echo 0 > /sys/class/gpio/gpio$1/value

echo $1 > /sys/class/gpio/unexport

说明:shell脚本可传入参数,例如$1代表第1个参数,$2代表第2个参数,以此类推。

  • 为ledonoff.sh添加可执行权限

pi@raspberrypi:~ $ sudo chmod +x ledonoff.sh

  • 运行脚本

pi@raspberrypi:~ $ sudo ./ledonoff.sh 18

运行结果:LED点亮,持续5秒钟关闭。

2.4 用Python通过PRI.GPIO命令控制GPIO

用Python控制GPIO,最便捷的方法就是使用python类库,比如树莓派系统本身集成的RPi.GPIO。

在putty的ssh终端输入命令:

  • 进入python交互界面

pi@raspberrypi:~ $ python

>>> 这是python的提示符。

  • 导入python类库RPi.GPIO,命名为别名为GPIO

>>> import RPi.GPIO as GPIO

引入之后,就可以使用 GPIO 模块的函数了。

  • 设置BOARD编码方式,基于BCM

树莓派3 GPIO分为如下的三种编码方式:物理引脚BOARD编码,BCM编码,以及 wiringPi 编码。

>>> GPIO.setmode(GPIO.BCM)

  • 输出模式

>>> GPIO.setup(18,GPIO.OUT)

  • GPIO18输出高电平,LED点亮

>>> GPIO.output(18,GPIO.HIGH)

  • GPIO18输出低电平,LED熄灭

>>> GPIO.output(18,GPIO.LOW)

  • 用完后进行清理

>>> GPIO.cleanup()

  • 退出python交互界面

>>> Ctrl+D

2.5 用Python脚本控制GPIO

  • 新建一个名为blinky.py的脚本。

pi@raspberrypi:~ $ sudo nano blinky.py

脚本写下面的内容:

import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BCM)

GPIO.setup(18,GPIO.OUT)

while True:

GPIO.output(18,GPIO.HIGH)

time.sleep(1)

GPIO.output(18,GPIO.LOW)

time.sleep(1)

 

GPIO.cleanup()

说明:while True下面的循环体要缩进,用空格或Tab(但不能混用)键缩进就行。

  • 为blinky.py添加可执行权限

pi@raspberrypi:~ $ sudo chmod +x blinky.py

  • 运行Python脚本

pi@raspberrypi:~ $ sudo python blinky.py

LED闪烁。

  • 停止运行

用 Ctrl+C 来中断循环。

3. 借助wiringPi GPIO用C语言控制GPIO

树莓派内核中已经编译自带了gpio的驱动,我们常通过一些第三方写好的库函数来完成具体的操作,比较常见的操作库函数有:

  • Python GPIO

Python GPIO已经集成到了树莓派内核,为树莓派官方资料中推荐且容易上手。python GPIO是一个小型的python库,可以帮助用户完成raspberry相关IO口操作,但是python GPIO库还没有支持SPI、I2C或者1-wire等总线接口。

常见C语言库有:

  • wiringPi (http://wiringpi.com/)

wiringPi适合那些具有C语言基础,在接触树莓派之前已经接触过单片机或者嵌入式开发的人群。wiringPi的API函数和arduino非常相似,这也使得它广受欢迎。作者给出了大量的说明和示例代码,这些示例代码也包括UART设备,I2C设备和SPI设备等。

  • BCM2835 C Library (http://www.airspayce.com/mikem/bcm2835/)

BCM2835 C Library可以理解为使用C语言实现的相关底层驱动,BCM2835 C Library的驱动库包括GPIO. SPI和UART等,可以通过学习BCM2835 C Library熟悉BCM2835相关的寄存器操作。如果有机会开发树莓派上的linux驱动,或自主开发python或PHP扩展驱动,可以从BCM2835 C Library找到不少的“灵感”。

3.1 WiringPi GPIO安装

WiringPi是应用于树莓派平台的GPIO控制库函数,WiringPi遵守GUN Lv3。wiringPi使用C或者C++开发并且可以被其他语言包转,例如python、ruby或者PHP等。

wiringPi包括一套gpio控制命令,使用gpio命令可以控制树莓派GPIO管脚。用户可以利用gpio命令通过shell脚本控制或查询GPIO管脚。

  • wiringPi安装

更新列表:

pi@raspberrypi:~ $ sudo apt-get update

更新软件:

pi@raspberrypi:~ $ sudo apt-get upgrade

安装:

pi@raspberrypi:~ $ sudo apt-get install wiringpi

  • 测试

wiringPi包括一套gpio命令,使用gpio命令可以控制树莓派上的各种接口,通过以下指令可以测试wiringPi是否安装成功。

pi@raspberrypi:~ $ gpio -v

树莓派Zero W GPIO控制 树莓派 第13张

  • 查看GPIO图

pi@raspberrypi:~ $ gpio readall

树莓派Zero W GPIO控制 树莓派 第14张

3.2 编写代码

  • 新建一个名为led_blink.c的源程序

pi@raspberrypi:~ $ sudo nano led_blink.c

  • 内容如下

#include <wiringPi.h>

int main(void) {

wiringPiSetup();

pinMode (1, OUTPUT);

for(;;) {

digitalWrite(1, HIGH);delay (500);

digitalWrite(1, LOW);delay (500) ;

}

}

说明:看看上一小节的图,BCM编号的GPIO18引脚在wiringPi编号中是1。

3.3 编译运行

  • 编译

pi@raspberrypi:~ $ gcc led_blink.c -o led_blink -l wiringPi

-l wiringPi表示动态加载wiringPi共享库。

  • 运行

pi@raspberrypi:~ $ sudo ./led_blink

用 Ctrl+C 来中断循环。

4.  借助BCM2835 C Library用C语言控制GPIO

4.1 下载安装

先看看最新版本:http://www.airspayce.com/mikem/bcm2835

树莓派Zero W GPIO控制 树莓派 第15张

  • 下载bcm2835-1.56.tar.gz

pi@raspberrypi:~ $ wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.56.tar.gz

  • 解压缩

pi@raspberrypi:~ $ tar xvzf bcm2835-1.56.tar.gz

  • 配置编译

进入压缩之后的目录:

pi@raspberrypi:~ $ cd bcm2835-1.56

执行配置命令:

pi@raspberrypi:~/bcm2835-1.56 $ ./configure

pi@raspberrypi:~/bcm2835-1.56 $ make

  • 执行检查

pi@raspberrypi:~/bcm2835-1.56 $ sudo make check

  • 安装bcm2835库:

pi@raspberrypi:~/bcm2835-1.56 $ sudo make install

4.2 编写代码

  • 新建一个名为blink_led.c的源程序

pi@raspberrypi:~/bcm2835-1.56 $ cd ~

pi@raspberrypi:~ $ sudo nano blink_led.c

  • 内容如下

#include <bcm2835.h>

#define PIN RPI_GPIO_P1_12

int main(int argc, char **argv) {

if (!bcm2835_init())

return 1;

 

bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);

 

while (1) {

bcm2835_gpio_write(PIN, HIGH);

bcm2835_delay(500);

bcm2835_gpio_write(PIN, LOW);

bcm2835_delay(500);

}

bcm2835_close();

return 0;

}

说明:GPIO的编号方式不同,采用PCB板的物理接口编号,led连在树莓派Zero W板子的12引脚上。

4.3 编译运行

  • 编译

pi@raspberrypi:~ $ gcc blink_led.c -o blink_led -l bcm2835

-l bcm2835表示动态加载bcm2835共享库

  • 运行

sudo ./blink_led

用 Ctrl+C 来中断循环。

 参考文档

  1. 树莓派介绍
  2. 电脑连接树莓派PiZeroW
  3. 树莓派+温度传感器DS18B20
  4. 树莓派GPIO控制--C语言篇https://blog.csdn.net/hu7850/article/details/51785560
  5. 远程控制通讯——基于树莓派 Python gpiozero 远程控制LED灯并返回控制结果https://blog.csdn.net/NCTU_to_prove_safety/article/details/65446454
  6. RPi Low-level peripherals
    https://elinux.org/RPi_Low-level_peripherals
  7. 樹莓派+溫度感測器實現室內溫度監控:http://shumeipai.nxez.com/2013/10/03/raspberry-pi-temperature-sensor-monitors.html
  8. Raspberry Pi Temperature Sensor
    http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/temperature/
  9. https://www.ccarea.cn/archives/215

参与评论