狗趴(GodPub),开源硬件学习与实践

标题: 【Joytag 小项目】智能小终端 (设想) [打印本页]

作者: 卓泰科技    时间: 2015-2-17 23:00
标题: 【Joytag 小项目】智能小终端 (设想)
话说,一直想做这么个小东西。
主要功能用来显示时间。
既然都能显示时间了,那么加个闹钟功能貌似也不过分。
如果再加上星期、农历以及节气等,听起来似乎更加高大上。
然后如果加上天气预报显示,是不是会更加方便?
既然有预报了,那么要不要加个室内外温度度的实时数据呢?
然后.....

然后就整日沉浸在空想中,始终未能动手。
时间就这样流逝了,时钟还未诞生......

群里一哥们正在做一个时钟万年历,所以又勾起我做这个小终端的兴致。
那么先来明确一下需求吧:

显示功能

设置功能


报警功能


基本方案

显示部分:

首先,因为要显示的内容比较多,所以摒弃1602等方案。
初步计划使用手头现有的串口液晶模块(使用比较方便)

设定部分:

使用按键比较麻烦,所以计划通过网络设置。
基本方案为使用ESP8266 WIFI模块将终端接入家庭网络。
时间设定部分,采取NTP自动校时。
其余设置部分:
1)终端使用AP+STA模式,自带web配置界面?
2)类似虚拟主机web界面,将数据存入,终端前去获取?
3)智能路由器方案
4)其它

时间存储以及农历显示
使用现有的RTC模块完成
(节日节气,应该可以自己查表实现)

天气预报:
难点在于如何找到可用并且稳定的数据源

报警功能:
报警功能计划使用声光报警两种方式
可以通过蜂鸣器报警以及LED闪烁实现。
另外,可以通过控制屏幕字体、背景等颜色,来显示温湿度超限等信息。

其它:
待补充


作者: 囧囧-科技大神粉    时间: 2015-2-17 23:48
一个1602不行,来2个如何?还不行就3个,反正i2C,屏多线少



作者: 卓泰科技    时间: 2015-2-20 20:32
囧囧-科技大神粉 发表于 2015-2-17 23:48
一个1602不行,来2个如何?还不行就3个,反正i2C,屏多线少

买不起好多1602

作者: 卓泰科技    时间: 2015-2-20 20:51
RTC

查了一下自己手头的器件

RTC模块有三款

后两款使用I2C接口,貌似后边一种更高端,决定先用这个。


DS3231模块

模块参数:



接线说明(以Arduino uno r3为例):




作者: 卓泰科技    时间: 2015-2-20 21:05
DS3231简单例子:

DS3231_TEST.ino
  1. /*
  2. DS3231_test.pde
  3. Eric Ayars
  4. 4/11

  5. Test/demo of read routines for a DS3231 RTC.

  6. Turn on the serial monitor after loading this to check if things are
  7. working as they should.

  8. */

  9. #include <DS3231.h>
  10. #include <Wire.h>

  11. DS3231 Clock;
  12. bool Century=false;
  13. bool h12;
  14. bool PM;
  15. byte ADay, AHour, AMinute, ASecond, ABits;
  16. bool ADy, A12h, Apm;

  17. byte year, month, date, DoW, hour, minute, second;

  18. void setup() {
  19.         // Start the I2C interface
  20.         Wire.begin();
  21.         Clock.setSecond(50);//Set the second
  22.         Clock.setMinute(59);//Set the minute
  23.         Clock.setHour(11);  //Set the hour
  24.         Clock.setDoW(5);    //Set the day of the week
  25.         Clock.setDate(31);  //Set the date of the month
  26.         Clock.setMonth(5);  //Set the month of the year
  27.         Clock.setYear(13);  //Set the year (Last two digits of the year)
  28.         // Start the serial interface
  29.         Serial.begin(115200);
  30. }
  31. void ReadDS3231()
  32. {
  33.   int second,minute,hour,date,month,year,temperature;
  34.   second=Clock.getSecond();
  35.   minute=Clock.getMinute();
  36.   hour=Clock.getHour(h12, PM);
  37.   date=Clock.getDate();
  38.   month=Clock.getMonth(Century);
  39.   year=Clock.getYear();
  40.   
  41.   temperature=Clock.getTemperature();
  42.   
  43.   Serial.print("20");
  44.   Serial.print(year,DEC);
  45.   Serial.print('-');
  46.   Serial.print(month,DEC);
  47.   Serial.print('-');
  48.   Serial.print(date,DEC);
  49.   Serial.print(' ');
  50.   Serial.print(hour,DEC);
  51.   Serial.print(':');
  52.   Serial.print(minute,DEC);
  53.   Serial.print(':');
  54.   Serial.print(second,DEC);
  55.   Serial.print('\n');
  56.   Serial.print("Temperature=");
  57.   Serial.print(temperature);
  58.   Serial.print('\n');
  59. }
  60. void loop() {
  61.   ReadDS3231();
  62.   delay(1000);
  63. }
复制代码

AT24C32_TEST.ino
  1. #include <Wire.h> //I2C library

  2. void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  3.     int rdata = data;
  4.     Wire.beginTransmission(deviceaddress);
  5.     Wire.write((int)(eeaddress >> 8)); // MSB
  6.     Wire.write((int)(eeaddress & 0xFF)); // LSB
  7.     Wire.write(rdata);
  8.     Wire.endTransmission();
  9.   }

  10.   // WARNING: address is a page address, 6-bit end will wrap around
  11.   // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
  12.   void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  13.     Wire.beginTransmission(deviceaddress);
  14.     Wire.write((int)(eeaddresspage >> 8)); // MSB
  15.     Wire.write((int)(eeaddresspage & 0xFF)); // LSB
  16.     byte c;
  17.     for ( c = 0; c < length; c++)
  18.       Wire.write(data[c]);
  19.     Wire.endTransmission();
  20.   }

  21.   byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  22.     byte rdata = 0xFF;
  23.     Wire.beginTransmission(deviceaddress);
  24.     Wire.write((int)(eeaddress >> 8)); // MSB
  25.     Wire.write((int)(eeaddress & 0xFF)); // LSB
  26.     Wire.endTransmission();
  27.     Wire.requestFrom(deviceaddress,1);
  28.     if (Wire.available()) rdata = Wire.read();
  29.     return rdata;
  30.   }

  31.   // maybe let's not read more than 30 or 32 bytes at a time!
  32.   void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  33.     Wire.beginTransmission(deviceaddress);
  34.     Wire.write((int)(eeaddress >> 8)); // MSB
  35.     Wire.write((int)(eeaddress & 0xFF)); // LSB
  36.     Wire.endTransmission();
  37.     Wire.requestFrom(deviceaddress,length);
  38.     int c = 0;
  39.     for ( c = 0; c < length; c++ )
  40.       if (Wire.available()) buffer[c] = Wire.read();
  41.   }
  42.   void setup()
  43.   {
  44.     int addr=0,i;   
  45.     Wire.begin(); // initialise the connection
  46.     Serial.begin(9600);   
  47.     Serial.println("Write:");
  48.     for(i=0;i<26;i++)
  49.     {
  50.      i2c_eeprom_write_byte(0x57,addr,i+65);
  51.      addr++;
  52.      addr=addr%26;     
  53.      Serial.print(char(i+65));
  54.      delay(10); //add a small delay
  55.     }
  56.     Serial.print('\n');   
  57.   }

  58.   void loop()
  59.   {
  60.     int i,b;
  61.     int addr=0; //first address   
  62.     Serial.println("Read:");
  63.     for(i=0;i<26;i++)
  64.     {     
  65.       b = i2c_eeprom_read_byte(0x57, i); //access an address from the memory
  66.       Serial.print(char(b));  
  67.   }
  68.      Serial.print('\n');
  69.     delay(2000);
  70.   }
复制代码

Arduino库以及芯片资料:
DS3231 Arduino库: DS3231.zip (5.87 KB, 下载次数: 2)
DS3231 芯片资料: DS3231.pdf (361.01 KB, 下载次数: 1)
AT24C32芯片资料: 24C32.pdf (209.71 KB, 下载次数: 0)

作者: 卓泰科技    时间: 2015-2-20 21:26
关于闰年

因为万年历(农历)问题涉及到闰年,这个是小学生的知识,但是早就还给体育老师了。所以复习了一下。


闰年知识

闰年(Leap Year)是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的。补上时间差的年份为闰年。
闰年有366天。

通常的解释是说一年有多少天多少小时多少分,取整数365还有多余的,累积达到一天24小时后,就多加一天的年是闰年。这个解释只是告诉了大家怎么计算,是人为设置的东西。

最根本的原因是:地球绕太阳运行周期为365天5小时48分46秒(合365.24219天)即一回归年(tropical year)。公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为四年累计一天,故四年于2月加1天,使当年的历年长度为366日,这一年就为闰年。现行公历中每400年有97个闰年。按照每四年一个闰年计算,平均每年就要多算出0.0078天,这样经过四百年就会多算出大约3天来。因此每四百年中要减少三个闰年。所以公历规定:年份是整百数时,必须是400的倍数才是闰年;不是400的倍数的年份,即使是4的倍数也是平年。

这就是通常所说的:四年一闰,百年不闰,四百年再闰。 例如,2000年是闰年,1900年则是平年。

公历闰年计算

(按一回归年365天5小时48分45.5秒)
①、普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1900年不是闰年)
②、世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
③、对于数值很大的年份,这年如果能被3200整除,并且能被172800整除则是闰年。如172800年是闰年,86400年不是闰年(因为虽然能被3200整除,但不能被172800整除)(此按一回归年365天5h48'45.5''计算)。

根据需求,我们只需考虑简单的情况。


计算方式

符合如下条件为闰年,否则为平年:
if((year%4==0 && year%100!=0) || year%400==0)



作者: 卓泰科技    时间: 2015-2-20 23:00
公历农历转换

百度了一下,没发现啥简单的算法。
一般公历农历转换代码的本质都是查表。

网上找到几组,贴过来以免忘记


1)最精简的公历农历转换程序(C源程序)
原帖地址:http://bbs.21ic.com/icview-137951-1-1.html
此程序为本人所写,免费供有需要的人使用,无版权纠纷;
程序的功能是输入2000年2月5日(正月初一)至2100年12月31日之间的公历日期,输出对应的农历日期(闰月以月份+128表示);
该程序比较精简,适合资源紧张的MCU场合。由IAR编译成MSP430的目标代码,大约占用600个字节的程序空间,如改用汇编,去除多余的头尾,应该可以缩减到500字节以内;

