[Shell]串口校时脚本

Photobucket

通过串口来给单片机时钟校时,是我特别喜欢的功能,我写的时钟程序(包括TCA1602TC8)基本都有这个功能。最早用C#做console应用来写,然后用ruby脚本实现。而既然最近在学习使用 Shell 来实现一些简单的应用,当然早就想着用纯shell脚本来实现这样的功能。

用C#的优点是 IDE 很强大,借助各种代码补齐,很快就能实现功能,缺点是使用环境基本仅限于 windows 平台,而我现在已经越来越少碰 windows了,而且还是需要编译,调试什么的都算麻烦。Ruby脚本的话,优点自然就是跨平台,无需编译,不过又感觉还是有点“拿电线杆吃面”的味道——大材小用。能用 Shell 实现自然最好,虽然某种意义上来说,抛弃了 windows 平台,但对于我个人来说关系不大,毕竟现在的开发都是在 Ubuntu Linux 下完成,而且我也希望借着展现 Linux | Shell 平台的强大,让更多的朋友开始接触 Linux ,并开始学习使用。学习 Shell 是个很有意思的过程,因为可以调用的命令实在太多了,而在这些命令,基本在终端上就可以尝试调用,记得在旁边再开一个 man 页面,三两下就大概知道这个命令是怎么一回事。而当了解到这些命令以后,不单在脚本中能发挥作用,在日常的终端操作上也能排上用场。这和调用什么类库、函数库、Gem是完全不一样的感觉和效果。Ruby脚本的运行,也要以安装ruby为前提;而Shell脚本,尤其是只用到bash命令的脚本,只要在最简的Linux平台上,尤其是嵌入式平台上都能直接运用。

#!/bin/bash
# filename: SerialTiming.sh
# Description: To sync the RTC chip on Arduino, which needs correspondent program.
# Author: Weihong Guan (@aGuegu)
# blog: http://aguegu.net

port=${1:-"/dev/ttyACM0"}
baud=${2:-"9600"}

stty -F $port $baud cs8 -cstopb -parenb cread clocal
exec 3> $port
sleep 2

date +"[%T %D %w]" >$port 
printf "mcu reply: \e[1;34m"
sleep 2
head $port -n 2
echo -e "\e[0mdone."

exec 3>&-

这里又有几个要点:

1. 把数据发送给串口,可以直接使用重定向实现,既然所有的设备都是文件,可以把串口设备 /dev/ttyACM0 或 /dev/ttyUSB0 理解为类似与/dev/null、/dev/zero 这样的设备。

stty settings

2. 难点是串口的设置,而这些可以通过 stty 命令来实现,咋一看,好像配置很简单,但实际上加上 -a (全显)参数,立马就晕了。很多参数的意义及功用,现在还不太了解。就一般意义的串口通讯来说,主要的参数包括“波特率”、“数据位”、“停止位”、“校验位”。波特率可以直接写,cs8 表示数据位为8位,-cstopb 表示停止位为1(如果不带’-‘,则停止位为2),-parenb 表示校验位不使能。如果不带这些参数,则默认参数可能和我们所需要的不一致,造成无法正常通讯。

3. 熟悉Arduino的默认硬件平台的,都比较清楚,Arduino会通过串口芯片的DTR引脚实现一个打开串口时的“硬复位”,方便程序的下载。如果单纯使用重定向发送数据的话,数据基本在芯片的复位过程中就发完了。“打开串口”的操作,可以通过重定向文件描述符的方法实现。并通过一个sleep延时,避过芯片复位。如果已经屏蔽了硬复位,那么重定向和这个延时都会显得多余。

4. 单片机通过串口返回的数据,也可以通过 head 打印出来,用 cat 会造成操作无法结束的问题,有点诡异。在这里一样也加上延时,是给数据返回的时候,毕竟9600的波特率速度还是很慢,而且我的反馈字符串中会完整打印新的日期时间,所以多给一点时间。在打印过程中,我还加上了颜色设置,让Arduino的返回更加明显一些。

Photobucket

5. 最后记得重新恢复重定向,否则会导致设备占用。

这个Bash版本的校时报文格式为“[HH:MM:SS MM/DD/YY W]”,和过去的几个版本是不同的,所以也不能和过去的相应硬件相兼容。过去C#的时候,数值使用字节数据进行发送,这样在下位机(单片机)程序最简单,上位机(PC)的程序相对复杂,需要将系统时间转化为字节数据。Ruby的版本中,将字节数据改为文本数据,这样下位机需要进行文本数据到字节数据的转换,而且数据量更多一些,比方说,原来发送“34”这个数据,按字节只需要发送一个字节”0x22″,而按文本发送需要发送’3’、‘4’两个字节,但是这样上位机能实现就变得很简单,只需要发送一个格式化过的日期时间字符串即可,使用脚本即能轻松实现。因为使用的是文本,使用一般的串口助手,终端工具(minicom,screen,putty)都可以实现交互,为命令内容的自定义也提供方便。

因为 bash 是最基本命令“接口”,这个脚本稍微改造,就可以用在嵌入式Linux系统,比方说树莓派或MK802上,毕竟在ARM平台上直接为各种传感器等周边元件寻找或配置驱动还相对比较困难,而这又正是Arduino平台的优势,通过串口搭建Arduino与ARM之间的沟通桥梁,进行数据交互就更加简单。不烦把本例中的校时报文理解为Linux对Arduino的查询指令,而将Arduino的返回理解为查询结果,这样就实现了一个嵌入式Linux平台与Arduino实现交互的系统原型。

视频中的硬件,由圣源电子提供:
Arduino UNO
Ds132 时钟模块
LCD1602 on I2C

代码及脚本托管地址:https://github.com/aguegu/nixie-tube/tree/master/Ds1302

参考资料:

关于aGuegu

向着更高的逼格
此条目发表在Shell, 时钟分类目录,贴了, , , , , , , , 标签。将固定链接加入收藏夹。
  • sunny

    我向清华推荐了你们的产品,赶紧邮件联系