来自微芯片的摩尔斯电码
微型射频收发器上的PIC微处理器程序示例。
引言
我们将看到莫尔斯电码如何用于从一个包含LED和PIC16F886微处理器的微型IQRF(参见参考文献[1])TR-52BA板进行通信。该程序用C语言编写,并由B. Knudsen Data [2]提供的免费CC5X C Compiler for the PICmicro Devices版本3.4编译。
莫尔斯电码是塞缪尔·F·B·莫尔斯和阿尔弗雷德·威尔在176年前开发的,用于将文本信息以一系列开/关音调、灯光或咔哒声的形式传输,熟练的听众或观察者可以直接理解[3]。我们将使用莫尔斯电码广播TR-52BA [5]板的当前状态和已安装的应用程序信息。
IQRF平台和TR-52收发器
IQRF [1]是一个完整的模块化无线连接平台,基于智能收发器,价格实惠且易于使用。射频收发器[4]是集无线电发射器和接收器于一体的设备。在这个项目中,我们并不真正关心无线电连接。IQRF收发器配备了内置的PIC微控制器,我们想对其进行编程。我们将使用配备PIC 16F688微控制器的TR-52BA收发器。我们的程序应该在任何IQRF智能收发器上运行良好,此处所示的原理适用于各种PIC微控制器。
时序
莫尔斯电码由点(短促的蜂鸣声,称为“滴”)和划(较长的蜂鸣声,称为“嗒”)组成。划的长度是点的三倍,字符内的蜂鸣声之间有一个与一个点持续时间相同的停顿,字符之间有一个与一个划持续时间相同的停顿。单词之间的停顿应该持续7个点。对于更快的传输,即CODEX,点应该持续50毫秒;对于较慢的传输,即PARIS,点应该持续60毫秒。收发器计时器以10毫秒为间隔。我们将定义两个宏来方便地处理计时
// macro controls the hand speed (10*ms)
// 1 dot 60ms PARIS
// 1 dot 50ms CODEX
#define dot 6
#define dash 18
为方便和提高代码的可读性,我们将时间处理封装到三个函数中。
void pause( uns8 delay )
{
delay *= dot;
waitDelay( delay );
}
该函数接收参数delay,其中包含以点为单位的所需延迟长度。因此,我们将其乘以点宏,以获得10毫秒的倍数值,然后将该值发送给操作系统函数waitDelay()
。有关操作系统提供的所有好东西的完整列表,请参见[6]。
顺便说一句:我们正在修改程序内部的传入参数。这是良性的,C函数参数是按值传递,而不是按引用传递。
void dit()
{
_LEDG = 1;
waitDelay(dot);
_LEDG = 0;
waitDelay(dot);
}
预定义地址_LEDG
就像一个二进制变量,它与焊接在收发器绿色LED上的PIC引脚相关联。将值设置为1将点亮绿色LED。将_LEDG
设置为0将关闭灯。RT-52BA上还有一个红色LED。我们可以使用_LEDR
变量以相同的方式控制它。
我怎么知道要使用_LEDG
?IQRF提供了一个很好的开发环境,可以从[7]免费下载。预定义内存位置的描述在*memory.h*文件中。
另请注意,我们在蜂鸣声后包含了一个持续一个点长的暂停,以将该蜂鸣声与下一个蜂鸣声分开。dah()
函数与dit()
非常相似,唯一的区别是蜂鸣声更长。
void dah()
{
_LEDG = 1;
waitDelay(dash);
_LEDG = 0;
waitDelay(dot);
}
莫尔斯电码表编码
微小的PIC芯片上没有多少RAM可以浪费。因此,我们需要计划高效地将莫尔斯电码存储在内存中。莫尔斯电码仅由点和划组成,自然建议使用二进制存储,其中1表示划,0表示点。例如,字母C(划-点-划-点)将被编码为1010或十六进制的0xA。幸运的是,Knudsen的C语言进行了扩展,支持二进制字面量,您可以将其写为bin(xxxxxx)或0bxxxxxx,其中x是0或1。该语法允许使用“.”(句点)符号来分隔各个位,以提高可读性。
单个字符的莫尔斯电码长度各不相同。由于长度不超过5个蜂鸣,因此还剩下3位用于在存储代码的同一字节中存储代码的长度。我们决定将长度存储在最右边的位中。例如,字母C将是0b0.1010.100。最后3位100(十进制值4)告诉我们C的代码有4个蜂鸣。字节的中间部分“1010”是代码,最左边的额外0是一位我们没有使用的位。
将整个代码按字母顺序排序存储在数组中非常自然,有助于为给定字符选择代码。
static uns8 m[26]; // character codes
m[ 0]=0b000.01.010;//A
m[ 1]=0b0.1000.100;//B
/* and so on */
encoded_character = m[ character_to_encode – ‘A’];
我们利用了所有大写字母都是连续按字母顺序进行ANSI编码的知识。我们可以对小写字母使用相同的技巧。
一旦找到字符的代码,就可以通过将其发送到以下函数来广播它
void key(uns8 a)
{
uns8 n = a & 7; // beep count
for( n = n + 2; n > 2; n--)
{
uns8 mask = ( 1 << n );
if( a & mask )
{
dah();
}
else
{
dit();
}
}
pause(2); // 3 dots between characters, 1 was already after the beep
}
字符中的蜂鸣声数量通过掩码从代码字节中提取。数字7在二进制中是0b000111,与其进行按位AND操作会删除字节中的所有其他1。我们将值存储在变量n中
uns8 n = a & 7;
然后,我们从位置 n+2(位从右开始索引,从0开始)开始遍历代码字节中的位,并一直向下到索引3。我们不想广播用于存储和获取代码长度的最后3位。
要从代码字节中选择索引位,可以再次使用掩码。我们通过将值1左移到索引位的位置来创建掩码。
uns8 mask = ( 1 << n );
然后,如果掩码结果为1,则广播划,否则为点。
由于dit()
和dah()
函数被编写为在每次蜂鸣后插入一个持续一个点的暂停,因此我们需要添加一个持续两个点的暂停来完成字符。
代码的其他值得注意的部分
为了获取用户应用程序的状态信息,我们调用操作系统函数appInfo()
。该函数将用ANSI文本格式的信息填充bufferINFO内存的32个字节。我们遍历该缓冲区并广播存储在那里的文本。
PIC微处理器配备了看门狗定时器,作为防止死锁的保护措施[8]。如果程序长时间(在微电子世界中,4秒看起来很长)没有通知系统它处于活动状态,看门狗会重置处理器。由于我们有意延迟程序执行,因此我们需要不时地通知看门狗(“踢狗”)。我们通过调用操作系统函数clrwdt()
在广播每个字符之前完成此操作。
编程收发器
为了将所有部分整合在一起,我们使用与 IQRF IDE [7] 一起下载的名为 *template.c* 的代码模板文件。完整的代码已附上。现在我们将使用通过 USB 数据线连接到 PC 的 IQRF TR 主机 USB 模块 CK-USB-04。
- 将TR-52BA插入主机模块上的SIM卡连接器。
- 启动IQRF开发环境*iqrf_ide.exe*。
- 选择“编程”选项卡,单击“打开文件”,浏览到我们的程序,然后单击“打开”。
- 点击“编译”并检查编译报告是否有错误。应该没有错误。
- 点击“进入编程模式”并点击“上传”。一秒钟后,绿色LED将开始以莫尔斯电码显示收发器的应用程序状态。
我们的程序现在已编译并存储在收发器内存中。我们可以将TR-52BA从基本USB模块中取出,每当我们重置处理器或重新连接电源时,它都应该开始闪烁莫尔斯电码。我们仍然希望避免焊接,因此我们将已编程的收发器放入另一个内置蓄电池的IQRF基本模块DK-EVAL-04中。现在我们可以走到朋友们面前,用闪烁莫尔斯电码的小灯给他们留下深刻印象。
注释
我们的程序仅适用于英文大写/小写字母和空格字符。任何其他字符都将被忽略。有一天我们可能会扩展该程序以涵盖完整的莫尔斯电码。
参考文献
[1] IQRF无线平台 http://IQRF.ORG
[2] B. Knudsen Data 的 PICmicro Devices CC5X C 编译器 3.4 版 http://www.bknd.com/cc5x/
[3] 维基百科莫尔斯电码文章(2012年2月版) http://en.wikipedia.org/wiki/Morse_code
[4] 维基百科PIC微控制器文章(2012年2月版) http://en.wikipedia.org/wiki/PIC_microcontroller
[5] IQRF分销 http://IQRF.us
[6] IQRF OS 3.0 功能 http://iqrf.us/functions.html
[7] IQRF下载包括IQRF IDE开发环境,带有示例代码和新项目模板 http://iqrf.com/weben/index.php?sekce=support&id=download
[8] 维基百科看门狗定时器(2012年2月版) http://en.wikipedia.org/wiki/Watchdog_timer