芒果爱吃胡萝卜 - 树莓派gpio入门系列
type: channel
link: http://blog.mangolovecarrot.net/tag/%E6%A0%91%E8%8E%93%E6%B4%BEgpio%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/
items: 树莓派GPIO入门11-驱动液晶屏幕（二）
items: 树莓派GPIO入门11-驱动液晶屏幕（一）
items: 树莓派GPIO入门10-使用TLC5940芯片输出多路PWM
items: 树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管
items: 树莓派GPIO入门08-使用74HC595芯片驱动数码管（二）
items: 树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）
items: 树莓派GPIO入门07-利用声音传感器制作声控灯
items: 树莓派GPIO入门06-跟数字湿温度计DHT11通信
items: 树莓派GPIO入门05-驱动数码管显示数字
items: 树莓派GPIO入门04-使用按钮

树莓派GPIO入门11-驱动液晶屏幕（二）
type: item
date: 2017-03-05T07:24:00+08:00
description: 本系列将驱动一块1.44"的128x128像素的彩色液晶屏幕。本文是系列的第2篇，也是最后一篇，目标是在液晶屏上显示文字。最终效果硬件及连接参考本系列第一篇先运行程序看效果下载zip解压后有两个文件放在同一目录下。点此下载源代码和点阵字库文件然后，执行！sudo python progHz.py原理说明上一篇我们学过了如何在指定的区域里绘制色块的方法。说白了就是在一个指定矩形区域内按顺序设置每一个像素点的颜色。那么显示文字也是一样的道理。我们打算在某个位置显示一个汉字，要做的就是指定一个矩形区域用来绘制该汉字按顺序设置该区域的每一个像素点的颜色如果当前像素点不是组成汉字笔画的点，就画背景色，比如黑色如果当前像素点是组成汉字笔画的点，就画前景色，比如红色这样，一个黑底红字就显示出来了。汉字点阵问题来了。首先，指定一个多大的矩形区域？这个跟你要显示的文字大小有关。在本文的例程里我们绘制的是16x16像素的汉字。所以每次都需要指定一个16x16的区域用来绘图。其次，我怎么知道哪个点该显示背景色哪个点该显示前景色？这就涉及到“汉字点阵”这个概念了。这个本文不做赘述，请自行百度。简单来说就是，把每个汉字看作一个点的方阵，有笔画的地方我们用计算机的“1”表示，而没有笔画的地方用“0”来表示。比如汉字“三”的16X16大小的点阵数据应该是下面这个样子的：0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （第1行，点阵数据字节1/字节2） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （第2行，点阵数据字节3/字节4） 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 （第3行，点阵数据字节5/字节6） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （第4行，点阵数据字节7/字节8） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （第5行，点阵数据字节9/字节10） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （...） 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 （第16行，点阵数据字节31/字节32） 用上面32个字节就可以描述汉字“三”每个像素点的信息。按照这个点阵信息进行绘图不就可以显示出汉字“三”了吗？（0画一种颜色，1画另一种颜色）好，到这里你能理解了。点阵字库怎样得到指定汉字的点阵数据呢？方法有很多，本文介绍一种比较简单直观的方法--使用点阵字库文件。本文开头让你下载的HZK16.dat这个文件就是一个16x16像素的汉字点阵字库文件。很自然的问题又来了。有了字库文件，怎么从字库文件里提取某个汉字的点阵数据呢？我们一步步来。某个汉字的点阵信息是从某个起始位置（偏移值）开始的连续32个字节的数据。也就是找到数据的起始位置（偏移值），然后连续读取32个字节即可。有个公式可以计算出上面的偏移值，不要问我为什么。某汉字的字节偏移值 = ((汉字的区码 - 0xA1) 94 + 汉字的位码 - 0xA1) 32汉字的区码和位码就是该汉字以GB2312码编码时的第一和二个字节。简单吧？好了，原理就是这样了。具体实现请自己看示例代码。注释很详细，相信能看得懂。看不懂也不负责。本文是在第一篇后1年多才补上的，算是填坑，图片的显示就不再专门写文章了。原理都是一样的。弄到每个点的颜色信息，然后一个点一个点画呗。系列文章树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果树莓派GPIO入门03-GPIO控制RGB彩色LED灯树莓派GPIO入门04-使用按钮树莓派GPIO入门05-驱动数码管显示数字树莓派GPIO入门06-跟数字湿温度计DHT11通信树莓派GPIO入门07-利用声音传感器制作声控灯树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）树莓派GPIO入门08-使用74HC5…