程序特色在于用101个16位字表述了101年的农历大小月及闰月的数据。低12位表示对应12个月的月大或月小,最低位为正月,1表示月大;高4位为0时表示当年及下一年无闰月;高4位为1~12时表示下一年度的相应月存在闰月;高4位为13或14时,分别表示当前年的闰月为月小或月大。按照这个结构可以扩充到更多年份,但程序中对非闰年的公历1900,2200,2300,2500年份未作处理,仅对2100作为特例处理。另外,扩展到更多年份后某些变量可能存在溢出。
为简化程序,在转换函数内对输入日期的合法性未作判别,如输入1810-2-15、2008-6-31、2135-1-1等,将导致不可预料的输出结果。
提醒:程序仅对二三十个比较典型的日期进行了抽样测试,未做逐月验证,对于相近农历月大小颠倒的情况不能排除,如作为产品使用,请再次确认转换表数据的正确性。

//Lunar calendar convert program
//Designed by QQ984809120, 2009-10-6
/*
convert table(2000~2100) structure:
D15~D12=0000  Current and next year no leap month
D15~D12=0001~1100 leap month number of next year
D11~D0 = days of 12 months, 1: 30 days; 0: 29 days
D15~D12=1110  30 days in leap month of current year
D15~D12=1101  29 days in leap month of current year
*/
const unsigned int table[101] = {0x4693,
0xDA9B, 0x052B, 0x2A5B, 0xDAAE, 0x756A, 0xDDD5, 0x0BA4, 0x5B49, 0xDD53, 0x0A95,
0x452D, 0xD55D, 0x9AB5, 0xDBAA, 0x05D2, 0x6DA5, 0xEE8A, 0x0D4A, 0x4C95, 0xDA9E,
0x0556, 0x2AB5, 0xDADA, 0x66D2, 0xD765, 0x0725, 0x564B, 0xD657, 0x0CAB, 0x355A,
0xD56E, 0xBB69, 0xDF52, 0x0B52, 0x5B25, 0xDD2B, 0x0A4B, 0x54AB, 0xD2BB, 0x05AD,
0x2B6A, 0xDDAA, 0x7D92, 0xDEA5, 0x0D25, 0x5A55, 0xEA4D, 0x04B6, 0x35B5, 0xE6D2,
0x8EC9, 0xDF92, 0x0E92, 0x6D26, 0xE516, 0x0A57, 0x44D6, 0xE365, 0x0755, 0x3749,
0xD74B, 0x7693, 0xDAAB, 0x052B, 0x5A5B, 0xDABA, 0x056A, 0x4B65, 0xDBAA, 0x8B4A,
0xDD95, 0x0A95, 0x652D, 0xD56D, 0x0AB5, 0x55AA, 0xE5C5, 0x0DA5, 0x3D4A, 0xDE4D,
0x7C96, 0xDCCE, 0x0556, 0x5AB5, 0xEAD2, 0x06D2, 0x5EA5, 0xD72A, 0x868B, 0xD697,
0x04AB, 0x655B, 0xE556, 0x0B6A, 0x4752, 0xDB95, 0x0B25, 0x2A8B, 0xDA4F, 0x04AB};
/*Convert routine
00<yy<=100, 1<=mm<=12, 1<=dd<=31
*/

date_cvt (unsigned char yy, unsigned char mm, unsigned char dd, unsigned char *buff)
{ unsigned char i,j,leap;
  unsigned int days1,days2,x;
   days1 = yy * 365 + ((yy+3)>>2) + (mm-1)*30 + dd;
   if ((mm >2) && ((yy & 3) == 0) && (yy != 100))
       days1 ++;
   switch(mm)
    {
     case 3:  days1--;
              break;
     case 11:
     case 12: days1 ++;
     case 9:
     case 10: days1 ++;
     case 8:  days1 ++;
     case 2:
     case 6:
     case 7:  days1 ++;
    }   //------days from 1999-12-31
   days1 -=35;
   days2=0;
   leap=0xFF;
   for (i=0; i<=100; i++)
    {x=table;
     for (j=0; j<12; j++)
       {
         days2 += 29 + (x & 1);
         if (days2 >= days1)
           break;
  
         if (j==leap)
         {
         days2 += 16 + (table >> 12);
            if (days2 >= days1)
               {  j |= 0x80;
                  x = ~(table >> 12);
                  break;
                }
         }  
         x >>= 1;
       }
     if (days2 >= days1)
       break;
     
     leap = x-1;
    }
   * buff++ = i;  //output result
   * buff++ = j+1;
   * buff   = (unsigned char) (29 + (x & 1) -(days2-days1));
}
main()   /*main program*/
{ unsigned char buff[3]; //Save year(xx:20xx),month,day
  date_cvt( 9, 10, 6, &buff[0]);  //Only for example
}


作者: 卓泰科技    时间: 2015-2-20 23:14
2)

公历转农历C程序 收藏
注意只能到2049年!



#define uchar unsigned char
#define uint unsigned int
#include <intrins.h>
/*
公历年对应的农历数据,每年三字节,
格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
月份对应的位为1 表示本农历月大(30 天),为0 表示小(29 天)
第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期
*/
code uchar year_code[597]={
                    0x04,0xAe,0x53,    //1901 0
                    0x0A,0x57,0x48,    //1902 3
                    0x55,0x26,0xBd,    //1903 6
                    0x0d,0x26,0x50,    //1904 9
                    0x0d,0x95,0x44,    //1905 12
                    0x46,0xAA,0xB9,    //1906 15
                    0x05,0x6A,0x4d,    //1907 18
                    0x09,0xAd,0x42,    //1908 21
                    0x24,0xAe,0xB6,    //1909
                    0x04,0xAe,0x4A,    //1910
                    0x6A,0x4d,0xBe,    //1911
                    0x0A,0x4d,0x52,    //1912
                    0x0d,0x25,0x46,    //1913
                    0x5d,0x52,0xBA,    //1914
                    0x0B,0x54,0x4e,    //1915
                    0x0d,0x6A,0x43,    //1916
                    0x29,0x6d,0x37,    //1917
                    0x09,0x5B,0x4B,    //1918
                    0x74,0x9B,0xC1,    //1919
                    0x04,0x97,0x54,    //1920
                    0x0A,0x4B,0x48,    //1921
                    0x5B,0x25,0xBC,    //1922
                    0x06,0xA5,0x50,    //1923
                    0x06,0xd4,0x45,    //1924
                    0x4A,0xdA,0xB8,    //1925
                    0x02,0xB6,0x4d,    //1926
                    0x09,0x57,0x42,    //1927
                    0x24,0x97,0xB7,    //1928
                    0x04,0x97,0x4A,    //1929
                    0x66,0x4B,0x3e,    //1930
                    0x0d,0x4A,0x51,    //1931
                    0x0e,0xA5,0x46,    //1932
                    0x56,0xd4,0xBA,    //1933
                    0x05,0xAd,0x4e,    //1934
                    0x02,0xB6,0x44,    //1935
                    0x39,0x37,0x38,    //1936
                    0x09,0x2e,0x4B,    //1937
                    0x7C,0x96,0xBf,    //1938
                    0x0C,0x95,0x53,    //1939
                    0x0d,0x4A,0x48,    //1940
                    0x6d,0xA5,0x3B,    //1941
                    0x0B,0x55,0x4f,    //1942
                    0x05,0x6A,0x45,    //1943
                    0x4A,0xAd,0xB9,    //1944
                    0x02,0x5d,0x4d,    //1945
                    0x09,0x2d,0x42,    //1946
                    0x2C,0x95,0xB6,    //1947
                    0x0A,0x95,0x4A,    //1948
                    0x7B,0x4A,0xBd,    //1949
                    0x06,0xCA,0x51,    //1***
                    0x0B,0x55,0x46,    //1951
                    0x55,0x5A,0xBB,    //1952
                    0x04,0xdA,0x4e,    //1953
                    0x0A,0x5B,0x43,    //1954
                    0x35,0x2B,0xB8,    //1955
                    0x05,0x2B,0x4C,    //1956
                    0x8A,0x95,0x3f,    //1957
                    0x0e,0x95,0x52,    //1958
                    0x06,0xAA,0x48,    //1959
                    0x7A,0xd5,0x3C,    //1960
                    0x0A,0xB5,0x4f,    //1961
                    0x04,0xB6,0x45,    //1962
                    0x4A,0x57,0x39,    //1963
                    0x0A,0x57,0x4d,    //1964
                    0x05,0x26,0x42,    //1965
                    0x3e,0x93,0x35,    //1966
                    0x0d,0x95,0x49,    //1967
                    0x75,0xAA,0xBe,    //1968
                    0x05,0x6A,0x51,    //1969
                    0x09,0x6d,0x46,    //1970
                    0x54,0xAe,0xBB,    //1971
                    0x04,0xAd,0x4f,    //1972
                    0x0A,0x4d,0x43,    //1973
                    0x4d,0x26,0xB7,    //1974
                    0x0d,0x25,0x4B,    //1975
                    0x8d,0x52,0xBf,    //1976
                    0x0B,0x54,0x52,    //1977
                    0x0B,0x6A,0x47,    //1978
                    0x69,0x6d,0x3C,    //1979
                    0x09,0x5B,0x50,    //1980
                    0x04,0x9B,0x45,    //1981
                    0x4A,0x4B,0xB9,    //1982
                    0x0A,0x4B,0x4d,    //1983
                    0xAB,0x25,0xC2,    //1984
                    0x06,0xA5,0x54,    //1985
                    0x06,0xd4,0x49,    //1986
                    0x6A,0xdA,0x3d,    //1987
                    0x0A,0xB6,0x51,    //1988
                    0x09,0x37,0x46,    //1989
                    0x54,0x97,0xBB,    //1990
                    0x04,0x97,0x4f,    //1991
                    0x06,0x4B,0x44,    //1992
                    0x36,0xA5,0x37,    //1993
                    0x0e,0xA5,0x4A,    //1994
                    0x86,0xB2,0xBf,    //1995
                    0x05,0xAC,0x53,    //1996
                    0x0A,0xB6,0x47,    //1997
                    0x59,0x36,0xBC,    //1998
                    0x09,0x2e,0x50,    //1999 294
                    0x0C,0x96,0x45,    //2000 297
                    0x4d,0x4A,0xB8,    //2001
                    0x0d,0x4A,0x4C,    //2002
                    0x0d,0xA5,0x41,    //2003
                    0x25,0xAA,0xB6,    //2004
                    0x05,0x6A,0x49,    //2005
                    0x7A,0xAd,0xBd,    //2006
                    0x02,0x5d,0x52,    //2007
                    0x09,0x2d,0x47,    //2008
                    0x5C,0x95,0xBA,    //2009
                    0x0A,0x95,0x4e,    //2010
                    0x0B,0x4A,0x43,    //2011
                    0x4B,0x55,0x37,    //2012
                    0x0A,0xd5,0x4A,    //2013
                    0x95,0x5A,0xBf,    //2014
                    0x04,0xBA,0x53,    //2015
                    0x0A,0x5B,0x48,    //2016
                    0x65,0x2B,0xBC,    //2017
                    0x05,0x2B,0x50,    //2018
                    0x0A,0x93,0x45,    //2019
                    0x47,0x4A,0xB9,    //2020
                    0x06,0xAA,0x4C,    //2021
                    0x0A,0xd5,0x41,    //2022
                    0x24,0xdA,0xB6,    //2023
                    0x04,0xB6,0x4A,    //2024
                    0x69,0x57,0x3d,    //2025
                    0x0A,0x4e,0x51,    //2026
                    0x0d,0x26,0x46,    //2027
                    0x5e,0x93,0x3A,    //2028
                    0x0d,0x53,0x4d,    //2029
                    0x05,0xAA,0x43,    //2030
                    0x36,0xB5,0x37,    //2031
                    0x09,0x6d,0x4B,    //2032
                    0xB4,0xAe,0xBf,    //2033
                    0x04,0xAd,0x53,    //2034
                    0x0A,0x4d,0x48,    //2035
                    0x6d,0x25,0xBC,    //2036
                    0x0d,0x25,0x4f,    //2037
                    0x0d,0x52,0x44,    //2038
                    0x5d,0xAA,0x38,    //2039
                    0x0B,0x5A,0x4C,    //2040
                    0x05,0x6d,0x41,    //2041
                    0x24,0xAd,0xB6,    //2042
                    0x04,0x9B,0x4A,    //2043
                    0x7A,0x4B,0xBe,    //2044
                    0x0A,0x4B,0x51,    //2045
                    0x0A,0xA5,0x46,    //2046
                    0x5B,0x52,0xBA,    //2047
                    0x06,0xd2,0x4e,    //2048
                    0x0A,0xdA,0x42,    //2049
                    
};

