<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Mango Love Carrot]]></title>
  <subtitle><![CDATA[芒果爱吃胡萝卜]]></subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="http://blog.mangolovecarrot.net/"/>
  <updated>2017-09-18T15:05:01.000Z</updated>
  <id>http://blog.mangolovecarrot.net/</id>
  
  <author>
    <name><![CDATA[mango]]></name>
    <email><![CDATA[slipperstree#gmail.com]]></email>
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[ESP8266家族的小弟ESP01上手试玩(1)]]></title>
    <link href="http://blog.mangolovecarrot.net/2017/09/18/esp01/"/>
    <id>http://blog.mangolovecarrot.net/2017/09/18/esp01/</id>
    <published>2017-09-18T14:37:22.000Z</published>
    <updated>2017-09-18T15:05:01.000Z</updated>
    <content type="html"><![CDATA[<p>乘着物联网的东风，中国的安信可（AI-Thinker）推出的ESP8266系列可是火了一把。<br>所谓物美价廉，花很少的钱就能让你的老爷车51单片机系统插上无线的翅膀，真的是带你zb带你飞。。。<br>其实不仅仅是51，AVR/STM甚至Aduino系列都能鸡犬升天。<br>说了这么多废话，这篇文章不是教程，只是记录一下上手esp01时掉过的坑以及怎么爬出来的。。。</p>
<a id="more"></a>
<h3 id="一定要进入flash模式！！一定要进入flash模式！！一定要进入flash模式！！">一定要进入flash模式！！一定要进入flash模式！！一定要进入flash模式！！</h3><p>不然无法烧录。<br>进入方法 GPIO0下拉CH_PD上拉 的状态下reset，重新上电就行。</p>
<h3 id="■_■_■_重要！！！！_■_■_■">■ ■ ■ 重要！！！！ ■ ■ ■</h3><p>   ESP01 烧录这个模块的时候，我最初直接用USB转串口模块直接供电，最后烧录是成功了但是无限重启，各种奇怪的现象<br>         最后，用两节5号电池单独给模块供电（一定要跟USB串口模块共地，否则串口不能工作）后解决了。<br>         原因是电脑USB口驱动电流太小，实测ESP01上电电流达到200ma，直接把电源电压拉低到1.几伏特。模块当然无法工作。<br>         事后仔细查看了我用的USB转串口模块上使用的稳压芯片662K，这个芯片最高输出电流只有250ma，ESP01启动时需要200多ma的电流确实比较吃力。<br>         以后再购买USB转串口模块的时候可以注意一下输出电流的参数，大一点比较方便。<br>         后来又自己用输出电流800ma的LM1117T来供电，没有问题了。（注意尽量避免面包板跟杜邦线多次转接，会影响正常启动的）<br>         总结，电源很重要。奇怪的问题大多跟电源有关。</p>
<h3 id="Flasher的设置">Flasher的设置</h3><h4 id="■DIO">■DIO</h4><h4 id="■波特率选115200（注意，这里选的波特率并不是烧录完成以后的系统的默认波特率，只是烧录时使用的波特率而已，大一点就快一点）">■波特率选115200（注意，这里选的波特率并不是烧录完成以后的系统的默认波特率，只是烧录时使用的波特率而已，大一点就快一点）</h4><h4 id="■Flash大小可以用下面的esptool工具查看，同样需要先进入flash模式（GPIO0下拉CH_PD上拉）">■Flash大小可以用下面的esptool工具查看，同样需要先进入flash模式（GPIO0下拉CH_PD上拉）</h4><pre><code><span class="comment"><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">　　esptool<span class="class">.py</span> -<span class="tag">p</span> COM5 flash_id</span><br></pre></td></tr></table></figure></span>
</code></pre><p>　　※为了安装这个tool，需要先安装python27以上，然后再python里安装依赖包 setuptools / pyserial ，最后才能安装esptool成功。<br>      安装顺序:<br>        1 - python27  装完以后吧python安装目录以及python/script目录一起加入环境变量path<br>        2 - 进入文件夹 ./pythonLib/<br>            <figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">python</span> ez_setup.<span class="keyword">py</span> install (必须,安装pyserial用）</span><br><span class="line"><span class="keyword">python</span> <span class="built_in">get</span>-pip.<span class="keyword">py</span> install (非必须，只是为了方便以后用pip安装<span class="keyword">python</span>库)</span><br></pre></td></tr></table></figure></p>
<pre><code>  3 - 进入文件夹 ./pyserial-3.2.1/  
      <span class="comment"><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python setup<span class="class">.py</span> install</span><br></pre></td></tr></table></figure></span>

  4 - 进入文件夹 ./esptool-master/
      <span class="comment"><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python setup<span class="class">.py</span> install</span><br></pre></td></tr></table></figure></span>

运行时需要进入安装的目录。
常用命令 （COM5根据实际情况修改）
   擦除flash : 
   <span class="comment"><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">esptool<span class="class">.py</span> -<span class="tag">p</span> COM5 erase_flash</span><br></pre></td></tr></table></figure></span>

   查看芯片信息 : 
   <span class="comment"><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">esptool<span class="class">.py</span> -<span class="tag">p</span> COM5 flash_id</span><br></pre></td></tr></table></figure></span>

   详细命令:      [详细命令](https://github.com/espressif/esptool "详细命令")
</code></pre><h4 id="■esp_init_data_default-bin_烧录文件的烧录地址需要用到flash大小的信息。（这个data可以不烧录）">■esp_init_data_default.bin 烧录文件的烧录地址需要用到flash大小的信息。（这个data可以不烧录）</h4><p>　　　<a href="https://nodemcu.readthedocs.io/en/master/en/flash/" target="_blank" rel="external">https://nodemcu.readthedocs.io/en/master/en/flash/</a></p>
<p>　　　SDK Init Data</p>
<p>　　　0x7c000 for 512 kB, modules like most ESP-01, -03, -07 etc.<br>　　　0xfc000 for 1 MB, modules like ESP8285, PSF-A85, some ESP-01, -03 etc.<br>　　　0x1fc000 for 2 MB<br>　　　0x3fc000 for 4 MB, modules like ESP-12E, NodeMCU devkit 1.0, WeMos D1 mini<br>　　　0x7fc000 for 8 MB<br>　　　0xffc000 for 16 MB, modules like WeMos D1 mini pro<br>　　　See “4.1 Non-FOTA Flash Map” and “6.3 RF Initialization Configuration” of the ESP8266 Getting Started Guide for details on init </p>
<h4 id="■烧录完成后，去掉GPIO0的下拉，重新上电-">■烧录完成后，去掉GPIO0的下拉，重新上电.</h4><p>   第一次上电可能会看到 Formatting file system. Please wait…<br>   这种消息反复出现，不要以为又失败了无限重启，这是正常的，反复几次以后就进入NodeMCU系统了。</p>
<h4 id="下一篇可能会写一些具体的代码和实现的功能，可能。。。">下一篇可能会写一些具体的代码和实现的功能，可能。。。</h4>]]></content>
    <summary type="html">
    <![CDATA[<p>乘着物联网的东风，中国的安信可（AI-Thinker）推出的ESP8266系列可是火了一把。<br>所谓物美价廉，花很少的钱就能让你的老爷车51单片机系统插上无线的翅膀，真的是带你zb带你飞。。。<br>其实不仅仅是51，AVR/STM甚至Aduino系列都能鸡犬升天。<br>说了这么多废话，这篇文章不是教程，只是记录一下上手esp01时掉过的坑以及怎么爬出来的。。。</p>]]>
    
    </summary>
    
      <category term="ESP01" scheme="http://blog.mangolovecarrot.net/tags/ESP01/"/>
    
      <category term="ESP8266" scheme="http://blog.mangolovecarrot.net/tags/ESP8266/"/>
    
      <category term="无线模块" scheme="http://blog.mangolovecarrot.net/tags/%E6%97%A0%E7%BA%BF%E6%A8%A1%E5%9D%97/"/>
    
      <category term="单片机" scheme="http://blog.mangolovecarrot.net/categories/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门11-驱动液晶屏幕（二）]]></title>
    <link href="http://blog.mangolovecarrot.net/2017/03/05/raspi-study1102/"/>
    <id>http://blog.mangolovecarrot.net/2017/03/05/raspi-study1102/</id>
    <published>2017-03-04T23:24:30.000Z</published>
    <updated>2017-03-05T11:48:20.000Z</updated>
    <content type="html"><![CDATA[<p>本系列将驱动一块1.44”的128x128像素的彩色液晶屏幕。<br>本文是系列的第2篇，也是最后一篇，目标是在液晶屏上显示文字。</p>
<a id="more"></a>
<h3 id="最终效果">最终效果</h3><p><img src="lcd.jpg" alt="最终效果"></p>
<h3 id="硬件及连接">硬件及连接</h3><p>参考本系列第一篇</p>
<h3 id="先运行程序看效果">先运行程序看效果</h3><p>下载下面两个文件放在同一目录下。<br><a href="progHz.py" title="下载python程序">python程序</a><br><a href="HZK16.dat" title="下载点阵字库文件">点阵字库</a></p>
<p>然后，执行！<br><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="keyword">python</span> progHz.<span class="keyword">py</span></span><br></pre></td></tr></table></figure></p>
<h3 id="原理说明">原理说明</h3><p>上一篇我们学过了如何在指定的区域里绘制色块的方法。说白了就是在一个指定矩形区域内按顺序设置每一个像素点的颜色。<br>那么显示文字也是一样的道理。我们打算在某个位置显示一个汉字，要做的就是</p>
<ul>
<li>指定一个矩形区域用来绘制该汉字</li>
<li>按顺序设置该区域的每一个像素点的颜色</li>
<li>如果当前像素点不是组成汉字笔画的点，就画背景色，比如黑色</li>
<li>如果当前像素点是组成汉字笔画的点，就画前景色，比如红色<br>这样，一个黑底红字就显示出来了。</li>
</ul>
<h4 id="汉字点阵">汉字点阵</h4><p>问题来了。<br>首先，指定一个多大的矩形区域？这个跟你要显示的文字大小有关。在本文的例程里我们绘制的是16x16像素的汉字。所以每次都需要指定一个16x16的区域用来绘图。<br>其次，我怎么知道哪个点该显示背景色哪个点该显示前景色？这就涉及到“汉字点阵”这个概念了。这个本文不做赘述，请自行百度。<br>简单来说就是，把每个汉字看作一个点的方阵，有笔画的地方我们用计算机的“1”表示，而没有笔画的地方用“0”来表示。<br>比如汉字“三”的16X16大小的点阵数据应该是下面这个样子的：</p>
<pre><code><span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">1</span>行，点阵数据字节<span class="number">1</span>/字节<span class="number">2</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">2</span>行，点阵数据字节<span class="number">3</span>/字节<span class="number">4</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">3</span>行，点阵数据字节<span class="number">5</span>/字节<span class="number">6</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">4</span>行，点阵数据字节<span class="number">7</span>/字节<span class="number">8</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">5</span>行，点阵数据字节<span class="number">9</span>/字节<span class="number">10</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">1</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （<span class="keyword">...</span>）
<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> （第<span class="number">16</span>行，点阵数据字节<span class="number">31</span>/字节<span class="number">32</span>）
</code></pre><p>用上面32个字节就可以描述汉字“三”每个像素点的信息。<br>按照这个点阵信息进行绘图不就可以显示出汉字“三”了吗？（0画一种颜色，1画另一种颜色）<br>好，到这里你能理解了。</p>
<h4 id="点阵字库">点阵字库</h4><p>怎样得到指定汉字的点阵数据呢？<br>方法有很多，本文介绍一种比较简单直观的方法—使用点阵字库文件。<br>本文开头让你下载的HZK16.dat这个文件就是一个16x16像素的汉字点阵字库文件。<br>很自然的问题又来了。<br>有了字库文件，怎么从字库文件里提取某个汉字的点阵数据呢？<br>我们一步步来。</p>
<ul>
<li>某个汉字的点阵信息是从某个起始位置（偏移值）开始的连续32个字节的数据。也就是找到数据的起始位置（偏移值），然后连续读取32个字节即可。</li>
<li>有个公式可以计算出上面的偏移值，不要问我为什么。某汉字的字节偏移值 = ((汉字的区码 - 0xA1) <em> 94 + 汉字的位码 - 0xA1) </em> 32</li>
<li>汉字的区码和位码就是该汉字以GB2312码编码时的第一和二个字节。</li>
</ul>
<p>简单吧？<br>好了，原理就是这样了。具体实现请自己看示例代码。注释很详细，相信能看得懂。<br>看不懂也不负责。</p>
<p>本文是在第一篇后1年多才补上的，算是填坑，图片的显示就不再专门写文章了。原理都是一样的。弄到每个点的颜色信息，然后一个点一个点画呗。</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>本系列将驱动一块1.44”的128x128像素的彩色液晶屏幕。<br>本文是系列的第2篇，也是最后一篇，目标是在液晶屏上显示文字。</p>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="液晶屏" scheme="http://blog.mangolovecarrot.net/tags/%E6%B6%B2%E6%99%B6%E5%B1%8F/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门11-驱动液晶屏幕（一）]]></title>
    <link href="http://blog.mangolovecarrot.net/2016/01/30/raspi-study1101/"/>
    <id>http://blog.mangolovecarrot.net/2016/01/30/raspi-study1101/</id>
    <published>2016-01-30T08:03:19.000Z</published>
    <updated>2016-06-06T07:30:41.000Z</updated>
    <content type="html"><![CDATA[<p>本系列将驱动一块1.44”的128x128像素的彩色液晶屏幕。<br>并分几个篇幅分别讲述如何使其显示色块，英文数字，汉字以及图片。<br>本文是系列的第一篇，目标是点亮屏幕并显示指定色块。</p>
<a id="more"></a>
<h3 id="最终效果">最终效果</h3><p><img src="lcd.jpg" alt="最终效果"></p>
<h3 id="硬件">硬件</h3><ul>
<li>1.44英寸 spi接口 128x128液晶屏幕 X 1（淘宝10-20元）<br><img src="lcdfront.jpg" alt="正面"><br><img src="lcdback.jpg" alt="背面"></li>
</ul>
<h3 id="先上代码看效果">先上代码看效果</h3><p>这次直接上代码，大家自己复制代码保存为py文件。文件名无所谓。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> RPi.GPIO <span class="keyword">as</span> GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">cs=<span class="number">23</span>		<span class="comment"># 片选</span></span><br><span class="line">rs=<span class="number">17</span>		<span class="comment"># 数据 / 命令 切换</span></span><br><span class="line">sda=<span class="number">13</span>		<span class="comment"># 数据</span></span><br><span class="line">scl=<span class="number">19</span>		<span class="comment"># 时钟</span></span><br><span class="line">reset=<span class="number">27</span>	<span class="comment"># 复位</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 传输byte</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setByteData</span><span class="params">(data)</span>:</span></span><br><span class="line">	<span class="comment"># print ""</span></span><br><span class="line">	<span class="comment"># print "S-----------setByte---------------:", hex(data)</span></span><br><span class="line">	<span class="keyword">for</span> bit <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">8</span>):</span><br><span class="line">		<span class="comment"># 传入的数字从高位到低位依次判断是否为1，若为1则设置高电平，否则设置低电平</span></span><br><span class="line">		<span class="comment"># 判断的方法是先向左移位，把要判断的位移动到最高位然后跟0x80（1000 0000）相与，</span></span><br><span class="line">		<span class="comment"># 如果结果仍然是0x80（1000 0000）就表示最高位是1，否则最高位就是0</span></span><br><span class="line">		<span class="keyword">if</span> ((data&lt;&lt;bit) &amp; <span class="number">0x80</span> == <span class="number">0x80</span>):</span><br><span class="line">			setBitData(<span class="keyword">True</span>)</span><br><span class="line">			<span class="comment"># print "1",</span></span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			setBitData(<span class="keyword">False</span>)</span><br><span class="line">			<span class="comment"># print "0",</span></span><br><span class="line">	<span class="comment"># print ""</span></span><br><span class="line">	<span class="comment"># print "E-----------setByte---------------"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setBitData</span><span class="params">(data)</span>:</span></span><br><span class="line">	GPIO.output(scl, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(sda, data)</span><br><span class="line">	GPIO.output(scl, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_command</span><span class="params">(cmd)</span>:</span></span><br><span class="line">	GPIO.output(cs, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(rs, <span class="keyword">False</span>)</span><br><span class="line">	setByteData(cmd)</span><br><span class="line">	GPIO.output(cs, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_data</span><span class="params">(data)</span>:</span></span><br><span class="line">	GPIO.output(cs, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(rs, <span class="keyword">True</span>)</span><br><span class="line">	setByteData(data)</span><br><span class="line">	GPIO.output(cs, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_data_16bit</span><span class="params">(dataH, dataL)</span>:</span></span><br><span class="line">	write_data(dataH)</span><br><span class="line">	write_data(dataL)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">lcd_reset</span><span class="params">()</span>:</span></span><br><span class="line">    GPIO.output(reset, <span class="keyword">False</span>)</span><br><span class="line">    time.sleep(<span class="number">0.1</span>)</span><br><span class="line">    GPIO.output(reset, <span class="keyword">True</span>)</span><br><span class="line">    time.sleep(<span class="number">0.1</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">lcd_init</span><span class="params">()</span>:</span></span><br><span class="line">	lcd_reset()</span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0x11</span>) <span class="comment"># Exit Sleep</span></span><br><span class="line">	time.sleep(<span class="number">0.02</span>)</span><br><span class="line">	write_command(<span class="number">0x26</span>) <span class="comment"># Set Default Gamma</span></span><br><span class="line">	write_data(<span class="number">0x04</span>)</span><br><span class="line">	write_command(<span class="number">0xB1</span>)<span class="comment"># Set Frame Rate</span></span><br><span class="line">	write_data(<span class="number">0x0e</span>)</span><br><span class="line">	write_data(<span class="number">0x10</span>)</span><br><span class="line">	write_command(<span class="number">0xC0</span>) <span class="comment"># Set VRH1[4:0] &amp; VC[2:0] for VCI1 &amp; GVDD</span></span><br><span class="line">	write_data(<span class="number">0x08</span>)</span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_command(<span class="number">0xC1</span>) <span class="comment"># Set BT[2:0] for AVDD &amp; VCL &amp; VGH &amp; VGL</span></span><br><span class="line">	write_data(<span class="number">0x05</span>)</span><br><span class="line">	write_command(<span class="number">0xC5</span>) <span class="comment"># Set VMH[6:0] &amp; VML[6:0] for VOMH &amp; VCOML</span></span><br><span class="line">	write_data(<span class="number">0x38</span>)</span><br><span class="line">	write_data(<span class="number">0x40</span>)</span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0x3a</span>) <span class="comment"># Set Color Format</span></span><br><span class="line">	write_data(<span class="number">0x05</span>)</span><br><span class="line">	write_command(<span class="number">0x36</span>) <span class="comment"># RGB</span></span><br><span class="line">	write_data(<span class="number">0xc8</span>)</span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0x2A</span>) <span class="comment"># Set Column Address</span></span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x7F</span>)</span><br><span class="line">	write_command(<span class="number">0x2B</span>) <span class="comment"># Set Page Address</span></span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line">	write_data(<span class="number">0x7F</span>)</span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0xB4</span>) </span><br><span class="line">	write_data(<span class="number">0x00</span>)</span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0xf2</span>) <span class="comment"># Enable Gamma bit</span></span><br><span class="line">	write_data(<span class="number">0x01</span>)</span><br><span class="line">	write_command(<span class="number">0xE0</span>) </span><br><span class="line">	write_data(<span class="number">0x3f</span>)<span class="comment"># p1</span></span><br><span class="line">	write_data(<span class="number">0x22</span>)<span class="comment"># p2</span></span><br><span class="line">	write_data(<span class="number">0x20</span>)<span class="comment"># p3</span></span><br><span class="line">	write_data(<span class="number">0x30</span>)<span class="comment"># p4</span></span><br><span class="line">	write_data(<span class="number">0x29</span>)<span class="comment"># p5</span></span><br><span class="line">	write_data(<span class="number">0x0c</span>)<span class="comment"># p6</span></span><br><span class="line">	write_data(<span class="number">0x4e</span>)<span class="comment"># p7</span></span><br><span class="line">	write_data(<span class="number">0xb7</span>)<span class="comment"># p8</span></span><br><span class="line">	write_data(<span class="number">0x3c</span>)<span class="comment"># p9</span></span><br><span class="line">	write_data(<span class="number">0x19</span>)<span class="comment"># p10</span></span><br><span class="line">	write_data(<span class="number">0x22</span>)<span class="comment"># p11</span></span><br><span class="line">	write_data(<span class="number">0x1e</span>)<span class="comment"># p12</span></span><br><span class="line">	write_data(<span class="number">0x02</span>)<span class="comment"># p13</span></span><br><span class="line">	write_data(<span class="number">0x01</span>)<span class="comment"># p14</span></span><br><span class="line">	write_data(<span class="number">0x00</span>)<span class="comment"># p15</span></span><br><span class="line">	write_command(<span class="number">0xE1</span>) </span><br><span class="line">	write_data(<span class="number">0x00</span>)<span class="comment"># p1</span></span><br><span class="line">	write_data(<span class="number">0x1b</span>)<span class="comment"># p2</span></span><br><span class="line">	write_data(<span class="number">0x1f</span>)<span class="comment"># p3</span></span><br><span class="line">	write_data(<span class="number">0x0f</span>)<span class="comment"># p4</span></span><br><span class="line">	write_data(<span class="number">0x16</span>)<span class="comment"># p5</span></span><br><span class="line">	write_data(<span class="number">0x13</span>)<span class="comment"># p6</span></span><br><span class="line">	write_data(<span class="number">0x31</span>)<span class="comment"># p7</span></span><br><span class="line">	write_data(<span class="number">0x84</span>)<span class="comment"># p8</span></span><br><span class="line">	write_data(<span class="number">0x43</span>)<span class="comment"># p9</span></span><br><span class="line">	write_data(<span class="number">0x06</span>)<span class="comment"># p10</span></span><br><span class="line">	write_data(<span class="number">0x1d</span>)<span class="comment"># p11</span></span><br><span class="line">	write_data(<span class="number">0x21</span>)<span class="comment"># p12</span></span><br><span class="line">	write_data(<span class="number">0x3d</span>)<span class="comment"># p13</span></span><br><span class="line">	write_data(<span class="number">0x3e</span>)<span class="comment"># p14</span></span><br><span class="line">	write_data(<span class="number">0x3f</span>)<span class="comment"># p15</span></span><br><span class="line"></span><br><span class="line">	write_command(<span class="number">0x29</span>) <span class="comment">#  Display On</span></span><br><span class="line">	write_command(<span class="number">0x2C</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">show_single_color</span><span class="params">(DH,DL)</span>:</span></span><br><span class="line">	<span class="keyword">for</span> i <span class="keyword">in</span> xrange(<span class="number">0</span>,<span class="number">128</span>):</span><br><span class="line">		<span class="keyword">for</span> j <span class="keyword">in</span> xrange(<span class="number">0</span>,<span class="number">128</span>):</span><br><span class="line">			write_data_16bit(DH,DL)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	GPIO.setmode(GPIO.BCM)</span><br><span class="line">	GPIO.setup(cs, GPIO.OUT)</span><br><span class="line">	GPIO.setup(rs, GPIO.OUT)</span><br><span class="line">	GPIO.setup(sda, GPIO.OUT)</span><br><span class="line">	GPIO.setup(scl, GPIO.OUT)</span><br><span class="line">	GPIO.setup(reset, GPIO.OUT)</span><br><span class="line">	</span><br><span class="line">	lcd_init()</span><br><span class="line">	write_command(<span class="number">0x2C</span>)</span><br><span class="line"></span><br><span class="line">	show_single_color(<span class="number">0xf8</span>,<span class="number">0x00</span>) <span class="comment"># 红色背景</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span> <span class="keyword">True</span>:</span><br><span class="line">		<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">	<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理GPIO口</span></span><br><span class="line">GPIO.cleanup()</span><br></pre></td></tr></table></figure></p>
<p>然后，按下表连接液晶屏和树莓派。（连接完以后屏幕应该是白屏状态）</p>
<table>
<thead>
<tr>
<th>液晶屏</th>
<th>树莓派                        </th>
</tr>
</thead>
<tbody>
<tr>
<td>LCD</td>
<td>3.3V(不可以是5V！！)</td>
</tr>
<tr>
<td>SCK</td>
<td>GPIO19</td>
</tr>
<tr>
<td>SDA</td>
<td>GPIO13</td>
</tr>
<tr>
<td>AO</td>
<td>GPIO17</td>
</tr>
<tr>
<td>RESET</td>
<td>GPIO27</td>
</tr>
<tr>
<td>CS</td>
<td>GPIO23</td>
</tr>
<tr>
<td>GND</td>
<td>GND</td>
</tr>
<tr>
<td>VCC</td>
<td>3.3V(不可以是5V！！)</td>
</tr>
</tbody>
</table>
<p>然后，执行！<br><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="keyword">python</span> prog.<span class="keyword">py</span></span><br></pre></td></tr></table></figure></p>
<p>不出意外，你应该能看到屏幕被慢慢地扫描刷新成红屏了！！！<br><img src="lcd_red.jpg" alt="红屏"></p>
<h3 id="原理说明">原理说明</h3><p>想要跟硬件通信，给硬件发送指令，首先要搞清楚硬件的通信协议。<br>对于屏幕来说，其通信协议是由屏幕的主控IC芯片决定的，不同的主控IC芯片有不同的通信协议，也就是发送指令的方法。<br>不过，即使是不同的屏幕，也有可能使用同一款（或同系列）主控IC。<br>所以拿到一块屏幕首先要搞清楚这块屏幕使用的是哪种主控IC，谷歌，百度都可以，最方便的是问卖家。。。<br>本文使用的屏幕的主控IC是ST7735S，文末提供数据手册下载。<br>简单来说，通过SDA数据引脚和SCLK时钟引脚串行输入（从第一篇学习过来的一定不陌生）不同的指令数据就可以控制屏幕的输出。<br>指令数据分成两种，指令种类数据和指令内容数据。每次发送指令都是先发送指令种类再发送指令内容。<br>有点拗口，比如说我告诉屏幕“接下来我要改变屏幕颜色啦”，接着你发送了一串数字，硬件接收到这串数字后会作为一个颜色值应用在屏幕上。如果你告诉屏幕“接下来我要改变屏幕的亮度啦”，接着你又发送了一串数字，这次硬件接收到这一串数字后会作为亮度值应用在屏幕上。这么说你再不明白我就。。。。<br>再回过头来看代码：<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_command</span><span class="params">(cmd)</span>:</span></span><br><span class="line">	GPIO.output(cs, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(rs, <span class="keyword">False</span>)</span><br><span class="line">	setByteData(cmd)</span><br><span class="line">	GPIO.output(cs, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write_data</span><span class="params">(data)</span>:</span></span><br><span class="line">	GPIO.output(cs, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(rs, <span class="keyword">True</span>)</span><br><span class="line">	setByteData(data)</span><br><span class="line">	GPIO.output(cs, <span class="keyword">True</span>)</span><br></pre></td></tr></table></figure></p>
<p>上面这两个函数，一个用来发送指令种类，一个用来发送指令内容。区别仅仅在于rs引脚的电平高低不同。<br>另外，屏幕初始化函数lcd_init()里有一堆命令，天书一般，光是看就晕了。<br>别晕，这些代码大多只用执行一遍，最开始不必关心，照葫芦画瓢即可。<br>下面是你需要注意的关键指令种类和内容：</p>
<ul>
<li>0x2A：指定绘图指针的列起始和结束地址（X坐标范围）<br>指令内容是4个字节的32位数据，从高位到低位分别是<br>起始X坐标高8位<br>起始X坐标低8位<br>结束X坐标高8位<br>结束X坐标低8位</li>
<li>0x2B：指定绘图指针的行起始和结束地址（Y坐标范围）<br>指令内容是4个字节的32位数据，从高位到低位分别是<br>起始Y坐标高8位<br>起始Y坐标低8位<br>结束Y坐标高8位<br>结束Y坐标低8位</li>
</ul>
<p>下面的代码设定的范围是（0，0）-（127， 127），也就是全屏幕。<br><figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">write_command</span>(0x2A) # Set Column <span class="tag">Address</span></span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x7F)</span><br><span class="line"><span class="function">write_command</span>(0x2B) # Set Page <span class="tag">Address</span></span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x00)</span><br><span class="line"><span class="function">write_data</span>(0x7F)</span><br></pre></td></tr></table></figure></p>
<ul>
<li>0x2C：在当前指针位置（X,Y坐标）绘制指定颜色的像素点<br>指令内容是2个字节的颜色数据。<br>每次执行完一个像素点的绘色以后，硬件会根据设定好的开始坐标和结束坐标自动移动绘图指针到下一个位置，遇到边界自动换行。<br>下面的代码的意义是连续绘制128 X 128个像素点，并且颜色为红色（#0xF800）。<figure class="highlight r"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">write_command(<span class="number">0x2C</span>)</span><br><span class="line">show_single_color(<span class="number">0xf8</span>,<span class="number">0x00</span>) <span class="comment"># 红色背景</span></span><br><span class="line"><span class="keyword">...</span></span><br><span class="line"><span class="keyword">...</span></span><br><span class="line">def show_single_color(DH,DL):</span><br><span class="line">	<span class="keyword">for</span> i <span class="keyword">in</span> xrange(<span class="number">0</span>,<span class="number">128</span>):</span><br><span class="line">		<span class="keyword">for</span> j <span class="keyword">in</span> xrange(<span class="number">0</span>,<span class="number">128</span>):</span><br><span class="line">			write_data_16bit(DH,DL)</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>这就是本文示例代码显示红屏的原理。<br>其实只要学会了这3个命令的使用，基本上啥都能显示了，无非是效率问题。给大家留个作业，自己完成本文开头的最终效果彩带。<br>本节到此结束，下一节我们继续讨论。</p>
<h3 id="关于颜色的补充说明">关于颜色的补充说明</h3><p>有人问博主0xF800是什么鬼？红色难道不应该是0xFF0000吗？<br>这里就引出一个RGB颜色数据格式的问题，0xF800和0xFF0000都是红色，只是格式不一样。<br>我们常见的0xFF0000这种格式一共是24位，红绿蓝各用8位表示，所以红色就是FF,00,00。<br>而本文使用的是另一种叫RGB565的格式，这种格式一共只有16位，红绿蓝分别使用5位6位5位。<br><img src="rgb565.png" alt="RGB565"><br>根据上图，红色应该是11111000 00000000，也就是0xF800。<br><img src="16bit_colors.png" alt="常用RGB565颜色表"><br>其实，这款彩屏支持以下3种颜色格式</p>
<ul>
<li><p>4k Colors, RGB 4,4,4<br>3AH=“03h”</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">write_command</span><span class="params">(<span class="number">0</span>x3a)</span></span></span><br><span class="line"><span class="function"><span class="title">write_data</span><span class="params">(<span class="number">0</span>x03)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>65k Colors, RGB 5,6,5<br>3AH=“05h”（本文使用的格式）</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">write_command</span><span class="params">(<span class="number">0</span>x3a)</span></span></span><br><span class="line"><span class="function"><span class="title">write_data</span><span class="params">(<span class="number">0</span>x05)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>262k Colors, RGB 6,6,6<br>3AH=“06h”</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">write_command</span><span class="params">(<span class="number">0</span>x3a)</span></span></span><br><span class="line"><span class="function"><span class="title">write_data</span><span class="params">(<span class="number">0</span>x06)</span></span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>详细内容请自己参考文档（9.8 Data Color Coding）。</p>
<h3 id="资源下载">资源下载</h3><p><a href="ST7735S_V1.1_20111121.pdf" title="下载">主控IC芯片ST7735S资料</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>本系列将驱动一块1.44”的128x128像素的彩色液晶屏幕。<br>并分几个篇幅分别讲述如何使其显示色块，英文数字，汉字以及图片。<br>本文是系列的第一篇，目标是点亮屏幕并显示指定色块。</p>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="液晶屏" scheme="http://blog.mangolovecarrot.net/tags/%E6%B6%B2%E6%99%B6%E5%B1%8F/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门10-使用TLC5940芯片输出多路PWM]]></title>
    <link href="http://blog.mangolovecarrot.net/2016/01/24/raspi-study1001/"/>
    <id>http://blog.mangolovecarrot.net/2016/01/24/raspi-study1001/</id>
    <published>2016-01-24T05:30:14.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>在之前的章节，我们曾经用树莓派的IO口输出不同调宽的PWM信号来控制LED灯的亮度。<br>本文使用芯片TLC5940来输出多路PWM信号以同时控制多达16个LED的亮度。<br>在本文的基础上你可以发挥想象，制作出各种有趣的彩灯效果。</p>
<a id="more"></a>
<h3 id="最终效果TODO">最终效果TODO</h3><p>视频演示</p>
<h3 id="硬件">硬件</h3><ul>
<li>TLC5940芯片 X 1<br><img src="http://www.photo138.com/0/MS/ZC02400_2.jpg" alt="TLC5940芯片"></li>
<li>LED X 3</li>
<li>2-3k电阻一只</li>
</ul>
<h3 id="原理说明">原理说明</h3><p>简单的说，TLC5940是一个拥有16路输出的LED驱动芯片，每一路输出支持4096级！亮度调节。<br>老规矩，看一下它的引脚图：<br><img src="http://image.geek-workshop.com/forum/201404/11/105523kwtnhnhw0fvznhnx.jpg" alt="TLC5940的引脚图"><br>跟本文无关的内容或设置在此不做说明，请自己查询datasheet：</p>
<table>
<thead>
<tr>
<th>引脚</th>
<th>功能                        </th>
</tr>
</thead>
<tbody>
<tr>
<td>OUT0-15</td>
<td>16路PWM信号输出（负极）</td>
</tr>
<tr>
<td>VPRG</td>
<td>指定工作模式，接GND是我们需要的PWM模式</td>
</tr>
<tr>
<td>SIN</td>
<td>串行移位输入</td>
</tr>
<tr>
<td>SCLK</td>
<td>串行移位寄存器时钟（上升沿有效）          </td>
</tr>
<tr>
<td>XLAT</td>
<td>从移位寄存器写入GS寄存器（下文介绍）时钟（上升沿有效）</td>
</tr>
<tr>
<td>BLANK</td>
<td>当设为高电平时，关闭所有输出，GS计数器（下文介绍）也将重置</td>
</tr>
<tr>
<td>IREF</td>
<td>跟GND之间连接一个电阻，阻值决定了输出电流的最大值</td>
</tr>
<tr>
<td>GSCLK</td>
<td>GS时钟输入（下文介绍）</td>
</tr>
<tr>
<td>SOUT</td>
<td>串行输出，级联多块芯片时使用</td>
</tr>
</tbody>
</table>
<ol>
<li>先将BLANK设置为H，关闭所有输出。</li>
<li>输入各组亮度信息。跟我们之前学过的芯片一样，这款芯片同样是通过移位寄存器来输入数据的。<br>移位寄存器用于传送12bit X 16组PWM数值GSn(n=0-15)，共192bit。每组数据的值范围是0-4095。<br>传送顺序是倒序的：GS15，GS14。。。GS0。先传输的是OUT15的12位数据，其次是OUT14的12位数据。。。最后是OUT0的12位数据。<br>GSn决定了OUTn的PWM调宽。（GSn / 4095 = 0% - 100%）</li>
<li>192位数据全部传送完毕后制造XLAT的上升沿，将移位寄存器里的数据写入GS寄存器。</li>
<li>BLANK设置为L，打开所有输出</li>
<li>准备工作完毕，为了让TLC5940芯片正常工作，还需要向GSCLK输送时钟信号。<br>啥是时钟信号？简单的说就是高低电平不停交替的信号，也称作方波信号。<br>TLC5940会根据这个时钟信号进行从0-4095的计数（高低电平每交替一次数一次），一边计数一边检查各GSn的设定值，一旦到达GSn的值，则切换OUTn的电平一直计数到4095为止，再从0开始重新计数。从0计数到4095就是一个高低电平的切换周期。所以我们给5940提供的时钟频率越快，最后输出的PWM频率就越快。最后输出的PWM的频率 = 时钟信号的频率 / 4095。<br>比如时钟频率是8M，则最后从各OUT口输出的PWM频率是8MHz / 4095 = 1.953KHz。<br>根据TLC5940的官方文档，GSCLK可支持最高30MHz的时钟频率，也就是最高可以输出7.3KHz的PWM信号。如果是控制LED的亮度，那么让人眼感觉不到闪烁的最低频率应该是50Hz以上，所以我们应该至少给GSCLK提供不低于50 X 4095 = 200KHz的方波。树莓派Python的GPIO库翻转IO口的速度不高，实测速度只能达到60KHz，导致最后输出的PWM频率只有14Hz，会有明显的闪烁感。但我们主要是为了说明原理，明白原理了可以用别的方法来实现功能，比如使用c语言的wiringPi库的话效率会高不少，甚至可以使用外部的单片机或其他电路来产生高频率的时钟信号提供给TLC5940，这个作者也在探索中。以后有空再更新。</li>
</ol>
<h3 id="硬件连接">硬件连接</h3><table>
<thead>
<tr>
<th>模块1</th>
<th>引脚</th>
<th>模块2</th>
<th>引脚</th>
</tr>
</thead>
<tbody>
<tr>
<td>TLC5940</td>
<td>VPRG</td>
<td>树莓派</td>
<td>GPIO17</td>
</tr>
<tr>
<td>TLC5940</td>
<td>SIN</td>
<td>树莓派</td>
<td>GPIO13</td>
</tr>
<tr>
<td>TLC5940</td>
<td>SCLK</td>
<td>树莓派</td>
<td>GPIO19</td>
</tr>
<tr>
<td>TLC5940</td>
<td>XLAT</td>
<td>树莓派</td>
<td>GPIO27</td>
</tr>
<tr>
<td>TLC5940</td>
<td>BLANK</td>
<td>树莓派</td>
<td>GPIO23</td>
</tr>
<tr>
<td>TLC5940</td>
<td>IREF</td>
<td>树莓派</td>
<td>GND(中间串联一个2-3k的电阻)</td>
</tr>
<tr>
<td>TLC5940</td>
<td>SOUT</td>
<td>树莓派</td>
<td>GPIO4</td>
</tr>
<tr>
<td>TLC5940</td>
<td>OUT0</td>
<td>LED0</td>
<td>负极</td>
</tr>
<tr>
<td>TLC5940</td>
<td>OUT1</td>
<td>LED1</td>
<td>负极</td>
</tr>
<tr>
<td>TLC5940</td>
<td>OUT2</td>
<td>LED2</td>
<td>负极</td>
</tr>
<tr>
<td>TLC5940</td>
<td>VCC</td>
<td>树莓派</td>
<td>5V</td>
</tr>
<tr>
<td>TLC5940</td>
<td>GND</td>
<td>树莓派</td>
<td>GND</td>
</tr>
<tr>
<td>LED0,1,2</td>
<td>正极</td>
<td>树莓派</td>
<td>5V</td>
</tr>
</tbody>
</table>
<h3 id="代码（Python）">代码（Python）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> RPi.GPIO <span class="keyword">as</span> GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">VPRG=<span class="number">17</span></span><br><span class="line">SIN=<span class="number">13</span></span><br><span class="line">SCLK=<span class="number">19</span></span><br><span class="line">XLAT=<span class="number">27</span></span><br><span class="line">BLANK=<span class="number">23</span></span><br><span class="line">DCPRG=<span class="number">18</span></span><br><span class="line">GSCLK=<span class="number">4</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 传输GSData(0-4095)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setGSData</span><span class="params">(data)</span>:</span></span><br><span class="line">	<span class="comment"># print ""</span></span><br><span class="line">	<span class="comment"># print "S-----------setByte---------------:", hex(data)</span></span><br><span class="line">	<span class="keyword">for</span> bit <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">12</span>):</span><br><span class="line">		<span class="comment"># 传入的数字从高位到低位依次判断是否为1，若为1则设置高电平，否则设置低电平</span></span><br><span class="line">		<span class="comment"># 判断的方法是先向左移位，把要判断的位移动到最高位然后跟0x800（1000 0000 0000）相与，</span></span><br><span class="line">		<span class="comment"># 如果结果仍然是0x80（1000 0000 0000）就表示最高位是1，否则最高位就是0</span></span><br><span class="line">		<span class="keyword">if</span> ((data&lt;&lt;bit) &amp; <span class="number">0x800</span> == <span class="number">0x800</span>):</span><br><span class="line">			setBitData(<span class="keyword">True</span>)</span><br><span class="line">			<span class="comment"># print "1",</span></span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			setBitData(<span class="keyword">False</span>)</span><br><span class="line">			<span class="comment"># print "0",</span></span><br><span class="line">	<span class="comment"># print ""</span></span><br><span class="line">	<span class="comment"># print "E-----------setByte---------------"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setBitData</span><span class="params">(data)</span>:</span></span><br><span class="line">	GPIO.output(SCLK, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(SIN, data)</span><br><span class="line">	GPIO.output(SCLK, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出GSCLK时钟信号</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">runGSCLK</span><span class="params">()</span>:</span></span><br><span class="line">	i=<span class="number">0</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>):</span><br><span class="line">		i+=<span class="number">1</span></span><br><span class="line">		<span class="keyword">if</span> i&gt;=<span class="number">4096</span>:</span><br><span class="line">			<span class="comment"># 注意，每次计数到4095时需要手动重置一次芯片的计数器</span></span><br><span class="line">			GPIO.output(BLANK, <span class="keyword">True</span>)</span><br><span class="line">			<span class="comment">#time.sleep(0.001);</span></span><br><span class="line">			GPIO.output(BLANK, <span class="keyword">False</span>)</span><br><span class="line">			i=<span class="number">0</span></span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			GPIO.output(GSCLK, <span class="keyword">True</span>)</span><br><span class="line">			GPIO.output(GSCLK, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	GPIO.setmode(GPIO.BCM)</span><br><span class="line">	GPIO.setup(VPRG, GPIO.OUT)</span><br><span class="line">	GPIO.setup(SIN, GPIO.OUT)</span><br><span class="line">	GPIO.setup(SCLK, GPIO.OUT)</span><br><span class="line">	GPIO.setup(XLAT, GPIO.OUT)</span><br><span class="line">	GPIO.setup(BLANK, GPIO.OUT)</span><br><span class="line">	GPIO.setup(DCPRG, GPIO.OUT)</span><br><span class="line">	GPIO.setup(GSCLK, GPIO.OUT)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># VPRG设置为L，使其工作在GS mode</span></span><br><span class="line">	GPIO.output(VPRG, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># BLANK设置为H，关闭所有输出</span></span><br><span class="line">	GPIO.output(BLANK, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line">	GPIO.output(DCPRG, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 传送12bit X 16组PWM数值GSn(n=0-15)，共192bit</span></span><br><span class="line">	<span class="comment"># 每组数据的值范围是0-4095</span></span><br><span class="line">	<span class="comment"># 因为是通过移位寄存器传输，所以传送顺序是倒序的：GS15，GS14。。。GS0</span></span><br><span class="line">	<span class="comment"># GSn决定了OUTn的PWM调宽。（GSn / 4095 = 0% - 100%）</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS15 本文不使用15-3号输出，设为0</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS14</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS13</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS12</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS11</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS10</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS9</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS8</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS7</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS6</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS5</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS4</span></span><br><span class="line">	setGSData(<span class="number">0</span>) <span class="comment"># GS3</span></span><br><span class="line">	</span><br><span class="line">	<span class="comment"># print "GS2"</span></span><br><span class="line">	setGSData(<span class="number">4095</span>) <span class="comment"># GS2</span></span><br><span class="line"></span><br><span class="line">	<span class="comment"># print "GS1"</span></span><br><span class="line">	setGSData(<span class="number">2500</span>) <span class="comment"># GS1</span></span><br><span class="line"></span><br><span class="line">	<span class="comment"># print "GS0"</span></span><br><span class="line">	setGSData(<span class="number">1000</span>) <span class="comment"># GS0</span></span><br><span class="line"></span><br><span class="line">	<span class="comment"># 送完GS数据后，创造XLAT的上升沿，将移位寄存器的数据一次性送入GS寄存器</span></span><br><span class="line">	GPIO.output(XLAT, <span class="keyword">False</span>)</span><br><span class="line">	GPIO.output(XLAT, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># BLANK设置为L，打开所有输出</span></span><br><span class="line">	<span class="comment"># GPIO.output(BLANK, False)</span></span><br><span class="line"></span><br><span class="line">	<span class="comment"># 准备工作完毕，下面向GSCLK输送时钟信号（高低电平交互的方波信号）</span></span><br><span class="line">	<span class="comment"># TLC5940会根据这个时钟信号进行从0-4095的计数，一边计数一边检查各GSn的设定值，一旦到达GSn的值，则切换OUTn的电平</span></span><br><span class="line">	<span class="comment"># 一直计数到4095为止，再从0开始重新计数。从0计数到4095就是一个高低电平的切换周期。</span></span><br><span class="line">	<span class="comment"># 所以我们给5940提供的时钟频率越快，最后输出的PWM频率就越快</span></span><br><span class="line">	<span class="comment"># 最后输出的PWM的频率 = 时钟信号的频率 / 4095</span></span><br><span class="line">	<span class="comment"># 比如时钟频率是8M，则最后从各OUT口输出的PWM频率是8MHz / 4095 = 1.953KHz</span></span><br><span class="line">	<span class="comment"># 根据TLC5940的官方文档，GSCLK可支持最高30MHz的时钟频率，也就是最高可以输出7.3KHz的PWM信号。</span></span><br><span class="line">	<span class="comment"># 如果是控制LED的亮度，那么让人眼感觉不到闪烁的最低频率应该是50Hz以上，</span></span><br><span class="line">	<span class="comment"># 所以我们应该至少给GSCLK提供不低于50 X 4095 = 200KHz的方波。</span></span><br><span class="line">	<span class="comment"># 树莓派Python的GPIO库翻转IO口的速度不高，实测速度只能达到60KHz，</span></span><br><span class="line">	<span class="comment"># 导致最后输出的PWM频率只有14Hz，会有明显的闪烁感</span></span><br><span class="line">	runGSCLK()</span><br><span class="line"></span><br><span class="line"><span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">	<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理GPIO口</span></span><br><span class="line">GPIO.cleanup()</span><br></pre></td></tr></table></figure>
]]></content>
    <summary type="html">
    <![CDATA[<p>在之前的章节，我们曾经用树莓派的IO口输出不同调宽的PWM信号来控制LED灯的亮度。<br>本文使用芯片TLC5940来输出多路PWM信号以同时控制多达16个LED的亮度。<br>在本文的基础上你可以发挥想象，制作出各种有趣的彩灯效果。</p>]]>
    
    </summary>
    
      <category term="PWM" scheme="http://blog.mangolovecarrot.net/tags/PWM/"/>
    
      <category term="数字芯片" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E5%AD%97%E8%8A%AF%E7%89%87/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门09-使用MAX7219芯片驱动8位数码管]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/06/13/raspi-study0901/"/>
    <id>http://blog.mangolovecarrot.net/2015/06/13/raspi-study0901/</id>
    <published>2015-06-13T07:42:53.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>前面几篇我们学习了如何利用一片或多片级联的74HC595芯片来驱动显示数码管的方法。最开始我们提出的两个问题：</p>
<ol>
<li>占用IO口过多</li>
<li>做动态扫描时占用CPU资源太多导致显示不稳定</li>
</ol>
<p>第一个问题已经利用级联的74HC595解决了。（不管驱动几只数码管，只用3个IO即可）<br>但第二个问题依然存在，树莓派仍然需要不停地访问IO口进行动态扫描。<br>好，既然动态扫描占用CPU资源太多，那这活儿咱包出去让别人干不就行了？这就是本文主角MAX7219的特长，动态扫描这活儿MAX7219全包了，干的还比咱自己干得还好，一片MAX7219可最多支持显示8位8段数码管，还支持各种设置如亮度设置扫描位数设置等。而我们只用告诉它显示的内容就行了。</p>
<a id="more"></a>
<h3 id="最终效果">最终效果</h3><p>视频演示</p>
<iframe height="498" width="510" src="http://player.youku.com/embed/XMTI2MTU2OTc3Ng==" frameborder="0" allowfullscreen></iframe>

<h3 id="硬件">硬件</h3><ul>
<li>MAX7219显示芯片 X 1（2到3元一个）<br><img src="max7219.jpg" alt="MAX7219"></li>
<li>共阴（共阳不可以）4位数码管 X 2</li>
<li>10k电阻一只</li>
<li>10uF电容一只</li>
<li>0.1uF电容一只<br><img src="hardware.jpg" alt="硬件图"></li>
</ul>
<h3 id="原理说明_未完TODO">原理说明 未完TODO</h3><p>注：下面这些图都是从MAX7219官方资料里截取出来的，官方资料文末提供下载</p>
<ul>
<li>先看一下MAX7219的引脚图：<br>  <img src="01.png" alt="MAX7219的引脚图"><br>MAX7219一共有24根引脚，这里面有一些跟74HC595的引脚功能类似的引脚如下：</li>
</ul>
<table>
<thead>
<tr>
<th>MAX7219</th>
<th>74HC595</th>
<th>功能</th>
</tr>
</thead>
<tbody>
<tr>
<td>DIN</td>
<td>DS</td>
<td>串行输入</td>
</tr>
<tr>
<td>SEG A-G,DP</td>
<td>Q0-Q7</td>
<td>数码管段数据输出</td>
</tr>
<tr>
<td>CLK</td>
<td>SHCP</td>
<td>串行移位寄存器时钟</td>
</tr>
<tr>
<td>LOAD</td>
<td>STCP</td>
<td>内部寄存器锁存时钟</td>
</tr>
<tr>
<td>DOUT</td>
<td>Q7S</td>
<td>串行输出，级联多块芯片时使用</td>
</tr>
</tbody>
</table>
<p>可以看出，MAX7219跟74HC595一样也是通过DIN引脚串行输入数据，在CLK引脚的上升沿移入移位寄存器，在LOAD引脚的上升沿将位移寄存器的数据复制到内部的各种寄存器里。不同的是:</p>
<ol>
<li>74HC595的移位寄存器是8位的，而MAX7219的移位寄存器是16位的，每次串行输入数据需要连续输入16位数据。</li>
<li>74HC595内部只有1个8位的锁存器，功能很简单，只是原样输出到8根输出引脚。而MAX7219内部有好几个不同功能的寄存器。后面我会逐个说明。</li>
</ol>
<ul>
<li><p>我们再看一下官方文档里关于各引脚的功能说明：<br>  <img src="02.png" alt="MAX7219各引脚的功能说明"><br>  上面提过的不再赘述，说一下MAX7219特有的引脚。</p>
<ol>
<li>DIG0-DIG7这8个引脚作为位选端，分别连到8位数码管的共阴极，MAX7219在做动态扫描时会依次向共阴极DIG0-DIG7输出低电平，所以MAX7219不能驱动共阳极的数码管。其实也不是绝对不能，将位选端和段选端逆接就可以了，不过这样做的话，有3个弊端：<ul>
<li>不能使用MAX7219内部的译码功能，需要自己编写数字的字形码。增加了代码的复杂度。</li>
<li>需要以段单位来传输数据，而不能以位单位来传输数据。（即每次传输的是各位数码管的某一段的数据，而不是某位数码管各段的数据。第一次传所有数码管的A段数据，第二次传所有数码管的B段数据一直到8段数据全部传完）无疑进一步增加了代码的复杂度。</li>
<li>无法限制扫描位数，只能所有8位数码管同时扫描。（变成了限制扫描段数，如可以只显示所有数码管的A-C段。。。）</li>
</ul>
</li>
<li>ISET通过一只电阻连上VCC，通过调整这只电阻的阻值可以调整通过这只电阻的电流I，而最后输出到数码管上的最大电流就是这个电流I的100倍。如果这只电阻太小，导致输出到数码管的电流过大会烧坏数码管，所以官方文档里推荐这只电阻最小应该设置为9.7K欧，我手头上只有10K的电阻也是一样，只要别低于这个阻值就可以了。根据这个原理我们也可以接一个可调电阻在ISET上，可以随时调整数码管亮度。这种调整亮度的方法是通过模拟信号调制。MAX7219也支持通过数字信号来设置亮度（有16级亮度可调）。</li>
</ol>
</li>
<li><p>MAX7219内部的各模块的示意图：<br>  <img src="03.png" alt="MAX7219内部的各模块的示意图"><br>  最下面是一个16位的移位寄存器D0-D15，跟74HC595一样，通过DIN引脚串行输入数据，在CLK引脚的上升沿移入移位寄存器。<br>  D8-D11这4位数据用来指定内部寄存器地址。D0-D7是具体要传到寄存器里的数据。<br>  上面的图看上去有点复杂，其实简单地说就是我们每次要串行传输16位数据进去，然后在LOAD的上升沿，根据D8-D11指定的寄存器地址，将D0-D7存放在指定的寄存器里。这样多次传输数据就可以给所有的寄存器设值了。<br>  下面是MAX7219内部的寄存器一览：</p>
<ul>
<li>关断寄存器</li>
<li>译码模式寄存器</li>
<li>亮度寄存器</li>
<li>扫描限值寄存器</li>
<li><p>显示器测试寄存器</p>
<p>每个寄存器都有自己特殊的功能，后面我们会逐一介绍。</p>
</li>
</ul>
</li>
<li><p>串行传输时的数据格式如下：<br>  <img src="04.png" alt="MAX7219串行数据格式"><br>  你可能注意到了这幅图的顺序跟模块示意图里移位寄存器的顺序是相反的。<br>  D15-D0这个反向的顺序是你写代码时串行传输数据时的顺序，先传D15的数据，再传D14,D13…D0，这样传输完成后。实际的数据顺序就变成了D0,D1,D2…D15。为了便于编码，除了模块示意图是按实际顺序记载的，后面所有数据格式的示意图都是倒序记载的。</p>
</li>
<li><p>各寄存器地址如下：<br>  <img src="05.png" alt="MAX7219寄存器地址"></p>
</li>
</ul>
<ul>
<li><p>关断寄存器的数据格式：<br>  <img src="06.png" alt="MAX7219关断寄存器的数据格式"></p>
</li>
<li><p>译码模式寄存器的数据格式：<br>  <img src="07.png" alt="MAX7219译码模式寄存器的数据格式"></p>
</li>
<li><p>译码模式下的原码和译码的对应表：<br>  <img src="08.png" alt="MAX7219译码模式下的原码和译码的对应表"></p>
</li>
<li><p>非译码模式下的数据和数码管各段的对应表：<br>  <img src="09.png" alt="MAX7219非译码模式下的数据和数码管各段的对应表"></p>
</li>
<li><p>亮度寄存器的数据格式：<br>  <img src="10.png" alt="MAX7219亮度寄存器的数据格式"></p>
</li>
<li><p>扫描限值寄存器的数据格式：<br>  <img src="11.png" alt="MAX7219扫描限值寄存器的数据格式"></p>
</li>
<li><p>显示器测试寄存器的数据格式：<br>  <img src="12.png" alt="MAX7219显示器测试寄存器的数据格式"></p>
</li>
</ul>
<h3 id="硬件连接TODO">硬件连接TODO</h3><table>
<thead>
<tr>
<th>模块1</th>
<th>引脚</th>
<th>模块2</th>
<th>引脚</th>
</tr>
</thead>
<tbody>
<tr>
<td>MAX7219</td>
<td>DIN</td>
<td>树莓派</td>
<td>GPIO13</td>
</tr>
<tr>
<td>MAX7219</td>
<td>LOAD</td>
<td>树莓派</td>
<td>GPIO26</td>
</tr>
<tr>
<td>MAX7219</td>
<td>CLK</td>
<td>树莓派</td>
<td>GPIO19</td>
</tr>
<tr>
<td>MAX7219</td>
<td>GNDX2</td>
<td>树莓派</td>
<td>GND</td>
</tr>
<tr>
<td>MAX7219</td>
<td>V+</td>
<td>树莓派</td>
<td>5V</td>
</tr>
<tr>
<td>MAX7219</td>
<td>ISET</td>
<td>树莓派</td>
<td>5V(需串联一只10k电阻)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG0</td>
<td>数码管1</td>
<td>DIG1(引脚12)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG1</td>
<td>数码管1</td>
<td>DIG2(引脚9)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG2</td>
<td>数码管1</td>
<td>DIG3(引脚8)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG3</td>
<td>数码管1</td>
<td>DIG4(引脚6)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG4</td>
<td>数码管2</td>
<td>DIG1(引脚12)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG5</td>
<td>数码管2</td>
<td>DIG2(引脚9)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG6</td>
<td>数码管2</td>
<td>DIG3(引脚8)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DIG7</td>
<td>数码管2</td>
<td>DIG4(引脚6)</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG DP</td>
<td>数码管1/2</td>
<td>DP</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG G</td>
<td>数码管1/2</td>
<td>G</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG F</td>
<td>数码管1/2</td>
<td>F</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG E</td>
<td>数码管1/2</td>
<td>E</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG D</td>
<td>数码管1/2</td>
<td>D</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG C</td>
<td>数码管1/2</td>
<td>C</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG B</td>
<td>数码管1/2</td>
<td>B</td>
</tr>
<tr>
<td>MAX7219</td>
<td>SEG A</td>
<td>数码管1/2</td>
<td>A</td>
</tr>
<tr>
<td>MAX7219</td>
<td>DOUT</td>
<td>(级联用)</td>
<td>(不使用)</td>
</tr>
<tr>
<td>10/0.1uF电容</td>
<td>正极</td>
<td>MAX7219</td>
<td>V+</td>
</tr>
<tr>
<td>10/0.1uF电容</td>
<td>负极</td>
<td>MAX7219</td>
<td>GND</td>
</tr>
</tbody>
</table>
<h3 id="代码（Python）">代码（Python）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment"># 串行数据输入</span></span><br><span class="line">DIN = <span class="number">13</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 时钟脉冲信号——上升沿有效</span></span><br><span class="line">LOAD = <span class="number">26</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打入信号————上升沿有效</span></span><br><span class="line">CLK = <span class="number">19</span></span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(DIN, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LOAD, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(CLK, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 传输一个8位数</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setByte</span><span class="params">(byteData)</span>:</span></span><br><span class="line">	<span class="keyword">for</span> bit <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">8</span>):</span><br><span class="line">		<span class="comment"># 传入的数字从高位到低位依次判断是否为1，若为1则设置高电平，否则设置低电平</span></span><br><span class="line">		<span class="comment"># 判断的方法是先向左移位，把要判断的位移动到最高位然后跟0x80（1000 0000）相与，</span></span><br><span class="line">		<span class="comment"># 如果结果仍然是0x80（1000 0000）就表示最高位是1，否则最高位就是0</span></span><br><span class="line">		<span class="keyword">if</span> ((byteData&lt;&lt;bit) &amp; <span class="number">0x80</span> == <span class="number">0x80</span>):</span><br><span class="line">			setBitData(<span class="keyword">True</span>)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			setBitData(<span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 译码模式设置</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setDecodeMode</span><span class="params">(mode = <span class="number">4</span>)</span>:</span></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 指令寄存器地址设置：0xX9</span></span><br><span class="line">	<span class="comment"># D15-D12:任意</span></span><br><span class="line">	<span class="comment"># D11,10,9,8: 1,0,0,1</span></span><br><span class="line">	setByte(<span class="number">0x09</span>)</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (mode == <span class="number">1</span>) :</span><br><span class="line">		<span class="comment"># 所有数码管均不使用译码功能</span></span><br><span class="line">		<span class="comment"># 指令代码: 0x00</span></span><br><span class="line">		setByte(<span class="number">0x00</span>)</span><br><span class="line">	<span class="keyword">elif</span> (mode == <span class="number">2</span>) :</span><br><span class="line">		<span class="comment"># 只对DIG0号数码管进行译码，其他数码管不使用译码功能</span></span><br><span class="line">		<span class="comment"># 指令代码: 0x01</span></span><br><span class="line">		setByte(<span class="number">0x01</span>)</span><br><span class="line">	<span class="keyword">elif</span> (mode == <span class="number">3</span>) :</span><br><span class="line">		<span class="comment"># 对DIG0-3号数码管进行译码，其他数码管不使用译码功能</span></span><br><span class="line">		<span class="comment"># 指令代码: 0x0F</span></span><br><span class="line">		setByte(<span class="number">0x0f</span>)</span><br><span class="line">	<span class="keyword">elif</span> (mode == <span class="number">4</span>) :</span><br><span class="line">		<span class="comment"># 数码管7－0全部采用译码模式</span></span><br><span class="line">		<span class="comment"># 指令代码: 0xFF</span></span><br><span class="line">		setByte(<span class="number">0xff</span>)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 亮度设置</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setIntensity</span><span class="params">(mode = <span class="number">8</span>)</span>:</span></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 指令寄存器地址设置：0xXA</span></span><br><span class="line">	<span class="comment"># D15-D12:任意</span></span><br><span class="line">	<span class="comment"># D11,10,9,8: 1,0,1,0</span></span><br><span class="line">	setByte(<span class="number">0x0A</span>)</span><br><span class="line">	</span><br><span class="line">	<span class="comment"># 亮度从0到15共16个等级，指令的D3－D0就是数字0－15的二进制编码</span></span><br><span class="line">	<span class="comment"># D7-D4:任意</span></span><br><span class="line">	setByte(mode)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扫描显示位数设置(0-7)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setScanLimit</span><span class="params">(mode = <span class="number">7</span>)</span>:</span></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 指令寄存器地址设置：0xXB</span></span><br><span class="line">	<span class="comment"># D15-D12:任意</span></span><br><span class="line">	<span class="comment"># D11,10,9,8: 1,0,1,1</span></span><br><span class="line">	setByte(<span class="number">0x0B</span>)</span><br><span class="line">	</span><br><span class="line">	<span class="comment"># 扫描位数可设置0－7共8种选择，指令的D2－D0就是数字0－7的二进制编码</span></span><br><span class="line">	<span class="comment"># D7-D3:任意</span></span><br><span class="line">	<span class="comment"># D2-D0:0-7的3位二进制编码</span></span><br><span class="line">	setByte(mode)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关断模式设置</span></span><br><span class="line"><span class="comment"># mode: 1: 正常运行模式</span></span><br><span class="line"><span class="comment"># mode: 0: 关断模式</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setShutdownMode</span><span class="params">(mode = <span class="number">1</span>)</span>:</span></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 指令寄存器地址设置：0xXC</span></span><br><span class="line">	<span class="comment"># D15-D12:任意</span></span><br><span class="line">	<span class="comment"># D11,10,9,8: 1,1,0,0</span></span><br><span class="line">	setByte(<span class="number">0x0C</span>)</span><br><span class="line">	</span><br><span class="line">	<span class="comment"># 关断模式可设置0－1共2种选择，设置D0即可</span></span><br><span class="line">	<span class="comment"># D7-D1:任意</span></span><br><span class="line">	<span class="comment"># D0:1: 正常运行模式 0: 关断模式</span></span><br><span class="line">	setByte(mode)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试模式设置</span></span><br><span class="line"><span class="comment"># mode=0: 正常运行模式</span></span><br><span class="line"><span class="comment"># mode=1: 测试模式(全亮模式)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setDisplayTestMode</span><span class="params">(mode = <span class="number">0</span>)</span>:</span></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 指令寄存器地址设置：0xXF</span></span><br><span class="line">	<span class="comment"># D15-D12:任意</span></span><br><span class="line">	<span class="comment"># D11,10,9,8: 1,1,1,1</span></span><br><span class="line">	setByte(<span class="number">0x0f</span>)</span><br><span class="line">	</span><br><span class="line">	<span class="comment"># 测试模式可设置0－1共2种选择，设置D0即可</span></span><br><span class="line">	<span class="comment"># D7-D1:任意</span></span><br><span class="line">	<span class="comment"># D0:0: 正常运行模式 1: 测试模式(全亮模式)</span></span><br><span class="line">	setByte(mode)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定no(1-8)号数码管显示数字num(0-9)，第三个参数是显示不显示小数点（true/false）</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">showDigit</span><span class="params">(no, num, showDotPoint)</span>:</span></span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 设置指令寄存器地址：0xX1-0xX8</span></span><br><span class="line">	<span class="comment"># 格式：D15-D12:任意（我们这里设置0）</span></span><br><span class="line">	<span class="comment">#       D11-D8: 1-8的4位二进制编码：例：1（0,0,0,1）</span></span><br><span class="line">	setByte(no)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 设置显示内容</span></span><br><span class="line">	<span class="comment"># 格式：D7:显示小数点（1点亮）</span></span><br><span class="line">	<span class="comment">#       D6-D4:任意（我们这里设置0）</span></span><br><span class="line">	<span class="comment">#       D3-D0:数字0-9的4位二进制编码：例：2（0,0,1,0）</span></span><br><span class="line">	<span class="keyword">if</span> (showDotPoint):</span><br><span class="line">		<span class="comment"># 如果显示小数点则需要将数字的最高位（D7）设置为1(最高位跟1相或)</span></span><br><span class="line">		setByte(num | <span class="number">0x80</span>)</span><br><span class="line">	<span class="keyword">else</span>:</span><br><span class="line">		setByte(num)</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(LOAD, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setBitData</span><span class="params">(data)</span>:</span></span><br><span class="line">	RPi.GPIO.output(CLK, <span class="keyword">False</span>)</span><br><span class="line">	RPi.GPIO.output(DIN, data)</span><br><span class="line">	RPi.GPIO.output(CLK, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	<span class="comment"># 测试代码，亮度使用最低亮度，显示从0开始递增的数字。</span></span><br><span class="line">	setShutdownMode()</span><br><span class="line">	setDecodeMode()</span><br><span class="line">	setIntensity(<span class="number">0</span>)</span><br><span class="line">	setScanLimit()</span><br><span class="line">	setDisplayTestMode()</span><br><span class="line"></span><br><span class="line">	n=<span class="number">0</span></span><br><span class="line">	<span class="keyword">while</span> <span class="keyword">True</span>:</span><br><span class="line">		n=n+<span class="number">1</span></span><br><span class="line">		showDigit(<span class="number">8</span>, int(n)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">7</span>, int(n/<span class="number">10</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">6</span>, int(n/<span class="number">100</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">5</span>, int(n/<span class="number">1000</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">4</span>, int(n/<span class="number">10000</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">3</span>, int(n/<span class="number">100000</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">2</span>, int(n/<span class="number">1000000</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		showDigit(<span class="number">1</span>, int(n/<span class="number">10000000</span>)%<span class="number">10</span>, <span class="keyword">False</span>)</span><br><span class="line">		time.sleep(<span class="number">0.01</span>)</span><br><span class="line"><span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">	<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理GPIO口</span></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="资源下载">资源下载</h3><p><a href="prog.py" title="源码下载">源码</a><br><a href="MAX7219-MAX7221_cn.pdf" title="数据手册下载">MAX7219数据手册</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>前面几篇我们学习了如何利用一片或多片级联的74HC595芯片来驱动显示数码管的方法。最开始我们提出的两个问题：</p>
<ol>
<li>占用IO口过多</li>
<li>做动态扫描时占用CPU资源太多导致显示不稳定</li>
</ol>
<p>第一个问题已经利用级联的74HC595解决了。（不管驱动几只数码管，只用3个IO即可）<br>但第二个问题依然存在，树莓派仍然需要不停地访问IO口进行动态扫描。<br>好，既然动态扫描占用CPU资源太多，那这活儿咱包出去让别人干不就行了？这就是本文主角MAX7219的特长，动态扫描这活儿MAX7219全包了，干的还比咱自己干得还好，一片MAX7219可最多支持显示8位8段数码管，还支持各种设置如亮度设置扫描位数设置等。而我们只用告诉它显示的内容就行了。</p>]]>
    
    </summary>
    
      <category term="数字芯片" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E5%AD%97%E8%8A%AF%E7%89%87/"/>
    
      <category term="数码管" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E7%A0%81%E7%AE%A1/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门08-使用74HC595芯片驱动数码管（二）]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/06/08/raspi-study0802/"/>
    <id>http://blog.mangolovecarrot.net/2015/06/08/raspi-study0802/</id>
    <published>2015-06-08T12:44:50.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p><a href="../../../../2015/06/03/raspi-study0801/">上一篇</a>我们学习了如何利用74HC595这块显示驱动芯片来驱动1位8段数码管的方法。并逐一讲解了该芯片各引脚的功能。细心的童鞋可能注意到了，上次我们有一个Q7S引脚没有用到。这一篇我们就用这个引脚来级联两块74HC595芯片同时驱动8个8段数码管。在两块74HC595芯片的配合下，同样只需要3个GPIO口就能驱动八只8段数码管。而如果直接用GPIO驱动则需要至少16个GPIO口，节省了13个GPIO！而且按照本文的方法，你还可以级联更多的74HC595芯片，每多级联一片就能多驱动8只数码管，而需要的IO口仍然只有3个！妈妈再也不用担心我的IO口不够用了。</p>