树莓派GPIO入门11-驱动液晶屏幕（一）
type: item
date: 2016-01-30T16:03:00+08:00
description: 本系列将驱动一块1.44"的128x128像素的彩色液晶屏幕。并分几个篇幅分别讲述如何使其显示色块，英文数字，汉字以及图片。本文是系列的第一篇，目标是点亮屏幕并显示指定色块。最终效果硬件1.44英寸 spi接口 128x128液晶屏幕 X 1（淘宝10-20元）先上代码看效果这次直接上代码，大家自己复制代码保存为py文件。文件名无所谓。#!/usr/bin/env python import RPi.GPIO as GPIO import time cs=23 # 片选 rs=17 # 数据 / 命令 切换 sda=13 # 数据 scl=19 # 时钟 reset=27 # 复位 # 传输byte def setByteData(data): # print "" # print "S-----------setByte---------------:", hex(data) for bit in range(0,8): # 传入的数字从高位到低位依次判断是否为1，若为1则设置高电平，否则设置低电平 # 判断的方法是先向左移位，把要判断的位移动到最高位然后跟0x80（1000 0000）相与， # 如果结果仍然是0x80（1000 0000）就表示最高位是1，否则最高位就是0 if ((data<<bit) & 0x80 == 0x80): setBitData(True) # print "1", else: setBitData(False) # print "0", # print "" # print "E-----------setByte---------------" def setBitData(data): GPIO.output(scl, False) GPIO.output(sda, data) GPIO.output(scl, True) def write_command(cmd): GPIO.output(cs, False) GPIO.output(rs, False) setByteData(cmd) GPIO.output(cs, True) def write_data(data): GPIO.output(cs, False) GPIO.output(rs, True) setByteData(data) GPIO.output(cs, True) def write_data_16bit(dataH, dataL): write_data(dataH) write_data(dataL) def lcd_reset(): GPIO.output(reset, False) time.sleep(0.1) GPIO.output(reset, True) time.sleep(0.1) def lcd_init(): lcd_reset() write_command(0x11) # Exit Sleep time.sleep(0.02) write_command(0x26) # Set Default Gamma write_data(0x04) write_command(0xB1)# Set Frame Rate write_data(0x0e) write_data(0x10) write_command(0xC0) # Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD write_data(0x08) write_data(0x00) write_command(0xC1) # Set BT[2:0] for AVDD & VCL & VGH & VGL write_data(0x05) write_command(0xC5) # Set VMH[6:0] & VML[6:0] for VOMH & VCOML write_data(0x38) write_data(0x40) write_command(0x3a) # Set Color Format write_data(0x05) write_command(0x36) # RGB write_data(0xc8) write_command(0x2A) # Set Column Address write_data(0x00) write_data(0x00) write_data(0x00) write_data(0x7F) write_command(0x2B) # Set Page Address write_data(0x00) write_data(0x00) write_data(0x00) write_data(0x7F) write_command(0xB4) write…

树莓派GPIO入门10-使用TLC5940芯片输出多路PWM
type: item
date: 2016-01-24T13:30:00+08:00
description: 在之前的章节，我们曾经用树莓派的IO口输出不同调宽的PWM信号来控制LED灯的亮度。本文使用芯片TLC5940来输出多路PWM信号以同时控制多达16个LED的亮度。在本文的基础上你可以发挥想象，制作出各种有趣的彩灯效果。最终效果TODO视频演示硬件TLC5940芯片 X 1LED X 32-3k电阻一只原理说明简单的说，TLC5940是一个拥有16路输出的LED驱动芯片，每一路输出支持4096级！亮度调节。老规矩，看一下它的引脚图：跟本文无关的内容或设置在此不做说明，请自己查询datasheet：引脚功能OUT0-1516路PWM信号输出（负极）VPRG指定工作模式，接GND是我们需要的PWM模式SIN串行移位输入SCLK串行移位寄存器时钟（上升沿有效）XLAT从移位寄存器写入GS寄存器（下文介绍）时钟（上升沿有效）BLANK当设为高电平时，关闭所有输出，GS计数器（下文介绍）也将重置IREF跟GND之间连接一个电阻，阻值决定了输出电流的最大值GSCLKGS时钟输入（下文介绍）SOUT串行输出，级联多块芯片时使用先将BLANK设置为H，关闭所有输出。输入各组亮度信息。跟我们之前学过的芯片一样，这款芯片同样是通过移位寄存器来输入数据的。移位寄存器用于传送12bit X 16组PWM数值GSn(n=0-15)，共192bit。每组数据的值范围是0-4095。传送顺序是倒序的：GS15，GS14。。。GS0。先传输的是OUT15的12位数据，其次是OUT14的12位数据。。。最后是OUT0的12位数据。GSn决定了OUTn的PWM调宽。（GSn / 4095 = 0% - 100%）192位数据全部传送完毕后制造XLAT的上升沿，将移位寄存器里的数据写入GS寄存器。BLANK设置为L，打开所有输出准备工作完毕，为了让TLC5940芯片正常工作，还需要向GSCLK输送时钟信号。啥是时钟信号？简单的说就是高低电平不停交替的信号，也称作方波信号。TLC5940会根据这个时钟信号进行从0-4095的计数（高低电平每交替一次数一次），一边计数一边检查各GSn的设定值，一旦到达GSn的值，则切换OUTn的电平一直计数到4095为止，再从0开始重新计数。从0计数到4095就是一个高低电平的切换周期。所以我们给5940提供的时钟频率越快，最后输出的PWM频率就越快。最后输出的PWM的频率 = 时钟信号的频率 / 4095。比如时钟频率是8M，则最后从各OUT口输出的PWM频率是8MHz / 4095 = 1.953KHz。根据TLC5940的官方文档，GSCLK可支持最高30MHz的时钟频率，也就是最高可以输出7.3KHz的PWM信号。如果是控制LED的亮度，那么让人眼感觉不到闪烁的最低频率应该是50Hz以上，所以我们应该至少给GSCLK提供不低于50 X 4095 = 200KHz的方波。树莓派Python的GPIO库翻转IO口的速度不高，实测速度只能达到60KHz，导致最后输出的PWM频率只有14Hz，会有明显的闪烁感。但我们主要是为了说明原理，明白原理了可以用别的方法来实现功能，比如使用c语言的wiringPi库的话效率会高不少，甚至可以使用外部的单片机或其他电路来产生高频率的时钟信号提供给TLC5940，这个作者也在探索中。以后有空再更新。硬件连接模块1引脚模块2引脚TLC5940VPRG树莓派GPIO17TLC5940SIN树莓派GPIO13TLC5940SCLK树莓派GPIO19TLC5940XLAT树莓派GPIO27TLC5940BLANK树莓派GPIO23TLC5940IREF树莓派GND(中间串联一个2-3k的电阻)TLC5940SOUT树莓派GPIO4TLC5940OUT0LED0负极TLC5940OUT1LED1负极TLC5940OUT2LED2负极TLC5940VCC树莓派5VTLC5940GND树莓派GNDLED0,1,2正极树莓派5V代码（Python）#!/usr/bin/env python import RPi.GPIO as GPIO import time VPRG=17 SIN=13 SCLK=19 XLAT=27 BLANK=23 DCPRG=18 GSCLK=4 # 传输GSData(0-4095) def setGSData(data): # print "" # print "S-----------setByte---------------:", hex(data) for bit in range(0,12): # 传入的数字从高位到低位依次判断是否为1，若为1则设置高电平，否则设置低电平 # 判断的方法是先向左移位，把要判断的位移动到最高位然后跟0x800（1000 0000 0000）相与，…