///月份数据表
code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
code uint day_code2[3]={0x111,0x130,0x14e};

/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/
bit c_moon;
data uchar year_moon,month_moon,day_moon,week;
/*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/
bit get_moon_day(uchar month_p,uint table_addr)
{
uchar temp;
    switch (month_p){
        case 1:{temp=year_code[table_addr]&0x08;
             if (temp==0)return(0);else return(1);}
        case 2:{temp=year_code[table_addr]&0x04;
             if (temp==0)return(0);else return(1);}
        case 3:{temp=year_code[table_addr]&0x02;
             if (temp==0)return(0);else return(1);}
        case 4:{temp=year_code[table_addr]&0x01;
             if (temp==0)return(0);else return(1);}
        case 5:{temp=year_code[table_addr+1]&0x80;
             if (temp==0) return(0);else return(1);}
        case 6:{temp=year_code[table_addr+1]&0x40;
             if (temp==0)return(0);else return(1);}
        case 7:{temp=year_code[table_addr+1]&0x20;
             if (temp==0)return(0);else return(1);}
        case 8:{temp=year_code[table_addr+1]&0x10;
             if (temp==0)return(0);else return(1);}
        case 9:{temp=year_code[table_addr+1]&0x08;
             if (temp==0)return(0);else return(1);}
        case 10:{temp=year_code[table_addr+1]&0x04;
             if (temp==0)return(0);else return(1);}
        case 11:{temp=year_code[table_addr+1]&0x02;
             if (temp==0)return(0);else return(1);}
        case 12:{temp=year_code[table_addr+1]&0x01;
             if (temp==0)return(0);else return(1);}
        case 13:{temp=year_code[table_addr+2]&0x80;
             if (temp==0)return(0);else return(1);}
    }
}

/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/

void Conversion(bit c,uchar year,uchar month,uchar day)
{                         //c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
    uchar temp1,temp2,temp3,month_p;
    uint temp4,table_addr;
    bit flag2,flag_y;
    temp1=year/16;   //BCD->hex 先把数据转换为十六进制
    temp2=year%16;
    year=temp1*10+temp2;
    temp1=month/16;
    temp2=month%16;
    month=temp1*10+temp2;
    temp1=day/16;
    temp2=day%16;
    day=temp1*10+temp2;

    //定位数据表地址
    if(c==0){                  
        table_addr=(year+0x64-1)*0x3;
    }
    else {
        table_addr=(year-1)*0x3;
    }
    //定位数据表地址完成

    //取当年春节所在的公历月份
    temp1=year_code[table_addr+2]&0x60;
    temp1=_cror_(temp1,5);
    //取当年春节所在的公历月份完成

    //取当年春节所在的公历日
    temp2=year_code[table_addr+2]&0x1f;
    //取当年春节所在的公历日完成

    // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
    if(temp1==0x1){  
        temp3=temp2-1;  
    }  
    else{
        temp3=temp2+0x1f-1;        
    }
    // 计算当年春年离当年元旦的天数完成

    //计算公历日离当年元旦的天数,为了减少运算,用了两个表
    //day_code1[9],day_code2[3]
    //如果公历月在九月或前,天数会少于0xff,用表day_code1[9],
    //在九月后,天数大于0xff,用表day_code2[3]
    //如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1
    //如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1
    if (month<10){
        temp4=day_code1[month-1]+day-1;
    }
    else{
        temp4=day_code2[month-10]+day-1;
    }
    if ((month>0x2)&&(year%0x4==0)){  //如果公历月大于2月并且该年的2月为闰月,天数加1
        temp4+=1;
    }
    //计算公历日离当年元旦的天数完成

    //判断公历日在春节前还是春节后
    if (temp4>=temp3){ //公历日在春节后或就是春节当日使用下面代码进行运算
        temp4-=temp3;
        month=0x1;
        month_p=0x1;  //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月
        flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0
        flag_y=0;
        if(flag2==0)temp1=0x1d; //小月29天
        else temp1=0x1e; //大小30天
        temp2=year_code[table_addr]&0xf0;
        temp2=_cror_(temp2,4);  //从数据表中取该年的闰月月份,如为0则该年无闰月
        while(temp4>=temp1){
            temp4-=temp1;
            month_p+=1;
            if(month==temp2){
            flag_y=~flag_y;
            if(flag_y==0)month+=1;
            }
            else month+=1;
            flag2=get_moon_day(month_p,table_addr);
            if(flag2==0)temp1=0x1d;
            else temp1=0x1e;
        }
        day=temp4+1;
    }
    else{  //公历日在春节前使用下面代码进行运算
        temp3-=temp4;
        if (year==0x0){year=0x63;c=1;}
        else year-=1;
        table_addr-=0x3;
        month=0xc;
        temp2=year_code[table_addr]&0xf0;
        temp2=_cror_(temp2,4);
        if (temp2==0)month_p=0xc;
        else month_p=0xd; //
        /*
        month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,
无闰月指向12
        */
        flag_y=0;
        flag2=get_moon_day(month_p,table_addr);
        if(flag2==0)temp1=0x1d;
        else temp1=0x1e;
        while(temp3>temp1){
            temp3-=temp1;
            month_p-=1;
            if(flag_y==0)month-=1;
            if(month==temp2)flag_y=~flag_y;
            flag2=get_moon_day(month_p,table_addr);
            if(flag2==0)temp1=0x1d;
            else temp1=0x1e;
         }
        day=temp1-temp3+1;
    }
    c_moon=c;                 //HEX->BCD ,运算结束后,把数据转换为BCD数据
    temp1=year/10;
    temp1=_crol_(temp1,4);
    temp2=year%10;
    year_moon=temp1|temp2;
    temp1=month/10;
    temp1=_crol_(temp1,4);
    temp2=month%10;
    month_moon=temp1|temp2;
    temp1=day/10;
    temp1=_crol_(temp1,4);
    temp2=day%10;
    day_moon=temp1|temp2;
}
/*
函数功能:输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年)
调用函数示例:Conver_week(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读week得出阴历BCD数据
*/
code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
/*
算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期但如果是在
闰年又不到3 月份上述之和要减一天再除7
星期数为0
*/

void Conver_week(bit c,uchar year,uchar month,uchar day)
{//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
    uchar temp1,temp2;
    temp1=year/16;   //BCD->hex 先把数据转换为十六进制
    temp2=year%16;
    year=temp1*10+temp2;
    temp1=month/16;
    temp2=month%16;
    month=temp1*10+temp2;
    temp1=day/16;
    temp2=day%16;
    day=temp1*10+temp2;
    if (c==0){year+=0x64;}  //如果为21世纪,年份数加100
    temp1=year/0x4;  //所过闰年数只算1900年之后的
    temp2=year+temp1;
    temp2=temp2%0x7;  //为节省资源,先进行一次取余,避免数大于0xff,避免使用整型数据
    temp2=temp2+day+table_week[month-1];
    if (year%0x4==0&&month<3)temp2-=1;
    week=temp2%0x7;
}