<a id="more"></a>
<h3 id="最终效果">最终效果</h3><p>视频演示</p>
<iframe height="498" width="510" src="http://player.youku.com/embed/XMTI1NzE1MDQwOA==" frameborder="0" allowfullscreen></iframe>

<h3 id="硬件">硬件</h3><ul>
<li>74HC595显示芯片 X 2</li>
<li>共阳（或共阴）4位数码管 X 2<br><img src="hardware.jpg" alt="硬件图 由于大面包板已经被我插满了，所以用另一块小面包板来安放第二片74HC595"></li>
</ul>
<h3 id="原理说明">原理说明</h3><ul>
<li>我们已经知道，每次制造一次移位寄存器时钟引脚的上升沿，74HC595都会在这个上升沿将DS引脚上的数据存入内部的移位寄存器D0，同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7。而D7的数据会被输出到引脚Q7S上，如果Q7S引脚没有被使用，那么这一位数据就被丢掉了。</li>
<li>如果我们将Q7S引脚连接上另一块74HC595的DS引脚并保证两块芯片上的移位时钟的上升沿同时发生（将两块芯片的SHCP连在一起即可）的话，第一块74HC595的串行输出引脚Q7S就变成了第二块74HC595的串行输入数据源。Q7S上的数据会继续移位到第二块74HC595芯片的移位寄存器D0里（同样的，D0→D1→D2→…→D6→D7→Q7S）。</li>
<li>16位数据全部这样串行传输完毕后，制造两块芯片的锁存时钟STCP的上升沿（跟SHCP一样，两块芯片的STCP连在一起即可）即可同时输出16位数据。</li>
<li>利用上述级联原理加上前一篇学习的内容，我们可以这样静态驱动2只数码管：两只数码管的共阳(阴)极连接VCC(GND)，第一片595的Q0-Q7连到第一个数码管的A-G，Dp上，级联的第二片595的Q0-Q7连到第二只数码管的A-G,Dp上，然后用3根GPIO口驱动两片级联的74HC595芯片，连续串行输入两个数字的显示码共16位数据，然后同时制造锁存上升沿，将两个数字的显示码分别输出到两只数码管上即可。这样连接的话，N片级联的74HC595就能驱动N只数码管了。（咦，说好的驱动8位数码管的呢）</li>
<li>上面的做法当然没问题，而且有一个优点是静态显示所以显示很稳定，有兴趣自己试着做一下。缺点是浪费芯片，价格倒不贵可是连线复杂，占用电路板面积太多。本文采用动态扫描（原理参见本系列<a href="../../../../2015/05/05/raspi-study05/">第5篇</a>）的方式来使用两块级联的74HC595芯片驱动8位数码管。原理也很简单，稍微调整一下硬件的连接方式和传输数据的方式即可。</li>
<li>依然是两块74HC595级联，第一块595的输出引脚连到所有数码管的段引脚上（8只数码管的A-G,Dp引脚连在一起）,第二块595的输出引脚Q0-Q7分别连上8只数码管的共阳(阴)极上。第一块芯片的输出决定了数码管上显示什么数字。而8只数码管中哪一只会被点亮则取决于第二块芯片哪只数码管的共阳(阴)端是高(低)电平。</li>
<li>由于在我的硬件连接里，级联的第二块74HC595是负责位选的，所以应该先发送8位位选信号，再发送8位段选信号，在连续发完了16位数据以后，第一块74HC595的移位寄存器里保存着8位的段选信息，而在第二块74HC595的移位寄存器里保存着8位的位选信息。由于两片芯片的STCP是连在同一个GPIO口的，这个时候如果制造一次STCP的上升沿，两块595的位移寄存器里的数据会同时保存到自己的锁存器里，由于我的使能端OE连在GND始终有效，锁存器里的数据就直接输出到了芯片的输出引脚上。第二块芯片的8根输出引脚连接的是8位数码管的共阳端。只有输出高电平的引脚连接的数码管才会被点亮。</li>
<li>当然如果你喜欢，你也可以让8个数码管全部同时点亮，你只要让第二块595输出11111111就行了。不过显示的数字都是一样的。想显示不同的数字就要进行动态扫描，每次输出一个数字的显示码跟一个位选码，快速循环切换显示即可。</li>
</ul>
<p>跟上一篇一样，我也做了一个动画帮助你理解级联的过程。这个动画一开始已经是传输完前8位位选数据的状态了，动画里的位选数据是1000000，点亮第一个数码管，显示的内容由后8位段选数据决定，动画里是数字5。<br><img src="74hc595s.gif" alt="74HC595"></p>
<h3 id="硬件连接">硬件连接</h3><table>
<thead>
<tr>
<th>模块1</th>
<th>引脚</th>
<th>模块2</th>
<th>引脚</th>
</tr>
</thead>
<tbody>
<tr>
<td>74HC595_1</td>
<td>Q0</td>
<td>数码管1/2</td>
<td>DP</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q1</td>
<td>数码管1/2</td>
<td>G</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q2</td>
<td>数码管1/2</td>
<td>F</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q3</td>
<td>数码管1/2</td>
<td>E</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q4</td>
<td>数码管1/2</td>
<td>D</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q5</td>
<td>数码管1/2</td>
<td>C</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q6</td>
<td>数码管1/2</td>
<td>B</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q7</td>
<td>数码管1/2</td>
<td>A</td>
</tr>
<tr>
<td>74HC595_1</td>
<td>Q7S</td>
<td>74HC595_2</td>
<td>DS</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q0</td>
<td>数码管1</td>
<td>DIG1的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q1</td>
<td>数码管1</td>
<td>DIG2的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q2</td>
<td>数码管1</td>
<td>DIG3的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q3</td>
<td>数码管1</td>
<td>DIG4的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q4</td>
<td>数码管2</td>
<td>DIG1的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q5</td>
<td>数码管2</td>
<td>DIG2的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q6</td>
<td>数码管2</td>
<td>DIG3的共阳极</td>
</tr>
<tr>
<td>74HC595_2</td>
<td>Q7</td>
<td>数码管2</td>
<td>DIG4的共阳极</td>
</tr>
<tr>
<td>树莓派</td>
<td>GPIO13</td>
<td>74HC595_1</td>
<td>DS</td>
</tr>
<tr>
<td>树莓派</td>
<td>GPIO19</td>
<td>74HC595_1/2</td>
<td>SHCP</td>
</tr>
<tr>
<td>树莓派</td>
<td>GPIO26</td>
<td>74HC595_1/2</td>
<td>SHTP</td>
</tr>
<tr>
<td>树莓派</td>
<td>VCC</td>
<td>74HC595_1/2</td>
<td>VCC,MR</td>
</tr>
<tr>
<td>树莓派</td>
<td>GND</td>
<td>74HC595_1/2</td>
<td>GND,OE</td>
</tr>
</tbody>
</table>
<h3 id="代码（Python）">代码（Python）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment"># 串行数据输入引脚连接的GPIO口</span></span><br><span class="line">DS = <span class="number">13</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 移位寄存器时钟控制引脚连接的GPIO口——上升沿有效</span></span><br><span class="line">SHCP = <span class="number">19</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据锁存器时钟控制引脚连接的GPIO口——上升沿有效</span></span><br><span class="line">STCP = <span class="number">26</span></span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(DS, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(STCP, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(SHCP, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.output(STCP, <span class="keyword">False</span>)</span><br><span class="line">RPi.GPIO.output(SHCP, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 通过串行数据引脚向74HC595的传送一位数据</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setBitData</span><span class="params">(data)</span>:</span></span><br><span class="line">	<span class="comment"># 准备好要传送的数据</span></span><br><span class="line">	RPi.GPIO.output(DS, data)</span><br><span class="line">	<span class="comment"># 制造一次移位寄存器时钟引脚的上升沿（先拉低电平再拉高电平）</span></span><br><span class="line">	<span class="comment"># 74HC595会在这个上升沿将DS引脚上的数据存入移位寄存器D0</span></span><br><span class="line">	<span class="comment"># 同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7</span></span><br><span class="line">	<span class="comment"># 而D7的数据已经没有地方储存了，这一位数据会被输出到引脚Q7S上</span></span><br><span class="line">	<span class="comment"># 如果Q7S引脚没有被使用，那么这一位的数据就被丢掉了。</span></span><br><span class="line">	<span class="comment"># 而如果将Q7S引脚连接到另一块74HC595上的DS引脚，</span></span><br><span class="line">	<span class="comment"># 那么这一位数据就会继续位移到第二块595芯片的位移寄存器里去。</span></span><br><span class="line">	<span class="comment"># 这就是多块595芯片级联的原理。</span></span><br><span class="line">	RPi.GPIO.output(SHCP, <span class="keyword">False</span>)</span><br><span class="line">	RPi.GPIO.output(SHCP, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定第dig位(1-8)数码管显示数字num(0-9)，参数showDotPoint是显示不显示小数点（true/false）</span></span><br><span class="line"><span class="comment"># 由于我使用的数码管是共阳数码管，所以设置为低电平的段才会被点亮</span></span><br><span class="line"><span class="comment"># 如果你用的是共阴数码管，那么要将下面的True和False全部颠倒过来，或者统一在前面加上not</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">showDigit</span><span class="params">(dig, num, showDotPoint)</span>:</span></span><br><span class="line"></span><br><span class="line">	<span class="comment"># 由于在我的硬件连接里，级联的第二块74HC595是负责位选的，</span></span><br><span class="line">	<span class="comment"># 所以应该先发送8位位选信号，再发送8位段选信号，在连续发完了16位数据以后，</span></span><br><span class="line">	<span class="comment"># 第一块74HC595的移位寄存器里保存着8位的段选信息，而在第二块74HC595的移位寄存器里保存着8位的位选信息。</span></span><br><span class="line">	<span class="comment"># 由于两片芯片的STCP是连在同一个GPIO口的，这个时候如果制造一次STCP的上升沿，</span></span><br><span class="line">	<span class="comment"># 两块595的位移寄存器里的数据会同时保存到自己的锁存器里，由于我的使能端OE连在GND始终有效，锁存器里的数据就直接输出到了芯片的输出引脚上。</span></span><br><span class="line">	<span class="comment"># 第一块芯片的8根输出引脚连接的是所有数码管共用的abcdefg,dp引脚，决定了数码管上显示什么数字。而8只数码管中哪一只会被点亮则取决于哪只数码管的共阳端是高电平。</span></span><br><span class="line">	<span class="comment"># 第二块芯片的8根输出引脚连接的是8位数码管的共阳端。只有输出高电平的引脚连接的数码管会点亮。</span></span><br><span class="line">	<span class="comment"># 当然如果你喜欢，你也可以让8个数码管全部同时点亮，你只要让第二块595输出11111111就行了。不过显示的数字都是一样的。</span></span><br><span class="line">	<span class="comment"># 想显示不同的数字就要进行动态扫描，原理不再说明请参考本系列教程第5篇。</span></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">for</span> x <span class="keyword">in</span> range(<span class="number">1</span>,<span class="number">9</span>):</span><br><span class="line">		<span class="keyword">if</span> (x == dig):</span><br><span class="line">			setBitData(<span class="keyword">True</span>)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			setBitData(<span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (num == <span class="number">0</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint) <span class="comment"># DP</span></span><br><span class="line">		setBitData(<span class="keyword">True</span>)  <span class="comment"># G</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># F</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># E</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># D</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># C</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># B</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># A</span></span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">1</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">2</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">3</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">4</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">5</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">6</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">7</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">8</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">9</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 移位寄存器的8位数据全部传输完毕后，制造一次锁存器时钟引脚的上升沿（先拉低电平再拉高电平）</span></span><br><span class="line">	<span class="comment"># 74HC595会在这个上升沿将移位寄存器里的8位数据复制到8位的锁存器中（锁存器里原来的数据将被替换）</span></span><br><span class="line">	<span class="comment"># 到这里为止，这8位数据还只是被保存在锁存器里，并没有输出到数码管上。</span></span><br><span class="line">	<span class="comment"># 决定锁存器里的数据是否输出是由“输出使能端口”OE决定的。当OE设置为低电平时，锁存器里数据才会被输出到Q0-Q7这8个输出引脚上。</span></span><br><span class="line">	<span class="comment"># 在我的硬件连接里，OE直接连接在了GND上，总是保持低电平，所以移位寄存器的数据一旦通过时钟上升沿进入锁存器，也就相当于输出到LED上了。</span></span><br><span class="line">	RPi.GPIO.output(STCP, <span class="keyword">True</span>)</span><br><span class="line">	RPi.GPIO.output(STCP, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	<span class="comment"># 测试代码</span></span><br><span class="line">	<span class="keyword">while</span> (<span class="keyword">True</span>):</span><br><span class="line">		<span class="comment"># 8位数码管显示1-8，不显示小数点</span></span><br><span class="line">		<span class="keyword">for</span> dig <span class="keyword">in</span> range(<span class="number">1</span>,<span class="number">9</span>):</span><br><span class="line">			showDigit(dig, <span class="number">9</span>-dig, <span class="keyword">False</span>)</span><br><span class="line">			time.sleep(<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">	<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 最后清理GPIO口</span></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="资源下载">资源下载</h3><p><a href="74hc595_02.py" title="源码下载">点击下载源码</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="../../../../2015/06/03/raspi-study0801/">上一篇</a>我们学习了如何利用74HC595这块显示驱动芯片来驱动1位8段数码管的方法。并逐一讲解了该芯片各引脚的功能。细心的童鞋可能注意到了，上次我们有一个Q7S引脚没有用到。这一篇我们就用这个引脚来级联两块74HC595芯片同时驱动8个8段数码管。在两块74HC595芯片的配合下，同样只需要3个GPIO口就能驱动八只8段数码管。而如果直接用GPIO驱动则需要至少16个GPIO口，节省了13个GPIO！而且按照本文的方法，你还可以级联更多的74HC595芯片，每多级联一片就能多驱动8只数码管，而需要的IO口仍然只有3个！妈妈再也不用担心我的IO口不够用了。</p>]]>
    
    </summary>
    
      <category term="数字芯片" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E5%AD%97%E8%8A%AF%E7%89%87/"/>
    
      <category term="数码管" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E7%A0%81%E7%AE%A1/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门08-使用74HC595芯片驱动数码管（一）]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/06/03/raspi-study0801/"/>
    <id>http://blog.mangolovecarrot.net/2015/06/03/raspi-study0801/</id>
    <published>2015-06-03T13:36:58.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>之前我们学习了<a href="../../../../2015/05/05/raspi-study05/" title="树莓派GPIO入门05-驱动数码管显示数字">如何驱动数码管显示数字</a>。<br>但是这种做法有两个缺点。</p>