树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管
type: item
date: 2015-06-13T15:42:00+08:00
description: 前面几篇我们学习了如何利用一片或多片级联的74HC595芯片来驱动显示数码管的方法。最开始我们提出的两个问题：占用IO口过多做动态扫描时占用CPU资源太多导致显示不稳定第一个问题已经利用级联的74HC595解决了。（不管驱动几只数码管，只用3个IO即可）但第二个问题依然存在，树莓派仍然需要不停地访问IO口进行动态扫描。好，既然动态扫描占用CPU资源太多，那这活儿咱包出去让别人干不就行了？这就是本文主角MAX7219的特长，动态扫描这活儿MAX7219全包了，干的还比咱自己干得还好，一片MAX7219可最多支持显示8位8段数码管，还支持各种设置如亮度设置扫描位数设置等。而我们只用告诉它显示的内容就行了。最终效果视频演示http://v.youku.com/v_show/id_XMTI2MTU2OTc3Ng==.html?spm=a2hzp.8253869.0.0硬件MAX7219显示芯片 X 1（2到3元一个）共阴（共阳不可以）4位数码管 X 210k电阻一只10uF电容一只0.1uF电容一只原理说明注：下面这些图都是从MAX7219官方资料里截取出来的，官方资料文末提供下载先看一下MAX7219的引脚图： MAX7219一共有24根引脚，这里面有一些跟74HC595的引脚功能类似的引脚如下：MAX721974HC595功能DINDS串行输入SEG A-G,DPQ0-Q7数码管段数据输出CLKSHCP串行移位寄存器时钟LOADSTCP内部寄存器锁存时钟DOUTQ7S串行输出，级联多块芯片时使用可以看出，MAX7219跟74HC595一样也是通过DIN引脚串行输入数据，在CLK引脚的上升沿移入移位寄存器，在LOAD引脚的上升沿将位移寄存器的数据复制到内部的各种寄存器里。不同的是:74HC595的移位寄存器是8位的，而MAX7219的移位寄存器是16位的，每次串行输入数据需要连续输入16位数据。74HC595内部只有1个8位的锁存器，功能很简单，只是原样输出到8根输出引脚。而MAX7219内部有好几个不同功能的寄存器。后面我会逐个说明。我们再看一下官方文档里关于各引脚的功能说明： 上面提过的不再赘述，说一下MAX7219特有的引脚。DIG0-DIG7这8个引脚作为位选端，分别连到8位数码管的共阴极，MAX7219在做动态扫描时会依次向共阴极DIG0-DIG7输出低电平，所以MAX7219不能驱动共阳极的数码管。其实也不是绝对不能，将位选端和段选端逆接就可以了，不过这样做的话，有3个弊端：不能使用MAX7219内部的译码功能，需要自己编写数字的字形码。增加了代码的复杂度。需要以段单位来传输数据，而不能以位单位来传输数据。（即每次传输的是各位数码管的某一段的数据，而不是某位数码管各段的数据。第一次传所有数码管的A段数据，第二次传所有数码管的B段数据一直到8段数据全部传完）无疑进一步增加了代码的复杂度。无法限制扫描位数，只能所有8位数码管同时扫描。（变成了限制扫描段数，如可以只显示所有数码管的A-C段。。。）ISET通过一只电阻连上VCC，通过调整这只电阻的阻值可以调整通过这只电阻的电流I，而最后输出到数码管上的最大电流就是这个电流I的100倍。如果这只电阻太小，导致输出到数码管的电流过大会烧坏数码管，所以官方文档里推荐这只电阻最小应该设置为9.7K欧，我手头上只有10K的电阻也是一样，只要别低于这个阻值就可以了。根据这个原理我们也可以接一个可调电阻在ISET上，可以随时调整数码管亮度。这种调整亮度的方法是通过模拟信号调制。MAX7219也支持通过数字信号来设置亮度（有16级亮度可调）。MAX7219内部的各模块的示意图： 最下面是一个16位的移位寄存器D0-D15，跟74HC595一样，通过DIN引脚串行输入数据，在CLK引脚的上升沿移入移位寄存器。 D8-D11这4位数据用来指定内部寄存器地址。D0-D7是具体要传到寄存器里的数据。 上面的图看上去有点复杂，其实简单地说就是我们每次要串行传输16位数据进去，然后在LOAD的上升沿，根据D8-D11指定的寄存器地址，将D0-D7存放在指定的寄存器里。这样多次传输数据就可以给所有的寄存器设值了。 下面是MAX7219内部的寄存器一览：关断寄存器译码模式寄存器亮度寄存器扫描限值寄存器显示器测试寄存器每个寄存器都有自己特殊的功能，后面我们会逐一介绍。串行传输时的数据格式如下： 你可能注意到了这幅图的顺序跟模块示意图里移位寄存器的顺序是相反的。 D15-D0这个反向的顺序是你写代码时串行传输数据时的顺序，先传D15的数据，再传D14,D13...D0，这样传输完成后。实际的数据顺序就变成了D0,D1,D2...D15。为了便于编码，除了模块示意图是按实际顺序记载的，后面所有数据格式的示意图都是倒…