//test
uchar c_sun,year_sun,month_sun,day_sun;
void main(){
c_sun=1;
year_sun=0x2;
month_sun=0x11;
day_sun=0x3;
Conver_week(c_sun,year_sun,month_sun,day_sun);
Conversion(c_sun,year_sun,month_sun,day_sun);
while(1);
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lengshine/archive/2010/04/10/5470616.asp




作者: 卓泰科技    时间: 2015-2-20 23:15
3)

  1. #include <stdio.h>
  2. #include <afx.h>
  3. #include <windows.h>

  4. const WORD START_YEAR =1901;
  5. const WORD END_YEAR   =2050;


  6. /******************************************************************************
  7.   下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法.
  8.    
  9. *******************************************************************************/
  10. //数组gLunarDay存入阴历1901年到2100年每年中的月天数信息,
  11. //阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天
  12. WORD gLunarMonthDay[]=
  13. {
  14.         //测试数据只有1901.1.1 --2050.12.31
  15.   0X4ae0, 0Xa570, 0X5268, 0Xd260, 0Xd950, 0X6aa8, 0X56a0, 0X9ad0, 0X4ae8, 0X4ae0,   //1910
  16.   0Xa4d8, 0Xa4d0, 0Xd250, 0Xd548, 0Xb550, 0X56a0, 0X96d0, 0X95b0, 0X49b8, 0X49b0,   //1920
  17.   0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada8, 0X2b60, 0X9570, 0X4978, 0X4970, 0X64b0,   //1930
  18.   0Xd4a0, 0Xea50, 0X6d48, 0X5ad0, 0X2b60, 0X9370, 0X92e0, 0Xc968, 0Xc950, 0Xd4a0,   //1940
  19.   0Xda50, 0Xb550, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc958, 0Xa950, 0Xb4a8, 0X6ca0,   //1950
  20.   0Xb550, 0X55a8, 0X4da0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa950, 0Xe950, 0X6aa0, 0Xad50,   //1960
  21.   0Xab50, 0X4b60, 0Xa570, 0Xa570, 0X5260, 0Xe930, 0Xd950, 0X5aa8, 0X56a0, 0X96d0,   //1970
  22.   0X4ae8, 0X4ad0, 0Xa4d0, 0Xd268, 0Xd250, 0Xd528, 0Xb540, 0Xb6a0, 0X96d0, 0X95b0,   //1980
  23.   0X49b0, 0Xa4b8, 0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada0, 0Xab60, 0X9370, 0X4978,   //1990
  24.   0X4970, 0X64b0, 0X6a50, 0Xea50, 0X6b28, 0X5ac0, 0Xab60, 0X9368, 0X92e0, 0Xc960,   //2000
  25.   0Xd4a8, 0Xd4a0, 0Xda50, 0X5aa8, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc958, 0Xa950,   //2010
  26.   0Xb4a0, 0Xb550, 0Xb550, 0X55a8, 0X4ba0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa930, 0X74a8,   //2020
  27.   0X6aa0, 0Xad50, 0X4da8, 0X4b60, 0X9570, 0Xa4e0, 0Xd260, 0Xe930, 0Xd530, 0X5aa0,   //2030
  28.   0X6b50, 0X96d0, 0X4ae8, 0X4ad0, 0Xa4d0, 0Xd258, 0Xd250, 0Xd520, 0Xdaa0, 0Xb5a0,   //2040
  29.   0X56d0, 0X4ad8, 0X49b0, 0Xa4b8, 0Xa4b0, 0Xaa50, 0Xb528, 0X6d20, 0Xada0, 0X55b0,   //2050
  30.    
  31. };

  32. //数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年
  33. BYTE  gLunarMonth[]=
  34. {
  35.         0X00, 0X50, 0X04, 0X00, 0X20,   //1910
  36.         0X60, 0X05, 0X00, 0X20, 0X70,   //1920
  37.         0X05, 0X00, 0X40, 0X02, 0X06,   //1930
  38.         0X00, 0X50, 0X03, 0X07, 0X00,   //1940
  39.         0X60, 0X04, 0X00, 0X20, 0X70,   //1950
  40.         0X05, 0X00, 0X30, 0X80, 0X06,   //1960
  41.         0X00, 0X40, 0X03, 0X07, 0X00,   //1970
  42.         0X50, 0X04, 0X08, 0X00, 0X60,   //1980
  43.         0X04, 0X0a, 0X00, 0X60, 0X05,   //1990
  44.         0X00, 0X30, 0X80, 0X05, 0X00,   //2000
  45.         0X40, 0X02, 0X07, 0X00, 0X50,   //2010
  46.         0X04, 0X09, 0X00, 0X60, 0X04,   //2020
  47.         0X00, 0X20, 0X60, 0X05, 0X00,   //2030
  48.         0X30, 0Xb0, 0X06, 0X00, 0X50,   //2040
  49.         0X02, 0X07, 0X00, 0X50, 0X03    //2050
  50. };



  51. BOOL IsLeapYear(WORD iYear) {return !(iYear%4)&&(iYear%100) || !(iYear%400);}


  52. WORD  MonthDays(WORD iYear, WORD iMonth)
  53. {
  54.         switch(iMonth)
  55.         {
  56.         case 1:case 3:case 5:case 7:case 8:case 10:case 12:
  57.                 return 31;
  58.                 break;
  59.         case 4:case 6:case 9:case 11:
  60.                 return 30;
  61.                 break;
  62.         case 2:
  63.                 //如果是闰年
  64.                 if(IsLeapYear(iYear))
  65.                         return 29;
  66.                 else
  67.                         return 28;
  68.                 break;
  69.         }
  70.         return 0;
  71. }

  72. WORD  GetLeapMonth(WORD iLunarYear)
  73. {
  74.         BYTE &flag = gLunarMonth[(iLunarYear - START_YEAR)/2];
  75.         return  (iLunarYear - START_YEAR)%2 ? flag&0x0f : flag>>4;
  76. }

  77. LONG  LunarMonthDays(WORD iLunarYear, WORD iLunarMonth)
  78. {
  79.         if(iLunarYear < START_YEAR)  
  80.                 return 30L;

  81.         WORD height =0 ,low =29;
  82.         int iBit = 16 - iLunarMonth;

  83.     if(iLunarMonth > GetLeapMonth(iLunarYear) && GetLeapMonth(iLunarYear))
  84.                    iBit --;

  85.         if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<<iBit))
  86.                 low ++;
  87.             
  88.         if(iLunarMonth == GetLeapMonth(iLunarYear))
  89.                 if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<< (iBit -1)))
  90.                      height =30;
  91.                 else  
  92.                          height =29;

  93.         return MAKELONG(low, height);
  94. }

  95. WORD  LunarYearDays(WORD iLunarYear)
  96. {
  97.         /*
  98.         WORD days=348 ; //12*29
  99.         int  month = 12 ;

  100.         //如果iYear年有闰月,则为13个月
  101.     if(gLanarMonth[iYear - START_YEAR])  
  102.                 month ++;
  103.     //如果某月是三十天则days++
  104.         while(month >=0 && (gLanarMonthDay[iYear - START_YEAR] & (1 << (16 - month))))
  105.         {   
  106.                 days ++;  
  107.             month --;
  108.         }
  109.         return days;
  110.         */
  111.         WORD days =0;
  112.         for(WORD  i=1; i<=12; i++)
  113.         {  
  114.         LONG  tmp = LunarMonthDays(iLunarYear ,i);  
  115.                 days += HIWORD(tmp);
  116.                 days += LOWORD(tmp);
  117.         }
  118.     return days;
  119. }


  120. // add by handong: 显示 生肖  及 干支 纪年 :   pShX(兔(又名得到之兔))  pGZhi 甲子
  121. void FormatShengXiao(WORD  iYear, char *pShX, char *pGZhi)
  122. {        
  123.         char szText1[]="甲乙丙丁戊己庚辛壬癸";
  124.         char szText2[]="子丑寅卯辰巳午未申酉戌亥";
  125.         char szText3[]="鼠牛虎免龙蛇马羊猴鸡狗猪";
  126.         char szText4[]="屋上之鼠海内之牛山林之虎";
  127.         memcpy(pGZhi,  szText1+((iYear-4)%10)*2,2);
  128.         memcpy(pGZhi+2,szText2+((iYear-4)%12)*2,2);
  129.         pGZhi[4]=0;
  130.          
  131.         memcpy(pShX,szText3+((iYear-4)%12)*2,2);
  132.         strcpy(pShX+2,"(又名:)");
  133.          
  134. }         

  135. void  l_CalcLunarDate(WORD &iYear, WORD &iMonth ,WORD &iDay, LONG iSpanDays)
  136. {
  137.         //阳历1901年2月19日为阴历1901年正月初一
  138.         //阳历1901年1月1日到2月19日共有49天
  139.         if(iSpanDays <49)
  140.         {
  141.                 iYear  = START_YEAR-1;
  142.                 if(iSpanDays <19)
  143.                 {  
  144.                   iMonth = 11;   
  145.                   iDay   = 11+WORD(iSpanDays);
  146.                 }
  147.                 else
  148.                 {
  149.                         iMonth = 12;
  150.                         iDay   =  WORD(iSpanDays) -18;
  151.                 }
  152.                 return ;
  153.         }
  154.         //下面从阴历1901年正月初一算起
  155.         iSpanDays -=49;
  156.     iYear  = START_YEAR;
  157.         iMonth = 1;
  158.         iDay   = 1;
  159.         //计算年
  160.         LONG tmp = LunarYearDays(iYear);  
  161.         while(iSpanDays >= tmp)
  162.         {
  163.                 iSpanDays -= tmp;
  164.                 tmp = LunarYearDays(++iYear);
  165.         }
  166.     //计算月
  167.         tmp = LOWORD(LunarMonthDays(iYear, iMonth));
  168.         while(iSpanDays >= tmp)
  169.         {
  170.                 iSpanDays -= tmp;
  171.             if(iMonth == GetLeapMonth(iYear))
  172.                 {
  173.                         tmp  = HIWORD(LunarMonthDays(iYear, iMonth));
  174.                         if(iSpanDays < tmp)      
  175.                                 break;
  176.                         iSpanDays -= tmp;
  177.                 }
  178.                 tmp = LOWORD(LunarMonthDays(iYear, ++iMonth));
  179.         }
  180.         //计算日
  181.         iDay += WORD(iSpanDays);
  182. }
  183. LONG  CalcDateDiff(WORD iEndYear, WORD iEndMonth, WORD iEndDay,
  184.                                     WORD  iStartYear, WORD iStartMonth, WORD iStartDay)
  185. {
  186.         WORD monthday[]={0, 31, 59 ,90, 120, 151, 181, 212, 243, 273, 304, 334};  

  187.         //计算两个年份1月1日之间相差的天数
  188.         LONG iDiffDays =(iEndYear - iStartYear)*365;
  189.         iDiffDays += (iEndYear-1)/4 - (iStartYear-1)/4;
  190.         iDiffDays -= ((iEndYear-1)/100 - (iStartYear-1)/100);
  191.         iDiffDays += (iEndYear-1)/400 - (iStartYear-1)/400;

  192.     //加上iEndYear年1月1日到iEndMonth月iEndDay日之间的天数
  193.     iDiffDays += monthday[iEndMonth-1] +
  194.                                            (IsLeapYear(iEndYear)&&iEndMonth>2? 1: 0);
  195.     iDiffDays += iEndDay;

  196.         //减去iStartYear年1月1日到iStartMonth月iStartDay日之间的天数
  197.         iDiffDays -= (monthday[iStartMonth-1] +  
  198.                                   (IsLeapYear(iStartYear)&&iStartMonth>2 ? 1: 0));
  199.     iDiffDays -= iStartDay;      
  200.         return iDiffDays;
  201. }

  202. void GetLunarDate(WORD iYear, WORD iMonth, WORD iDay,
  203.                                      WORD &iLunarYear, WORD &iLunarMonth, WORD &iLunarDay)
  204. {
  205.    l_CalcLunarDate(iLunarYear, iLunarMonth, iLunarDay,  
  206.                                       CalcDateDiff(iYear, iMonth, iDay,1901,01,01));

  207. }


  208. //获取农历LunarY年LunarM月LunarD日公历日期(Y年M月D日)
  209. void CovertLunarToSolar(WORD LunarY,WORD LunarM,WORD LunarD,WORD &Y,WORD &M,WORD &D)
  210. {
  211.         CTime TmpDate(LunarY,LunarM,LunarD,12,12,12);
  212.         CTime Up,Down;
  213.         CTimeSpan       InterveDate(60,0,0,0); //前后2个月天搜索
  214.         CTimeSpan       OneDay(1,0,0,0);
  215.         WORD Year, Mon, Day;
  216.         WORD LunarYear,LunarMon,LunarDay;
  217.          
  218.         Up = TmpDate + InterveDate;
  219.         Down = TmpDate - InterveDate;
  220.          
  221.         CTimeSpan Days=Up-Down;
  222.          
  223.         int Len = Days.GetDays();
  224.         TmpDate=Down;
  225.         for(int i=0; i<Len; i++)
  226.         {
  227.                 TmpDate = TmpDate + OneDay;
  228.                 Year = TmpDate.GetYear(); Mon = TmpDate.GetMonth();  Day = TmpDate.GetDay();
  229.                 GetLunarDate(Year, Mon, Day, LunarYear, LunarMon, LunarDay);
  230.                 if( (LunarYear==LunarY) && (LunarMon==LunarM) && (LunarDay==LunarD) )//found
  231.                 {
  232.                         Y=Year; M=Mon; D=Day;
  233.                         return;                                          
  234.                 }
  235.         }
  236.   
  237. }
  238. //格式化农历中的year
  239. void FormatLunarYear(WORD  iYear, char *pBuffer)
  240. {        
  241.         char szText1[]="甲乙丙丁戊己庚辛壬癸";
  242.         char szText2[]="子丑寅卯辰巳午未申酉戌亥";
  243.         char szText3[]="鼠牛虎免龙蛇马羊猴鸡狗猪";

  244.         memcpy(pBuffer,  szText1+((iYear-4)%10)*2,2);
  245.         memcpy(pBuffer+2,szText2+((iYear-4)%12)*2,2);
  246.         pBuffer[4]=' ';
  247.         memcpy(pBuffer+5,szText3+((iYear-4)%12)*2,2);
  248.         strcpy(pBuffer+7,"年");
  249. }
  250. //格式化农历中的month
  251. void FormatMonth(WORD iMonth, char *pBuffer, BOOL bLunar)
  252. {
  253.    if(!bLunar && iMonth==1)
  254.    {
  255.            strcpy(pBuffer, " 正月");
  256.            return;
  257.    }

  258.    char szText[]="正二三四五六七八九十";
  259.    if(iMonth<=10)
  260.    {
  261.            memcpy(pBuffer, " ", 2);
  262.        memcpy(pBuffer+2, szText + (iMonth -1)*2, 2);
  263.        strcpy(pBuffer+4 , "月");
  264.            return;
  265.    }
  266.    if (iMonth == 11)
  267.            strcpy(pBuffer, "冬月");
  268.    else
  269.            strcpy(pBuffer, "腊月");
  270.     //strcpy(pBuffer+4 , "月");

  271.    
  272. }
  273. //格式化农历中的day
  274. void FormatLunarDay(WORD  iDay, char *pBuffer)
  275. {
  276.     char szText1[]="初十廿三";
  277.         char szText2[]="一二三四五六七八九十";
  278.         if(iDay != 20 && iDay !=30)
  279.         {
  280.                 memcpy(pBuffer, szText1 + (iDay-1)/10*2 ,2);
  281.                 memcpy(pBuffer+2, szText2 + ((iDay-1)%10)*2 ,2);
  282.                 pBuffer[4]='\0';
  283.         }
  284.         else
  285.         {
  286.         memcpy(pBuffer, szText1 + iDay/10*2, 2);
  287.                 strcpy(pBuffer+2, szText2 +18);
  288.         }
  289. }


  290. int main()
  291. {
  292.     WORD year,iyear;
  293.     WORD month,imonth;
  294.     WORD day,iday;
  295.     char pybuffer[20]={'\0'};
  296.     char pmbuffer[20]={'\0'};
  297.     char pdbuffer[20]={'\0'};
  298.     GetLunarDate(2013,01,28,year,month,day);
  299.     FormatLunarYear(year,pybuffer);
  300.     FormatMonth(month,pmbuffer,true);
  301.     FormatLunarDay(day,pdbuffer);
  302.     printf("%s %s %s\n",pybuffer,pmbuffer,pdbuffer);
  303.     CovertLunarToSolar(2012,12,17,iyear,imonth,iday);
  304.     printf("%d %d %d\n",iyear,imonth,iday);
  305.     return 0;
  306. }