<ol>
<li>需要占用大量IO口，在那篇文章里，我们为了驱动4位数码管一共使用了12个IO口。如果需要驱动8位数码管则至少需要16个IO口。</li>
<li>系统资源占用过多。还是在那篇文章里，为了实现数码管的动态扫描显示，需要不停地高速操作IO口，这对单任务的单片机比如51单片机来说问题并不太大，因为单任务的单片机的执行时序是由晶振来决定的，动态扫描的时间间隔可以控制地非常精确，数码管的显示会很稳定，不会出现闪烁的现象。但对于运行着多任务的Linux操作系统的树莓派来说，对IO口的大量反复操作以及大量使用sleep语句会导致CPU占用过多，最后导致动态扫描的间隔时间不均匀，体现为数码管显示不稳定，有明显闪烁的现象。为了改善这个问题我在那篇文章的最后还尝试用c语言来代替python语言，可实际效果有限。<br>使用GPIO直接驱动数码管时，上面这两个问题是不可避免的。想解决这两个问题，我们需要借助外部芯片的帮助。<br>接下来我将用几个篇幅来介绍如何使用显示驱动芯片74HC595来驱动数码管的方法。同时我们也可以学习到串行数据传输的方法以及一些数字芯片通用的一些概念，比如时钟引脚，上升沿，锁存，移位寄存等。理解了这些通用的概念对学习使用其他芯片是很有帮助的。</li>
</ol>
<a id="more"></a>
<h3 id="本文最终效果">本文最终效果</h3><p>在一块74HC595芯片的配合下，只需要3个GPIO就能驱动一只8段数码管。（直接用GPIO驱动需要至少8个GPIO口）<br>视频演示</p>
<iframe height="498" width="510" src="http://player.youku.com/embed/XMTI1NTAxMTMyMA==" frameborder="0" allowfullscreen></iframe>

