PIC微控制器

PIC是Microchip公司生产的微控制器,有8位、16位、32位的型号。其中PIC12系列为8引脚8位微控制器,它的引脚数非常少,很适合做一些小型项目。例如最简单的流水灯,如果用微控制器来做,那么就不需要其他IC芯片了(振荡器为微控制器自带,而移位寄存器的功能可以用软件实现)。

我有一片PIC12F629和一片PIC12F675。两者功能基本一致,后者多了A/D功能。之前我尝试自制PIC编程器给629编程,试了很久也没有成功,只好买了一个正规的编程器来用,结果发现629似乎被我折腾坏了。现在只剩下一片675,我用它制作了两个小项目:音乐播放器和字符显示器。

图中:上为字符显示器,下为音乐播放器。音乐播放器中的PIC芯片被拔下来了。

继续阅读 →

使用PSTricks作图

制作需要打印的文件的时候,插图的分辨率一定要足够高,否则看起来的效果十分恶心:

像这种在屏幕上显示就已经糊了的图(可能是在放大比例不正确的情况下通过截图得到的),打印出来更是惨不忍睹。

文档中许多非照片类的插图,如示意图、流程图等,可以用PSTricks来画,画出来的是高质量的矢量图,这样就无需关心分辨率的问题。

下图是我用PSTricks画的同一个零件的图纸。实际上,对于零件图纸,我觉得最好的方案是直接用CAD软件导出矢量图(SVG或者PostScript),非常省事。(但是似乎不是所有CAD软件都有导出矢量图的选项。)

继续阅读 →

快速二-十进制转换

TL;DR

将计算机内部存储的二进制数值转换为十进制以供输出是一件常见的工作。在一些场合,需要大量进行这种转换,这时希望速度能尽可能地快。

二–十进制转换大量用到整数除法和取余运算。朴素的教科书算法是这样的:

do {
	putchar(n % 10);
	n /= 10;
} while (n);

当然,输出是逆序的。这并不是什么本质的问题,实际代码再加上逆序的处理就可以了。

这种做法每个循环计算一次取余和一次除法。我现在有一个硬件(Nios II/e),没有硬件乘法器和除法器。乘除运算使用软件模拟,速度非常慢。软件模拟的除法,并不能同时得到商和余数。也就是说,为了得到商和余数,除法会被计算两遍。(这是编译器的优化问题,理论上可以通过改进编译器的优化能力解决)。

继续阅读 →

软件控制数码管动态扫描显示

TL;DR

数码管一般用来显示的数字,通常由7个笔画构成(有的还有1个小数点),所以也称为7段数码管。之前构建的Nios II系统就用了6个数码管输出信息。

传统上,要使用数码管,需要译码器将二进制编码的数字转换成7个笔画的编码,例如TTL的7447和CMOS的4511集成电路。

给每个数码管配置一个译码器,并且将每一位数字同时传送到各译码器上,这种方案叫做静态显示。静态显示原理简单,但是浪费硬件资源。

将译码器分时复用则构成动态显示电路:在一个时刻只点亮一个数码管,并使用一个扫描电路轮流扫描各个数码管。当扫描频率足够高时,显示的效果就像是所有数码管同时都被点亮。

继续阅读 →

TCP聊天室

我用Go编写了一个简单的聊天室程序。这个程序分为服务器端和客户端两部分。

服务器端用于监听主机上的端口,以便接受来自其他主机的连接。建立连接后,服务器从客户端处收集消息,然后广播到所有客户端。

客户端用于消息的输入和显示。当成功建立起到主机的连接后,输入的消息将被发送至服务器,而服务器发来的消息将被显示在屏幕上。

我用termui编写客户端的界面。虽然还有一些小问题,总体来说效果不错。

继续阅读 →

GNU Privacy Guard

GNU Privacy Guard简称GnuPG或GPG,是一款密码学工具。许多Linux系统上自带的gpg命令就是它。其最重要的功能是对数据进行加密、解密和签名。此外还带有密钥生成和管理功能。

GPG区别于一般加密工具的地方在于其使用非对称加密机制。加密时,使用收件人的公开密钥,该密钥公开发行可供所有人使用。解密时,使用收件人的私有密钥,该密钥由收件人严密保管。这样,收件人无需和发件人商定密码,就可以安全地通信。

签名是确保信息完整性的办法。使用发件人的私有密钥进行签名,其他人无法伪造,但所有人均可使用发件人的公开密钥进行验证。

我用GPG生成了一个密钥对,公共密钥已经上传到密钥服务器上,大家可以通过

gpg --recv-keys 0DB87340

下载这个密钥。其指纹为

2252 7AF4 8AFB 5635 72EC  AC4D 895C 7F46 0DB8 7340

理论上,如果有人要冒充我的身份,只需创造一个虚假的密钥上传到服务器,然后入侵存放这个页面的服务器,纂改上面的密钥编号和指纹。

当然要这么做也有一定难度,总之小心为好,导入密钥的时候务必需要通过可靠的方式(例如,当面)和密钥的持有人进行确认,然后对它签名,以示信任。

继续阅读 →

十二平均律

相差八度的两个音,在频率上相差了一倍。例如,A4的频率为440Hz,而A5的频率为880Hz,A3的频率则为220Hz。人耳听起来“距离相等”的若干个音,频率并非成等差数列,而是成等比数列。

“八度”的称谓源于八个频率递增的音,例如

C4 D4 E4 F4 G4 A4 B4 C5

它们构成C大调音阶,唱作do re mi fa so la si do(高)。有意思的是,音阶中的各个音也不是“等距离”分布的。音乐老师说过,mi和fa、si和do之间只相差半音,而其他相邻的音之间相差全音。

相差全音的两个音之间,还存在一个音,和这两个音的距离都是“半音”。例如,C4和D4之间的音,可以记作C♯4或者D♭4。如果把这些音也插进音阶里,就变成了13个音:

C4 C♯4 D4 D♯4 E4 F4 F♯4 G4 G♯4 A4 A♯4 B4 C5

这样一来,相邻的音的“距离”都相等。也就是说,这些音的频率成等比数列。相隔12个间隔的两个音的频率为2倍关系,即\(q^{12}=2\),\(q\)为公比,或者说是相邻两个音的频率之比。由此得\(q = \sqrt[12]{2}\approx 1.059463\)。这个规律最早由明朝的朱载堉提出,现在称为十二平均律

知道了十二平均律,再根据一个基准音的频率(如A4为440Hz),就可以推算出所有音的频率。

继续阅读 →

多重继承和虚基类

多重继承是面向对象编程(Object Oriented Programming, OOP)中的一个有争议的话题。并非所有OOP语言都支持多重继承(Java和C#均不支持)。C++作为万能语言是支持多重继承的典型例子,即便如此,一些C++的开发框架,例如MFC,也从不使用多重继承特性。Go虽然很少用到复杂的继承,但是它本身是支持多重继承的。

我想从对象的存储方式角度来分析多重继承和虚基类的问题。C++在这方面有些故弄玄虚,一个virtual关键字弄得让人有些摸不着头脑。Go的设计在提供多重继承功能的同时,也非常明确地指出了对象在内存中的存储形式,理解起来也容易许多。

继续阅读 →

幻方生成器

幻方(magic square)是休闲数学(recreational mathematics)所感兴趣的话题。相传在古代曾有神龟浮出水面,背上有图案,称为《洛书》:

载九履一,左三右七,二四为肩,六八为足,五居中腹。

这是一个3阶幻方,如下所示。它的特点是每行、每列、每条对角线上的数字之和都相等。

4 9 2
3 5 7
8 1 6
继续阅读 →