驾照到手

2010-11-2 21:11 | by 2ndboy

  今天上午是个值得纪念的日子(对我来说:))!路考通过,拿到驾照了,考试过程相当顺利,本来是要加到 5 档把车跑起来的,不过我只加到 3 档就被考官要求靠边停车,签字通过了,爽!

  回想过去的几个月,拿个驾照还真是不容易,上理论课(必须到场 5 次)、理论考试、上模拟器(必须上两次)、场考一直到今天的路考。这其中场考是最难熬的,我就在圆饼上栽了一次。话说这个圆饼,想想实际生活当中有什么用呢?!反而是曲线行驶和上坡起步会比较有用。第一次场考怕什么来什么,我圆饼一直不稳定,考试的时候偏偏就抽到圆饼,认栽!当然每个人的弱项不一样,比如很多人怕的单边桥,我从第一次学单边桥开始就从来没上不去或掉下来过:) 所以只怪运气不好。补考抽到的是曲线,我的强项,所以轻松通过。

  路考训练的时候一直比较顺手,所以今天的结果还是不意外的。这下好了,完成了今年的一桩心事。不过现在杭州车满为患,我上班又近,所以暂时还没打算给杭州再添个堵。这个事做完以后,也该想想再找个什么事情来折腾一下了:)

学习数码管的动态显示[译码器实现位选|基于普中 HC6800]

2010-10-30 17:08 | by 2ndboy

  开发板买来半个月,有空就会玩儿玩儿,不过我玩儿的都还是比较初级的东西,所以感觉也没什么可写的,今天就把搞定数码管动态显示的东西记一下吧。

  常见的数码管(7-segment display)封装形式有一位数字的,也有多位数字的。在只有一位数字的数码管上显示一个数字(或者在多位封装的数码管上显示若干个一样的数字)叫做静态显示,静态显示不是说显示的数字不可变,而是意味着在显示这个数字期间,数码管的状态不变,是静态的。数码管的动态显示用于多位数码管,拿 4 位数码管来举例,4 位数码管的所有段(segment)引脚是公用的,然后由 4 个位选引脚来决定哪个数字位有效。比如说我们想显示在这个 4 位数码管上显示 0123,那么实际上要做的事情其实是:

  1. 用位选选中 4 位数码管中的第一个数字位
  2. 给数码管送 0 这个数字的字模
  3. 关闭数码管的显示
  4. 用位选选中 4 位数码管中的第二个数字位
  5. 给数码管送 1 这个数字的字模
  6. ……以此类推……

从上面过程可以看出来,就算我们想显示的是一串恒定的数字 0123,但对于 4 位数码管来说,这个过程是一个动态的逐位显示的过程,所以叫动态显示。

环境准备

以下描述都以我手上的普中 HC6800 为准:

  1. 用跳线帽连接 J15 和 J16
  2. 用排线连接 JP10(P0)和 J12
  3. J21 接 VCC

原理

这里我们用 74HC138 这个译码器(Decoder)来实现 2 个 4 位数码管的位选:
Pin configuration of 74HC138
74HC138 的真值表如下:
Truth table of 74HC138
74HC138 有 3 个输入(接 P2.2、P2.3、P2.4),8 个输出,从真值表上可以看出,74HC138 的作用就相当于把一个 3 位二进制数的输入转换成某个输出脚上的低电平。2 个 4 位数码管,做位选刚好够用:)

HC6800 用的 2 个 4 位数码管是共阴极数码管,用 74HC573 锁存器(Latch)来驱动:
Pin configuration of 74HC573
74HC573 有 8 个输入,8 个输出:
Truth table of 74HC573
由于 J21 接了 VCC(LE 高电平),-OE 接了 GND,所以 74HC573 工作在 transparent mode,Dn 如果是低电平,对应的 Qn 也是低电平;如果 Dn 是高电平,对应的 Qn 也是高电平。74HC573 的作用应该是提供点亮数码管所需的电流(这里暂时存疑)。J12 和 JP10 连接以后,P0 就是 74HC573 的输入。

代码