<h3 id="硬件">硬件</h3><ul>
<li>74HC595显示芯片一只（0.5元一只）<br><img src="74hc595.jpg" alt="74HC595"></li>
<li>共阳（或共阴）数码管一只</li>
<li>限流电阻一只，330欧就够了。<br><img src="hardware.jpg" alt="硬件图 TODO"></li>
</ul>
<h3 id="原理说明">原理说明</h3><p>先转一段百度百科上74HC595芯片的简介。</p>
<blockquote>
<p>74HC595具有8位移位寄存器和一个存储器，三态输出功能。 移位寄存器和存储器有相互独立的时钟。数据在SH_cp（移位寄存器时钟输入）的上升沿输入到移位寄存器中，在ST_cp（存储器时钟输入）的上升沿输入到存储寄存器中去。如果两个时钟连在一起，则移位寄存器总是比存储寄存器早一个脉冲。移位寄存器有一个串行移位输入（Ds），和一个串行输出（Q7’）,和一个异步的低电平复位，存储寄存器有一个并行8位的，具备三态的总线输出，当使能OE时（为低电平），存储寄存器的数据输出到总线。</p>
</blockquote>
<p>看不懂吧，没关系，我们先看一下芯片的引脚图：<br><img src="01.jpg" alt="74HC595引脚图"><br>分别解释一下：</p>
<ul>
<li>GND接地，VCC接5V电源，这个就不用说了。</li>
<li>Q0-Q7这8根引脚是芯片的输出引脚，直接跟数码管的8段引脚相连。对应关系要看你怎么接线和写代码时传送数据的顺序了。</li>
<li>DS是串行输入引脚，所谓串行就是使数据在一根信号线上按顺序一位一位地传输，就像一串糖葫芦。这个引脚我们接到树莓派任意一个GPIO口上（输出模式）。</li>
<li>SHCP是移位寄存器的时钟引脚。听上去有点复杂，其实很简单。74HC595内部有一个8位的移位寄存器用来保存从DS引脚输入的数据。那么74HC595怎么知道什么时候该从DS引脚上取数据了呢？正是通过SHCP这个时钟引脚来实现的。只有在SHCP发生一次<em>上升沿</em>的时候，74HC595才会从DS引脚上取得当前的数据（高/低电平）并把取到的这一位数据保存到移位寄存器里。同样的，这个引脚也接到树莓派任意一个GPIO口上。当我们向芯片发送数据时，要先在DS引脚上准备好要传送的数据，然后制造一次SHCP引脚的上升沿（先拉低电平再拉高电平），74HC595会在这个上升沿将DS引脚上的数据存入移位寄存器D0，同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7。而原先D7的数据已经没有地方储存了，这一位数据会被输出到引脚Q7S上。这个引脚的作用我们下一篇再说，本文暂时用不到这个引脚。（注意这里说的不是输出引脚Q0-Q7，而是指内部的8位移位寄存器里每一个“小房间”，芯片手册上并没有给这些小房间编号，这里为了说明方便进行了编号）</li>
<li>STCP是芯片内部另外一个8位锁存寄存器的时钟引脚。当移位寄存器的8位数据全部传输完毕后，制造一次锁存器时钟引脚的上升沿（先拉低电平再拉高电平）。74HC595会在这个上升沿将移位寄存器里的8位数据复制到锁存器中（锁存器里原来的数据将被替换）。注意，到这里为止，这8位数据还只是被保存在锁存器里，并没有输出到数码管上。这个引脚同样连接到树莓派任意一个GPIO口上即可。</li>
<li>OE是输出使能引脚，在其他芯片里也很常见。作用是控制锁存器里的数据是否最终输出到Q0-Q7输出引脚上。低电平时输出，高电平时不输出（既不是高电平，也不是低电平而是高阻态，不通电）。本例为了方便直接接在GND上使其一直保持低电平输出数据。</li>
<li>MR是用来重置内部寄存器的引脚。低电平时重置内部寄存器(MemoryReset?)。本例为了方便直接连接在Vcc上一直保持高电平。</li>
<li>Q7S引脚，串行输出引脚，本文不使用，下一篇再解释它的作用。</li>
<li>关于锁存器。顾名思义就是将数据保存并锁定。一旦进入了锁存器，除非断电或重置数据（MR口设置为低电平），锁存器的数据不会再改变。好处是，当你需要更新数据时，将数据串行输入移位寄存器的过程中，锁存器里的数据不会有任何影响，也就不会有闪烁了。一直到移位寄存器8位数据准备完毕，再制造一次STCP的上升沿一次性更新锁存器的数据，更新输出。</li>
</ul>
<p>另外，我做了一个动画帮助你理解整个过程。<br><img src="74hc595.gif" alt="74HC595"></p>
<h3 id="硬件连接">硬件连接</h3><table>
<thead>
<tr>
<th>模块1</th>
<th>引脚</th>
<th>模块2</th>
<th>引脚</th>
</tr>
</thead>
<tbody>
<tr>
<td>74HC595</td>
<td>Q0</td>
<td>数码管</td>
<td>DP</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q1</td>
<td>数码管</td>
<td>G</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q2</td>
<td>数码管</td>
<td>F</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q3</td>
<td>数码管</td>
<td>E</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q4</td>
<td>数码管</td>
<td>D</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q5</td>
<td>数码管</td>
<td>C</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q6</td>
<td>数码管</td>
<td>B</td>
</tr>
<tr>
<td>74HC595</td>
<td>Q7</td>
<td>数码管</td>
<td>A</td>
</tr>
<tr>
<td>74HC595</td>
<td>DS</td>
<td>树莓派</td>
<td>GPIO13</td>
</tr>
<tr>
<td>74HC595</td>
<td>SHCP</td>
<td>树莓派</td>
<td>GPIO19</td>
</tr>
<tr>
<td>74HC595</td>
<td>SHTP</td>
<td>树莓派</td>
<td>GPIO26</td>
</tr>
<tr>
<td>74HC595</td>
<td>VCC,MR</td>
<td>树莓派</td>
<td>VCC</td>
</tr>
<tr>
<td>74HC595</td>
<td>GND,OE</td>
<td>树莓派</td>
<td>GND</td>
</tr>
<tr>
<td>数码管</td>
<td>1位共阳极</td>
<td>树莓派</td>
<td>VCC</td>
</tr>
</tbody>
</table>
<p>注意，共阳数码管的共阳极连接5V电源时要串联一只限流电阻防止数码管电流过大损坏电阻。<br>如果你用的是共阴极数码管就没关系了，74HC595输出的电流是控制好的可以直接连到阳极上。<br>我手头上没有单独的1位数码管，就用4位数码管代替了，本文只接通数码管DIG1的共阳极做演示。</p>
<h3 id="代码（Python）">代码（Python）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment"># 串行数据输入引脚连接的GPIO口</span></span><br><span class="line">DS = <span class="number">13</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 移位寄存器时钟控制引脚连接的GPIO口——上升沿有效</span></span><br><span class="line">SHCP = <span class="number">19</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据锁存器时钟控制引脚连接的GPIO口——上升沿有效</span></span><br><span class="line">STCP = <span class="number">26</span></span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(DS, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(STCP, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(SHCP, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.output(STCP, <span class="keyword">False</span>)</span><br><span class="line">RPi.GPIO.output(SHCP, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 通过串行数据引脚向74HC595的传送一位数据</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">setBitData</span><span class="params">(data)</span>:</span></span><br><span class="line">	<span class="comment"># 准备好要传送的数据</span></span><br><span class="line">	RPi.GPIO.output(DS, data)</span><br><span class="line">	<span class="comment"># 制造一次移位寄存器时钟引脚的上升沿（先拉低电平再拉高电平）</span></span><br><span class="line">	<span class="comment"># 74HC595会在这个上升沿将DS引脚上的数据存入移位寄存器D0</span></span><br><span class="line">	<span class="comment"># 同时D0原来的数据会顺移到D1，D1的数据位移到D2。。。D6的数据位移到D7</span></span><br><span class="line">	<span class="comment"># 而D7的数据已经没有地方储存了，这一位数据会被输出到引脚Q7S上</span></span><br><span class="line">	RPi.GPIO.output(SHCP, <span class="keyword">False</span>)</span><br><span class="line">	RPi.GPIO.output(SHCP, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定数码管显示数字num(0-9)，第2个参数是显示不显示小数点（true/false）</span></span><br><span class="line"><span class="comment"># 由于我使用的数码管是共阳数码管，所以设置为低电平的段才会被点亮</span></span><br><span class="line"><span class="comment"># 如果你用的是共阴数码管，那么要将下面的True和False全部颠倒过来，或者统一在前面加上not</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">showDigit</span><span class="params">(num, showDotPoint)</span>:</span></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (num == <span class="number">0</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint) <span class="comment"># DP</span></span><br><span class="line">		setBitData(<span class="keyword">True</span>)  <span class="comment"># G</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># F</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># E</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># D</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># C</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># B</span></span><br><span class="line">		setBitData(<span class="keyword">False</span>) <span class="comment"># A</span></span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">1</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">2</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">3</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">4</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">5</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">6</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">7</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">8</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">	<span class="keyword">elif</span> (num == <span class="number">9</span>) :</span><br><span class="line">		setBitData(<span class="keyword">not</span> showDotPoint)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">True</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line">		setBitData(<span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 移位寄存器的8位数据全部传输完毕后，制造一次锁存器时钟引脚的上升沿（先拉低电平再拉高电平）</span></span><br><span class="line">	<span class="comment"># 74HC595会在这个上升沿将移位寄存器里的8位数据复制到8位的锁存器中（锁存器里原来的数据将被替换）</span></span><br><span class="line">	<span class="comment"># 到这里为止，这8位数据还只是被保存在锁存器里，并没有输出到数码管上。</span></span><br><span class="line">	<span class="comment"># 决定锁存器里的数据是否输出是由“输出使能端口”OE决定的。当OE设置为低电平时，锁存器里数据才会被输出到Q0-Q7这8个输出引脚上。</span></span><br><span class="line">	<span class="comment"># 在我的硬件连接里，OE直接连接在了GND上，总是保持低电平，所以移位寄存器的数据一旦通过时钟上升沿进入锁存器，也就相当于输出到LED上了。</span></span><br><span class="line">	RPi.GPIO.output(STCP, <span class="keyword">True</span>)</span><br><span class="line">	RPi.GPIO.output(STCP, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	<span class="comment"># 测试代码</span></span><br><span class="line">	<span class="comment"># 从0显示到9，不显示小数点</span></span><br><span class="line">	<span class="keyword">for</span> x <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">10</span>):</span><br><span class="line">		showDigit(x, <span class="keyword">False</span>)</span><br><span class="line">		time.sleep(<span class="number">0.2</span>)</span><br><span class="line"></span><br><span class="line">	<span class="comment"># 再从0显示到9，显示小数点</span></span><br><span class="line">	<span class="keyword">for</span> y <span class="keyword">in</span> range(<span class="number">0</span>,<span class="number">10</span>):</span><br><span class="line">		showDigit(y, <span class="keyword">True</span>)</span><br><span class="line">		time.sleep(<span class="number">0.2</span>)</span><br><span class="line">					</span><br><span class="line"><span class="keyword">except</span> KeyboardInterrupt:</span><br><span class="line">	<span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 最后清理GPIO口</span></span><br><span class="line"><span class="comment"># 清理了IO是将所有使用中的IO口释放，并全部设置为输入模式</span></span><br><span class="line"><span class="comment"># 你会发现最后设置的数据在清理了IO口以后还会继续正常显示</span></span><br><span class="line"><span class="comment"># 这是因为数据一旦存入锁存器，除非断电或重置数据（MR口设置为低电平），</span></span><br><span class="line"><span class="comment"># 否则最后设置的数据会一直保留在74HC595芯片中。也就是被“锁存”了。</span></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="资源下载">资源下载</h3><p><a href="74hc595_01.py" title="源码下载">点击下载源码</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>之前我们学习了<a href="../../../../2015/05/05/raspi-study05/" title="树莓派GPIO入门05-驱动数码管显示数字">如何驱动数码管显示数字</a>。<br>但是这种做法有两个缺点。</p>
<ol>
<li>需要占用大量IO口，在那篇文章里，我们为了驱动4位数码管一共使用了12个IO口。如果需要驱动8位数码管则至少需要16个IO口。</li>
<li>系统资源占用过多。还是在那篇文章里，为了实现数码管的动态扫描显示，需要不停地高速操作IO口，这对单任务的单片机比如51单片机来说问题并不太大，因为单任务的单片机的执行时序是由晶振来决定的，动态扫描的时间间隔可以控制地非常精确，数码管的显示会很稳定，不会出现闪烁的现象。但对于运行着多任务的Linux操作系统的树莓派来说，对IO口的大量反复操作以及大量使用sleep语句会导致CPU占用过多，最后导致动态扫描的间隔时间不均匀，体现为数码管显示不稳定，有明显闪烁的现象。为了改善这个问题我在那篇文章的最后还尝试用c语言来代替python语言，可实际效果有限。<br>使用GPIO直接驱动数码管时，上面这两个问题是不可避免的。想解决这两个问题，我们需要借助外部芯片的帮助。<br>接下来我将用几个篇幅来介绍如何使用显示驱动芯片74HC595来驱动数码管的方法。同时我们也可以学习到串行数据传输的方法以及一些数字芯片通用的一些概念，比如时钟引脚，上升沿，锁存，移位寄存等。理解了这些通用的概念对学习使用其他芯片是很有帮助的。</li>
</ol>]]>
    
    </summary>
    
      <category term="数字芯片" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E5%AD%97%E8%8A%AF%E7%89%87/"/>
    
      <category term="数码管" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E7%A0%81%E7%AE%A1/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门07-利用声音传感器制作声控灯]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/05/22/raspi-study07/"/>
    <id>http://blog.mangolovecarrot.net/2015/05/22/raspi-study07/</id>
    <published>2015-05-21T16:03:16.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>本文我们用声音传感器来制作一个简易的声控灯。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="xg.jpg" alt="树莓派GPIO入门07-利用声音传感器制作声控灯"><br>视频演示：</p>
<iframe height="498" width="510" src="http://player.youku.com/embed/XOTYyMjQ4MTUy" frameborder="0" allowfullscreen></iframe>