树莓派GPIO入门08-使用74HC595芯片驱动数码管（二）
type: item
date: 2015-06-08T20:44:00+08:00
description: 上一篇我们学习了如何利用74HC595这块显示驱动芯片来驱动1位8段数码管的方法。并逐一讲解了该芯片各引脚的功能。细心的童鞋可能注意到了，上次我们有一个Q7S引脚没有用到。这一篇我们就用这个引脚来级联两块74HC595芯片同时驱动8个8段数码管。在两块74HC595芯片的配合下，同样只需要3个GPIO口就能驱动八只8段数码管。而如果直接用GPIO驱动则需要至少16个GPIO口，节省了13个GPIO！而且按照本文的方法，你还可以级联更多的74HC595芯片，每多级联一片就能多驱动8只数码管，而需要的IO口仍然只有3个！妈妈再也不用担心我的IO口不够用了。最终效果视频演示http://v.youku.com/v_show/id_XMTI1NzE1MDQwOA==.html?spm=a2hzp.8253869.0.0硬件74HC595显示芯片 X 2共阳（或共阴）4位数码管 X 2原理说明我们已经知道，每次制造一次移位寄存器时钟引脚的上升沿，74HC595都会在这个上升沿将DS引脚上的数据存入内部的移位寄存器D0，同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7。而D7的数据会被输出到引脚Q7S上，如果Q7S引脚没有被使用，那么这一位数据就被丢掉了。如果我们将Q7S引脚连接上另一块74HC595的DS引脚并保证两块芯片上的移位时钟的上升沿同时发生（将两块芯片的SHCP连在一起即可）的话，第一块74HC595的串行输出引脚Q7S就变成了第二块74HC595的串行输入数据源。Q7S上的数据会继续移位到第二块74HC595芯片的移位寄存器D0里（同样的，D0→D1→D2→...→D6→D7→Q7S）。16位数据全部这样串行传输完毕后，制造两块芯片的锁存时钟STCP的上升沿（跟SHCP一样，两块芯片的STCP连在一起即可）即可同时输出16位数据。利用上述级联原理加上前一篇学习的内容，我们可以这样静态驱动2只数码管：两只数码管的共阳(阴)极连接VCC(GND)，第一片595的Q0-Q7连到第一个数码管的A-G，Dp上，级联的第二片595的Q0-Q7连到第二只数码管的A-G,Dp上，然后用3根GPIO口驱动两片级联的74HC595芯片，连续串行输入两个数字的显示码共16位数据，然后同时制造锁存上升沿，将两个数字的显示码分别输出到两只数码管上即可。这样连接的话，N片级联的74HC595就能驱动N只数码管了。（咦，说好的驱动8位数码管的呢）上面的做法当然没问题，而且有一个优点是静态显示所以显示很稳定，有兴趣自己试着做一下。缺点是浪费芯片，价格倒不贵可是连线复杂，占用电路板面积太多。本文采用动态扫描（原理参见本系列第5篇）的方式来使用两块级联的74HC595芯片驱动8位数码管。原理也很简单，稍微调整一下硬件的连接方式和传输数据的方式即可。依然是两块74HC595级联，第一块595的输出引脚连到所有数码管的段引脚上（8只数码管的A-G,Dp引脚连在一起）,第二块595的输出引脚Q0-Q7分别连上8只数码管的共阳(阴)极上。第一块芯片的输出决定了数码管上显示什么数字。而8只数码管中哪一只会被点亮则取决于第二块芯片哪只数码管的共阳(阴)端是高(低)电平。由于在我的硬件连接里，级联的第二块74HC595是负责位选的，所以应该先发送8位位选信号，再发送8位段选信号，在连续发完了16位数据以后，第一块74HC595的移位寄存器里保存着8位的段选信息，而在第二块74HC595的移位寄存器里保存着8位的位选信息。由于两片芯片的STCP是连在同一个GPIO口的，这个时候如果制造一次STCP的上升沿，两块595的位移寄存器里的数据会同时保存到自己的锁存器里，由于我的使能端OE连在GND始终有效，锁存器里的数据就直接输出到了芯片的输出引脚上。第二块芯片的8根输出引脚连接的是8位数码管的共阳端。只有输出高电平的引脚连接的数码管才会被点亮。当然如果你喜欢，你也可以让8个数码管全部同时点亮，你只要让第二块595输出11111111就行了。不过显示的数字都是一样的。想显示不同的数字就要进行动态扫描，每次输出一个数字的显示码跟一个位选码，快速循环切换显示即可。跟上一篇一样，我也做了一个动画帮助你理解级联的过程。这个动画一开始已经是传输完前8位位选数据的状态了，动画里的位选数据是1000000，点亮第一个数码管，显示的内容由后8位段选数据决定，动画里是数字5。硬件连接模块1引脚模块2引脚74HC595_1Q0数码管1/2DP74HC595_1Q1数码管1/2G74HC595_1Q2数码管1/2F74HC595_1Q3数码管1/2E74HC595_1Q4数码管1/2D74HC595_1Q5数码管1/2C74HC595_1Q6数码管1/2B74HC595_1…