SSD.h

  1. #ifndef __SEVEN_SEGMENT_DISPLAY__20101030__
  2.  #define __SEVEN_SEGMENT_DISPLAY__20101030__
  3.  
  4.  unsigned char
  5.  GetSSDCode(
  6.      unsigned char n,
  7.      bit bWithDP// Decimal Point
  8.      bit bCC );    // Common Cathode(-) or Common Anode(+)
  9.  
  10.  unsigned char
  11.  GetEmptySSDCode( bit bCC )// Common Cathode(-) or Common Anode(+)
  12.  
  13.  #endif  // __SEVEN_SEGMENT_DISPLAY__20101030__

SSD.c

  1. /*
  2.     A
  3.   +---+
  4.  F|   |B
  5.   +-G-+
  6.  E|   |C
  7.   +---+  oDP
  8.     D
  9.  
  10.   7 6 5 4 3 2 1 0
  11.  DP G F E D C B A
  12.   8 4 2 1,8 4 2 1
  13.  */
  14.  unsigned char code SSDCodes[] =
  15.  {
  16.      0x3F// 0 = ABCDEF
  17.      0x06// 1 = BC
  18.      0x5B// 2 = ABGED
  19.      0x4F// 3 = ABCDG
  20.      0x66// 4 = BCFG
  21.      0x6D// 5 = ACDFG
  22.      0x7D// 6 = ACDEFG
  23.      0x07// 7 = ABC
  24.      0x7F// 8 = ABCDEFG
  25.      0x6F// 9 = ABCDFG
  26.      0x77// A = ABCEFG
  27.      0x7C// b = CDEFG
  28.      0x39// C = ADEF
  29.      0x5E// d = BCDEG
  30.      0x79// E = ADEFG
  31.      0x71// F = AEFG
  32.  };
  33.  
  34.  unsigned char
  35.  GetSSDCode(
  36.      unsigned char n,
  37.      bit bWithDP// Decimal Point
  38.      bit bCC )     // Common Cathode(-) or Common Anode(+)
  39.  {
  40.      unsigned char SSDCode;
  41.      if( n >= 0 && n < sizeof( SSDCodes ) / sizeof( SSDCodes[0] ) )
  42.          SSDCode = SSDCodes[n];
  43.  
  44.      if( bWithDP )
  45.          SSDCode |= 0x80;
  46.  
  47.      return( bCC ? SSDCode : ~SSDCode );
  48.  }
  49.  
  50.  unsigned char
  51.  GetEmptySSDCode( bit bCC )  // Common Cathode(-) or Common Anode(+)
  52.  {
  53.      return( bCC ? 0 : 0xFF );
  54.  }

main.c

  1. #include <reg52.h>
  2.  #include "SSD.h"
  3.  
  4.  sbit DecoderA = P2^2;
  5.  sbit DecoderB = P2^3;
  6.  sbit DecoderC = P2^4;
  7.  
  8.  void Display( unsigned char pos, unsigned char n )
  9.  {
  10.      switch( pos )
  11.      {
  12.          case 0: DecoderC = 0; DecoderB = 0; DecoderA = 0; break;
  13.          case 1: DecoderC = 0; DecoderB = 0; DecoderA = 1; break;
  14.          case 2: DecoderC = 0; DecoderB = 1; DecoderA = 0; break;
  15.          case 3: DecoderC = 0; DecoderB = 1; DecoderA = 1; break;
  16.          case 4: DecoderC = 1; DecoderB = 0; DecoderA = 0; break;
  17.          case 5: DecoderC = 1; DecoderB = 0; DecoderA = 1; break;
  18.          case 6: DecoderC = 1; DecoderB = 1; DecoderA = 0; break;
  19.          case 7: DecoderC = 1; DecoderB = 1; DecoderA = 1; break;
  20.      }
  21.      P0 = GetSSDCode( n, 0, 1 );
  22.  }
  23.  
  24.  void main()
  25.  {
  26.      unsigned char i = 0;
  27.      do
  28.      {
  29.          for( i = 0; i < 8; ++i )
  30.          {
  31.              Display( i, i );
  32.              P0 = GetEmptySSDCode( 1 );
  33.          }
  34.      }
  35.      while( 1 );   
  36.  }

程序烧进 89C52 以后会看到 2 个 4 位数码管上显示 0 到 7 这 8 个数字。

