[摘要]: 本文描述了一种利用华邦四位机来设计带有农历24节气的万年历的设计方法,同时对于其中软件的算法和硬件的电路设计进行了计算和分析。
[关键字]:节气, 列表法, 微处理器, 单片机, 算法
在当前的产品设计中,人们在追求产品高性能的同时,也在追求产品的低成本。这就对开发工程师提出了更高的要求。
对于万年历的产品市场上已经有了很多,但是带有农历24节气,同时用LED数码管显示的万年历在市场上的销售价明显偏高,究其原因是因为如果将农历24节气设计加入其中,就要增加软件程序,这样就会使相应的程序存贮空间加大,自然硬件成本就会随之增加。所以,最好可以找到一种既可以实现其功能,又可以节约成本的单片机来实现。
以下就是丰宝电子科技公司开发部门研发出的一种只是利用的华邦的四位机就可以实现的带有农历24节气的万年历的产品设计思路,由于用的是4位机,它的ROM空间和RAM空间比起8位机就少得多,这样对软件的设计提出了更高的要求,要求能够找到适合4位机上使用的简易算法。
对于阳历农历的算法比较简单,而且规律很容易找到。这里就不再赘述。我们这里重点讨论一下对于农历中二十四个节气的算法。还考虑到单片机的性能情况和万年历的使用寿命,我们设计的是有限年(如50年)万年历,因此这里我们的算法也是按着50年为年限来设计。
一、万年历农历节气算法:
为了便于考察50年的无规律的农历节气分布时间,我们利用C语言在计算机中,实现了50年(2000~2049年)的阳历和农历节气分布时间表。由于数据庞大,所以仅仅列出其中部分阳历年对应的前6个节气日期,简表见表1。
这张复杂冗长的节气表中,每年的节气具体日期虽然都在一定的范围内变动,但是变动的趋势毫无规律可寻,每个月的具体节气日期有时候推前一两天,有时候推后一两天。
但是,从这张复杂的表格中的众多数据中,我们发现这样一个规律:虽然,这些节气的日期变化趋势无法获得,但是,这些日期的变化总是在3天之内变化的。
表格1、阳历年中农历节气日期表
| 年\月 | 1 | 2 | 3 | 4~12 |
| 2000 | 6 21 | 4 19 | 5 20 | 上半月节气日期 下半月节气日期 |
| ⋯⋯ | ⋯⋯ | |||
| 2043 | 5 20 | 4 19 | 6 21 | 上半月节气日期 下半月节气日期 |
| 2044 | 6 20 | 4 19 | 5 20 | 上半月节气日期 下半月节气日期 |
| 2045 | 5 20 | 3 18 | 5 20 | 上半月节气日期 下半月节气日期 |
| ⋯⋯ | ⋯⋯ | |||
| 2049 | 5 19 | 3 18 | 5 20 | 上半月节气日期 下半月节气日期 |
例如:每年的第一个节气(小寒)出现的1月的5日,6日两天中的某一天;每年的第二个节气(大寒)出现在1月的20日,21日,19日三天中的某一天。
这样,我们只要固定每个节气的基本日期,然后专门针对这两三天编制一个相对日期的表格就可以了。考虑到最多变化范围是3天,所以这个相对日期可以取值为1、0和-1。
我们选定的基本日期如下:
- 一月到三月的节气基本日期: 6/20 、4/19、 6/21;
- 四月到六月的节气基本日期: 5/20 、6/21、 6/21;
- 六月到九月的节气基本日期: 7/23 、8/23、 8/23;
- 十月到十二月的节气基本日期:8/24 、8/22、 7/22;
- 四月到六月的节气基本日期: 5/20 、6/21、 6/21;
根据以上的思想,我们得到了下面的表格2。
并且,仔细观察表2,我们还可以得到以下关于节气日期相对值的规律性结论:
- 1、 只有以下四个节气(2、12、19、22)同时出现三个相对值(1,-1和0)的情况。
- 2、 其它的20个节气中仅仅出现了0和-1这两个相对值。
- 3、 在有三个相对值的四个节气(2、12、19、22)中,2044年以前,出现的非零相对值都是1;而2044年以及2044年以后,出现的非零相对值都是-1;
表格2、阳历年中农历节气日期固定日期和相对值表
- 2、 其它的20个节气中仅仅出现了0和-1这两个相对值。
| 阴历 节气 | 1 2 | 3 4 | 5 6 | 7~23 8-24 |
| 阳历 年\月 | 1 | 2 | 3 | 4~12 |
| 基本 日期 | 6 20 | 4 19 | 6 21 | 上半月节气日期固定值 下半月节气日期固定值 |
| 2000 | 0 1 | 0 0 | -1 -1 | 上半月节气日期相对值 下半月节气日期相对值 |
| ⋯⋯ | ⋯⋯ | |||
| 2043 | -1 0 | 0 0 | 0 0 | 上半月节气日期相对值 下半月节气日期相对值 |
| 2044 | 0 0 | 0 0 | -1 -1 | 上半月节气日期相对值 下半月节气日期相对值 |
| 2045 | -1 0 | -1 -1 | -1 -1 | 上半月节气日期相对值 下半月节气日期相对值 |
| ⋯⋯ | ⋯⋯ | |||
| 2049 | -1 -1 | -1 -1 | -1 -1 | 上半月节气日期 下半月节气日期 |
也就是说在50年内,大寒(2)、夏至(12)、寒露(19)和小雪(22)这四个节气日期变化相对较多,一共有3天,它们的日期相对值可能需要使用三个状态值来表示。
下面是以上三条农历节气日期规律的相对值分布简图。