复制代码

http://my.bccn.net/paste/487/

作者: 卓泰科技    时间: 2015-2-20 23:19
4)

  1.     #include <time.h>  
  2.     #include <stdio.h>  
  3.     #include <string.h>  
  4.       
  5.     unsigned int LunarCalendarDay;  
  6.     unsigned int LunarCalendarTable[199] =  
  7.     {  
  8.         0x04AE53,0x0A5748,0x5526BD,0x0D2650,0x0D9544,0x46AAB9,0x056A4D,0x09AD42,0x24AEB6,0x04AE4A,/*1901-1910*/  
  9.         0x6A4DBE,0x0A4D52,0x0D2546,0x5D52BA,0x0B544E,0x0D6A43,0x296D37,0x095B4B,0x749BC1,0x049754,/*1911-1920*/  
  10.         0x0A4B48,0x5B25BC,0x06A550,0x06D445,0x4ADAB8,0x02B64D,0x095742,0x2497B7,0x04974A,0x664B3E,/*1921-1930*/  
  11.         0x0D4A51,0x0EA546,0x56D4BA,0x05AD4E,0x02B644,0x393738,0x092E4B,0x7C96BF,0x0C9553,0x0D4A48,/*1931-1940*/  
  12.         0x6DA53B,0x0B554F,0x056A45,0x4AADB9,0x025D4D,0x092D42,0x2C95B6,0x0A954A,0x7B4ABD,0x06CA51,/*1941-1950*/  
  13.         0x0B5546,0x555ABB,0x04DA4E,0x0A5B43,0x352BB8,0x052B4C,0x8A953F,0x0E9552,0x06AA48,0x6AD53C,/*1951-1960*/  
  14.         0x0AB54F,0x04B645,0x4A5739,0x0A574D,0x052642,0x3E9335,0x0D9549,0x75AABE,0x056A51,0x096D46,/*1961-1970*/  
  15.         0x54AEBB,0x04AD4F,0x0A4D43,0x4D26B7,0x0D254B,0x8D52BF,0x0B5452,0x0B6A47,0x696D3C,0x095B50,/*1971-1980*/  
  16.         0x049B45,0x4A4BB9,0x0A4B4D,0xAB25C2,0x06A554,0x06D449,0x6ADA3D,0x0AB651,0x093746,0x5497BB,/*1981-1990*/  
  17.         0x04974F,0x064B44,0x36A537,0x0EA54A,0x86B2BF,0x05AC53,0x0AB647,0x5936BC,0x092E50,0x0C9645,/*1991-2000*/  
  18.         0x4D4AB8,0x0D4A4C,0x0DA541,0x25AAB6,0x056A49,0x7AADBD,0x025D52,0x092D47,0x5C95BA,0x0A954E,/*2001-2010*/  
  19.         0x0B4A43,0x4B5537,0x0AD54A,0x955ABF,0x04BA53,0x0A5B48,0x652BBC,0x052B50,0x0A9345,0x474AB9,/*2011-2020*/  
  20.         0x06AA4C,0x0AD541,0x24DAB6,0x04B64A,0x69573D,0x0A4E51,0x0D2646,0x5E933A,0x0D534D,0x05AA43,/*2021-2030*/  
  21.         0x36B537,0x096D4B,0xB4AEBF,0x04AD53,0x0A4D48,0x6D25BC,0x0D254F,0x0D5244,0x5DAA38,0x0B5A4C,/*2031-2040*/  
  22.         0x056D41,0x24ADB6,0x049B4A,0x7A4BBE,0x0A4B51,0x0AA546,0x5B52BA,0x06D24E,0x0ADA42,0x355B37,/*2041-2050*/  
  23.         0x09374B,0x8497C1,0x049753,0x064B48,0x66A53C,0x0EA54F,0x06B244,0x4AB638,0x0AAE4C,0x092E42,/*2051-2060*/  
  24.         0x3C9735,0x0C9649,0x7D4ABD,0x0D4A51,0x0DA545,0x55AABA,0x056A4E,0x0A6D43,0x452EB7,0x052D4B,/*2061-2070*/  
  25.         0x8A95BF,0x0A9553,0x0B4A47,0x6B553B,0x0AD54F,0x055A45,0x4A5D38,0x0A5B4C,0x052B42,0x3A93B6,/*2071-2080*/  
  26.         0x069349,0x7729BD,0x06AA51,0x0AD546,0x54DABA,0x04B64E,0x0A5743,0x452738,0x0D264A,0x8E933E,/*2081-2090*/  
  27.         0x0D5252,0x0DAA47,0x66B53B,0x056D4F,0x04AE45,0x4A4EB9,0x0A4D4C,0x0D1541,0x2D92B5          /*2091-2099*/  
  28.     };  
  29.     int MonthAdd[12] = {0,31,59,90,120,151,181,212,243,273,304,334};  
  30.     int LunarCalendar(int year,int month,int day)  
  31.     {  
  32.         int Spring_NY,Sun_NY,StaticDayCount;  
  33.         int index,flag;  
  34.         //Spring_NY 记录春节离当年元旦的天数。  
  35.         //Sun_NY 记录阳历日离当年元旦的天数。  
  36.         if ( ((LunarCalendarTable[year-1901] & 0x0060) >> 5) == 1)  
  37.             Spring_NY = (LunarCalendarTable[year-1901] & 0x001F) - 1;  
  38.         else  
  39.             Spring_NY = (LunarCalendarTable[year-1901] & 0x001F) - 1 + 31;  
  40.         Sun_NY = MonthAdd[month-1] + day - 1;  
  41.         if ( (!(year % 4)) && (month > 2))  
  42.             Sun_NY++;  
  43.         //StaticDayCount记录大小月的天数 29 或30  
  44.         //index 记录从哪个月开始来计算。  
  45.         //flag 是用来对闰月的特殊处理。  
  46.         //判断阳历日在春节前还是春节后  
  47.         if (Sun_NY >= Spring_NY)//阳历日在春节后(含春节那天)  
  48.         {  
  49.             Sun_NY -= Spring_NY;  
  50.             month = 1;  
  51.             index = 1;  
  52.             flag = 0;  
  53.             if ( ( LunarCalendarTable[year - 1901] & (0x80000 >> (index-1)) ) ==0)  
  54.                 StaticDayCount = 29;  
  55.             else  
  56.                 StaticDayCount = 30;  
  57.             while (Sun_NY >= StaticDayCount)  
  58.             {  
  59.                 Sun_NY -= StaticDayCount;  
  60.                 index++;  
  61.                 if (month == ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20) )  
  62.                 {  
  63.                     flag = ~flag;  
  64.                     if (flag == 0)  
  65.                         month++;  
  66.                 }  
  67.                 else  
  68.                     month++;  
  69.                 if ( ( LunarCalendarTable[year - 1901] & (0x80000 >> (index-1)) ) ==0)  
  70.                     StaticDayCount=29;  
  71.                 else  
  72.                     StaticDayCount=30;  
  73.             }  
  74.             day = Sun_NY + 1;  
  75.         }  
  76.         else //阳历日在春节前  
  77.         {  
  78.             Spring_NY -= Sun_NY;  
  79.             year--;  
  80.             month = 12;  
  81.             if ( ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20) == 0)  
  82.                 index = 12;  
  83.             else  
  84.                 index = 13;  
  85.             flag = 0;  
  86.             if ( ( LunarCalendarTable[year - 1901] & (0x80000 >> (index-1)) ) ==0)  
  87.                 StaticDayCount = 29;  
  88.             else  
  89.                 StaticDayCount = 30;  
  90.             while (Spring_NY > StaticDayCount)  
  91.             {  
  92.                 Spring_NY -= StaticDayCount;  
  93.                 index--;  
  94.                 if (flag == 0)  
  95.                     month--;  
  96.                 if (month == ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20))  
  97.                     flag = ~flag;  
  98.                 if ( ( LunarCalendarTable[year - 1901] & (0x80000 >> (index-1)) ) ==0)  
  99.                     StaticDayCount = 29;  
  100.                 else  
  101.                     StaticDayCount = 30;  
  102.             }  
  103.             day = StaticDayCount - Spring_NY + 1;  
  104.         }  
  105.         LunarCalendarDay |= day;  
  106.         LunarCalendarDay |= (month << 6);  
  107.         if (month == ((LunarCalendarTable[year - 1901] & 0xF00000) >> 20))  
  108.             return 1;  
  109.         else  
  110.             return 0;  
  111.     }  
  112.     main()  
  113.     {  
  114.         const char *ChDay[] = {"*","初一","初二","初三","初四","初五",  
  115.                                "初六","初七","初八","初九","初十",  
  116.                                "十一","十二","十三","十四","十五",  
  117.                                "十六","十七","十八","十九","二十",  
  118.                                "廿一","廿二","廿三","廿四","廿五",  
  119.                                "廿六","廿七","廿八","廿九","三十"  
  120.                               };  
  121.         const char *ChMonth[] = {"*","正","二","三","四","五","六","七","八","九","十","十一","腊"};  
  122.         struct tm * Local;  
  123.         long t;  
  124.         int year,month,day;  
  125.         char str[13] = "";  
  126.     #if 0  
  127.         t = time(NULL);  
  128.         Local = localtime(&t);  
  129.         year = Local->tm_year + 1900;  
  130.         month = Local->tm_mon + 1;  
  131.         day = Local-> tm_mday;  
  132.     #else  
  133.         year = 2013;  
  134.         month = 2;  
  135.         day = 10;  
  136.         printf("请依次输入公历的年月日(例如2013年1月2日,输入:2013-1-2)");  
  137.         scanf("%d-%d-%d", &year, &month, &day);   
  138.     #endif  
  139.         printf("%d年%d月%d日\t",year,month,day);  
  140.         if (LunarCalendar(year,month,day))  
  141.         {  
  142.             strcat(str,"闰");  
  143.             strcat(str,ChMonth[(LunarCalendarDay & 0x3C0) >> 6]);  
  144.         }  
  145.         else  
  146.             strcat(str,ChMonth[(LunarCalendarDay & 0x3C0) >> 6]);  
  147.         strcat(str,"月");  
  148.         strcat(str,ChDay[LunarCalendarDay & 0x3F]);  
  149.         puts(str);  
  150.         getchar();  
  151.     }  