重拾爱好——从单片机开始

2010-10-14 23:15 | by 2ndboy

  从小就喜欢鼓捣东西,记得小时候拆散过家里的 2、3 个收音机,当然是没本事装回去的:) 二舅舅对模电非常精通(小时候不知道模电这个词,都叫无线电),然后记得好像是在上初中以后,舅舅为了鼓励我也学好无线电,还特意送了我一套无线电开发板和指针式万用表。估计知道单片机开发板的人大把,见过模电开发板的就不多,那是一个类似 2D 乐高的装置,每个晶体管零件都被单独封装在一个立方体的小塑料块里,小立方体的顶上是零件符号,4 个外壁是 4 个金属触点,跟里面的晶体管触角相连,所以你把若干个立方体插在基座上连在一起就可以组合出各种电路来(基座上有电源和扬声器触点)。不过那时候实在是理解不了那么许多概念,所以基本上只会按图索骥的组合出一些随机手册上的东西来,比如说一个光敏的报警器,或者是收音机。后来觉得报警器放在开发板上太大太笨重,就找齐了所需的零件,自己用电烙铁做了个成品出来。不过那时候我们住的那个小城里没有什么电子市场,更没有淘宝,所以根本没有电路板和面包板可买,我焊东西都是把电路图画在一块大小合适的硬纸板上,然后在合适的位置穿孔,插零件再焊起来的,成品看起来相当的土:D

  总的来说,我的模电启蒙就是这些,明白电阻、三极管大概能干些什么的,但是离自己设计电路做东西还差得十万八千里。后来接触了 8 位学习机、286,从《电脑报》上看到了 Bill Gates 的创业史,兴奋的了不得,就立志将来要做个程序员(那是上初中时候的事儿)。一旦选择了把软件作为业余爱好,我的硬件就完全放下,荒废了(其实也没什么可荒的,因为懂的也不多:D)。后来先是在初中阶段学 Basic,中考以后学 C,高中阶段不断的练手,直至大学进到梦寐以求的计算机专业(后来悲哀的发现这个选择是个彻底的错误,正确的选择应该是选其它专业,然后继续把软件开发做业余爱好,结合到所学的专业里),毕业以后做了一直想做的软件开发。

  到今年,入行也有 8 年多了,平时在看 IT 新闻的时候偶尔会看到老外做的一些电子 DIY,佩服的不得了,感觉太有才了,这比成天玩儿看得见摸不着的软件可有意思多了,也萌生过再学学电路知识的念头,不过一直没付诸行动。在刚刚过去的这个国庆期间,受到一些事情的启发,于是打算重拾电子制作这个爱好,也能把业余时间利用的更好一些。放假回来之后就查了一些资料,现在是数字电路的天下,虽然大学期间模电数电的课都上过,不过那时候基本上是纯粹为了拿学分,老师讲的也不深,所以到了现在更是忘得一干二净,算是回炉重造!

  几番搜索下来决定从单片机入手学习,就从受众甚广的 51 单片机开始。网上找到了口碑甚佳的郭天翔的《十天学会单片机》,然后知道了名气很大的 TX-1C,不过在淘宝上几番比较以后发现 TX-1C 的性价比不怎么高,最后买了一套普中 HC6800 V2.6,价格是 TX-1C 的一半,功能比 TX-1C 还要多,然后又买了数字万用表烙铁之类的加一块儿才是 TX-1C 的价格:) 接下来没事的时候就可以鼓捣鼓捣 51 开发板了,也算是重拾爱好。但愿过几年可以达到自己设计电路做些小玩意儿的水平:)

DokuWiki – 知识管理(整理)工具有着落了