图1、农历节气日期相对值分布简图
根据表格2和图1所示意的农历节气日期排布规律和形式,我们就可以构造一个表格,并且结合相应的算法来计算某个阳历日期所对应的阴历节气了。
利用上节分析结果,我们设想使用最少的字节来编制一个表格,使得它包含了50年内的所有相对值分布信息。由于一年包含农历的24个节气,也就是说共有24个日期相对值状态量。
为了能够尽量减少存储空间,我们使用一个位来代表一个农历的节气日期相对值。这样1年的24个节气就可以用24个位来表示,也就是3个字节(每个字节8个位)表示。
由于农历节气日期相对值最多有三种状态:-1、0和1,而一个位仅仅有2种状态:0和1,为了能够把3种状态融合进两种状态中 ,我们根据上节中节气日期相对值的规律性结论,采取了具有条件的二值状态来表示三值状态,制定了如下的编码规则:
表格3、位状态编码规则
| 位值 | 节气日期相对值 | 备注 | ||
| 0 | 0 | 适合于表格的50年所有节气 | ||
| 1 | 1 | 适合于2044年以前的2、12、19、22四个节气 | ||
| -1 | 2044年和其后的2、12、19、22四个节气 以及其它20个节气 | |||
利用以上的规则我们就可以对于50年的24个节气进行编码,得到如下的编码表:
表格4、最终的编码表
| 年份 | LBA表值 |
| 2000 | 4E A6 99 |
| 2001 |
9C A2 98 |
| 2002 |
80 00 18 |
| 2003 | 00 10 24 |
| ⋯⋯ | ⋯⋯ |
| 2042 | 9E A2 98 |
| 2043 | 80 82 18 |
| 2044 | 0F EF FB |
| 2045 | BF E6 D9 |
| 2046 | 9E A6 98 |
| 2047 | 80 82 18 |
| 2048 | 0F FF FF |
| 2049 | FC EF D9 |
由此看出,使用这种编码的方式对农历日期相对值进行编码方法,一年的24个节气的日期只需要3个字节表示就可以明确表示了。50年的节气表,只需要150个字节的存储空间。年份越多,这种编码发方式能够节约的存储空间越大,优势越明显。
二、万年历的硬件实现
我们使用的单片机是华邦公司的四位机。这种单片机的结构跟8位机的类似,虽然它的功能不如8位单片机。但是,它具有结构简单、成本低的优势,同时还包括了普通单片机的基本功能。它包含了128个字节的RAM,2k的ROM,定时器,外部中断,内部中断,此外,还有省电功能和驱动LED的功能。下图就是利用华邦四位机W741E260实现万年历功能的原理框图,

其中,对于阳历日期,农历日期的显示,是利用LED数码显示来实现,而对于二十四节气则是利用24个发光二极管,在制做外观模具时,可以将二十四节气标志在外观模具上,如果到了相对应的节气,相应的发光二极管就会点亮。
利用了此方案实现 ,就用一个华邦的4位机,硬件成本就可以大大降低。
三、万年历的软件实现
由于万年历的其它的功能程序已经占用了较大的存储空间。所以能够用于农历节气查询的程序的空间不大,仅仅有0.5k的容量。也就是说表格和查表程序一共只有0.5k的空间,表格占用的空间越大,可写程序的空间就越小。
如果使用把50年农历24节气日期表格1,仅仅表格就需要使用50×24个字节=1200个字节的存储空间,其要求空间远远超出了0.5k的容量。而使用编码方法得到的表格,只需要150个字节,存储空间仅仅是表格1所需存储空间的1/8,其它剩余的部分可以供查表的程序使用。
在单片机中,查表程序是使用汇编程序完成的,实现起来也很容易。为了便于理解,我们在这里把查表程序用C语言实现的部分编写如下:
输入参数是阳历的年月日:day,month,year,要求查表寻找它附近的农历节气和农历节气的日期。
if(day >= 15 ) half_mon = 1; //判断是否是上半月
else half_mon =0;
col = (month-1) *2 + half_mon;// 获得节气顺序标号(0~23)
kc_byte = col/8; //获得节气日期的相对值所在的字节位置(0~2)
kc_bit = col%8; //获得节气日期的相对值在字节中的位位置(0~7)
tmp_modi = modi_datas[year-2000][kc_byte];
//获得节气日期相对值所在字节
value = ( (tmp_modi << kc_bit) & 0x80 ); // 获得节气日期相对值状态
if( value != 0 ){//判断年份,以决定节气相对值1代表1,还是-1。
if( (col== 1 col== 11 col== 18 col== 21) && year < 2044)
J_qi = days[col] +1;//年份<2044的四个特定月份中,取+1。
else
J_qi = days[col] -1;//其他情况下,取-1。
}
else
J_qi = days[col];//状态为0,节气日期相对值为节气基本日期值。
从而获得了输入阳历日期(年月日)附近的节气准确日期值。
通过上面的编码和查询的方法,我们实现了基于四位单片机的万年历的研制和实现。它用汇编程序方便地实现了阴历24节气功能,同时还可以方便地算出某年的某天距离下一个节气的天数。
从上面可以看出,此算法思路清晰明了,实现起来非常方便,节省了大量的ROM空间,最重要的是节省了成本,只需要一片四位单片机加一点外围电路就可以实现这些功能。