复制代码

http://blog.csdn.net/syrchina/article/details/8538516


作者: 卓泰科技    时间: 2015-2-20 23:28
农历算法简介以及公式

一、节气的计算

  先给节气进行编号,从近日点开始的第一个节气编为0,编号如下及其相应的月份如下:
            
0 小寒 腊月
            
            
6  清明 三月
            
            
12 小暑 六月
            
            
18 寒露 九月
            
            
1 大寒 腊月
            
            
7  谷雨 三月
            
            
13 大暑 六月
            
            
19 霜降 九月
            
            
2 立春  正月
            
            
8  立夏 四月
            
            
14 立秋 七月
            
            
20 立冬 十月
            
            
3 雨水 正月
            
            
9  小满 四月
            
            
15 处暑 七月
            
            
21 小雪 十月
            
            
4 惊蛰 二月
            
            
10 芒种 五月
            
            
16 白露 八月
            
            
22 大雪 冬月
            
            
5 春分 二月
            
            
11 夏至 五月
            
            
17 秋分 八月
            
            
23 冬至 冬月
            


把当天和1900年1月0日(星期日)的差称为积日,那么第y年(1900年算第0年)第x 个节气的积日是
        F = 365.242 * y + 6.2 + 15.22 * x - 1.9 * sin(0.262 * x)
这个公式的误差在0.05天左右。

二、朔日的计算

  从1900年开始的第m个朔日的公式是
        M = 1.6 + 29.5306 * m + 0.4 * sin(1 - 0.45058 * m)
这个公式的误差在0.2天左右。


三、年份的确定

  1864年1月0日是农历癸亥年,所以用当年减去1864,用10除得的余数作为年份天干的,用12除得的余数作为年份的地支,数字对应的天干和地支如下。
            
数字
            
            
0
            
            
1
            
            
2
            
            
3
            
            
4
            
            
5
            
            
6
            
            
7
            
            
8
            
            
9
            
            
10
            
            
11
            
            
天干
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
地支
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            


当年的1月0日换算为积日,可以用年份减去1900得到的年数被4整除,所得商数作为 y(D4),余数作为y(M4),y(M4)为零的年份是公历闰年,积日是
        D(1) = 1461 * y(D4) - 1
y(M4)不为零的年份是公历平年,积日是
        D(1) = 1461 * y(D4) + 365 * y(M4)

四、月份的确定
  计算前一年冬至的积日F(0),并用F(0)计算冬至所在的朔月m及其朔日M(0),就可以推算冬至的农历日期,冬至所在的农历月份总是十一月。计算下一个中气F(1)和下一个朔日M(1),如果F(1)<M(1),那么该月就是上一个月的闰月,并把这个中气作为F(2),以后的中气、朔日和农历月份也这样确定。


有关农历的东西有以下几篇文章:

计算某天是星期几【C代码】
农历算法简介以及公式
农历中天干地支的计算【C代码】
农历一百年算法(1921~2021)【C语言代码】
农历两百年算法(1901~2100)【C语言代码】
作者: 卓泰科技    时间: 2015-2-20 23:32
好复杂的农历
先不深入研究了,否则估计这里就卡死了。
这个毛病要改。
作者: 卓泰科技    时间: 2015-2-20 23:40
发一个移植于C51的公历转农历的程序
http://www.geek-workshop.com/thread-12245-1-1.html

万年历制作练习, 开发记录中 ,已基本完成开发,上传了源代码
http://www.geek-workshop.com/thread-12768-1-1.html