<h3 id="硬件">硬件</h3><ul>
<li>面包板</li>
<li>杜邦线</li>
<li>LED发光二极管一只</li>
<li>声音传感器一只<br><img src="hardware.jpg" alt="硬件图"></li>
</ul>
<h3 id="原理说明">原理说明</h3><p>声音传感器有3根引脚，电源正极，电源负极，数据OUT，分别接到树莓派的VCC，GND和任意一个GPIO口上（输入模式）。<br>当声音传感器检测到有声音就会从OUT口输出低电平，注意低电平并不会持续，声音一旦结束传感器也会马上停止输出低电平。<br>另外，在传感器上有一个电位器，上面有一个十字形的旋钮，用小螺丝刀或小刀可以旋转十字，调整声音敏感度。（触发音量的阈值）<br>LED的短针负极脸上GND，长针连上另一个GPIO口（输出模式），当树莓派接收到传感器发出的低电平信号时，输出高/低电平，打开/关闭LED灯。</p>
<h3 id="硬件连接">硬件连接</h3><ol>
<li>声音传感器电源正极 - 树莓派的VCC</li>
<li>声音传感器电源负极 - 树莓派的GND</li>
<li>声音传感器数据OUT - 树莓派的GPIO4</li>
<li>LED长针 - 树莓派的GPIO17</li>
<li>LED短针 - 树莓派的GND</li>
</ol>
<h3 id="代码（Python）">代码（Python）</h3><figure class="highlight monkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#!/usr/bin/env python</span><span class="preprocessor"></span><br><span class="line"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor"><span class="keyword">import</span> RPi.GPIO</span></span><br><span class="line"><span class="preprocessor"><span class="keyword">import</span> time</span><span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># LED正极连接的GPIO口</span></span><br><span class="line">LED = <span class="number">17</span><span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 声音感应器OUT口连接的GPIO口</span></span><br><span class="line">SENSOR = <span class="number">4</span><span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 当前LED灯的开关状态</span></span><br><span class="line">flg = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)<span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 指定GPIO4（声音感应器的OUT口连接的GPIO口）的模式为输入模式</span><span class="preprocessor"></span><br><span class="line"># 默认拉高到高电平，低电平表示OUT口有输出</span></span><br><span class="line">RPi.GPIO.setup(SENSOR, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP)<span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 指定GPIO17（LED长针连接的GPIO针脚）的模式为输出模式</span></span><br><span class="line">RPi.GPIO.setup(LED, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	<span class="keyword">while</span> <span class="literal">True</span>:<span class="preprocessor"></span><br><span class="line">		# 检测声音感应器是否输出低电平，若是低电平，表示声音被检测到，点亮或关闭LED灯</span></span><br><span class="line">		<span class="keyword">if</span> (RPi.GPIO.input(SENSOR) == <span class="number">0</span>):</span><br><span class="line">			flg = <span class="keyword">not</span> flg</span><br><span class="line">			RPi.GPIO.output(LED, flg)<span class="preprocessor"></span><br><span class="line">			# 稍微延时一会，避免刚点亮就熄灭，或者刚熄灭就点亮。</span></span><br><span class="line">			time.sleep(<span class="number">0.5</span>)</span><br><span class="line"></span><br><span class="line">except KeyboardInterrupt:</span><br><span class="line">	pass</span><br><span class="line"></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="资源下载">资源下载</h3><p><a href="prog.py" title="源码下载">点击下载源码</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>本文我们用声音传感器来制作一个简易的声控灯。<br>]]>
    
    </summary>
    
      <category term="传感器" scheme="http://blog.mangolovecarrot.net/tags/%E4%BC%A0%E6%84%9F%E5%99%A8/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门06-跟数字湿温度计DHT11通信]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/05/17/raspi-study06/"/>
    <id>http://blog.mangolovecarrot.net/2015/05/17/raspi-study06/</id>
    <published>2015-05-17T14:27:04.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>本文我们利用树莓派的GPIO口来跟数字湿温度计模块DHT11进行通信取得温度和湿度数据并显示在数码管上，通过按钮来切换显示温度或湿度。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="xg.jpg" alt="树莓派GPIO入门06-跟数字湿温度计DHT11通信"><br>\</p>