树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）
type: item
date: 2015-06-03T21:36:00+08:00
description: 之前我们学习了如何驱动数码管显示数字。但是这种做法有两个缺点。需要占用大量IO口，在那篇文章里，我们为了驱动4位数码管一共使用了12个IO口。如果需要驱动8位数码管则至少需要16个IO口。系统资源占用过多。还是在那篇文章里，为了实现数码管的动态扫描显示，需要不停地高速操作IO口，这对单任务的单片机比如51单片机来说问题并不太大，因为单任务的单片机的执行时序是由晶振来决定的，动态扫描的时间间隔可以控制地非常精确，数码管的显示会很稳定，不会出现闪烁的现象。但对于运行着多任务的Linux操作系统的树莓派来说，对IO口的大量反复操作以及大量使用sleep语句会导致CPU占用过多，最后导致动态扫描的间隔时间不均匀，体现为数码管显示不稳定，有明显闪烁的现象。为了改善这个问题我在那篇文章的最后还尝试用c语言来代替python语言，可实际效果有限。使用GPIO直接驱动数码管时，上面这两个问题是不可避免的。想解决这两个问题，我们需要借助外部芯片的帮助。接下来我将用几个篇幅来介绍如何使用显示驱动芯片74HC595来驱动数码管的方法。同时我们也可以学习到串行数据传输的方法以及一些数字芯片通用的一些概念，比如时钟引脚，上升沿，锁存，移位寄存等。理解了这些通用的概念对学习使用其他芯片是很有帮助的。本文最终效果在一块74HC595芯片的配合下，只需要3个GPIO就能驱动一只8段数码管。（直接用GPIO驱动需要至少8个GPIO口）视频演示http://v.youku.com/v_show/id_XMTI1NTAxMTMyMA==.html?spm=a2hzp.8253869.0.0硬件74HC595芯片一只（0.5元一只）共阳（或共阴）数码管一只限流电阻一只，330欧就够了。原理说明先转一段百度百科上74HC595芯片的简介。74HC595具有8位移位寄存器和一个存储器，三态输出功能。 移位寄存器和存储器有相互独立的时钟。数据在SH_cp（移位寄存器时钟输入）的上升沿输入到移位寄存器中，在ST_cp（存储器时钟输入）的上升沿输入到存储寄存器中去。如果两个时钟连在一起，则移位寄存器总是比存储寄存器早一个脉冲。移位寄存器有一个串行移位输入（Ds），和一个串行输出（Q7’）,和一个异步的低电平复位，存储寄存器有一个并行8位的，具备三态的总线输出，当使能OE时（为低电平），存储寄存器的数据输出到总线。看不懂吧，没关系，我们先看一下芯片的引脚图：分别解释一下：GND接地，VCC接5V电源，这个就不用说了。Q0-Q7这8根引脚是芯片的输出引脚，直接跟数码管的8段引脚相连。对应关系要看你怎么接线和写代码时传送数据的顺序了。DS是串行输入引脚，所谓串行就是使数据在一根信号线上按顺序一位一位地传输，就像一串糖葫芦。这个引脚我们接到树莓派任意一个GPIO口上（输出模式）。SHCP是移位寄存器的时钟引脚。听上去有点复杂，其实很简单。74HC595内部有一个8位的移位寄存器用来保存从DS引脚输入的数据。那么74HC595怎么知道什么时候该从DS引脚上取数据了呢？正是通过SHCP这个时钟引脚来实现的。只有在SHCP发生一次上升沿的时候，74HC595才会从DS引脚上取得当前的数据（高/低电平）并把取到的这一位数据保存到移位寄存器里。同样的，这个引脚也接到树莓派任意一个GPIO口上。当我们向芯片发送数据时，要先在DS引脚上准备好要传送的数据，然后制造一次SHCP引脚的上升沿（先拉低电平再拉高电平），74HC595会在这个上升沿将DS引脚上的数据存入移位寄存器D0，同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7。而原先D7的数据已经没有地方储存了，这一位数据会被输出到引脚Q7S上。这个引脚的作用我们下一篇再说，本文暂时用不到这个引脚。（注意这里说的不是输出引脚Q0-Q7，而是指内部的8位移位寄存器里每一个“小房间”，芯片手册上并没有给这些小房间编号，这里为了说明方便进行了编号）STCP是芯片内部另外一个8位锁存寄存器的时钟引脚。当移位寄存器的8位数据全部传输完毕后，制造一次锁存器时钟引脚的上升沿（先拉低电平再拉高电平）。74HC595会在这个上升沿将移位寄存器里的8位数据复制到锁存器中（锁存器里原来的数据将被替换）。注意，到这里为止，这8位数据还只是被保存在锁存器里，并没有输出到数码管上。这个引脚同样连接到树莓派任意一个GPIO口上即可。OE是输出使能引脚，在其他芯片里也很常见。作用是控制锁存器里的数据是否最终输出到Q0-Q7输出引脚上。低电平时输出，高电平时不输出（既不是高电平，也不是低电平而是高阻态，不通电）。本例为了方便直接接在GND上使其一直保持低电平输出数据。MR是用来重置内部寄存器的引脚。低电平时重置内部寄存器(MemoryReset?)。本…