2010-9-27 21:14 | by 2ndboy

  最初接触 Wiki 是在 2004 年左右,那时候用的是 UseMod Wiki。当时就觉得 Wiki 是一个知识管理的好工具,而且非常方便多人协作来贡献信息(Google Docs 的多人实时协作编辑何尝不是一种对 Wiki 的增强呢?!),所以就想尝试用 Wiki 来管理和整理自己平时的一些积累。但是当时一来没有稳定可用的空间,二来我对当时接触到的一些 Wiki 系统不太透明的数据存放方式不太感冒,觉得编辑者无法完全掌控数据的存储层次关系,所以后来就没有了下文。

  最近工作上打算跟跨分公司的同事一起编辑一些文档,所以就又捡起 Wiki 来研究了一番,这一研究不要紧,让我这跨度达 6、7 年的寻找知识管理工具之旅有了个结果。

  一开始为了安装配置简单,所以就比较随便的找到了 PmWiki 来用,搜寻的主要方向当然是在我比较熟悉的 PHP 领域了,PmWiki 是用 PHP 实现的,而且不依赖于数据库,是把所有 page 保存在磁盘上的 TXT 文件中的。这一特性相当的吸引我!因为我在工作以后的一段时间里,逐渐形成了记工作日志的习惯,这样有些事情在时隔数月已经忘记的情况下仍然可以通过使用 Windows 自带的文件内容搜索回想起来。这些工作日志都是记在 TXT 文件里,按年份和月份分目录存放的。所以我现在仍然可以很轻松的查到自己在 2003 年的某一天里遇到和解决过什么棘手的问题:) 不得不表扬一下自己,这是个好习惯,虽然有时候你会觉得“浪费”了一点时间:)

  用了几天 PmWiki 之后偶然的看到了 Riku 的这篇“用 DokuWiki 打造个人知识管理系统”,于是很幸运的认识了 DokuWiki。(推荐另外一篇不错的比较 PmWiki 和 DokuWiki 的文章——“优秀的 Wiki 程序:PmWiki 和 DokuWiki”)

  试用之下惊喜异常:) 因为俺觉得,这下找到真正想要的东西了!跟 PmWiki 一样,DokuWiki 也是用文本文件来存储 Wiki pages 的,但是 DokuWiki 的 Wiki Page 文件是纯粹的 Wiki content,而 PmWiki 的 page 文件里同时混杂了 page 的修订历史记录,其实就凭这一条就能吸引住有数据洁癖的我:) DokuWiki 这种把 page 数据和 page 修订数据分开存放的方法其实相当科学,既方便了数据备份和迁移也方便了修订数据的清理(个人认为 Wiki 的这个类 VCS feature 在某些情况下很有用,但是在另外一些场合下是完全多余的)。另外 DokuWiki 对于中文的支持比 PmWiki 要好,虽然在 DokuWiki 里对中文 page name 或者 namespace 的支持也“不好”,但是个人认为这其实不算什么缺点:) DokuWiki 的 namespace 也深得我心,namespace 在 DokuWiki 里就是给 page 进行分类的,而在存储系统里它们二者就对应着文件夹和文件,这跟我记工作日志的习惯简直太一致了!大爱!

  其它优点还包括了数量众多的 plugin 支持,强大的 ACL 控制能力等等。说到 plugin,DokuWiki 里有很多 export to PDF plugin,这个特性也非常吸引我,想想你编辑和整理的众多信息可以很轻松的做成 PDF 文件保存和分发,而且所用的编辑语法又是简单的 Wiki 语法而非天书般的 DocBook,简直是太爽了!这方面,时间关系我只尝试了 dw2pdf,而且暂时没找到支持中文的方法,最终格式效果方面也还有瑕疵,就留待以后去研究了。

  我在空间里装上了 DokuWiki,地址是 http://wiki.2ndboy.net(也可以点 blog 顶上的链接进入),今后会陆续记录一些 blog 不方便和不适合记录的东西,欢迎有空坐坐:)

Hudson 的分布式 build