<h3 id="硬件">硬件</h3><ul>
<li>数码管</li>
<li>杜邦线</li>
<li>面包板</li>
<li>按钮1只</li>
<li>数字湿温度计DHT11模块。（我们这个教程里用到的所有电子元件均可在淘宝购买到）<br><img src="hardware.jpg" alt="硬件图"></li>
</ul>
<h3 id="原理说明">原理说明</h3><p>原始的DHT11模块有4根引脚，长成这个样子：<br><img src="DHT11_org.png" alt="原始DHT11模块"><br>由图可以看出4根引脚里除了VCC，GND，DATA以外，还有一个引脚是N/A，也就是不使用。（不使用引出来干嘛？好看吗？不解）<br>本文使用的是又被封装了一次的模块，去掉了无用的引脚。其他3个引脚保留。功能完全一样，所以如果你手头上的DHT11是有4根引脚的请忽略N/A针脚，其他的跟我使用的这种完全通用。3个针脚分别连接到3.3v电源，GND和任意GPIO口上。根据数据手册（文末提供下载）的说明，总线（DATA引脚）在空闲状态需要保持高电平状态，所以我们除了将DATA引脚接到一个GPIO口上，还要通过一个4.7K（经实测2K左右的就够了）的电阻将DATA引脚并联到VCC上。这个电阻也称上拉电阻，电阻就是一般的电阻，只是在这里起的作用是上拉电平的作用所以称之为上拉电阻。<br>与DHT11通信时，发送和接收信息都在一根DATA口上，这种只用1根总线的数据传输方式称为单总线模式。<br>向DHT11发送数据时，GPIO口需要设置为OUTPUT模式，从DHT11接收数据时GPIO口需要切换成INPUT模式。<br>具体通信的时序如下：</p>
<ol>
<li>由于有上拉电阻存在，总线（DATA）空闲状态为高电平。</li>
<li>树莓派GPIO口设置为OUTPUT模式。</li>
<li>树莓派向DHT11发送起始信号。方式是GPIO口设置低电平并持续一段时间，根据数据手册的说明，这段时间必须大于18毫秒，保证DHT11能检测到起始信号。</li>
<li>树莓派起始信号输出完毕，切换到输入模式，等待DHT11响应。一旦切换到输入模式GPIO口就不再输出电平信号，总线处于释放状态，由于有上拉电阻的存在，总线被拉回高电平。</li>
<li>在总线被拉回至高电平通知DHT11主机已经准备好接受数据以后，DHT11还会继续等待20-40us左右以后才会开始发送反馈信号。</li>
<li>DHT11开始发送反馈信号，总线被DHT11拉低，持续80us左右。</li>
<li>这个持续了80us左右的低电平的反馈信号结束以后，DHT11又会将DATA口拉回高电平并再次持续80us左右。</li>
<li>DHT11开始正式传输40bit的二进制数据（0或1）。每一个bit的数据（0或者1）总是由一段持续50us的低电平信号开始，再由一段持续26us-28us（数据0）或者持续70us（数据1）的高电平结束。一直到40位数据传输完毕。这40位的数据内容是：<br>8bit湿度整数数据 + 8bit湿度小数数据 + 8bi温度整数数据 + 8bit温度小数数据 + 8bit校验和。而校验和数据应该等于“湿度整数数据+湿度小数数据+温度整数数据+温度小数数据”所得结果的末8位。<br>我们的程序就应该遵循上述时序来与DHT11进行数据通信。</li>
</ol>
<h3 id="硬件连接">硬件连接</h3><p>下面的连接图只标出了DHT11的连线和上拉电阻的连线方法。数码管和按钮的连线请参考<a href="../../../../2015/05/05/raspi-study05/" title="树莓派GPIO入门05-驱动数码管显示数字">上一篇</a>。<br><img src="connect.png" alt="硬件连接图"></p>
<h3 id="关键代码">关键代码</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">readDHT11</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> i,j,cnt = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; RETRY; ++j)</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">5</span>; ++i) &#123;</span><br><span class="line">      data[i] = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// GPIO口模式设置为输出模式</span></span><br><span class="line">    pinMode (DATA, OUTPUT) ;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 先拉高DATA一段时间，准备发送开始指令</span></span><br><span class="line">    digitalWrite (DATA, HIGH);</span><br><span class="line">    usleep(<span class="number">500000</span>);  <span class="comment">// 500 ms</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 拉低DATA口，输出开始指令（至少持续18ms）</span></span><br><span class="line">    digitalWrite (DATA, LOW);</span><br><span class="line">    usleep(TIME_START);</span><br><span class="line">    digitalWrite (DATA, HIGH);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 开始指令输出完毕，切换到输入模式，等待DHT11输出信号。</span></span><br><span class="line">    <span class="comment">// 由于有上拉电阻的存在，所以DATA口会维持高电平。</span></span><br><span class="line">    pinMode (DATA, INPUT);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 在DATA口被拉回至高电平通知DHT11主机已经准备好接受数据以后，</span></span><br><span class="line">    <span class="comment">// DHT11还会继续等待20-40us左右以后才会开始发送反馈信号，所以我们把这段时间跳过去</span></span><br><span class="line">    <span class="comment">// 如果长时间（1000us以上）没有低电平的反馈表示有问题，结束程序</span></span><br><span class="line">    cnt=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (digitalRead(DATA) == HIGH) &#123;</span><br><span class="line">      cnt++;</span><br><span class="line">      <span class="keyword">if</span> (cnt &gt; MAXCNT)</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"DHT11未响应，请检查连线是否正确，元件是否正常工作。\n"</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 这个反馈响应信号的低电平会持续80us左右，但我们不需要精确计算这个时间</span></span><br><span class="line">    <span class="comment">// 只要一直循环检查DATA口的电平有没有恢复成高电平即可</span></span><br><span class="line">    cnt=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (digitalRead(DATA) == LOW) &#123;</span><br><span class="line">      cnt++;</span><br><span class="line">      <span class="keyword">if</span> (cnt &gt; MAXCNT)</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"DHT11未响应，请检查连线是否正确，元件是否正常工作。\n"</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这个持续了80us左右的低电平的反馈信号结束以后，DHT11又会将DATA口拉回高电平并再次持续80us左右</span></span><br><span class="line">    <span class="comment">// 然后才会开始发送真正的数据。所以跟上面一样，我们再做一个循环来检测这一段高电平的结束。</span></span><br><span class="line">    cnt=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (digitalRead(DATA) == HIGH) &#123;</span><br><span class="line">      cnt++;</span><br><span class="line">      <span class="keyword">if</span> (cnt &gt; MAXCNT)</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"DHT11未响应，请检查连线是否正确，元件是否正常工作。\n"</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ##################### 40bit的数据传输开始 ######################</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">40</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="comment">// 每一个bit的数据（0或者1）总是由一段持续50us的低电平信号开始</span></span><br><span class="line">      <span class="comment">// 跟上面一样我们用循环检测的方式跳过这一段</span></span><br><span class="line">      <span class="keyword">while</span> (digitalRead(DATA) == LOW) &#123;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 接下来的高电平持续的时间是判断该bit是0还是1的关键。</span></span><br><span class="line">      <span class="comment">//    根据DHT11的说明文档，我们知道 这段高电平持续26us-28us左右的话表示这是数据0。</span></span><br><span class="line">      <span class="comment">//    如果这段高电平持续时间为70us左右表示这是数据1。</span></span><br><span class="line">      <span class="comment">// 方法1：在高电平开始的时候记下时间，在高电平结束的时候再记一个时间，</span></span><br><span class="line">      <span class="comment">//        通过计算两个时间的间隔就能得知是数据0还是数据1了。</span></span><br><span class="line">      <span class="comment">// 方法2：在高电平开始的以后我们延时40us，然后再次检测DATA口:</span></span><br><span class="line">      <span class="comment">//        (a) 如果此时DATA口是低电平，表示当前位的数据已经发送完并进入下一位数据的传输准备阶段（低电平50us）了。</span></span><br><span class="line">      <span class="comment">//        由于数据1的高电平持续时间是70us，所以如果是数据1，此时DATA口应该还是高电平才对，</span></span><br><span class="line">      <span class="comment">//        据此我们可以断言刚才传输的这一位数据是0。</span></span><br><span class="line">      <span class="comment">//        (b) 如果延时40us以后DATA口仍然是高电平，那么我们可以断言这一位数据一定是1了，因为数据0只会持续26us。</span></span><br><span class="line">      <span class="comment">// 方法3：循环检测电平状态并计数，每检查一次如果电平状态没变就让计数器加一，一直到电平状态变成低电平为止。</span></span><br><span class="line">      <span class="comment">//        数据0的高电平持续时间短，所以计数一定比数据1的计数少，由于微秒级别的延时太短，这个计数会有一定误差。</span></span><br><span class="line">      <span class="comment">//        我们需要先在自己的树莓派上用printf打印出每一位数据计数的结果，然后观察计数结果来设定一个阈值，</span></span><br><span class="line">      <span class="comment">//        高于这个阈值的就认为的数据1，低于这个值的就认为是数据0。</span></span><br><span class="line">      <span class="comment">// 我们这里采用简单易行的方法3。</span></span><br><span class="line">      <span class="comment">// 实际上，由于要求的时序太短，在树莓派上很难通过方法1和方法2实现。这也是我使用c而不是python的原因。</span></span><br><span class="line">      <span class="comment">//    特别是方法2，因为linux里有一个系统级的延时函数usleep，单位确实是微秒。</span></span><br><span class="line">      <span class="comment">//    貌似用usleep(40)就可以了，实际测试的结果是延时远远超过40us。其原因是usleep这个函数的延时方法是</span></span><br><span class="line">      <span class="comment">//    暂停当前进程并放开cpu权限让cpu可以在这段时间里去处理其他任务。这样做的好处是不会浪费cpu资源，</span></span><br><span class="line">      <span class="comment">//    但问题是当系统将cpu权限交还给我们的进程的这个过程本身就要耗费若干ms（毫秒哦）</span></span><br><span class="line">      <span class="comment">//    所以导致usleep这个函数实际上没有办法做到延时几十微秒。</span></span><br><span class="line">      cnt=<span class="number">0</span>;</span><br><span class="line">      <span class="keyword">while</span> (digitalRead(DATA) == HIGH) &#123;</span><br><span class="line">        <span class="comment">// 当所有数据传输完以后，DHT11会放开总线，DATA口就会被上拉电阻一直拉高。</span></span><br><span class="line">        <span class="comment">// 所以如果超过一定时间电平还没有被拉低就表示所有的数据已经传输完毕，停止检测。</span></span><br><span class="line">        cnt++;</span><br><span class="line">        <span class="keyword">if</span> (cnt &gt; MAXCNT)</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (cnt &gt; MAXCNT)</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 将当前位的计数保存起来</span></span><br><span class="line">      bits[i] = cnt;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 整理数据，将位数据转成5个数字</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">40</span>; ++i) &#123;</span><br><span class="line">      data[i/<span class="number">8</span>] &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">      <span class="keyword">if</span> (bits[i] &gt; VAL) </span><br><span class="line">      &#123;</span><br><span class="line">        data[i/<span class="number">8</span>] |= <span class="number">1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//下面这句话就是用来测试自己的设备应该设定多少阈值的测试代码</span></span><br><span class="line">      <span class="comment">//printf("bits[%d] = %d (%d) \n", i, bits[i], bits[i]&gt;200?1:0 );</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 往屏幕上输出取得的数据</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">5</span>; ++i) &#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"data[%d] = %d \n"</span>, i, data[i] );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 用校验和来检查接收数据是否完整</span></span><br><span class="line">    <span class="keyword">if</span> (data[<span class="number">4</span>] == (data[<span class="number">0</span>] + data[<span class="number">1</span>] + data[<span class="number">2</span>] + data[<span class="number">3</span>]) &amp; <span class="number">0xFF</span> ) &#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"校验成功！ \n"</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 将湿度，温度数据赋值给显示用的湿度，温度变量</span></span><br><span class="line">      shidu = data[<span class="number">0</span>];</span><br><span class="line">      wendu = data[<span class="number">2</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">"校验不成功，重新取值！ \n"</span>);</span><br><span class="line">      <span class="comment">// 校验不成功，重新取值，连续10次取值不成功就放弃。一般连线和逻辑正确的话连续10次取值出错是不可能的。</span></span><br><span class="line">      <span class="keyword">continue</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="校验和">校验和</h3><p>下图是实际运行时利用校验和检测到数据出现了接收错误的情况<br><img src="run.png" alt="利用校验和来检查接收数据的正确性"></p>
<h3 id="资源下载">资源下载</h3><p><a href="prog.c" title="C源码下载">点击下载C源码</a><br><a href="DHT11.pdf" title="DHT11数据手册下载">点击下载DHT11模块产品手册</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>本文我们利用树莓派的GPIO口来跟数字湿温度计模块DHT11进行通信取得温度和湿度数据并显示在数码管上，通过按钮来切换显示温度或湿度。<br>]]>
    
    </summary>
    
      <category term="传感器" scheme="http://blog.mangolovecarrot.net/tags/%E4%BC%A0%E6%84%9F%E5%99%A8/"/>
    
      <category term="数码管" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E7%A0%81%E7%AE%A1/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门05-驱动数码管显示数字]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/05/05/raspi-study05/"/>
    <id>http://blog.mangolovecarrot.net/2015/05/05/raspi-study05/</id>
    <published>2015-05-05T14:30:04.000Z</published>
    <updated>2015-05-23T09:32:44.000Z</updated>
    <content type="html"><![CDATA[<p>这次我们用树莓派的GPIO口驱动数码管来显示数字，进而制作一个简单的电子钟，通过按钮来切换显示时间或日期。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="xg.jpg" alt="树莓派GPIO入门05-驱动数码管显示数字"></p>
<h3 id="硬件">硬件</h3><ul>
<li>数码管一只。因为需要显示日期时间所以需要能显示4个数字的数码管，也称4位数码管。淘宝买1块多钱一只。注意数码管有共阳和共阴的。我这里使用的是共阳的。至于区别，下面的原理说明里会详细解释。</li>
<li>杜邦线若干。</li>
<li>面包板一块。</li>
<li>按钮1只。</li>
</ul>
<h3 id="原理说明">原理说明</h3><ul>
<li>标准的数码管从显示内容上分7段和8段数码管两种。8段比7段多一个右下角的小数点。还有一些其他特殊的如可以显示米字形的数码管不在本文讨论范围内，其实原理都是一样的。</li>
<li>8段数码管由8个发光二极管组成，其中7个用于组成数字，1个用于显示小数点。每一根的编号如下图的右上角所示(A-G,DP)。<br><img src="3461.jpg" alt="4位共阳8段数码管原理图"></li>
<li><p>数码管从电源极性上分共阳和共阴两种。解释一下，如果数码管上每一个独立的发光二极管都单独引出两根引脚，一根接正极(阳)一根接负极(阴)，那么一个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口均输出高电平即可。写成代码就是：</p>
<figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 定义各段发光二极管对应的GPIO口</span></span><br><span class="line">LED_A = <span class="number">26</span></span><br><span class="line">LED_B = <span class="number">19</span></span><br><span class="line">LED_C = <span class="number">13</span></span><br><span class="line">LED_D = <span class="number">6</span></span><br><span class="line">LED_E = <span class="number">5</span></span><br><span class="line">LED_F = <span class="number">11</span></span><br><span class="line">LED_G = <span class="number">9</span></span><br><span class="line">LED_DP = <span class="number">10</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 定义数码管共阳极对应的GPIO口</span></span><br><span class="line">VCC = <span class="number">12</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 避免闪烁，在输出数字字形信号前先拉低共阳端，关闭显示</span></span><br><span class="line">RPi.GPIO.output(VCC, <span class="keyword">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出数字1的字形信号</span></span><br><span class="line">RPi.GPIO.output(LED_A, <span class="keyword">True</span>)</span><br><span class="line">RPi.GPIO.output(LED_B, <span class="keyword">False</span>)</span><br><span class="line">RPi.GPIO.output(LED_C, <span class="keyword">False</span>)</span><br><span class="line">RPi.GPIO.output(LED_D, <span class="keyword">True</span>)</span><br><span class="line">RPi.GPIO.output(LED_E, <span class="keyword">True</span>)</span><br><span class="line">RPi.GPIO.output(LED_F, <span class="keyword">True</span>)</span><br><span class="line">RPi.GPIO.output(LED_G, <span class="keyword">True</span>)</span><br><span class="line">RPi.GPIO.output(LED_DP, <span class="keyword">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 最后拉高共阳段，显示数字</span></span><br><span class="line">RPi.GPIO.output(VCC, <span class="keyword">True</span>)</span><br></pre></td></tr></table></figure>
</li>
<li><p>本文使用的数码管是8段共阳4位(4个数字)数码管，型号是F3461BH。上面说了共阳数码管每个数字需要9个引脚来控制，那么4个数字就需要36个引脚吗？显然不现实，树莓派的io口也完全不够用。这就引出另一个概念，静态显示和动态扫描显示。</p>
</li>
<li><p>静态显示，就是前面说的每一个数字需要占用8个io口，每多一个数字就需要额外的8个io口，如果数字位数不多，io口够用的话，这样做完全没问题。实际应用中往往需要显示多个数字，io口基本上是不够用的。这就需要动态扫描显示了。下面摘一段百度百科关于动态扫描显示的说明(稍有改动):</p>
<blockquote>
<p>数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一，动态驱动是将所有数码管的8个显示笔划”a,b,c,d,e,f,g,dp”的同名端连在一起引出8个引脚，每个数字再单独引出共阳(阴)端，这样总引脚数就只要8 + 数字个数即可，本文使用的8段4位数码管正是引出了12个引脚。至于哪个引脚对应哪一段，哪几个引脚分别对应各数字的共阳(阴)端，就需要商家提供电路图了。当然也可以自己慢慢试，这不在本文讨论范围，大家可以自己摸索。当树莓派输出8个段信号时，所有数码管都会接收到相同的信号，但究竟是哪个数码管会显示出字形，取决于这个数码管对应的共阳(阴)极(后统称位选端)有无导通。所以我们只要将需要显示的数码管的位选端选通，该位就显示出字形，没有选通的数码管就不会亮。通过分时轮流控制各个数码管的的位选端，就使各个数码管轮流受控显示，这就是动态驱动。在轮流显示过程中，每位数码管的点亮时间为1～2ms，由于人的视觉暂留现象及发光二极管的余辉效应，尽管实际上各位数码管并非同时点亮，但只要扫描的速度足够快，给人的印象就是一组稳定的显示数据，不会有闪烁感，动态显示的效果和静态显示是一样的，能够节省大量的I/O端口，而且功耗更低。</p>
</blockquote>
</li>
<li><p>综上，比如我们想要在4位共阳数码管上显示1234这4个数字，要做的就是：</p>
<ol>
<li>避免闪烁，在输出数字字形信号前先拉低所有4个共阳极，关闭所有显示。</li>
<li>拉低1号数码管的共阳极，关闭显示。</li>
<li>输出1号数码管上希望显示的数字字形信号。</li>
<li>只拉高1号数码管的共阳极，让1号数码管显示上面设置好的数字字形。</li>
<li>延时一段时间（1ms左右）</li>
<li>拉低1号数码管的共阳极，关闭显示。</li>
<li>输出2号数码管上希望显示的数字字形信号。</li>
<li>只拉高2号数码管的共阳极，让2号数码管显示上面设置好的数字字形。</li>
<li>延时一段时间（1ms左右）</li>
<li>拉低2号数码管的共阳极，关闭显示。</li>
<li>输出3号数码管上希望显示的数字字形信号。</li>
<li>只拉高3号数码管的共阳极，让3号数码管显示上面设置好的数字字形。</li>
<li>延时一段时间（1ms左右）</li>
<li>拉低3号数码管的共阳极，关闭显示。</li>
<li>输出4号数码管上希望显示的数字字形信号。</li>
<li>只拉高4号数码管的共阳极，让4号数码管显示上面设置好的数字字形。</li>
<li>延时一段时间（1ms左右）</li>
<li>返回step2，循环执行。</li>
</ol>
</li>
<li>取得日期和时间的方法不是本文的重点，大家自己看代码。</li>
</ul>
<h3 id="硬件连接">硬件连接</h3><p><img src="connect.png" alt="硬件连接图"></p>
<h3 id="代码">代码</h3><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env python</span><br><span class="line"># encoding: utf-8</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"># 定义单个数码管各段led对应的GPIO口</span><br><span class="line">LED_A = 26</span><br><span class="line">LED_B = 19</span><br><span class="line">LED_C = 13</span><br><span class="line">LED_D = 6</span><br><span class="line">LED_E = 5</span><br><span class="line">LED_F = 11</span><br><span class="line">LED_G = 9</span><br><span class="line">LED_DP = 10</span><br><span class="line"></span><br><span class="line"># 定义1到4号数码管阳极对应的GPIO口</span><br><span class="line">DIGIT1 = 12</span><br><span class="line">DIGIT2 = 16</span><br><span class="line">DIGIT3 = 20</span><br><span class="line">DIGIT4 = 21</span><br><span class="line"></span><br><span class="line"># 定义按钮输入的GPIO口</span><br><span class="line">btn = 27</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(LED_A, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_B, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_C, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_D, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_E, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_F, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_G, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(LED_DP, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(DIGIT1, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(DIGIT2, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(DIGIT3, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(DIGIT4, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.output(DIGIT1, True)</span><br><span class="line">RPi.GPIO.output(DIGIT2, True)</span><br><span class="line">RPi.GPIO.output(DIGIT3, True)</span><br><span class="line">RPi.GPIO.output(DIGIT4, True)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(btn, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP)</span><br><span class="line"></span><br><span class="line"># 指定no(1-4)号数码管显示数字num(0-9)，第三个参数是显示不显示小数点（<span class="keyword">true</span>/<span class="keyword">false</span>）</span><br><span class="line">def showDigit(no, num, showDotPoint):</span><br><span class="line">    # 先将正极拉低，关掉显示</span><br><span class="line">	RPi.GPIO.output(DIGIT1, False)</span><br><span class="line">	RPi.GPIO.output(DIGIT2, False)</span><br><span class="line">	RPi.GPIO.output(DIGIT3, False)</span><br><span class="line">	RPi.GPIO.output(DIGIT4, False)</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (num == 0) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, False)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, True)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 1) :</span><br><span class="line">		RPi.GPIO.output(LED_A, True)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, True)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, True)</span><br><span class="line">		RPi.GPIO.output(LED_G, True)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 2) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, True)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, False)</span><br><span class="line">		RPi.GPIO.output(LED_F, True)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 3) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, True)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 4) :</span><br><span class="line">		RPi.GPIO.output(LED_A, True)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, True)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 5) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, True)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 6) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, True)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, False)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 7) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, True)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, True)</span><br><span class="line">		RPi.GPIO.output(LED_G, True)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 8) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, False)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	elif (num == 9) :</span><br><span class="line">		RPi.GPIO.output(LED_A, False)</span><br><span class="line">		RPi.GPIO.output(LED_B, False)</span><br><span class="line">		RPi.GPIO.output(LED_C, False)</span><br><span class="line">		RPi.GPIO.output(LED_D, False)</span><br><span class="line">		RPi.GPIO.output(LED_E, True)</span><br><span class="line">		RPi.GPIO.output(LED_F, False)</span><br><span class="line">		RPi.GPIO.output(LED_G, False)</span><br><span class="line">		RPi.GPIO.output(LED_DP, not showDotPoint)</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (no == 1) :</span><br><span class="line">		RPi.GPIO.output(DIGIT1, True)</span><br><span class="line">	elif (no == 2) :</span><br><span class="line">		RPi.GPIO.output(DIGIT2, True)</span><br><span class="line">	elif (no == 3) :</span><br><span class="line">		RPi.GPIO.output(DIGIT3, True)</span><br><span class="line">	elif (no == 4) :</span><br><span class="line">		RPi.GPIO.output(DIGIT4, True)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	t=0.005</span><br><span class="line">	<span class="keyword">while</span> True:</span><br><span class="line">		# 按钮按下时显示日期，否则显示时间</span><br><span class="line">		# 为了区别左右的数字，让第二个数码管的小数点显示出来</span><br><span class="line">		#（本来应该是一个冒号，我们这个数码管没有，就用小数点代替了）</span><br><span class="line">		<span class="keyword">if</span> (RPi.GPIO.input(btn) == 1):</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(1, <span class="keyword">int</span>(time.strftime(<span class="string">"%H"</span>,time.localtime(time.time()))) / 10, False)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(2, <span class="keyword">int</span>(time.strftime(<span class="string">"%H"</span>,time.localtime(time.time()))) % 10, True)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(3, <span class="keyword">int</span>(time.strftime(<span class="string">"%M"</span>,time.localtime(time.time()))) / 10, False)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(4, <span class="keyword">int</span>(time.strftime(<span class="string">"%M"</span>,time.localtime(time.time()))) % 10, False)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(1, <span class="keyword">int</span>(time.strftime(<span class="string">"%m"</span>,time.localtime(time.time()))) / 10, False)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(2, <span class="keyword">int</span>(time.strftime(<span class="string">"%m"</span>,time.localtime(time.time()))) % 10, True)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(3, <span class="keyword">int</span>(time.strftime(<span class="string">"%d"</span>,time.localtime(time.time()))) / 10, False)</span><br><span class="line">			time.sleep(t)</span><br><span class="line">			showDigit(4, <span class="keyword">int</span>(time.strftime(<span class="string">"%d"</span>,time.localtime(time.time()))) % 10, False)</span><br><span class="line">			</span><br><span class="line">except KeyboardInterrupt:</span><br><span class="line">	pass</span><br><span class="line"></span><br><span class="line"># 最后清理GPIO口（不做也可以，建议每次程序结束时清理一下，好习惯）</span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="性能改善">性能改善</h3><p>当你照着这篇文章成功在数码管上显示出数字后，你可能会郁闷的发现数字有一点点闪烁，显示的不是非常稳定，这种情况在树莓派1代上更明显。</p>
<ul>
<li>python库对gpio口不停操作时对cpu的占用率很高，而一旦cpu的占用率一高，就不能保证延时函数的准确性，而在动态扫描时延时的不准确会导致数码管的亮度不稳定，比如第一只数码管显示了2ms而第二只显示了1ms的话，第一只数码管的亮度就会略高于第二只数码管，而参差不齐的延时最后就表现为数字显示有闪烁的感觉。</li>
<li>python库本身翻转gpio口的效率就不高，有兴趣可以参照<a href="http://codeandlife.com/2012/07/03/benchmarking-raspberry-pi-gpio-speed/" target="_blank" rel="external">这个页面</a>，有各种语言各种库对gpio的操作速度比较。比较结果是c的wiringPi库完胜其他方式。其实python库已经是表现不错的了，但还是被c甩了N条街。python翻转io口的频率在70kHz左右，而wiringPi则可以达到4MHz！这个已经是数量级上的差距了。</li>
<li><p>抱着试一试的心情，我用c语言的wiringPi库把上面这个程序重写了一遍，代码是这个样子的：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#<span class="keyword">include</span> &lt;wiringPi.h&gt;</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> &lt;unistd.h&gt;</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">include</span> &lt;time.h&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义单个数码管各段led对应的GPIO口</span></span><br><span class="line"><span class="comment">// 使用命令 "gpio readall" 来获取当前pi版本对应的各引脚的wiringPi和BCM的编号</span></span><br><span class="line"><span class="comment">// 再本程序中应该使用wiringPi编号</span></span><br><span class="line"><span class="comment">// 我的pi2 Mode B执行结果如下：（wPi列就是wiringPi编号）</span></span><br><span class="line"><span class="comment">// 之前Python版本的代码使用的是BCM编号，所以在不改变硬件接线的情况下，我们需要把原来BCM编号改成对应的wiringPi编号。</span></span><br><span class="line"><span class="comment">/* </span><br><span class="line"> +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+</span><br><span class="line"> | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |</span><br><span class="line"> +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+</span><br><span class="line"> |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |</span><br><span class="line"> |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5V      |     |     |</span><br><span class="line"> |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |</span><br><span class="line"> |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |</span><br><span class="line"> |     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |</span><br><span class="line"> |  17 |   0 | GPIO. 0 |  OUT | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |</span><br><span class="line"> |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |</span><br><span class="line"> |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |</span><br><span class="line"> |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |</span><br><span class="line"> |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |</span><br><span class="line"> |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |</span><br><span class="line"> |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |</span><br><span class="line"> |     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |</span><br><span class="line"> |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |</span><br><span class="line"> |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |</span><br><span class="line"> |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |</span><br><span class="line"> |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |</span><br><span class="line"> |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |</span><br><span class="line"> |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |</span><br><span class="line"> |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |</span><br><span class="line"> +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+</span><br><span class="line"> | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |</span><br><span class="line"> +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+</span><br><span class="line">*/</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_A 25 <span class="comment">//BCM：26</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_B 24 <span class="comment">//BCM：19</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_C 23 <span class="comment">//BCM：13</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_D 22 <span class="comment">//BCM：6</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_E 21 <span class="comment">//BCM：5</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_F 14 <span class="comment">//BCM：11</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_G 13 <span class="comment">//BCM：9</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> LED_DP 12 <span class="comment">//BCM：10</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义1到4号数码管阳极对应的GPIO口</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> DIGIT1 26 <span class="comment">//BCM：12</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> DIGIT2 27 <span class="comment">//BCM：16</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> DIGIT3 28 <span class="comment">//BCM：20</span></span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> DIGIT4 29 <span class="comment">//BCM：21</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义按钮输入的GPIO口</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> btn 2 <span class="comment">//BCM：27</span></span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> FALSE 0</span></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> TRUE  1</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor">#<span class="keyword">define</span> t 5000 <span class="comment">//usleep延时长度（单位um微秒，1000um＝1ms，1000ms＝1s）</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 指定no(1-4)号数码管显示数字num(0-9)，第三个参数是显示不显示小数点（1/0）</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">showDigit</span><span class="params">(<span class="keyword">int</span> no, <span class="keyword">int</span> num, <span class="keyword">int</span> showDotPoint)</span></span>;</span><br><span class="line"></span><br><span class="line">time_t now;</span><br><span class="line"><span class="keyword">struct</span> tm *tm_now;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">(<span class="keyword">void</span>)</span> </span>&#123;</span><br><span class="line">  wiringPiSetup () ;</span><br><span class="line"></span><br><span class="line">  pinMode (LED_A, OUTPUT) ;</span><br><span class="line">  pinMode (LED_B, OUTPUT) ;</span><br><span class="line">  pinMode (LED_C, OUTPUT) ;</span><br><span class="line">  pinMode (LED_D, OUTPUT) ;</span><br><span class="line">  pinMode (LED_E, OUTPUT) ;</span><br><span class="line">  pinMode (LED_F, OUTPUT) ;</span><br><span class="line">  pinMode (LED_G, OUTPUT) ;</span><br><span class="line">  pinMode (LED_DP, OUTPUT) ;</span><br><span class="line"></span><br><span class="line">  pinMode (DIGIT1, OUTPUT) ;</span><br><span class="line">  pinMode (DIGIT2, OUTPUT) ;</span><br><span class="line">  pinMode (DIGIT3, OUTPUT) ;</span><br><span class="line">  pinMode (DIGIT4, OUTPUT) ;</span><br><span class="line"></span><br><span class="line">  pinMode (btn, INPUT) ;</span><br><span class="line">  pullUpDnControl (btn, PUD_UP) ;</span><br><span class="line"></span><br><span class="line">  digitalWrite (DIGIT1, HIGH) ;</span><br><span class="line">  digitalWrite (DIGIT2, HIGH) ;</span><br><span class="line">  digitalWrite (DIGIT3, HIGH) ;</span><br><span class="line">  digitalWrite (DIGIT4, HIGH) ;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (; ; )</span><br><span class="line">  &#123;</span><br><span class="line">    time(&amp;now);</span><br><span class="line">    tm_now=localtime(&amp;now);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 按钮按下时显示日期，否则显示时间</span></span><br><span class="line">    <span class="comment">// 为了区别左右的数字，让第二个数码管的小数点显示出来</span></span><br><span class="line">    <span class="comment">//（本来应该是一个冒号，我们这个数码管没有，就用小数点代替了）</span></span><br><span class="line">    <span class="keyword">if</span> (digitalRead(btn) == HIGH) &#123;</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">1</span>, tm_now-&gt;tm_hour / <span class="number">10</span>, FALSE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">2</span>, tm_now-&gt;tm_hour % <span class="number">10</span>, TRUE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">3</span>, tm_now-&gt;tm_min / <span class="number">10</span>, FALSE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">4</span>, tm_now-&gt;tm_min % <span class="number">10</span>, FALSE);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// 取得的月份和日期都是从0开始的，所以显示前需要加1</span></span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">1</span>, (tm_now-&gt;tm_mon+<span class="number">1</span>) / <span class="number">10</span>, FALSE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">2</span>, (tm_now-&gt;tm_mon+<span class="number">1</span>) % <span class="number">10</span>, TRUE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">3</span>, (tm_now-&gt;tm_mday+<span class="number">1</span>) / <span class="number">10</span>, FALSE);</span><br><span class="line">      usleep(t);</span><br><span class="line">      showDigit(<span class="number">4</span>, (tm_now-&gt;tm_mday+<span class="number">1</span>) % <span class="number">10</span>, FALSE);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span> ;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">showDigit</span><span class="params">(<span class="keyword">int</span> no, <span class="keyword">int</span> num, <span class="keyword">int</span> showDotPoint)</span> </span>&#123;</span><br><span class="line">  <span class="comment">// 先将正极拉低，关掉显示</span></span><br><span class="line">  digitalWrite (DIGIT1, LOW) ;</span><br><span class="line">  digitalWrite (DIGIT2, LOW) ;</span><br><span class="line">  digitalWrite (DIGIT3, LOW) ;</span><br><span class="line">  digitalWrite (DIGIT4, LOW) ;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (num == <span class="number">0</span>) &#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, LOW) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 1)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, HIGH) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, HIGH) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, HIGH) ;</span><br><span class="line">    digitalWrite (LED_G, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 2)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, HIGH) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, LOW) ;</span><br><span class="line">    digitalWrite (LED_F, HIGH) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 3)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, HIGH) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 4)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, HIGH) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, HIGH) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 5)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, HIGH) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 6)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, HIGH) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, LOW) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 7)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, HIGH) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, HIGH) ;</span><br><span class="line">    digitalWrite (LED_G, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 8)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, LOW) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(num == 9)</span> </span>&#123;</span><br><span class="line">    digitalWrite (LED_A, LOW) ;</span><br><span class="line">    digitalWrite (LED_B, LOW) ;</span><br><span class="line">    digitalWrite (LED_C, LOW) ;</span><br><span class="line">    digitalWrite (LED_D, LOW) ;</span><br><span class="line">    digitalWrite (LED_E, HIGH) ;</span><br><span class="line">    digitalWrite (LED_F, LOW) ;</span><br><span class="line">    digitalWrite (LED_G, LOW) ;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">if</span> (showDotPoint == <span class="number">1</span>) &#123;</span><br><span class="line">    digitalWrite (LED_DP, LOW) ;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    digitalWrite (LED_DP, HIGH) ;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (no == <span class="number">1</span>) &#123;</span><br><span class="line">    digitalWrite (DIGIT1, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(no == 2)</span> </span>&#123;</span><br><span class="line">    digitalWrite (DIGIT2, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(no == 3)</span> </span>&#123;</span><br><span class="line">    digitalWrite (DIGIT3, HIGH) ;</span><br><span class="line">  &#125; <span class="function"><span class="keyword">else</span> <span class="title">if</span> <span class="params">(no == 4)</span> </span>&#123;</span><br><span class="line">    digitalWrite (DIGIT4, HIGH) ;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>c的wiringPi库的安装和代码的编译执行方法请自行百度。</p>
</li>
<li><p>c语言测试结果是显示稳定了很多，但仍然有一点不稳定不仔细观察基本看不出来了。这个应该跟我代码的效率有关，逻辑应该还可以精简节省cpu资源。这个以后再试了。我们这个系列主要是让大家了解各种基本外设传感器的原理和使用方法。用c语言也只是做一点延伸，以后的教程还是以python为主。</p>
</li>
</ul>
<h3 id="源代码下载">源代码下载</h3><p><a href="prog.py" title="Python源代码下载">点击下载Python源码</a><br><a href="prog.c" title="c源代码下载">点击下载c源码</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>这次我们用树莓派的GPIO口驱动数码管来显示数字，进而制作一个简单的电子钟，通过按钮来切换显示时间或日期。<br>]]>
    
    </summary>
    
      <category term="数码管" scheme="http://blog.mangolovecarrot.net/tags/%E6%95%B0%E7%A0%81%E7%AE%A1/"/>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门04-使用按钮]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/05/03/raspi-study04/"/>
    <id>http://blog.mangolovecarrot.net/2015/05/03/raspi-study04/</id>
    <published>2015-05-03T12:38:36.000Z</published>
    <updated>2015-05-03T13:18:42.000Z</updated>
    <content type="html"><![CDATA[<p><a href="../../../../2015/04/29/raspi-study03/" title="树莓派GPIO入门03-GPIO控制RGB彩色LED灯">上一篇</a>我们通过程序控制彩色LED发出不同颜色的光。这次我们用3个按钮来手动控制彩色LED灯分别发出红，绿，蓝光并可以同时按下不同按钮以显示混合颜色的光。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="ani.gif" alt="树莓派GPIO入门04-使用按钮"></p>
<h3 id="硬件">硬件</h3><ul>
<li>跟上一节一样，彩色RGB二极管一只。</li>
<li>杜邦线若干。</li>
<li>面包板一块。</li>
<li>按钮3只。这种按钮是最常见的小按钮，有四只引脚。分别两两相通。按下按钮以后原来不通的引脚之间会被联通。把按钮翻过来看腹部可以看到联通的引脚之间有凹槽相连，很容易辨认。</li>
</ul>
<p><img src="01.jpg" alt="硬件图"></p>
<h3 id="原理说明">原理说明</h3><p>从树莓派上引GND（负极）到面包板上，3个按钮默认不联通的两只引脚的一只接到GND上。另一只接到树莓派GPIO口上。这3个GPIO口在程序里设置为输入模式，并且默认拉到高电平。当某个按钮被按下，即联通GND端到GPIO口上，此时从GPIO口取到的状态为低电平。程序侦测到低电平时就认为按钮被按下，从而可以做你想做的事情（点亮红/绿/蓝灯）。</p>
<h3 id="硬件连接">硬件连接</h3><p><img src="connect.png" alt="硬件连接图"></p>
<h3 id="代码">代码</h3><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env python</span><br><span class="line"># encoding: utf-8</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">R,G,B=15,18,14</span><br><span class="line"></span><br><span class="line"># 按钮输出针脚连接的GPIO口</span><br><span class="line">btnR, btnG, btnB=21,20,16</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(R, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(G, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(B, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line"># 按钮连接的GPIO针脚的模式设置为信号输入模式，同时默认拉高GPIO口电平，</span><br><span class="line"># 当GND没有被接通时，GPIO口处于高电平状态，取的的值为1</span><br><span class="line"># 注意到这是一个可选项，如果不在程序里面设置，通常的做法是通过一个上拉电阻连接到VCC上使之默认保持高电平</span><br><span class="line">RPi.GPIO.setup(btnR, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP)</span><br><span class="line">RPi.GPIO.setup(btnG, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP)</span><br><span class="line">RPi.GPIO.setup(btnB, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_UP)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line"></span><br><span class="line">	RPi.GPIO.output(R, True)</span><br><span class="line">	RPi.GPIO.output(G, True)</span><br><span class="line">	RPi.GPIO.output(B, True)</span><br><span class="line">	<span class="keyword">while</span> True:</span><br><span class="line">		time.sleep(0.01)</span><br><span class="line">		</span><br><span class="line">		# 检测按钮1是否被按下，如果被按下(低电平)，则亮红灯(输出低电平)，否则关红灯</span><br><span class="line">		<span class="keyword">if</span> (RPi.GPIO.input(btnR) == 0):</span><br><span class="line">			RPi.GPIO.output(R, False)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			RPi.GPIO.output(R, True)</span><br><span class="line">		</span><br><span class="line">		# 检测按钮2是否被按下，如果被按下(低电平)，则亮绿灯(输出低电平)，否则关绿灯</span><br><span class="line">		<span class="keyword">if</span> (RPi.GPIO.input(btnG) == 0):</span><br><span class="line">			RPi.GPIO.output(G, False)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			RPi.GPIO.output(G, True)</span><br><span class="line">		</span><br><span class="line">		# 检测按钮3是否被按下，如果被按下(低电平)，则亮蓝灯(输出低电平)，否则关蓝灯</span><br><span class="line">		<span class="keyword">if</span> (RPi.GPIO.input(btnB) == 0):</span><br><span class="line">			RPi.GPIO.output(B, False)</span><br><span class="line">		<span class="keyword">else</span>:</span><br><span class="line">			RPi.GPIO.output(B, True)</span><br><span class="line"></span><br><span class="line">except KeyboardInterrupt:</span><br><span class="line">	pass</span><br><span class="line"></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="源代码下载">源代码下载</h3><p><a href="prog.py" title="源代码下载">点击下载</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="../../../../2015/04/29/raspi-study03/" title="树莓派GPIO入门03-GPIO控制RGB彩色LED灯">上一篇</a>我们通过程序控制彩色LED发出不同颜色的光。这次我们用3个按钮来手动控制彩色LED灯分别发出红，绿，蓝光并可以同时按下不同按钮以显示混合颜色的光。<br>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门03-GPIO控制RGB彩色LED灯]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/04/29/raspi-study03/"/>
    <id>http://blog.mangolovecarrot.net/2015/04/29/raspi-study03/</id>
    <published>2015-04-29T13:33:38.000Z</published>
    <updated>2015-05-03T12:49:03.000Z</updated>
    <content type="html"><![CDATA[<p><a href="../../../../2015/04/28/raspi-study02/" title="树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果">上一篇</a>我们学会如何通过PWM来控制LED的亮度，这次我们还是利用PWM来控制一个RGB彩色LED灯来显示各种我们想要的颜色。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="ani.gif" alt="树莓派GPIO入门03-GPIO控制RGB彩色LED灯"></p>
<h3 id="硬件">硬件</h3><ul>
<li>彩色RGB二极管。我用的是淘宝买的带4根引脚的S801。你也可以用别的原理都是一样的。</li>
<li>杜邦线4条。3根连接红色绿色蓝色，还有一根连接树莓派5V电源引脚。</li>
</ul>
<p><img src="01.jpg" alt="硬件图"></p>
<h3 id="原理说明">原理说明</h3><p>这个RGB彩色LED里其实有3个灯，分别是红灯绿灯和蓝灯。控制这三个灯分别发出不同强度的光，混合起来就能发出各种颜色的光了。 LED灯上的4根引脚分别是VCC，R，G，B。 VCC需要接到电源正极。我们把它连到树莓派的5V引脚上。 R,G,B分别是红绿蓝灯的负极接口。我们把它们连接到树莓派的GPIO口上。 然后跟前一篇一样，使用PWM来控制3个小灯的明暗程度即可混合出各种不同颜色的光。</p>
<h3 id="硬件连接">硬件连接</h3><p><img src="connect.png" alt="硬件连接图"><br><img src="connect1.png" alt="引脚原理图"></p>
<h3 id="代码">代码</h3><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env python</span><br><span class="line"># encoding: utf-8</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> RPi.GPIO</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">R,G,B=15,18,14</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setup(R, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(G, RPi.GPIO.OUT)</span><br><span class="line">RPi.GPIO.setup(B, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line">pwmR = RPi.GPIO.PWM(R, 70)</span><br><span class="line">pwmG = RPi.GPIO.PWM(G, 70)</span><br><span class="line">pwmB = RPi.GPIO.PWM(B, 70)</span><br><span class="line"></span><br><span class="line">pwmR.start(0)</span><br><span class="line">pwmG.start(0)</span><br><span class="line">pwmB.start(0)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line"></span><br><span class="line">	t = 0.4</span><br><span class="line">	<span class="keyword">while</span> True:</span><br><span class="line">		# 红色灯全亮，蓝灯，绿灯全暗（红色）</span><br><span class="line">		pwmR.ChangeDutyCycle(0)</span><br><span class="line">		pwmG.ChangeDutyCycle(100)</span><br><span class="line">		pwmB.ChangeDutyCycle(100)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 绿色灯全亮，红灯，蓝灯全暗（绿色）</span><br><span class="line">		pwmR.ChangeDutyCycle(100)</span><br><span class="line">		pwmG.ChangeDutyCycle(0)</span><br><span class="line">		pwmB.ChangeDutyCycle(100)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 蓝色灯全亮，红灯，绿灯全暗（蓝色）</span><br><span class="line">		pwmR.ChangeDutyCycle(100)</span><br><span class="line">		pwmG.ChangeDutyCycle(100)</span><br><span class="line">		pwmB.ChangeDutyCycle(0)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 红灯，绿灯全亮，蓝灯全暗（黄色）</span><br><span class="line">		pwmR.ChangeDutyCycle(0)</span><br><span class="line">		pwmG.ChangeDutyCycle(0)</span><br><span class="line">		pwmB.ChangeDutyCycle(100)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 红灯，蓝灯全亮，绿灯全暗（洋红色）</span><br><span class="line">		pwmR.ChangeDutyCycle(0)</span><br><span class="line">		pwmG.ChangeDutyCycle(100)</span><br><span class="line">		pwmB.ChangeDutyCycle(0)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 绿灯，蓝灯全亮，红灯全暗（青色）</span><br><span class="line">		pwmR.ChangeDutyCycle(100)</span><br><span class="line">		pwmG.ChangeDutyCycle(0)</span><br><span class="line">		pwmB.ChangeDutyCycle(0)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 红灯，绿灯，蓝灯全亮（白色）</span><br><span class="line">		pwmR.ChangeDutyCycle(0)</span><br><span class="line">		pwmG.ChangeDutyCycle(0)</span><br><span class="line">		pwmB.ChangeDutyCycle(0)</span><br><span class="line">		time.sleep(t)</span><br><span class="line">		</span><br><span class="line">		# 调整红绿蓝LED的各个颜色的亮度组合出各种颜色</span><br><span class="line">		<span class="keyword">for</span> r in xrange (0, 101, 20):</span><br><span class="line">			pwmR.ChangeDutyCycle(r)</span><br><span class="line">			<span class="keyword">for</span> g in xrange (0, 101, 20):</span><br><span class="line">				pwmG.ChangeDutyCycle(g)</span><br><span class="line">				<span class="keyword">for</span> b in xrange (0, 101, 20):</span><br><span class="line">					pwmB.ChangeDutyCycle(b)</span><br><span class="line">					time.sleep(0.01)</span><br><span class="line"></span><br><span class="line">except KeyboardInterrupt:</span><br><span class="line">	pass</span><br><span class="line"></span><br><span class="line">pwmR.stop()</span><br><span class="line">pwmG.stop()</span><br><span class="line">pwmB.stop()</span><br><span class="line"></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure>
<h3 id="源代码下载">源代码下载</h3><p><a href="prog.py" title="源代码下载">点击下载</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="../../../../2015/04/28/raspi-study02/" title="树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果">上一篇</a>我们学会如何通过PWM来控制LED的亮度，这次我们还是利用PWM来控制一个RGB彩色LED灯来显示各种我们想要的颜色。<br>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门02-GPIO控制LED亮度，制作呼吸灯效果]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/04/28/raspi-study02/"/>
    <id>http://blog.mangolovecarrot.net/2015/04/28/raspi-study02/</id>
    <published>2015-04-28T12:12:01.000Z</published>
    <updated>2015-04-29T13:37:47.000Z</updated>
    <content type="html"><![CDATA[<p><a href="../../../../2015/04/20/raspi-study01/" title="树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁">上一篇</a>我们通过控制GPIO口输出高低电平来控制一只发光二极管的亮灭。这次我们来控制发光二极管的亮度。最后做出呼吸灯的效果。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="ani.gif" alt="GPIO口控制亮度制作呼吸灯"></p>
<h3 id="硬件">硬件</h3><ul>
<li>树莓派一台。</li>
<li>LED发光管</li>
<li>杜邦线两条<br><img src="01.jpg" alt="硬件图"></li>
</ul>
<h3 id="原理说明">原理说明</h3><p>我们知道，通过LED的电流越大，LED越亮，电流越小，LED越暗。如果可以控制输出电流大小就可以控制LED的明暗了。<br>但是树莓派的各引脚并没有直接调整输出电流大小的功能。要想别的办法。<br>我们先学习一个名词：脉宽调制（PWM）<br>简单的说，PWM技术就是不停的通断电路并控制通断持续的时间片段长度来控制用电器在单位时间内实际得到的电能。<br>这么说好像还是复杂了，再简单点说，如果你的手足够快，打开电灯开关后马上关闭，如果这个时间间隔足够短，灯丝还没有全部亮起来就暗下去了。你再次打开电灯再关闭，再打开再关闭。。。如果你一直保持相同的频率，那么电灯应该会保持一个固定的亮度不变。理论上，你可以通过调整开灯持续的时间长度和关灯持续的时间长度的比例就能得到不同亮度了。这个比例被称为“占空比”。<br>PWM就是差不多这个意思。<br>树莓派1代B型的26个针脚里，有一个特殊的GPIO口是支持硬件PWM的，不过从B+开始不知道什么原因这个很实用的接口被去掉了。<br>但是没关系，根据我上面的描述，我们完全可以自己写一个程序来模拟PWM。<br>不想自己写，没关系，我们强大的GPIO库已经帮我们写好了，直接用就可以了。</p>
<h3 id="硬件连接">硬件连接</h3><p>跟前一篇一模一样的连接方式。<br><img src="connect.jpg" alt="原理图"></p>
<h3 id="代码">代码</h3><p>直接看代码和注释吧，一看就能明白。<br><figure class="highlight vala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#!/usr/bin/env python</span></span><br><span class="line"><span class="preprocessor"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line">import RPi.GPIO</span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)</span><br><span class="line">RPi.GPIO.setup(<span class="number">14</span>, RPi.GPIO.OUT)</span><br><span class="line"></span><br><span class="line"><span class="preprocessor"># 创建一个 PWM 实例，需要两个参数，第一个是GPIO端口号，这里我们用14号</span></span><br><span class="line"><span class="preprocessor"># 第二个是频率（Hz），频率越高LED看上去越不会闪烁，相应对CPU要求就越高，设置合适的值就可以</span></span><br><span class="line">pwm = RPi.GPIO.PWM(<span class="number">14</span>, <span class="number">80</span>)</span><br><span class="line"></span><br><span class="line"><span class="preprocessor"># 启用 PWM，参数是占空比，范围：0.0 &lt;= 占空比 &gt;= 100.0</span></span><br><span class="line">pwm.start(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">	<span class="keyword">while</span> True:</span><br><span class="line">		# 电流从小到大，LED由暗到亮</span><br><span class="line">		<span class="keyword">for</span> i in xrange(<span class="number">0</span>, <span class="number">101</span>, <span class="number">1</span>):</span><br><span class="line">			# 更改占空比，</span><br><span class="line">			pwm.ChangeDutyCycle(i)</span><br><span class="line">			time.sleep(<span class="number">.02</span>)</span><br><span class="line">			</span><br><span class="line">		# 再让电流从大到小，LED由亮变暗</span><br><span class="line">		<span class="keyword">for</span> i in xrange(<span class="number">100</span>, -<span class="number">1</span>, -<span class="number">1</span>):</span><br><span class="line">			pwm.ChangeDutyCycle(i)</span><br><span class="line">			time.sleep(<span class="number">.02</span>)</span><br><span class="line"></span><br><span class="line"><span class="preprocessor"># 最后一段是一个小技巧。这个程序如果不强制停止会不停地执行下去。</span></span><br><span class="line"><span class="preprocessor"># 而Ctrl+C强制终端程序的话，GPIO口又没有机会清理。</span></span><br><span class="line"><span class="preprocessor"># 加上一个try except 可以捕捉到Ctrl+C强制中断的动作，</span></span><br><span class="line"><span class="preprocessor"># 试图强制中断时，程序不会马上停止而是会先跳到这里来做一些你想做完的事情，比如清理GPIO口。</span></span><br><span class="line">except KeyboardInterrupt:</span><br><span class="line">	pass</span><br><span class="line"></span><br><span class="line"><span class="preprocessor"># 停用 PWM</span></span><br><span class="line">pwm.stop()</span><br><span class="line"></span><br><span class="line"><span class="preprocessor"># 清理GPIO口</span></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure></p>
<h3 id="源代码下载">源代码下载</h3><p><a href="prog.py" title="源代码下载">点击下载</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="../../../../2015/04/20/raspi-study01/" title="树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁">上一篇</a>我们通过控制GPIO口输出高低电平来控制一只发光二极管的亮灭。这次我们来控制发光二极管的亮度。最后做出呼吸灯的效果。<br>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[从同一台终端分别向Gitcafe不同帐号Push的方法]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/04/22/useMultiGitcafePagesWithSSHAgent/"/>
    <id>http://blog.mangolovecarrot.net/2015/04/22/useMultiGitcafePagesWithSSHAgent/</id>
    <published>2015-04-21T19:21:55.000Z</published>
    <updated>2015-04-26T14:11:42.000Z</updated>
    <content type="html"><![CDATA[<h1 id="需求">需求</h1><p>拥有多个不同内容的个人静态站点（均使用Hexo），各自拥有独立域名，希望托管在gitcafe上操作：gitcafe的每一个帐号可以开设一个静态页面的站点（gitcafe pages服务）<br><a id="more"></a></p>
<h1 id="操作">操作</h1><p>申请了多个gitcafe的id，且每一个id都开设了gitcafe pages进行deploy的时候希望通过ssh密钥验证的方式，所以在每个id的gitcafe的设置里都需要设定ssh公钥。可能是出于安全的考虑，在gitcafe里即使是不同的id也不允许使用相同的公钥所以我为每一个id都生成了一对专用的公钥和私钥（文件名不同，均放置在~/.ssh/下面）</p>
<h1 id="问题">问题</h1><p>当我利用hexo进行deploy的时候，只有其中一个站点能成功deploy，其他几个均报错提示用户AAA没有push到BBB账户的权限！</p>
<blockquote>
<p>Error: PERMISSION DENIED: User AAA can’t write to BBB/BBB.</p>
</blockquote>
<h1 id="分析">分析</h1><p>虽然为每个账户都生成了独立的私钥密钥，但是ssh连接的时候，ssh客户端并不知道针对不同用户id应该使用哪个私钥。那么就需要在每一次deploy之前明确告诉接下来的ssh连接要使用的私钥。</p>
<h1 id="解决">解决</h1><p>ssh-agent可以在其生命周期内使用指定的密钥文件。在hexo deploy之前指定，deploy结束后退出ssh-agent即可。（退出以后再进入需要重新指定）<br>新建一个sh文件，代码如下。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#! /bin/bash</span><br><span class="line"></span></span><br><span class="line"><span class="comment"># 启动ssh-agent</span></span><br><span class="line"><span class="built_in">eval</span> `ssh-agent`</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定接下来要使用的私钥</span></span><br><span class="line">ssh-add ~/.ssh/id_rsa_<span class="keyword">for</span>_BBB</span><br><span class="line"></span><br><span class="line"><span class="comment"># 做你想做的工作，我这里是使用hexo向gitcafe部署博客文件。（hexo的ssh连接信息已经实现配置好了，这部分不是本文重点，省略）</span></span><br><span class="line">hexo d</span><br><span class="line"></span><br><span class="line"><span class="comment"># 做完你要做的工作以后记得退出ssh-agent</span></span><br><span class="line"><span class="built_in">eval</span> `ssh-agent -k`</span><br></pre></td></tr></table></figure>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="需求">需求</h1><p>拥有多个不同内容的个人静态站点（均使用Hexo），各自拥有独立域名，希望托管在gitcafe上操作：gitcafe的每一个帐号可以开设一个静态页面的站点（gitcafe pages服务）<br>]]>
    
    </summary>
    
      <category term="git" scheme="http://blog.mangolovecarrot.net/tags/git/"/>
    
      <category term="hexo" scheme="http://blog.mangolovecarrot.net/tags/hexo/"/>
    
      <category term="ssh" scheme="http://blog.mangolovecarrot.net/tags/ssh/"/>
    
      <category term="技术" scheme="http://blog.mangolovecarrot.net/categories/%E6%8A%80%E6%9C%AF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/04/20/raspi-study01/"/>
    <id>http://blog.mangolovecarrot.net/2015/04/20/raspi-study01/</id>
    <published>2015-04-20T07:26:10.000Z</published>
    <updated>2015-05-12T14:20:45.000Z</updated>
    <content type="html"><![CDATA[<h3 id="对象读者">对象读者</h3><p>我假设你的树莓派已经连上你家里的路由(有线无线都行)。并且你已经可以在另外一台设备(台式机，笔记本，手机，平板电脑都可以) 上通过SSH软件登陆到你的树莓派了。当然你也可以直接在树莓派上通过HDMI连接显示器，通过USB键盘鼠标直接进行操作。不管怎样，你可以启动树莓派并进入树莓派的linux命令行界面。<br><a id="more"></a></p>
<h3 id="最终效果">最终效果</h3><p><img src="ani.gif" alt="控制你的LED发光管按一定时间间隔闪烁"></p>
<h3 id="硬件">硬件</h3><ul>
<li>树莓派一台。1代B,B+或者2015年刚出的2代都可以。我自己用的是2代，GPIO的管脚编号可能会稍微有些差异，相应的需要注意或修改的地方我会在文中说明。另外，今后教程的硬件部分不再特意提到树莓派了。 </li>
<li>LED发光管(可以理解成小灯泡)一只，什么颜色都可以，一般卖电子零件的商店肯定有卖。或者去淘宝买。几块钱就可以买到一把。 </li>
<li>母头杜邦线两条，就是电线，带插头的是公头，带插座的是母头。我们这个实验用两端都是母头的杜邦线。 </li>
<li><img src="01.jpg" alt="硬件图"></li>
</ul>
<h3 id="原理说明">原理说明</h3><p>LED灯有一长一短两根针脚，如果将较长的一根连上电源正极，较短的一根脸上电源负极造成电位差就可以点亮LED灯。<br>但如果两个针脚同时都是负极（低电平）或者都是正极（高电平）则不会产生电位差也就不会被点亮。<br>将较短的一根连上树莓派的GND（也就是负极）端，较长的一根不要直接连上树莓派的5V或者3.3V（两者都可理解为正极或高电平，以后统称高低电平，不再另行解释），而是连接到一个GPIO针脚上。<br>然后我们可以通过程序控制GPIO口的电位高低状态即可控制LED的亮（GPIO口设置为高电平）或灭（GPIO口设置为低电平）。</p>
<h3 id="树莓派GPIO针脚说明（适合1代Mode_B+或者2代Mode_B）">树莓派GPIO针脚说明（适合1代Mode B+或者2代Mode B）</h3><p>先看一下实物图：<br><img src="PI.jpg" alt="实物图"><br>右上角有左右两排共40根针脚，并不是所有的针脚都是GPIO针脚。详情参考下图：<br><img src="GPIO.jpg" alt="树莓派GPIO针脚说明"><br>注意这两张图的上下左右顺序已经对齐了，实际连线的时候不要看错方向接错针脚。否则有损坏树莓派的可能。</p>
<h3 id="硬件连接">硬件连接</h3><p><img src="connect.png" alt="原理图"></p>
<h3 id="选择开发语言">选择开发语言</h3><p>控制GPIO口有很多方式，比如</p>
<ul>
<li>shell直接控制</li>
<li>raspberry-gpio-python库（Python语言）</li>
<li>wiringPi库（C语言）</li>
<li>BCM2835 C Library（C语言）<br>我们采用易于开发的python脚本语言作为开发语言。</li>
</ul>
<h3 id="安装Python以及GPIO库">安装Python以及GPIO库</h3><ol>
<li><p>先安装python-dev，输入以下指令。</p>
<figure class="highlight q"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-<span class="built_in">get</span> install python-<span class="built_in">dev</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>安装RPi.GPIO，依次输入以下指令。特别说明，由于RPi.GPIO仍处于不断完善的过程中，推荐去<a href="http://sourceforge.net/projects/raspberry-gpio-python/" title="GPIO官网" target="_blank" rel="external">官网</a>下载最新代码。</p>
<figure class="highlight vala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor"># 下载 </span></span><br><span class="line">$ wget http:<span class="comment">//raspberry-gpio-python.googlecode.com/files/RPi.GPIO-0.5.3a.tar.gz</span></span><br><span class="line"><span class="preprocessor"># 有朋友反映上面这句执行不成功提示连接超时，原因是国内google被墙了</span></span><br><span class="line"><span class="preprocessor"># 这里我提供我已经下载好的文件，下载链接在文章最后</span></span><br><span class="line"><span class="preprocessor"># 解压缩 </span></span><br><span class="line">$ tar xvzf RPi.GPIO-<span class="number">0.5</span><span class="number">.3</span>a.tar.gz</span><br><span class="line"><span class="preprocessor"># 进入解压之后的目录 </span></span><br><span class="line">$ cd RPi.GPIO-<span class="number">0.5</span><span class="number">.3</span>a </span><br><span class="line"><span class="preprocessor"># 启动安装 </span></span><br><span class="line">$ sudo python setup.py install</span><br></pre></td></tr></table></figure>
</li>
</ol>
<h3 id="写代码">写代码</h3><p>代码里有详细的注释，代码很简单。<br><figure class="highlight monkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="preprocessor">#!/usr/bin/env python</span><span class="preprocessor"></span><br><span class="line"># encoding: utf-8</span></span><br><span class="line"></span><br><span class="line"><span class="preprocessor"><span class="keyword">import</span> RPi.GPIO</span></span><br><span class="line"><span class="preprocessor"><span class="keyword">import</span> time</span><span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 指定GPIO口的选定模式为GPIO引脚编号模式（而非主板编号模式）</span></span><br><span class="line">RPi.GPIO.setmode(RPi.GPIO.BCM)<span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 指定GPIO14（就是LED长针连接的GPIO针脚）的模式为输出模式</span><span class="preprocessor"></span><br><span class="line"># 如果上面GPIO口的选定模式指定为主板模式的话，这里就应该指定8号而不是14号。</span></span><br><span class="line">RPi.GPIO.setup(<span class="number">14</span>, RPi.GPIO.OUT)<span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 循环10次</span></span><br><span class="line"><span class="keyword">for</span> i in range(<span class="number">0</span>, <span class="number">10</span>):<span class="preprocessor"></span><br><span class="line">	# 让GPIO14输出高电平（LED灯亮）</span></span><br><span class="line">	RPi.GPIO.output(<span class="number">14</span>, <span class="literal">True</span>)<span class="preprocessor"></span><br><span class="line">	# 持续一段时间</span></span><br><span class="line">	time.sleep(<span class="number">0.5</span>)<span class="preprocessor"></span><br><span class="line">	# 让GPIO14输出低电平（LED灯灭）</span></span><br><span class="line">	RPi.GPIO.output(<span class="number">14</span>, <span class="literal">False</span>)<span class="preprocessor"></span><br><span class="line">	# 持续一段时间</span></span><br><span class="line">	time.sleep(<span class="number">0.5</span>)<span class="preprocessor"></span><br><span class="line"></span><br><span class="line"># 最后清理GPIO口（不做也可以，建议每次程序结束时清理一下，好习惯）</span></span><br><span class="line">RPi.GPIO.cleanup()</span><br></pre></td></tr></table></figure></p>
<h3 id="源代码下载">源代码下载</h3><p><a href="prog.py" title="源代码下载">点击下载源码</a><br><a href="RPi.GPIO-0.5.11.tar.gz" title="下载RPi.GPIO">点击下载RPi.GPIO</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<h3 id="对象读者">对象读者</h3><p>我假设你的树莓派已经连上你家里的路由(有线无线都行)。并且你已经可以在另外一台设备(台式机，笔记本，手机，平板电脑都可以) 上通过SSH软件登陆到你的树莓派了。当然你也可以直接在树莓派上通过HDMI连接显示器，通过USB键盘鼠标直接进行操作。不管怎样，你可以启动树莓派并进入树莓派的linux命令行界面。<br>]]>
    
    </summary>
    
      <category term="树莓派GPIO入门系列" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BEGPIO%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/categories/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[SSH暴力扫描的防范手段]]></title>
    <link href="http://blog.mangolovecarrot.net/2015/03/27/pi-ssh-scan/"/>
    <id>http://blog.mangolovecarrot.net/2015/03/27/pi-ssh-scan/</id>
    <published>2015-03-27T10:47:37.000Z</published>
    <updated>2015-04-20T05:52:59.000Z</updated>
    <content type="html"><![CDATA[<p>之前买了块树莓派在家里搭了一台服务器玩，为了在外面方便访问，在路由器给小pi设置成了DMZ主机，并开启了SSH服务。一直用的很开心。<br>前几天偶然打开系统日志发现每天都有大量的SSH登录失败的log。<br><a id="more"></a></p>
<h1 id="背景">背景</h1><p>之前买了一块树莓派在家里搭了一台服务器玩，为了在外面方便访问，在路由器给小pi设置成了DMZ主机，并开启了SSH服务。一直用的很开心。<br>前几天偶然打开系统日志发现每天都有大量的SSH登录失败的log。基本上长成下面这个样子：<br><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:30</span><span class="pseudo">:39</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1088]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">root</span> <span class="tag">from</span> 115<span class="class">.230</span><span class="class">.126</span><span class="class">.148</span> <span class="tag">port</span> 34063 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:30</span><span class="pseudo">:42</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1088]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">root</span> <span class="tag">from</span> 115<span class="class">.230</span><span class="class">.126</span><span class="class">.148</span> <span class="tag">port</span> 34063 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:30</span><span class="pseudo">:57</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1251]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">root</span> <span class="tag">from</span> 115<span class="class">.230</span><span class="class">.126</span><span class="class">.148</span> <span class="tag">port</span> 40513 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:30</span><span class="pseudo">:58</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1255]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">invalid</span> <span class="tag">user</span> <span class="tag">user</span> <span class="tag">from</span> 111<span class="class">.73</span><span class="class">.46</span><span class="class">.22</span> <span class="tag">port</span> 4918 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:30</span><span class="pseudo">:59</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1251]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">root</span> <span class="tag">from</span> 115<span class="class">.230</span><span class="class">.126</span><span class="class">.148</span> <span class="tag">port</span> 40513 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:31</span><span class="pseudo">:01</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1251]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">root</span> <span class="tag">from</span> 115<span class="class">.230</span><span class="class">.126</span><span class="class">.148</span> <span class="tag">port</span> 40513 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:31</span><span class="pseudo">:10</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1370]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">invalid</span> <span class="tag">user</span> <span class="tag">ubnt</span> <span class="tag">from</span> 111<span class="class">.73</span><span class="class">.46</span><span class="class">.22</span> <span class="tag">port</span> 4432 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:31</span><span class="pseudo">:14</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1370]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">invalid</span> <span class="tag">user</span> <span class="tag">ubnt</span> <span class="tag">from</span> 111<span class="class">.73</span><span class="class">.46</span><span class="class">.22</span> <span class="tag">port</span> 4432 <span class="tag">ssh2</span></span><br><span class="line"><span class="tag">Mar</span> 26 09<span class="pseudo">:31</span><span class="pseudo">:19</span> <span class="tag">raspberrypi</span> <span class="tag">sshd</span><span class="attr_selector">[1370]</span>: <span class="tag">Failed</span> <span class="tag">password</span> <span class="tag">for</span> <span class="tag">invalid</span> <span class="tag">user</span> <span class="tag">ubnt</span> <span class="tag">from</span> 111<span class="class">.73</span><span class="class">.46</span><span class="class">.22</span> <span class="tag">port</span> 4432 <span class="tag">ssh2</span></span><br></pre></td></tr></table></figure></p>
<p>虽然对自己设置的密码强度有信心，但自己家里被人偷窥的感觉总是不爽。<br>解决方案有很多：</p>
<ul>
<li>被动方式。监视系统日志，发现有连续登录失败的尝试就屏蔽来源ip的请求，也就是封IP。</li>
<li>弱主动方式。修改SSH端口，SSH默认端口是22，改个端口可以档掉一部分扫描，但挡不住连端口也一起扫描的家伙。</li>
<li>强主动方式。关掉SSH的密码登录验证，只允许使用公密钥方式登录。这种方式最安全，缺点是初始设置稍微麻烦点，且用一个新的客户端总要进行初始设置。</li>
</ul>
<p>下面一个一个试着做。</p>
<h1 id="扫描系统日志，封IP">扫描系统日志，封IP</h1><p>系统日志的位置：<br>/var/log/auth.log</p>
<p>这个日志文件专门记录登入登出以及调用sudo等敏感操作。我们需要的尝试登录失败的记录就在里面。<br>我写了一个简单的shell程序。每一步都做了注释，应该很好懂。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span><br><span class="line"></span></span><br><span class="line"><span class="comment"># 日志文件</span></span><br><span class="line">LOG_FILE=<span class="string">"/var/log/auth.log"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 上一次login失败的ip</span></span><br><span class="line">last_ip=<span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 上一次列入黑名单的ip</span></span><br><span class="line">last_blocked_ip=<span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 当前处理行数</span></span><br><span class="line">lines=<span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 每次运行时都删掉之前生成的ip列表文件</span></span><br><span class="line">rm -rf block_ip.log</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取错误日志总行数，以便输出处理进度</span></span><br><span class="line">total=<span class="string">"<span class="variable">$(grep "Failed" $&#123;LOG_FILE&#125; | wc -l)</span>"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检索错误日志，并逐行取得试图登录系统的ip</span></span><br><span class="line">grep <span class="string">"Failed"</span> <span class="variable">$LOG_FILE</span> | <span class="keyword">while</span> <span class="built_in">read</span> LINE; <span class="keyword">do</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment"># 从当前行取得ip</span></span><br><span class="line">  <span class="comment"># awk NF-3 的意思是以空格或tab为分隔符，从后往前数第3个项目</span></span><br><span class="line">  ip=<span class="string">"<span class="variable">$(echo $&#123;LINE&#125; | awk '&#123;print $(NF-3)</span>&#125;')"</span></span><br><span class="line">  lines=$((<span class="variable">$lines</span> + <span class="number">1</span>))</span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 下面这条语句实现了显示进度的功能，注意最后是以\r结尾的，作用是不换行，把光标移动到行首</span></span><br><span class="line">  <span class="built_in">printf</span> <span class="string">"Progress Line: <span class="variable">$lines</span>"</span>/<span class="string">"<span class="variable">$total</span>\r"</span></span><br><span class="line">  <span class="comment">#echo $lines"/"$total</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 同一个IP连续两次登录错误的话就认为是恶意登录，将该ip记录到ip列表文件中</span></span><br><span class="line">  <span class="keyword">if</span> [ <span class="string">"<span class="variable">$last_ip</span>"</span> == <span class="string">"<span class="variable">$ip</span>"</span> ] &amp;&amp; [ <span class="string">"<span class="variable">$ip</span>"</span> != <span class="string">"<span class="variable">$last_blocked_ip</span>"</span>   ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"<span class="variable">$ip</span>"</span> &gt;&gt; block_ip.log</span><br><span class="line">    last_blocked_ip=<span class="variable">$ip</span></span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">  last_ip=<span class="variable">$ip</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 至此，所有日志里试图连续尝试登录失败的ip全部被记录在*block_ip.log*这个文件中了。</span></span><br><span class="line"><span class="comment"># 接着我们把这个列表里重复的ip删掉</span></span><br><span class="line">sort block_ip.log | uniq &gt; sorted_ip.log</span><br><span class="line"></span><br><span class="line"><span class="comment"># 这样我们就得到了一个不重复的，试图暴力破解我们密码的坏人的ip列表</span></span><br><span class="line"><span class="comment"># 屏蔽他们！</span></span><br><span class="line">cat sorted_ip.log | <span class="keyword">while</span> <span class="built_in">read</span> LINE; <span class="keyword">do</span></span><br><span class="line">&#123;</span><br><span class="line">  ip=<span class="variable">$&#123;LINE&#125;</span></span><br><span class="line">  <span class="comment"># 将ip加入黑名单</span></span><br><span class="line">  iptables -A INPUT <span class="operator">-s</span> <span class="string">"<span class="variable">$ip</span>"</span> -j DROP</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>这样，封ip就成功了。<br>这个程序还可以改成使用 tail -f 不停监视最新的日志，随时封新发现的ip的模式。有兴趣的可以自己动手改一下。</p>
<h1 id="修改SSH端口">修改SSH端口</h1><p>todo</p>
<h1 id="关掉SSH的密码登录验证">关掉SSH的密码登录验证</h1><p>todo</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>之前买了块树莓派在家里搭了一台服务器玩，为了在外面方便访问，在路由器给小pi设置成了DMZ主机，并开启了SSH服务。一直用的很开心。<br>前几天偶然打开系统日志发现每天都有大量的SSH登录失败的log。<br>]]>
    
    </summary>
    
      <category term="LINUX" scheme="http://blog.mangolovecarrot.net/tags/LINUX/"/>
    
      <category term="SSH" scheme="http://blog.mangolovecarrot.net/tags/SSH/"/>
    
      <category term="树莓派" scheme="http://blog.mangolovecarrot.net/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
      <category term="技术" scheme="http://blog.mangolovecarrot.net/categories/%E6%8A%80%E6%9C%AF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[生命，宇宙以及一切的答案]]></title>
    <link href="http://blog.mangolovecarrot.net/2014/09/11/yhxmyzn42/"/>
    <id>http://blog.mangolovecarrot.net/2014/09/11/yhxmyzn42/</id>
    <published>2014-09-11T08:07:52.000Z</published>
    <updated>2015-04-20T04:43:08.000Z</updated>
    <content type="html"><![CDATA[<p>一般情况下如果有一个问题恰好是你所不知道的（大多数情况下都会是这样），你大概会立刻去百度或者Google一下，这往往很有效。但当你想了解<strong>“生命，宇宙以及一切”</strong>这种宏大问题的答案时，你如果还指望Google能给你答案就奇怪了，实际上这并不是最奇怪的，最奇怪的是Google的确会告诉你这个问题的答案就像你问的只是一加一等于几一样。<br><a id="more"></a></p>
<blockquote>
<p>What is the answer to life, the universe, and everything?<br>42</p>
</blockquote>
<p>没错，Google给出的答案是42。<br>另外，在Google的总部还矗立着这样一座雕塑：<br><img src="http://static.flickr.com/69/162655998_65078555eb_o.jpg" alt="42"><br>你同样可以去问苹果的Siri，只是你需要用你蹩脚（或是非常蹩脚）的英文念出上面这句话。<br>那么，为什么是42？<br>这是在向一本（或一个系列）80年代出版的科幻小说致敬。书名是《The Hitchhiker’s Guide to the Galaxy》（中文译名《银河系漫游指南》或《银河系搭便车指南》）。它是一个叫道格拉斯·亚当斯的人写的，他当过阿拉伯王公的保镖，准备着一旦有人举着鸡蛋或者炸弹尖叫着跑过来，就立刻鼠窜，他客串过PINKFLOYD的吉他手，因为跟乐队成员是好朋友，他还做过鸡场清洁工。。。<br>这个系列一共有5部，被称为…<strong>银河系漫游五部曲</strong>也被誉为<strong>科幻圣经</strong>，包括：</p>
<ul>
<li>《银河系漫游指南》</li>
<li>《宇宙尽头餐馆》</li>
<li>《生命、宇宙及一切》</li>
<li>《再见，谢谢鱼》</li>
<li>《基本无害》</li>
</ul>
<p>这是一本很好玩的书，绝对有趣，我想作者应该会是一个更有趣的人。遗憾的是他40多岁就去世了，否则他可以在有生之年多写一些有趣的书可以让这个世界变得更有趣一点点。（同样有趣且英年早逝的另一个作家是中国作家王小波）<br>这本书有趣到几乎翻到任何一页有能让你开心一笑的无厘头，假装严肃等等一切荒诞不经的桥段。比如：</p>
<ul>
<li>有一种理论宣称，如果任何一个人真正发现了宇宙存在的原因、宇宙存在的目的，宇宙就会立刻消失，被某种更为怪异、更难以理解的玩意儿取代。还有另外一种理论宣称，上述事件已经发生过了。</li>
<li>有两个原因让《银河系漫游指南》超过《银河系百科全书》，成为所有知识和智慧的标准：“第一，它稍微便宜一点儿；第二、它的封面上以大而友善的字体写着：不要恐慌。” </li>
<li>关于如何走私鹦鹉生殖腺，《指南》说：“把它插在一根小棍上，这是非常惹人厌恶但极受欢迎的鸡尾酒装饰物，很多有钱白痴愿意花一大笔钱买这东西，只是为了给其他的有钱白痴留下深刻印象。”</li>
<li>这是一副祖·杰塔200型超级色度危险感应太阳镜，专门用于帮助人们在面对危险时采取一种放松的态度。一旦感应到出现麻烦的第一个征兆，它就会完全变黑，阻止你再看到任何可能警示你的东西。</li>
<li>在一个无限大的宇宙里（比如，我们生活的这个），不论是你能想象的东西，还是你不能想象的东西，都能在某个地方自己长出来。近来就有人发现了一座森林，里面的树上都结着棘轮螺丝刀果实。棘轮螺丝刀果实的一生非常有趣。当被摘下来以后，它需要一个黑洞洞、灰扑扑的抽屉来装自己，一装就是好几年。然后，某一天晚上，它会突然孵化，褪掉自己那快碎成渣的表皮，变成一个完全认不出来的金属物品，两头都有突起，身上有棱，还有为螺丝准备的凹槽。到达这个形态的棘轮螺丝刀果实，一旦被发现，就会马上被扔掉。没人知道这一切有什么意义。大自然，大概正以她无穷的智慧，考虑着这个问题吧。</li>
<li>“我的快乐能力，”他接着说，“小的可以装进火柴盒。而且你不必把火柴取出来。”</li>
<li>“我做过一次演讲。”他突然开口道，前言不搭后语。“你很快就会明白我为什么说起这个。那是因为我的脑子运行过于迅速了。粗略算来，我至少比你聪明三百亿倍。举个例子吧。想个数字，随便哪个。”“嗯，五。”床垫说。“错。”马文说，“明白了？”床垫被深深地震撼了。它意识到，自己面前这位绝非寻常人等。</li>
<li>遥远的黑暗中，突然亮起一行古怪的绿色霓虹灯。它静静地亮出如下字样：“你被转移了。”那行字又熄灭了。阿瑟一点也不喜欢那种熄灭方式。它是以一种带有鄙视感的、花哨的效果熄灭的。于是，阿瑟告诉自己，这只是可笑的幻觉。霓虹灯要么开、要么关，取决于是否有电流从中通过。他告诉自己，霓虹灯在两种状态之间转换，绝不可能有什么鄙视感的花哨效果。</li>
<li>不过，最最惊天动地的飞船，当数“版求一号”。那是版求星人制造的第一艘飞船，它惊人不是因为它很棒。它可一点也不棒。它约等于一块废铁。看上去，像是在谁家后院里胡乱拼成的——它的确也是。最最惊人的地方，不在于它有多好（它一点也不好），而是它竟然被造出来了。</li>
</ul>
<p>书中这种有趣的描写俯拾皆是。最后再解释一下42这个答案是怎么来的。</p>
<blockquote>
<p>一个具有超级智慧的泛维度种族就曾建造了一台巨型超级电脑，被称为“沉思”，用来计算关于生命、宇宙以及一切终极问题的答案。<br>经过七百五十万年的漫长岁月，沉思计算着、衡量着，最后宣布，这个问题的答案是42——但所有人都已经忘记当初的问题是什么，于是，一台更大的电脑被建造出来，以寻求对应于这个答案的确切问题究竟是什么。因为，只有当确切地知道问题是什么时，才能理解这个答案的意思……<br>这台电脑被称为“地球”，它是如此之大，常常被错当成一颗行星。在它表面游荡的那些长得和猿差不多的奇怪生物尤其爱犯这个错误，这些家伙完全没有意识到他们只不过是一个巨型电脑程序的一部分而已<br>如果不是为了那个大目的，发生在这个叫做地球的玩意儿上的其他所有事情就完全没有一丁点儿意义了。连这么简单明显的常识都意识不到，实在是太怪了。<br>不幸的是，就在最后结果即将出来之前的关键时刻，地球被沃贡人摧毁了。完全出乎意料。而沃贡人的目的只是为了腾出地方来修建——沃贡人是这样宣称的——一条新的超空间通道。</p>
</blockquote>
<p>噗。。。</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>一般情况下如果有一个问题恰好是你所不知道的（大多数情况下都会是这样），你大概会立刻去百度或者Google一下，这往往很有效。但当你想了解<strong>“生命，宇宙以及一切”</strong>这种宏大问题的答案时，你如果还指望Google能给你答案就奇怪了，实际上这并不是最奇怪的，最奇怪的是Google的确会告诉你这个问题的答案就像你问的只是一加一等于几一样。<br>]]>
    
    </summary>
    
      <category term="书评" scheme="http://blog.mangolovecarrot.net/tags/%E4%B9%A6%E8%AF%84/"/>
    
      <category term="搞笑" scheme="http://blog.mangolovecarrot.net/tags/%E6%90%9E%E7%AC%91/"/>
    
      <category term="科幻" scheme="http://blog.mangolovecarrot.net/tags/%E7%A7%91%E5%B9%BB/"/>
    
      <category term="道格拉斯" scheme="http://blog.mangolovecarrot.net/tags/%E9%81%93%E6%A0%BC%E6%8B%89%E6%96%AF/"/>
    
      <category term="读书" scheme="http://blog.mangolovecarrot.net/categories/%E8%AF%BB%E4%B9%A6/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[WINSCP文件名显示乱码问题]]></title>
    <link href="http://blog.mangolovecarrot.net/2014/08/25/WINSCP%E6%96%87%E4%BB%B6%E5%90%8D%E6%98%BE%E7%A4%BA%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/"/>
    <id>http://blog.mangolovecarrot.net/2014/08/25/WINSCP文件名显示乱码问题/</id>
    <published>2014-08-25T05:01:11.000Z</published>
    <updated>2015-04-20T04:43:08.000Z</updated>
    <content type="html"><![CDATA[<p>最近捣鼓树莓派用的最多的软件就是putty跟winscp。在日文系统下，winscp的文件列表里的中文文件名全是乱码。后来发现只要在登录设置窗口里把utf-8编码的开关打开就能正常显示了。(注意，是登录设置窗口。不是主菜单里的环境设置)<br><a id="more"></a><br>修改前(默认)<br><img src="01.png" alt="01"></p>
<p>修改后<br><img src="02.png" alt="02"></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>最近捣鼓树莓派用的最多的软件就是putty跟winscp。在日文系统下，winscp的文件列表里的中文文件名全是乱码。后来发现只要在登录设置窗口里把utf-8编码的开关打开就能正常显示了。(注意，是登录设置窗口。不是主菜单里的环境设置)<br>]]>
    
    </summary>
    
      <category term="技术" scheme="http://blog.mangolovecarrot.net/categories/%E6%8A%80%E6%9C%AF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[利用webpy搭建一个简单的网页版hexo编辑器]]></title>
    <link href="http://blog.mangolovecarrot.net/2014/08/20/lets_webpy/"/>
    <id>http://blog.mangolovecarrot.net/2014/08/20/lets_webpy/</id>
    <published>2014-08-20T09:52:35.000Z</published>
    <updated>2015-04-20T04:43:08.000Z</updated>
    <content type="html"><![CDATA[<p>相信看到本文的读者都已经搭建了自己的hexo站点。hexo（或者任何其他静态html框架）有一个非常不方便的地方就是每次写博客，你都必须ssh到你的服务器上执行以下命令来创建一篇新文章：<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">hexo</span> n 文章标题</span><br></pre></td></tr></table></figure></p>
<a id="more"></a>
<p>然后再用nano或者是vim等文字编辑器来更新这个md文件。编辑完以后再执行下面两条命令生成文章并发布。<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo <span class="keyword">g</span></span><br><span class="line">hexo <span class="literal">d</span></span><br></pre></td></tr></table></figure></p>
<p>这个过程很geek，可能也是最先吸引程序猿们使用这套东西的原因。但最终你会觉得厌烦，为什么我把精力集中在写文章上呢？<br>本文的目的就是利用强大方便的webpy来搭建一个简单但完备的在线版hexo编辑器，这个编辑器应该具有：</p>
<ul>
<li>发布新文章</li>
<li>修改旧文章</li>
<li>删除旧文章</li>
<li>通过web页面指示后台执行hexo命令生成html并发布</li>
</ul>
<p>我们开始吧</p>
<h1 id="安装">安装</h1><h2 id="安装hexo">安装hexo</h2><h2 id="安装webpy">安装webpy</h2><h1 id="验证">验证</h1><h2 id="验证hexo">验证hexo</h2><h2 id="验证webpy">验证webpy</h2><h1 id="造轮子">造轮子</h1><h2 id="设计">设计</h2><h3 id="首页">首页</h3><p>首页分成有两个部分。</p>
<ol>
<li>顶部的命令按钮区。<br>目前只有一个最基本的功能按钮，写新文章。</li>
<li>文章列表区。<br>初期显示时取得hexo的_post目录下所有文件(文章)的列表显示。每一个文件都有一组对应的操作按钮。(目前只有最基本的修改和删除按钮)为了页面整洁，这些操作按钮默认不显示，当点到某文章时才动态显示出来。</li>
</ol>
<h3 id="创建新文章页">创建新文章页</h3><p>这个页面接收一个新标题(其实是文件名)作为参数并显示在页面顶部。不可修改。主体只需要一个文本框和一个提交按钮。文本框用来编辑md源文件。点击提交按钮则将文章写入文件然后调用hexo命令生成html并发布。</p>
<h3 id="修改旧文章页">修改旧文章页</h3><p>布局基本和创建新文章一样。一个编辑文本框，一个提交按钮。</p>
<h3 id="其他">其他</h3><h4 id="回收站功能">回收站功能</h4><h4 id="登录功能">登录功能</h4><h2 id="关键代码">关键代码</h2><ul>
<li><p>为了避免中文乱码，统一设置字符集为UTF-8</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">import sys</span><br><span class="line"><span class="function"><span class="title">reload</span><span class="params">(sys)</span></span></span><br><span class="line">sys.<span class="function"><span class="title">setdefaultencoding</span><span class="params">(<span class="string">'utf8'</span>)</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>取得文章列表函数</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这里替换成你自己的hexo根目录</span></span><br><span class="line">hexoRoot = <span class="string">'/home/pi/hexo_root'</span></span><br><span class="line">postDir = hexoRoot + <span class="string">'/source/_posts/'</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getWzList</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="comment"># Make list for show</span></span><br><span class="line">    wzList = []</span><br><span class="line">    idx = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> lists <span class="keyword">in</span> os.listdir(postDir): </span><br><span class="line">        path = os.path.join(postDir, lists) </span><br><span class="line">        <span class="keyword">if</span> os.path.isfile(path):</span><br><span class="line">            wzList.append([os.path.basename(path), <span class="string">'wz_'</span>+str(idx)])</span><br><span class="line">            idx = idx + <span class="number">1</span></span><br><span class="line">    wzList.sort(reverse=<span class="keyword">True</span>)</span><br><span class="line">    <span class="keyword">return</span> wzList</span><br></pre></td></tr></table></figure>
</li>
<li><p>首页基本上什么都不做直接返回文章列表给模板</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">index</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">GET</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> render.index(getWzList())</span><br></pre></td></tr></table></figure>
</li>
<li><p>创建新文章时调用hexo命令<br>为了执行hexo命令需要更改工作目录到你的hexo根目录下。<br>记得要先备份一下当前工作目录，执行完hexo命令以后需要恢复原来的工作目录，否则读取模板文件时会出错。</p>
<figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 更改工作目录</span></span><br><span class="line">sWebpyDir = os.getcwd()</span><br><span class="line">os.<span class="keyword">chdir</span>(hexoRoot)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 执行 Hexo n ... 这里的sNewTitle是从index页面传过来的参数</span></span><br><span class="line">os.<span class="keyword">system</span>(<span class="string">'hexo n '</span> + sNewTitle)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 恢复原来的webpy的工作目录</span></span><br><span class="line">os.<span class="keyword">chdir</span>(sWebpyDir)</span><br></pre></td></tr></table></figure>
</li>
<li><p>读取md文件</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">now = datetime<span class="class">.datetime</span><span class="class">.now</span>()</span><br><span class="line">filename = now.<span class="function"><span class="title">strftime</span><span class="params">(<span class="string">'%Y-%m-%d-'</span>)</span></span> + sNewTitle + <span class="string">'.md'</span></span><br><span class="line">fileHandle = open ( postDir + filename )</span><br><span class="line">fileContent = fileHandle.<span class="function"><span class="title">read</span><span class="params">()</span></span></span><br><span class="line">fileHandle.<span class="function"><span class="title">close</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="运行效果">运行效果</h2>]]></content>
    <summary type="html">
    <![CDATA[<p>相信看到本文的读者都已经搭建了自己的hexo站点。hexo（或者任何其他静态html框架）有一个非常不方便的地方就是每次写博客，你都必须ssh到你的服务器上执行以下命令来创建一篇新文章：<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">hexo</span> n 文章标题</span><br></pre></td></tr></table></figure></p>]]>
    
    </summary>
    
      <category term="python" scheme="http://blog.mangolovecarrot.net/tags/python/"/>
    
      <category term="webpy" scheme="http://blog.mangolovecarrot.net/tags/webpy/"/>
    
      <category term="技术" scheme="http://blog.mangolovecarrot.net/categories/%E6%8A%80%E6%9C%AF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Hexo，肚脐？]]></title>
    <link href="http://blog.mangolovecarrot.net/2014/08/16/Hexo/"/>
    <id>http://blog.mangolovecarrot.net/2014/08/16/Hexo/</id>
    <published>2014-08-15T23:59:28.000Z</published>
    <updated>2015-04-20T04:43:08.000Z</updated>
    <content type="html"><![CDATA[<h1 id="概要">概要</h1><p>这个博客运行在我自己家里的树莓派上。几天前曾经用sqlite+wordpress搭建过<a href="http://mangolovecarrot.net:8080/wordpress/" target="_blank" rel="external">另一个博客</a>，你访问一下试试就知道有多慢了(如果已经访问不了那就是已经被我删掉了)，打开一个页面平均需要5秒以上，这还是没有加载任何第3方插件的情况下，于是放弃。<br><a id="more"></a></p>
<h1 id="Hexo">Hexo</h1><p>几番搜寻，决定采用静态html式的博客框架，这种框架最大的优点就是快快快。#(废话，静态页面当然快)#<br>最后采用的是一个叫Hexo(很像<em>肚脐</em>的日语发音<em>heso</em>，作者<a href="http://zespia.tw/blog/2012/10/11/hexo-debut/" target="_blank" rel="external">自己说的</a>)的框架，作者是一个台湾大学生。该框架是基于Node.js的javascript框架。相比其他类似框架的好处是通过makedown生成静态html非常快。另外就是它那<a href="http://hexo.io/docs/writing.html" target="_blank" rel="external">逼格奇高</a>的程序猿写作方式我很喜欢。</p>
<h2 id="安装">安装</h2><p>安装Hexo很简单，但在这之前你还需要这些：</p>
<ul>
<li><strong>Git</strong>，一个源码管理工具，如果你希望把你生成的网站发布到GitHub上去的话那就安装吧。如果你仅仅只是使用Hexo来生成静态html页面然后发布到本地web服务器上的话可以跳过这一步。要注意的是，以后当你想更换Hexo的主题时你还是需要使用Git工具来下载那些托管在GitHub上的主题包。<em>（当然这并不是必须的）</em></li>
<li><strong>lighttpd</strong>，一个轻量级的web服务器，用来将网站发布在你本地，你也可以选择其他任何你熟悉的webserver比如apache。当然，如果你选择发布在GitHub上<em>（意味着你不能使用自己喜欢的域名）</em>那么你可以跳过这一步。</li>
<li><strong>Node.js</strong>，一个强大的javascript库，是Hexo的基础，必须安装。</li>
</ul>
<h3 id="安装_Git">安装 Git</h3><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-<span class="keyword">get</span> install git</span><br></pre></td></tr></table></figure>
<h3 id="安装_lighttpd">安装 lighttpd</h3><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-<span class="keyword">get</span> install lighttpd</span><br></pre></td></tr></table></figure>
<h3 id="安装_Node-js和npm">安装 Node.js和npm</h3><p>关于安装这个，Hexo官网给出的方法是<br><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">wget -qO- http<span class="variable">s:</span>//raw.github.<span class="keyword">com</span>/creationix/nvm/master/install.<span class="keyword">sh</span> | <span class="keyword">sh</span></span><br><span class="line">nvm install <span class="number">0.10</span></span><br></pre></td></tr></table></figure></p>
<p>我按照上面的命令试图安装，这种方法是下载最新src并在本地进行编译，我那可怜的树莓派足足跑了1个小时还没编译完成，最后强制中断了。<br>我依然采用万能的apt-get来进行安装（这要归功于写出raspbian系统并为这个系统提供了几乎所有常用的并且已经编译完成的软件包的大牛们）<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get <span class="operator"><span class="keyword">install</span> nodejs</span><br><span class="line">sudo apt-<span class="keyword">get</span> <span class="keyword">install</span> npm</span></span><br></pre></td></tr></table></figure></p>
<h3 id="安装_Hexo">安装 Hexo</h3><p>很简单也是一行命令搞定<br><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm <span class="keyword">install</span> -g hexo</span><br></pre></td></tr></table></figure></p>
<h2 id="创建Hexo文件系统">创建Hexo文件系统</h2><p>进入任意目录执行以下命令即可创建一个Hexo的一整套文件系统。由于我打算部署在lighttpd里，所以我将Hexo的文件系统创建在lighttpd服务器的根目录<strong>/var/www</strong>下，注意更新该目录需要root权限，所以请记得使用sudo<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo <span class="keyword">su</span></span><br><span class="line"><span class="keyword">cd</span> /<span class="keyword">var</span>/www</span><br><span class="line">hexo init hx</span><br></pre></td></tr></table></figure></p>
<p>不出意外，在<strong>/var/www</strong>下会生成一个名为<strong>hx</strong>的文件夹，这就是hexo的文件系统了。</p>
<h1 id="写博客">写博客</h1><p><em>未完待续</em></p>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="概要">概要</h1><p>这个博客运行在我自己家里的树莓派上。几天前曾经用sqlite+wordpress搭建过<a href="http://mangolovecarrot.net:8080/wordpress/">另一个博客</a>，你访问一下试试就知道有多慢了(如果已经访问不了那就是已经被我删掉了)，打开一个页面平均需要5秒以上，这还是没有加载任何第3方插件的情况下，于是放弃。<br>]]>
    
    </summary>
    
      <category term="git" scheme="http://blog.mangolovecarrot.net/tags/git/"/>
    
      <category term="hexo" scheme="http://blog.mangolovecarrot.net/tags/hexo/"/>
    
      <category term="lighttpd" scheme="http://blog.mangolovecarrot.net/tags/lighttpd/"/>
    
      <category term="webserver" scheme="http://blog.mangolovecarrot.net/tags/webserver/"/>
    
      <category term="Hexo" scheme="http://blog.mangolovecarrot.net/categories/Hexo/"/>
    
  </entry>
  
</feed>