树莓派GPIO入门07-利用声音传感器制作声控灯
type: item
date: 2015-05-22T00:03:00+08:00
description: 本文我们用声音传感器来制作一个简易的声控灯。最终效果视频演示：http://v.youku.com/v_show/id_XOTYyMjQ4MTUy.html?spm=a2hzp.8253869.0.0硬件面包板杜邦线LED发光二极管一只声音传感器一只原理说明声音传感器有3根引脚，电源正极，电源负极，数据OUT，分别接到树莓派的VCC，GND和任意一个GPIO口上（输入模式）。当声音传感器检测到有声音就会从OUT口输出低电平，注意低电平并不会持续，声音一旦结束传感器也会马上停止输出低电平。另外，在传感器上有一个电位器，上面有一个十字形的旋钮，用小螺丝刀或小刀可以旋转十字，调整声音敏感度。（触发音量的阈值）LED的短针负极脸上GND，长针连上另一个GPIO口（输出模式），当树莓派接收到传感器发出的低电平信号时，输出高/低电平，打开/关闭LED灯。硬件连接声音传感器电源正极 - 树莓派的VCC声音传感器电源负极 - 树莓派的GND声音传感器数据OUT - 树莓派的GPIO4LED长针 - 树莓派的GPIO17LED短针 - 树莓派的GND代码（Python）#!/usr/bin/env python # encoding: utf-8 import RPi.GPIO import time # LED正极连接的GPIO口 LED = 17 # 声音感应器OUT口连接的GPIO口 SENSOR = 4 # 当前LED灯的开关状态 flg = False RPi.GPIO.setmode(RPi.GPIO.BCM) # 指定GPIO4（声音感应器的OUT口连接的GPIO口）的模式为输入模式 # 默认拉高到高电平，低电平表示OUT口有输出 RPi.GPIO.setup(SENSOR, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP) # 指定GPIO17（LED长针连接的GPIO针脚）的模式为输出模式 RPi.GPIO.setup(LED, RPi.GPIO.OUT) try: while True: # 检测声音感应器是否输出低电平，若是低电平，表示声音被检测到，点亮或关闭LED灯 if (RPi.GPIO.input(SENSOR) == 0): flg = not flg RPi.GPIO.output(LED, flg) # 稍微延时一会，避免刚点亮就熄灭，或者刚熄灭就点亮。 time.sleep(0.5) except KeyboardInterrupt: pass RPi.GPIO.cleanup()资源下载点击下载源码系列文章树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果树莓派GPIO入门03-GPIO控制RGB彩色LED灯树莓派GPIO入门04-使用按钮树莓派GPIO入门05-驱动数码管显示数字树莓派GPIO入门06-跟数字湿温度计DHT11通信树莓派GPIO入门07-利用声音传感器制作声控灯【当前文章】树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）树莓派GPIO入门08-使用74HC595芯片驱动数码管（二）树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管树莓派GPIO入门10-使用TLC5940芯片输出多路PWM树莓派GPIO入门11-驱动液晶屏幕（一）树莓派GPIO入门11-驱动液晶屏幕（二）