2010-9-14 22:18 | by 2ndboy

  前段时间一直比较忙,最近几天利用稍稍松下来一点的时间研究了一下 Hudson 的分布式 build。同样,以下内容都只在 Windows 平台下验证通过。

  一般来说,如果项目需要在不同的平台上进行编译的话,分布式 build 就比较有用了。假设某项目需要在 Windows、Linux 和 Mac 进行编译,那么可以拿一台 Windows 主机安装 Hudson 做 master,同时进行 Windows 平台上的 build。然后再分别在一台 Linux 主机和一台 Mac 主机上配置 Hudson salve。之后就可以在 master 上创建 job,然后在不同的平台上做 build 了。

  另外一种用途就是纯粹的负载均衡了,默认情况下 Hudson 在一台主机上只允许同时进行两项 job(当然这个可以在系统设置的“# of executors”里进行修改,但是这个数字肯定是跟主机的配置情况相关的),如果你有数十个 job 需要同时做 build 的话,为了便于统一管理,这时用到分布式 build 也是个不错的主意。

  下面就是一些设置步骤的记录:

Slave 端主机的设置

Hudson 在 Windows 平台下是通过 DCOM 对 slave 进行操作的,所以首先要保证 slave 主机的 DCOM 相关 service 可以正常工作。

Master 在操作 slave 主机时需要以 slave 主机上的用户身份登录进行,所以要在 slave 主机上为 Hudson 创建一个管理员帐号。

在 slave 主机上为 Hudson 无色一个栖身之所,比如 D:\HudsonSlave。这个目录无需手工创建。

Master 端的设置

以管理员身份登录 Hudson 的 master 端,进入“系统管理”->“管理节点”->“新建节点”,如下图:
新建节点
注意“节点名称”不能随便写,因为我们后面要创建/连接的是一个 Windows 平台的节点,所以节点名称一定要用 IP 地址或者主机名称。“Dumb Slave”一定要选,否则无法继续。

新建节点的填写例子见下图:
节点设置
“Remote FS root”填写的是位于 slave 主机上的路径,就是刚才你为 slave 选的那块宝地。
“Labels”比较有用,它是用来描述 slave 的一些标签,在绑定 job 时用于标识节点,不填的话默认就是节点名称。
“Usage”有两个选项,分别是不绑定 job 和只能跑绑定 job,按照实际需要选择。
“Launch method”我们这里选择“Let Hudson control this Windows salve as a Windows service”,这样设置成功以后 slave 主机上的 slave 进程会被作为服务来运行。
“Administrator user name”和“Password”填写你在 slave 主机上为 Hudson 创建的用户名和密码即可。
保存以后 Hudson 就会尝试连接 slave 主机,然后用设置的管理员用户身份登录 slave 主机,创建 slave 目录,上传 slave 程序,把它作为 service 安装。

节点创建成功以后你就会在 Hudson master 界面左边的生成状态栏里看到 salve 了。同时在 slave 主机上你会发现 Hudson 已经建好了给 slave 使用的文件夹并且上传了一些文件,同时你会在 slave 的 service 列表里看到一个新 service,如下图:
Hudson slave service

Slave 的使用

Slave 连好以后,你就可以给它分配活儿干了。当然,这个新“奴隶”能干什么活儿跟你在创建它的时候的设置很有关系,如果你创建它的时候在 Usage 里选的是“Utilize this slave as much as possible”的话,那么普通的 job 不用做什么额外设置就可以跑在这个 slave 上了。但是如果你在 Usage 里选的是“Leave this machine for tied jobs only”的话,那么只有跟这个 slave 进行了绑定的 job 才能跑在这个 slave 上。

其实由于配置和程序安装的情况不同,一般来说让 job 跑在特定的 slave 上更常用些。把 job 跟 slave 绑定很简单,进入 job 设置,在“Tie this project to a node”里选中某个 salve(或者 master)就可以了。这样这个这个 job 以后就只能跑在某个特定的节点上了。

Slave 的删除

在 master 的管理节点页面里删掉 slave 只会让 slave 在 master 上不可见、不可用,但是 Hudson 不会对 slave 上的文件和 service 做任何删除操作。

在 slave 主机上彻底删除 slave 需要两个步骤,删除 service 和删除 slave 程序。由于 Hudson slave service 的名称里有盘符和路径分隔符,所以用“sc delete xxx”是不管用的,需要在命令行下进入 slave 目录运行“hudson-slave.exe uninstall”,之后就可以把整个 slave 目录干掉了。

后记

结合之前的那篇“用 Hudson 实现 Visual Studio (C++) 项目的 daily build”,看完这两篇 post 以后在日常工作里应用 Hudson 应该已经没什么大问题了。我陆续抽时间把我使用 Hudson 的过程写出来,希望对想要学习使用 Hudson 的同道有所帮助,同时也为这个优秀的持续集成工具的普及做些事情,Hudson 是个好东西:D