一个写得不错的公历转农历程序
http://www.jhmcu.com/yi-ge-xie-de-bu-cuo-di-gong-li-zhuan-nong-li-cheng-xu

  1. 公历转农历程序:



  2. //公历转农历和星期
  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. #include <intrins.h>
  6. /*
  7. 公历年对应的农历数据,每年三字节,
  8. 格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小
  9. 第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
  10. 月份对应的位为1 表示本农历月大(30 天),为0 表示小(29 天)
  11. 第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期
  12. */
  13. code uchar year_code[597] = {
  14. 0x04,0xAe,0x53, //1901 0
  15. 0x0A,0x57,0x48, //1902 3
  16. 0x55,0x26,0xBd, //1903 6
  17. 0x0d,0x26,0x50, //1904 9
  18. 0x0d,0x95,0x44, //1905 12
  19. 0x46,0xAA,0xB9, //1906 15
  20. 0x05,0x6A,0x4d, //1907 18
  21. 0x09,0xAd,0x42, //1908 21
  22. 0x24,0xAe,0xB6, //1909
  23. 0x04,0xAe,0x4A, //1910
  24. 0x6A,0x4d,0xBe, //1911
  25. 0x0A,0x4d,0x52, //1912
  26. 0x0d,0x25,0x46, //1913
  27. 0x5d,0x52,0xBA, //1914
  28. 0x0B,0x54,0x4e, //1915
  29. 0x0d,0x6A,0x43, //1916
  30. 0x29,0x6d,0x37, //1917
  31. 0x09,0x5B,0x4B, //1918
  32. 0x74,0x9B,0xC1, //1919
  33. 0x04,0x97,0x54, //1920
  34. 0x0A,0x4B,0x48, //1921
  35. 0x5B,0x25,0xBC, //1922
  36. 0x06,0xA5,0x50, //1923
  37. 0x06,0xd4,0x45, //1924
  38. 0x4A,0xdA,0xB8, //1925
  39. 0x02,0xB6,0x4d, //1926
  40. 0x09,0x57,0x42, //1927
  41. 0x24,0x97,0xB7, //1928
  42. 0x04,0x97,0x4A, //1929
  43. 0x66,0x4B,0x3e, //1930
  44. 0x0d,0x4A,0x51, //1931
  45. 0x0e,0xA5,0x46, //1932
  46. 0x56,0xd4,0xBA, //1933
  47. 0x05,0xAd,0x4e, //1934
  48. 0x02,0xB6,0x44, //1935
  49. 0x39,0x37,0x38, //1936
  50. 0x09,0x2e,0x4B, //1937
  51. 0x7C,0x96,0xBf, //1938
  52. 0x0C,0x95,0x53, //1939
  53. 0x0d,0x4A,0x48, //1940
  54. 0x6d,0xA5,0x3B, //1941
  55. 0x0B,0x55,0x4f, //1942
  56. 0x05,0x6A,0x45, //1943
  57. 0x4A,0xAd,0xB9, //1944
  58. 0x02,0x5d,0x4d, //1945
  59. 0x09,0x2d,0x42, //1946
  60. 0x2C,0x95,0xB6, //1947
  61. 0x0A,0x95,0x4A, //1948
  62. 0x7B,0x4A,0xBd, //1949
  63. 0x06,0xCA,0x51, //1950
  64. 0x0B,0x55,0x46, //1951
  65. 0x55,0x5A,0xBB, //1952
  66. 0x04,0xdA,0x4e, //1953
  67. 0x0A,0x5B,0x43, //1954
  68. 0x35,0x2B,0xB8, //1955
  69. 0x05,0x2B,0x4C, //1956
  70. 0x8A,0x95,0x3f, //1957
  71. 0x0e,0x95,0x52, //1958
  72. 0x06,0xAA,0x48, //1959
  73. 0x7A,0xd5,0x3C, //1960
  74. 0x0A,0xB5,0x4f, //1961
  75. 0x04,0xB6,0x45, //1962
  76. 0x4A,0x57,0x39, //1963
  77. 0x0A,0x57,0x4d, //1964
  78. 0x05,0x26,0x42, //1965
  79. 0x3e,0x93,0x35, //1966
  80. 0x0d,0x95,0x49, //1967
  81. 0x75,0xAA,0xBe, //1968
  82. 0x05,0x6A,0x51, //1969
  83. 0x09,0x6d,0x46, //1970
  84. 0x54,0xAe,0xBB, //1971
  85. 0x04,0xAd,0x4f, //1972
  86. 0x0A,0x4d,0x43, //1973
  87. 0x4d,0x26,0xB7, //1974
  88. 0x0d,0x25,0x4B, //1975
  89. 0x8d,0x52,0xBf, //1976
  90. 0x0B,0x54,0x52, //1977
  91. 0x0B,0x6A,0x47, //1978
  92. 0x69,0x6d,0x3C, //1979
  93. 0x09,0x5B,0x50, //1980
  94. 0x04,0x9B,0x45, //1981
  95. 0x4A,0x4B,0xB9, //1982
  96. 0x0A,0x4B,0x4d, //1983
  97. 0xAB,0x25,0xC2, //1984
  98. 0x06,0xA5,0x54, //1985
  99. 0x06,0xd4,0x49, //1986
  100. 0x6A,0xdA,0x3d, //1987
  101. 0x0A,0xB6,0x51, //1988
  102. 0x09,0x37,0x46, //1989
  103. 0x54,0x97,0xBB, //1990
  104. 0x04,0x97,0x4f, //1991
  105. 0x06,0x4B,0x44, //1992
  106. 0x36,0xA5,0x37, //1993
  107. 0x0e,0xA5,0x4A, //1994
  108. 0x86,0xB2,0xBf, //1995
  109. 0x05,0xAC,0x53, //1996
  110. 0x0A,0xB6,0x47, //1997
  111. 0x59,0x36,0xBC, //1998
  112. 0x09,0x2e,0x50, //1999 294
  113. 0x0C,0x96,0x45, //2000 297
  114. 0x4d,0x4A,0xB8, //2001
  115. 0x0d,0x4A,0x4C, //2002
  116. 0x0d,0xA5,0x41, //2003
  117. 0x25,0xAA,0xB6, //2004
  118. 0x05,0x6A,0x49, //2005
  119. 0x7A,0xAd,0xBd, //2006
  120. 0x02,0x5d,0x52, //2007
  121. 0x09,0x2d,0x47, //2008
  122. 0x5C,0x95,0xBA, //2009
  123. 0x0A,0x95,0x4e, //2010
  124. 0x0B,0x4A,0x43, //2011
  125. 0x4B,0x55,0x37, //2012
  126. 0x0A,0xd5,0x4A, //2013
  127. 0x95,0x5A,0xBf, //2014
  128. 0x04,0xBA,0x53, //2015
  129. 0x0A,0x5B,0x48, //2016
  130. 0x65,0x2B,0xBC, //2017
  131. 0x05,0x2B,0x50, //2018
  132. 0x0A,0x93,0x45, //2019
  133. 0x47,0x4A,0xB9, //2020
  134. 0x06,0xAA,0x4C, //2021
  135. 0x0A,0xd5,0x41, //2022
  136. 0x24,0xdA,0xB6, //2023
  137. 0x04,0xB6,0x4A, //2024
  138. 0x69,0x57,0x3d, //2025
  139. 0x0A,0x4e,0x51, //2026
  140. 0x0d,0x26,0x46, //2027
  141. 0x5e,0x93,0x3A, //2028
  142. 0x0d,0x53,0x4d, //2029
  143. 0x05,0xAA,0x43, //2030
  144. 0x36,0xB5,0x37, //2031
  145. 0x09,0x6d,0x4B, //2032
  146. 0xB4,0xAe,0xBf, //2033
  147. 0x04,0xAd,0x53, //2034
  148. 0x0A,0x4d,0x48, //2035
  149. 0x6d,0x25,0xBC, //2036
  150. 0x0d,0x25,0x4f, //2037
  151. 0x0d,0x52,0x44, //2038
  152. 0x5d,0xAA,0x38, //2039
  153. 0x0B,0x5A,0x4C, //2040
  154. 0x05,0x6d,0x41, //2041
  155. 0x24,0xAd,0xB6, //2042
  156. 0x04,0x9B,0x4A, //2043
  157. 0x7A,0x4B,0xBe, //2044
  158. 0x0A,0x4B,0x51, //2045
  159. 0x0A,0xA5,0x46, //2046
  160. 0x5B,0x52,0xBA, //2047
  161. 0x06,0xd2,0x4e, //2048
  162. 0x0A,0xdA,0x42, //2049
  163. 0x35,0x5B,0x37, //2050
  164. 0x09,0x37,0x4B, //2051
  165. 0x84,0x97,0xC1, //2052
  166. 0x04,0x97,0x53, //2053
  167. 0x06,0x4B,0x48, //2054
  168. 0x66,0xA5,0x3C, //2055
  169. 0x0e,0xA5,0x4f, //2056
  170. 0x06,0xB2,0x44, //2057
  171. 0x4A,0xB6,0x38, //2058
  172. 0x0A,0xAe,0x4C, //2059
  173. 0x09,0x2e,0x42, //2060
  174. 0x3C,0x97,0x35, //2061
  175. 0x0C,0x96,0x49, //2062
  176. 0x7d,0x4A,0xBd, //2063
  177. 0x0d,0x4A,0x51, //2064
  178. 0x0d,0xA5,0x45, //2065
  179. 0x55,0xAA,0xBA, //2066
  180. 0x05,0x6A,0x4e, //2067
  181. 0x0A,0x6d,0x43, //2068
  182. 0x45,0x2e,0xB7, //2069
  183. 0x05,0x2d,0x4B, //2070
  184. 0x8A,0x95,0xBf, //2071
  185. 0x0A,0x95,0x53, //2072
  186. 0x0B,0x4A,0x47, //2073
  187. 0x6B,0x55,0x3B, //2074
  188. 0x0A,0xd5,0x4f, //2075
  189. 0x05,0x5A,0x45, //2076
  190. 0x4A,0x5d,0x38, //2077
  191. 0x0A,0x5B,0x4C, //2078
  192. 0x05,0x2B,0x42, //2079
  193. 0x3A,0x93,0xB6, //2080
  194. 0x06,0x93,0x49, //2081
  195. 0x77,0x29,0xBd, //2082
  196. 0x06,0xAA,0x51, //2083
  197. 0x0A,0xd5,0x46, //2084
  198. 0x54,0xdA,0xBA, //2085
  199. 0x04,0xB6,0x4e, //2086
  200. 0x0A,0x57,0x43, //2087
  201. 0x45,0x27,0x38, //2088
  202. 0x0d,0x26,0x4A, //2089
  203. 0x8e,0x93,0x3e, //2090
  204. 0x0d,0x52,0x52, //2091
  205. 0x0d,0xAA,0x47, //2092
  206. 0x66,0xB5,0x3B, //2093
  207. 0x05,0x6d,0x4f, //2094
  208. 0x04,0xAe,0x45, //2095
  209. 0x4A,0x4e,0xB9, //2096
  210. 0x0A,0x4d,0x4C, //2097
  211. 0x0d,0x15,0x41, //2098
  212. 0x2d,0x92,0xB5, //2099
  213. };
  214. ///月份数据表
  215. code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
  216. code uint day_code2[3]={0x111,0x130,0x14e};
  217. /*
  218. 函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
  219. 调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
  220. 如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
  221. c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
  222. 纪,c_sun=1为19世纪
  223. 调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
  224. */
  225. bit c_moon;
  226. data uchar year_moon,month_moon,day_moon,week;
  227. /*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/
  228. bit get_moon_day(uchar month_p,uint table_addr)
  229. {
  230.         uchar temp;
  231.         switch (month_p)
  232.         {
  233.                 case 1:{temp=year_code[table_addr]&0x08;
  234.                         if (temp==0)return(0);else return(1);}
  235.                 case 2:{temp=year_code[table_addr]&0x04;
  236.                         if (temp==0)return(0);else return(1);}
  237.                 case 3:{temp=year_code[table_addr]&0x02;
  238.                         if (temp==0)return(0);else return(1);}
  239.                 case 4:{temp=year_code[table_addr]&0x01;
  240.                         if (temp==0)return(0);else return(1);}
  241.                 case 5:{temp=year_code[table_addr+1]&0x80;
  242.                         if (temp==0) return(0);else return(1);}
  243.                 case 6:{temp=year_code[table_addr+1]&0x40;
  244.                         if (temp==0)return(0);else return(1);}
  245.                 case 7:{temp=year_code[table_addr+1]&0x20;
  246.                         if (temp==0)return(0);else return(1);}
  247.                 case 8:{temp=year_code[table_addr+1]&0x10;
  248.                         if (temp==0)return(0);else return(1);}
  249.                 case 9:{temp=year_code[table_addr+1]&0x08;
  250.                         if (temp==0)return(0);else return(1);}
  251.                 case 10:{temp=year_code[table_addr+1]&0x04;
  252.                         if (temp==0)return(0);else return(1);}
  253.                 case 11:{temp=year_code[table_addr+1]&0x02;
  254.                         if (temp==0)return(0);else return(1);}
  255.                 case 12:{temp=year_code[table_addr+1]&0x01;
  256.                         if (temp==0)return(0);else return(1);}
  257.                 case 13:{temp=year_code[table_addr+2]&0x80;
  258.                         if (temp==0)return(0);else return(1);}
  259.         }
  260. }
  261. /*
  262. 函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
  263. 调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
  264. 如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
  265. c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
  266. 纪,c_sun=1为19世纪
  267. 调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
  268. */
  269. void Conversion(bit c,uchar year,uchar month,uchar day)
  270. { //c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
  271.         uchar temp1,temp2,temp3,month_p;
  272.         uint temp4,table_addr;
  273.         bit flag2,flag_y;
  274.         temp1=year/16; //BCD->hex 先把数据转换为十六进制
  275.         temp2=year%16;
  276.         year=temp1*10+temp2;
  277.         temp1=month/16;
  278.         temp2=month%16;
  279.         month=temp1*10+temp2;
  280.         temp1=day/16;
  281.         temp2=day%16;
  282.         day=temp1*10+temp2;
  283.         //定位数据表地址
  284.         if(c==0)
  285.         {
  286.                 table_addr=(year+0x64-1)*0x3;
  287.         }
  288.         else
  289.         {
  290.                 table_addr=(year-1)*0x3;
  291.         }
  292.         //定位数据表地址完成
  293.         //取当年春节所在的公历月份
  294.         temp1=year_code[table_addr+2]&0x60;
  295.         temp1=_cror_(temp1,5);
  296.         //取当年春节所在的公历月份完成
  297.         //取当年春节所在的公历日
  298.         temp2=year_code[table_addr+2]&0x1f;
  299.         //取当年春节所在的公历日完成
  300.         // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
  301.         if(temp1==0x1)
  302.         {
  303.                 temp3=temp2-1;
  304.         }
  305.         else
  306.         {
  307.                 temp3=temp2+0x1f-1;
  308.         }
  309.         // 计算当年春年离当年元旦的天数完成
  310.         //计算公历日离当年元旦的天数,为了减少运算,用了两个表
  311.         //day_code1[9],day_code2[3]
  312.         //如果公历月在九月或前,天数会少于0xff,用表day_code1[9],
  313.         //在九月后,天数大于0xff,用表day_code2[3]
  314.         //如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1
  315.         //如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1
  316.         if (month<10)
  317.         {
  318.                 temp4=day_code1[month-1]+day-1;
  319.         }
  320.         else
  321.         {
  322.                 temp4=day_code2[month-10]+day-1;
  323.         }
  324.         if ((month>0x2)&&(year%0x4==0))
  325.         { //如果公历月大于2月并且该年的2月为闰月,天数加1
  326.                 temp4+=1;
  327.         }
  328.         //计算公历日离当年元旦的天数完成
  329.         //判断公历日在春节前还是春节后
  330.         if (temp4>=temp3)
  331.         { //公历日在春节后或就是春节当日使用下面代码进行运算
  332.                 temp4-=temp3;
  333.                 month=0x1;
  334.                 month_p=0x1; //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月
  335.                 flag2=get_moon_day(month_p,table_addr);
  336.                 //检查该农历月为大小还是小月,大月返回1,小月返回0
  337.                 flag_y=0;
  338.                 if(flag2==0)temp1=0x1d; //小月29天
  339.                 else temp1=0x1e; //大小30天
  340.                 temp2=year_code[table_addr]&0xf0;
  341.                 temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月
  342.                 while(temp4>=temp1)
  343.                 {
  344.                 temp4-=temp1;
  345.                 month_p+=1;
  346.                 if(month==temp2)
  347.                 {
  348.                 flag_y=~flag_y;
  349.                 if(flag_y==0)
  350.                 month+=1;
  351.                 }
  352.                 else month+=1;
  353.                 flag2=get_moon_day(month_p,table_addr);
  354.                 if(flag2==0)temp1=0x1d;
  355.                 else temp1=0x1e;
  356.                 }
  357.                 day=temp4+1;
  358.         }
  359.         else
  360.         { //公历日在春节前使用下面代码进行运算
  361.                 temp3-=temp4;
  362.                 if (year==0x0)
  363.                 {
  364.                         year=0x63;c=1;
  365.                 }
  366.                 else year-=1;
  367.                 table_addr-=0x3;
  368.                 month=0xc;
  369.                 temp2=year_code[table_addr]&0xf0;
  370.                 temp2=_cror_(temp2,4);
  371.                 if (temp2==0)
  372.                         month_p=0xc;
  373.                 else
  374.                         month_p=0xd; //
  375.                 /*month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12*/
  376.                 flag_y=0;
  377.                 flag2=get_moon_day(month_p,table_addr);
  378.                 if(flag2==0)temp1=0x1d;
  379.                 else temp1=0x1e;
  380.                 while(temp3>temp1)
  381.                 {
  382.                         temp3-=temp1;
  383.                         month_p-=1;
  384.                         if(flag_y==0)month-=1;
  385.                         if(month==temp2)flag_y=~flag_y;
  386.                                 flag2=get_moon_day(month_p,table_addr);
  387.                         if(flag2==0)temp1=0x1d;
  388.                         else temp1=0x1e;
  389.                 }
  390.                 day=temp1-temp3+1;
  391.         }
  392.         c_moon=c; //HEX->BCD ,运算结束后,把数据转换为BCD数据
  393.         temp1=year/10;
  394.         temp1=_crol_(temp1,4);
  395.         temp2=year%10;
  396.         year_moon=temp1|temp2;
  397.         temp1=month/10;
  398.         temp1=_crol_(temp1,4);
  399.         temp2=month%10;
  400.         month_moon=temp1|temp2;
  401.         temp1=day/10;
  402.         temp1=_crol_(temp1,4);
  403.         temp2=day%10;
  404.         day_moon=temp1|temp2;
  405. }
  406. /*函数功能:输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年)
  407. 调用函数示例:Conver_week(c_sun,year_sun,month_sun,day_sun)
  408. 如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
  409. c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
  410. 纪,c_sun=1为19世纪
  411. 调用函数后,原有数据不变,读week得出阴历BCD数据
  412. */
  413. code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
  414. /*
  415. 算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期但如果是在
  416. 闰年又不到3 月份上述之和要减一天再除7
  417. 星期数为0
  418. */
  419. void Conver_week(bit c,uchar year,uchar month,uchar day)
  420. {//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
  421.         uchar temp1,temp2;
  422.         temp1=year/16; //BCD->hex 先把数据转换为十六进制
  423.         temp2=year%16;
  424.         year=temp1*10+temp2;
  425.         temp1=month/16;
  426.         temp2=month%16;
  427.         month=temp1*10+temp2;
  428.         temp1=day/16;
  429.         temp2=day%16;
  430.         day=temp1*10+temp2;
  431.         if (c==0){year+=0x64;} //如果为21世纪,年份数加100
  432.         temp1=year/0x4; //所过闰年数只算1900年之后的
  433.         temp2=year+temp1;
  434.         temp2=temp2%0x7; //为节省资源,先进行一次取余,避免数大于0xff,避免使用整型数据
  435.         temp2=temp2+day+table_week[month-1];
  436.         if (year%0x4==0&&month<3)temp2-=1;
  437.         week=temp2%0x7;
  438. }

  439. //=========================================
  440. //TEST
  441. //=========================================
  442. uchar c_sun,year_sun,month_sun,day_sun;

  443. //主程序
  444. void main()
  445. {
  446.         c_sun=1;
  447.         year_sun=0x2;
  448.         month_sun=0x11;
  449.         day_sun=0x3;
  450.         Conver_week(c_sun,year_sun,month_sun,day_sun);
  451.         Conversion(c_sun,year_sun,month_sun,day_sun);
  452.         while(1);
  453. }



  454. 这个公历转农历算法,可以直接应用在单片机设计的数码钟上,只要调用Conversion(); 函数,传递公历的日期(BCD码),就可以输出农历的日期(BCD码)。很简单就可以应用到自己设计的单片机系统中。
复制代码



作者: 卓泰科技    时间: 2015-2-20 23:42
被公历农历转换折腾办法,我发现这是病
得治
总想找到最优的方法
一劳永逸
其实这是不现实的




欢迎光临 狗趴(GodPub),开源硬件学习与实践 (http://forum.godpub.com/) Powered by Discuz! X3.2