树莓派GPIO入门06-跟数字湿温度计DHT11通信
type: item
date: 2015-05-17T22:27:00+08:00
description: 本文我们利用树莓派的GPIO口来跟数字湿温度计模块DHT11进行通信取得温度和湿度数据并显示在数码管上，通过按钮来切换显示温度或湿度。最终效果硬件数码管杜邦线面包板按钮1只数字湿温度计DHT11模块。（我们这个教程里用到的所有电子元件均可在淘宝购买到）原理说明原始的DHT11模块有4根引脚，长成这个样子：由图可以看出4根引脚里除了VCC，GND，DATA以外，还有一个引脚是N/A，也就是不使用。（不使用引出来干嘛？好看吗？不解）本文使用的是又被封装了一次的模块，去掉了无用的引脚。其他3个引脚保留。功能完全一样，所以如果你手头上的DHT11是有4根引脚的请忽略N/A针脚，其他的跟我使用的这种完全通用。3个针脚分别连接到3.3v电源，GND和任意GPIO口上。根据数据手册（文末提供下载）的说明，总线（DATA引脚）在空闲状态需要保持高电平状态，所以我们除了将DATA引脚接到一个GPIO口上，还要通过一个4.7K（经实测2K左右的就够了）的电阻将DATA引脚并联到VCC上。这个电阻也称上拉电阻，电阻就是一般的电阻，只是在这里起的作用是上拉电平的作用所以称之为上拉电阻。与DHT11通信时，发送和接收信息都在一根DATA口上，这种只用1根总线的数据传输方式称为单总线模式。向DHT11发送数据时，GPIO口需要设置为OUTPUT模式，从DHT11接收数据时GPIO口需要切换成INPUT模式。具体通信的时序如下：由于有上拉电阻存在，总线（DATA）空闲状态为高电平。树莓派GPIO口设置为OUTPUT模式。树莓派向DHT11发送起始信号。方式是GPIO口设置低电平并持续一段时间，根据数据手册的说明，这段时间必须大于18毫秒，保证DHT11能检测到起始信号。树莓派起始信号输出完毕，切换到输入模式，等待DHT11响应。一旦切换到输入模式GPIO口就不再输出电平信号，总线处于释放状态，由于有上拉电阻的存在，总线被拉回高电平。在总线被拉回至高电平通知DHT11主机已经准备好接受数据以后，DHT11还会继续等待20-40us左右以后才会开始发送反馈信号。DHT11开始发送反馈信号，总线被DHT11拉低，持续80us左右。这个持续了80us左右的低电平的反馈信号结束以后，DHT11又会将DATA口拉回高电平并再次持续80us左右。DHT11开始正式传输40bit的二进制数据（0或1）。每一个bit的数据（0或者1）总是由一段持续50us的低电平信号开始，再由一段持续26us-28us（数据0）或者持续70us（数据1）的高电平结束。一直到40位数据传输完毕。这40位的数据内容是：8bit湿度整数数据 + 8bit湿度小数数据 + 8bi温度整数数据 + 8bit温度小数数据 + 8bit校验和。而校验和数据应该等于“湿度整数数据+湿度小数数据+温度整数数据+温度小数数据”所得结果的末8位。我们的程序就应该遵循上述时序来与DHT11进行数据通信。硬件连接下面的连接图只标出了DHT11的连线和上拉电阻的连线方法。数码管和按钮的连线请参考上一篇。关键代码void readDHT11() { int i,j,cnt = 0; for (j = 0; j < RETRY; ++j) { for (i = 0; i < 5; ++i) { data[i] = 0; } // GPIO口模式设置为输出模式 pinMode (DATA, OUTPUT) ; // 先拉高DATA一段时间，准备发送开始指令 digitalWrite (DATA, HIGH); usleep(500000); // 500 ms // 拉低DATA口，输出开始指令（至少持续18ms） digitalWrite (DATA, LOW); usleep(TIME_START); digitalWrite (DATA, HIGH); // 开始指令输出完毕，切换到输入模式，等待DHT11输出信号。 // 由于有上拉电阻的存在，所以DATA口会维持高电平。 pinMode (DATA, INPUT); // 在DATA口被拉回至高电平通知DHT11主机已经准备好接受数据以后， // DHT11还会继续等待20-40us左右以后才会开始发送反馈信号，所以我们把这段时间跳过去 // 如果长时间（1000us以上）没有低电平的反馈表示有问题，结束程序 cnt=0; while (digitalRead(DATA) == HIGH) { cnt++; if (cnt > MAXCNT) { printf("DHT11未响应，请检查连线是否正确，元件是否正常工作。\n"); exit(1); } } // 这个反馈响应信号的低电平会持续80us左右，但我们不需要精确计算这个时间 // 只要一直循环检查DATA…

树莓派GPIO入门05-驱动数码管显示数字
type: item
date: 2015-05-05T22:30:00+08:00
description: 这次我们用树莓派的GPIO口驱动数码管来显示数字，进而制作一个简单的电子钟，通过按钮来切换显示时间或日期。最终效果硬件数码管一只。因为需要显示日期时间所以需要能显示4个数字的数码管，也称4位数码管。淘宝买1块多钱一只。注意数码管有共阳和共阴的。我这里使用的是共阳的。至于区别，下面的原理说明里会详细解释。杜邦线若干。面包板一块。按钮1只。原理说明标准的数码管从显示内容上分7段和8段数码管两种。8段比7段多一个右下角的小数点。还有一些其他特殊的如可以显示米字形的数码管不在本文讨论范围内，其实原理都是一样的。8段数码管由8个发光二极管组成，其中7个用于组成数字，1个用于显示小数点。每一根的编号如下图的右上角所示(A-G,DP)。数码管从电源极性上分共阳和共阴两种。解释一下，如果数码管上每一个独立的发光二极管都单独引出两根引脚，一根接正极(阳)一根接负极(阴)，那么一个8段数码管就需要16根引脚来控制。但其实这8段数码管完全可以在内部共用一个阳级，只控制各段发光二极管的阴级联通即可，这就是共阳。反之亦然，叫共阴。共阳或共阴的每个8段数码管只需要引出9个引脚，1个阳(阴)级接到树莓派vcc(gnd)上，另外8个分别连到gpio口上，通过控制io口高低电平即可显示所需数字。比如一只共阳数码管想显示数字1，看LED编号图可知需要点亮b段和c段，其他全灭。那么连到共阳端引脚的io口输出高电平，连到引脚b、c的io口输出低电平，连到引脚a、d、e、f、g、dp的io口均输出高电平即可。写成代码就是：# 定义各段发光二极管对应的GPIO口 LED_A = 26 LED_B = 19 LED_C = 13 LED_D = 6 LED_E = 5 LED_F = 11 LED_G = 9 LED_DP = 10 # 定义数码管共阳极对应的GPIO口 VCC = 12 # 避免闪烁，在输出数字字形信号前先拉低共阳端，关闭显示 RPi.GPIO.output(VCC, False) # 输出数字1的字形信号 RPi.GPIO.output(LED_A, True) RPi.GPIO.output(LED_B, False) RPi.GPIO.output(LED_C, False) RPi.GPIO.output(LED_D, True) RPi.GPIO.output(LED_E, True) RPi.GPIO.output(LED_F, True) RPi.GPIO.output(LED_G, True) RPi.GPIO.output(LED_DP, True) # 最后拉高共阳段，显示数字 RPi.GPIO.output(VCC, True)本文使用的数码管是8段共阳4位(4个数字)数码管，型号是F3461BH。上面说了共阳数码管每个数字需要9个引脚来控制，那么4个数字就需要36个引脚吗？显然不现实，树莓派的io口也完全不够用。这就引出另一个概念，静态显示和动态扫描显示。静态显示，就是前面说的每一个数字需要占用8个io口，每多一个数字就需要额外的8个io口，如果数字位数不多，io口够用的话，这样做完全没问题。实际应用中往往需要显示多个数字，io口基本上是不够用的。这就需要动态扫描显示了。下面摘一段百度百科关于动态扫描显示的说明(稍有改动):数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一，动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起引出8个引脚，每个数字再单独引出共阳(阴)端，这样总引脚数就只要8 + 数字个数即可，本文使用的8段4位数码管正是引出了12个引脚。至于哪个引脚对应哪一段，哪几个引脚分别对应各数字的共阳(阴)端，就需要商家提供电路图了。当然也可以自己慢慢试，这不在本文讨论范围，大家可以自己摸索。当树莓派输出8个段信号时，所有数码管都会接收到相同的信号，但究竟是哪个数码管会显示出字形，取决于这个数码管对应的共阳(阴)极(后统称位选端)有无导通。所以我们只要将需要显示的数码管的位选端选通，该位就显示出字形，没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的位选端，就使各个数码管轮流受控显示，这就是动态驱动。在轮流显示过程中，每位数码管的点亮时间为1～2ms，由于人的视觉暂留现象及发光二极管的余辉效应，尽管实际上各位数码管并非同时点亮，但只要扫描的速度足够快，给人的印象就是一组稳定的显示数据，不会有闪烁感，动态显示的效果和静态显示是一样的，能够节省大量的I/O端口，而且功耗更低。综上，比如我们想要在4位共阳数码管上显示1234这4个数字，要做的就是：避免闪烁，在输出数字字形信号前先拉低所有4个共阳极，关闭所有显示。拉低1号数码管的共阳极，关闭显示。输出1号数码管上希望显示的数字字形…

树莓派GPIO入门04-使用按钮
type: item
date: 2015-05-03T20:38:00+08:00
description: 上一篇我们通过程序控制彩色LED发出不同颜色的光。这次我们用3个按钮来手动控制彩色LED灯分别发出红，绿，蓝光并可以同时按下不同按钮以显示混合颜色的光。最终效果硬件跟上一节一样，彩色RGB二极管一只。杜邦线若干。面包板一块。按钮3只。这种按钮是最常见的小按钮，有四只引脚。分别两两相通。按下按钮以后原来不通的引脚之间会被联通。把按钮翻过来看腹部可以看到联通的引脚之间有凹槽相连，很容易辨认。原理说明从树莓派上引GND（负极）到面包板上，3个按钮默认不联通的两只引脚的一只接到GND上。另一只接到树莓派GPIO口上。这3个GPIO口在程序里设置为输入模式，并且默认拉到高电平。当某个按钮被按下，即联通GND端到GPIO口上，此时从GPIO口取到的状态为低电平。程序侦测到低电平时就认为按钮被按下，从而可以做你想做的事情（点亮红/绿/蓝灯）。硬件连接代码#!/usr/bin/env python # encoding: utf-8 import RPi.GPIO import time R,G,B=15,18,14 # 按钮输出针脚连接的GPIO口 btnR, btnG, btnB=21,20,16 RPi.GPIO.setmode(RPi.GPIO.BCM) RPi.GPIO.setup(R, RPi.GPIO.OUT) RPi.GPIO.setup(G, RPi.GPIO.OUT) RPi.GPIO.setup(B, RPi.GPIO.OUT) # 按钮连接的GPIO针脚的模式设置为信号输入模式，同时默认拉高GPIO口电平， # 当GND没有被接通时，GPIO口处于高电平状态，取的的值为1 # 注意到这是一个可选项，如果不在程序里面设置，通常的做法是通过一个上拉电阻连接到VCC上使之默认保持高电平 RPi.GPIO.setup(btnR, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP) RPi.GPIO.setup(btnG, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP) RPi.GPIO.setup(btnB, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP) try: RPi.GPIO.output(R, True) RPi.GPIO.output(G, True) RPi.GPIO.output(B, True) while True: time.sleep(0.01) # 检测按钮1是否被按下，如果被按下(低电平)，则亮红灯(输出低电平)，否则关红灯 if (RPi.GPIO.input(btnR) == 0): RPi.GPIO.output(R, False) else: RPi.GPIO.output(R, True) # 检测按钮2是否被按下，如果被按下(低电平)，则亮绿灯(输出低电平)，否则关绿灯 if (RPi.GPIO.input(btnG) == 0): RPi.GPIO.output(G, False) else: RPi.GPIO.output(G, True) # 检测按钮3是否被按下，如果被按下(低电平)，则亮蓝灯(输出低电平)，否则关蓝灯 if (RPi.GPIO.input(btnB) == 0): RPi.GPIO.output(B, False) else: RPi.GPIO.output(B, True) except KeyboardInterrupt: pass RPi.GPIO.cleanup()源代码下载点击下载系列文章树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果树莓派GPIO入门03-GPIO控制RGB彩色LED灯树莓派GPIO入门04-使用按钮【当前文章】树莓派GPIO入门05-驱动数码管显示数字树莓派GPIO入门06-跟数字湿温度计DHT11通信树莓派GPIO入门07-利用声音传感器制作声控灯树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）树莓派GPIO入门08-使用74HC595芯片驱动数码管（二）树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管树莓派GPIO入门10-使用TLC5940芯片输出多路PWM树莓派GPIO入门11-驱动液晶屏幕（一）树莓派GPIO入门11-驱动液晶屏幕（二）