www.pudn.com > LPCARM_GPS_stat_machine.rar > main.c, change:2007-01-28,size:19533b


/*-------------------------------------------------------------------------- 
             LPCARM之GPS应用及使用状态机解码祥解 
 
本程序在周立功的LPC213x开发板上调试通过,用汽车电子的串口通V3.22进行输出测试。 
 
本程序是在FIFO和RTC例程的基础上追加GPS解码部分构成的。 
注:只对常用的GPRMC和GPGGA语句进行了解码。 
 
本程序主要是熟悉NMEA0183语句及使用状态机解码的优缺点,以及与传统解码程序的不同点。 
 
菜地公告:引用本文必须注明出处!!! 
 
菜农HotPower 2007.1.28 20:55 于西安大雁塔菜地 http://HotPower.21ic.org/ 
---------------------------------------------------------------------------*/ 
 
#include  
#include  
#include "LPC213xdef.h"	//水鸟HotPower的LPCARM菜鸟作 
#include "main.h" //配置头文件 
 
	 
void __swi(0) Enable(void);//同时开放FIQ/IRQ中断 
void __SWI_0			   (void) { 
int tmp; 
  __asm 
  { 
    MRS tmp, SPSR 
    BIC tmp, tmp, #0xc0 
    MSR SPSR_c, tmp 
  } 
} 
 
void __swi(1) Disable(void);//同时关闭FIQ/IRQ中断 
void __SWI_1			   (void) { 
int tmp; 
  __asm 
  { 
    MRS tmp, SPSR 
    ORR tmp, tmp, #0xc0 
    MSR SPSR_c, tmp 
  } 
} 
 
void IRQ_BOD(void) __irq 
{ 
  POWER->P_CONP &= ~(1 << PCRTC); 
  VIC->IntEnable = 0; 
  VIC->SoftIntClr = 0xffffffff;//清除所有软中断标志 
  VIC->IntSelect   = 0;//全部中断为IRQ中断或默认中断 
  VIC->VectAddr = 0;		// 向量中断结束 
  POWER->P_CON = (1 << PD);//掉电 
} 
 
void IRQ_RTC(void) __irq 
{ 
  Rtc.Sec	= RTC->RTC_SEC; 
  if (Rtc.Sec == 0) { 
    Rtc.Min	= RTC->RTC_MIN; 
	if (Rtc.Min == 0) { 
      Rtc.Hour	= RTC->RTC_HOUR; 
	  if (Rtc.Hour == 0) { 
        Rtc.Doy	= RTC->RTC_DOY; 
	    if (Rtc.Doy == 1) { 
          Rtc.Month	= RTC->RTC_MONTH; 
		  if (Rtc.Month == 1) { 
            Rtc.Year = RTC->RTC_YEAR; 
          } 
        } 
      } 
    } 
  } 
  RTC->RTC_ILR = (1 << RTCALF) | (1 << RTCCIF);	// 清除RTC增量和报警中断标志 
  VIC->VectAddr = 0;		// 向量中断结束 
} 
 
/*----------------------------------- 
     串口0中断服务程序 
-----------------------------------*/ 
void IRQ_UART0 (void) __irq 
{ 
unsigned int i; 
unsigned char ch; 
  switch(U0->IIR & 0x0f) { 
    case 0x06://接收线状态 
	  switch (U0->LSR) { 
	    case 0x63: 
		  break; 
	  } 
	  break; 
/*----------------------------------------------------------------- 
    串口接收部分代码 
用while循环从FIFO中快速地取出全部数据,也可不用循环每次取出一个字节 
的数据但达不到FIFO的功效。 
-----------------------------------------------------------------*/ 
    case 0x04://接收数据可用 
    case 0x0c://字符超时指示 
	  while (U0->LSR & 0x01) {//从FIFO中取出全部数据 
	    ch = U0->RBR;//从FIFO中取出1个字符的数据 
	    Uart.RxBuffer[Uart.RxCount ++] = ch;//暂存入缓冲区 
/*----------------------------------------------------------------- 
    串口接收解码程序激活部分代码 
当接收字符为换行符后,软件激活用户软件中断IRQ_WriteRTC(), 
进入命令解码分析及执行 
-----------------------------------------------------------------*/ 
		if (ch == '\n') {//时间设置和NMEA0183语句的结尾符都是\r\n 
		  VIC->SoftInt = (1 << VICIntSel_SoftInt22);//激活Time/GPS解码程序 
		} 
	  } 
      break; 
/*----------------------------------------------------------------- 
    串口发送激活部分代码 
由于U0->IIR & 0x0f==1时为LPCARM保留中断,可用于软件模拟激活UART0中断 
利用此漏洞来实现非典的思想来达到实战的要求。 
-----------------------------------------------------------------*/ 
	case 0x01://LPCARM保留中断,可用于软件模拟激活UART0中断 
     if (!(VIC->SoftInt & (1 << VICIntSel_UART0))) {//硬件UART0中断 
	   break;//正常的UART0中断退出 
	 } 
	 //至此成功利用了软件模拟中断偷入敌阵~~~继续运行,以达到发送首字符的目的 
/*----------------------------------------------------------------- 
    串口发送部分代码 
这里主要是充分地利用LPCARM的16个字节的FIFO来实现“无限FIFO” 
-----------------------------------------------------------------*/ 
    case 0x02://THRE中断 
  	  Uart.TxBusy = Uart.TxCount != Uart.TxdCount;//保证FIFO发送全部结束时,缓冲区空不拒绝发送 
	  for (i = 0; (i < 16) && (Uart.TxCount != Uart.TxdCount); i ++) {//1次写入FIFO最多16个字节 
		ch = Uart.TxBuffer[Uart.TxdCount ++];//取出缓冲区1个字节数据 
	    U0->THR = ch;//将缓冲区1个字节数据写入FIFO 
	  } 
	  VIC->SoftIntClr = (1 << VICIntSel_UART0);//这里必须清除此软件标志!!! 
	  break; 
  } 
  VIC->VectAddr = 0x00;		/* 通知VIC中断处理结束							*/ 
} 
 
/*----------------------------------------- 
     串口命令解码分析及执行(使用状态机) 
------------------------------------------*/ 
void IRQ_WriteRTC(void) __irq 
{ 
unsigned int state = 0, recno = 0;//状态机初始化 
unsigned char ch, crc, sum = 0; 
unsigned int i, val; 
unsigned char str[256];//虽然浪费,但算法简单 
unsigned char count; 
unsigned char prnstrg[] = "GPS数据校验成功!!!\r\n"; 
unsigned char prnstrb[] = "GPS数据校验失败!!!\r\n"; 
  while (Uart.RxdCount != Uart.RxCount) { 
    ch = Uart.RxBuffer[Uart.RxdCount ++]; 
	switch (state) { 
      case 0://同步状态 
	    if (ch == '$') {//在字符串中搜索'$' 
	      state = 1;//搜索成功,进入命令分析状态 
          crc = 0; 
	    } 
		count = 0; 
		break; 
      case 1://命令分析状态 
        crc ^= ch; 
	    if (ch != ',') {//$Date,2007-01-28,$Time,11:11:11,$Week,0 
	      str[count ++] = ch;//合法数据 
	    } 
	    else {//命令分析开始 
	      switch(str[0]) { 
		    case 'D'://Date 
		      if ((str[1] == 'a') && (str[2] == 't') && (str[3] == 'e')) { 
			    state = 2;//进入Date命令分析状态  
				count = 0; 
			  } 
			  else { 
			    state = 0;//Date解码失败!!! 
			  } 
		      break; 
		    case 'T'://Time 
		      if ((str[1] == 'i') && (str[2] == 'm') && (str[3] == 'e')) { 
			    state = 3;//进入Time命令分析状态  
				count = 0; 
			  } 
			  else { 
			    state = 0;//Time解码失败!!! 
			  } 
		      break; 
		    case 'W'://Week 
		      if ((str[1] == 'e') && (str[2] == 'e') && (str[3] == 'k')) { 
			    state = 4;//进入Week命令分析状态  
				count = 0; 
			  } 
			  else { 
			    state = 0;//Week解码失败!!! 
			  } 
		      break; 
		    case 'G'://只分析GPRMC和GPGGA语句 
			  if (str[1] == 'P') { 
			    if (str[2] == 'R') {//可能是GPRMC语句 
				  if ((str[3] == 'M') && (str[4] == 'C')) { 
			        state = 5;//进入GPRMC语句分析状态  
				    count = 0; 
					recno = 1;//11 
				  } 
				  else { 
			        state = 0;//GPRMC语句解码失败!!! 
				  } 
				} 
				else if (str[2] == 'G') {//可能是GPGGA语句 
				  if ((str[3] == 'G') && (str[4] == 'A')) { 
			        state = 6;//进入GPGGA语句分析状态  
				    count = 0; 
					recno = 1;//12 
				  } 
				  else { 
			        state = 0;//GPGGA语句解码失败!!! 
				  } 
				} 
				else { 
			      state = 0;//GPS解码失败!!! 
				} 
			  } 
			  else { 
			    state = 0;//GPS解码失败!!! 
			  } 
		      break; 
			default://其他命令出错 
			  state = 0;//失败!!! 
		  } 
	    } 
		break; 
      case 2://Date命令分析状态,例$Date,2007-01-28 
	    if ((ch == '-') || ((ch >= '0') && (ch <= '9'))){ 
	      str[count ++] = ch;//合法数据 
		} 
	    if ((count > 10) || (ch == '\n')) { 
		  if ((count == 10) && (ch == '\n')) { 
            RTC->RTC_CCR = 0;  
            val = 0;  
			for (i = 0; i < 4; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			if (val < 10000) {//万年历,严防万年虫出现 
			  RTC->RTC_YEAR = val; 
			} 
            val = 0;  
			for (i = 5; i < 7; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			if ((val >= 1) && (val <= 12)) {//倒塌了,LPCARM连此都不校验 
			  RTC->RTC_MONTH = val; 
			} 
            val = 0;  
			for (i = 8; i < 10; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			if ((val > 0) && (val <= GetDom(RTC->RTC_YEAR, RTC->RTC_MONTH))) {//合法日 
			  RTC->RTC_DOY = val;//允许改写 
			} 
//LPCARM的RTC只能在0时星期加1且不校对,故增加星期自动调节功能。 
			val = GetDow(RTC->RTC_YEAR, RTC->RTC_MONTH, RTC->RTC_DOY);//计算某日的星期数 
			if (val != RTC->RTC_DOW) { 
			  RTC->RTC_DOW = val;//星期纠错 
			} 
            RTC->RTC_CCR = (1 << CLKEN) | (1 << CLKSRC);//启动RTC 
		  } 
	      state = 0;//成功结束或失败!!! 
		}  
		break; 
      case 3://Time命令分析状态,例$Time,11:11:11 
	    if ((ch == ':') || ((ch >= '0') && (ch <= '9'))){ 
	      str[count ++] = ch;//合法数据 
		} 
	    if ((count > 8) || (ch == '\n')) { 
		  if ((count == 8) && (ch == '\n')) { 
            RTC->RTC_CCR = 0;  
            val = 0;  
			for (i = 0; i < 2; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			RTC->RTC_HOUR = val % 24; 
            val = 0;  
			for (i = 3; i < 5; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			RTC->RTC_MIN = val % 60; 
            val = 0;  
			for (i = 6; i < 8; i ++) { 
	          ch = str[i]; 
			  val = val * 10 + (ch - '0'); 
			} 
			RTC->RTC_SEC = val % 60; 
            RTC->RTC_CCR = (1 << CLKEN) | (1 << CLKSRC);// 启动RTC 
		  } 
	      state = 0;//成功结束或失败!!! 
		}  
		break; 
      case 4://Week命令分析状态,例$Week,0 
	    if ((ch == ':') || ((ch >= '0') && (ch <= '9'))){ 
	      str[count ++] = ch;//合法数据 
		} 
	    if ((count > 1) || (ch == '\n')) { 
		  if ((count == 1) && (ch == '\n')) { 
            RTC->RTC_CCR = 0;  
	        ch = str[0]; 
			val = ch - '0'; 
			RTC->RTC_DOW = val;//故意没校验,主要是验证$Date命令的正确性 
            RTC->RTC_CCR = (1 << CLKEN) | (1 << CLKSRC);// 启动RTC 
		  } 
	      state = 0;//成功结束或失败!!! 
		}  
		break; 
      case 5://GPRMC语句分析状态 
/*---------------------------------------------------------------------- 
NMEA0183语句(推荐定位信息(GPRMC)) 
$GPRMC,030545,A,3414.2522,N,10853.9838,E,0.0,0.0,300305,2.5,W*61 
 
NMEA0183语句翻译 
    $GPRMC,            讯息代码 
<1> 030545,            UTC 时间   北京时间=UTC 时间+8小时=11:05:45 
<2> A,                 定位状态, A=有效定位,V=无效定位 
<3> 3414.2522,         纬度       北纬34.142522度 
<4> N,                 纬度半球N(北半球)或S(南半球) 
<5> 10853.9838,        经度       东经108.539838度 
<6> E,                 经度半球E(东经)或W(西经) 
<7> 0.0,               地面速率   0.0 
<8> 0.0,               地面航向   0.0 
<9> 300305,            UTC 日期   2005年03月30日 
<10>2.5,               磁偏角     2.5度 
<11>W                  磁偏角方向 E(东)或W(西) 
    *61                总和检查码 *61 
----------------------------------------------------------------------*/ 
		if (ch > ' '){ 
		  if (ch == '*') {//GPRMC语句解码参数部分结束 
		    state = 7;//进入GPRMC语句校验分析状态  
	        str[count ++] = 0;//打印结束串 
		  } 
		  else { 
            crc ^= ch; 
	        if (ch != ',') { 
	          str[count ++] = ch; 
			} 
			else { 
	          str[count ++] = 0;//打印结束串 
			} 
		  } 
		  if (str[count - 1] == 0) {//需要打印 
		    switch(recno) { 
			  case 1://030545,            UTC 时间   北京时间=UTC 时间+8小时=11:05:45 
			    break; 
			  case 2://A,                 定位状态, A=有效定位,V=无效定位 
			    break; 
			  case 3://3414.2522,         纬度       北纬34.142522度 
			    break; 
			  case 4://N,                 纬度半球N(北半球)或S(南半球) 
			    break; 
			  case 5://10853.9838,        经度       东经108.539838度 
			    break; 
			  case 6://E,                 经度半球E(东经)或W(西经) 
			    break; 
			  case 7://0.0,               地面速率   0.0 
			    break; 
			  case 8://0.0,               地面航向   0.0 
			    break; 
			  case 9://300305,            UTC 日期   2005年03月30日 
			    break; 
			  case 10://2.5,               磁偏角     2.5度 
			    break; 
			  case 11://W                  磁偏角方向 E(东)或W(西) 
			    break; 
			} 
		    recno ++; 
		    count = 0; 
		  } 
		} 
		else {//防止\r\n死锁 
		  state = 0;// 
		} 
    	break; 
      case 6://GPGGA语句分析状态 
/*---------------------------------------------------------------------- 
NMEA0183语句(卫星定位信息(GPGGA)) 
$GPGGA,030545,3414.2522,N,10853.9838,E,1,05,2.9,442.2,M,-29.4,M,,*69 
 
NMEA0183语句翻译 
     $GPGGA,           讯息代码 
<1>  030545,           UTC 时间   北京时间=UTC 时间+8小时=11:05:45  
<2>  3414.2522,        纬度       北纬34.142522度 
<3>  N,                纬度半球N(北半球)或S(南半球) 
<4>  10853.9838,       经度       东经108.539838度 
<5>  E,                经度半球E(东经)或W(西经) 
<6>  1,                GPS 状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算 
<7>  05,               正在使用解算位置的卫星数量(00~12)(前面的0 也将被传输) 
<8>  2.9,              HDOP水平精度因子(0.5~99.9) 
<9>  442.2,            海拔高度442.2公尺(-9999.9~99999.9) 
<10> M,                海拔高度单位公尺 
<11> -29.4,            地表平均高度-29.4公尺 
<12> M,                地表平均高度单位公尺 
<13>  , 
     *69               总和检查码 *69 
----------------------------------------------------------------------*/ 
		if (ch > ' '){ 
		  if (ch == '*') {//GPRMC语句解码参数部分结束 
		    state = 7;//进入GPRMC语句校验分析状态  
	        str[count ++] = 0;//打印结束串 
		  } 
		  else { 
            crc ^= ch; 
	        if (ch != ',') { 
	          str[count ++] = ch; 
			} 
			else { 
	          str[count ++] = 0;//打印结束串 
			} 
		  } 
		  if (str[count - 1] == 0) {//需要打印 
		    switch(recno) { 
			  case 1://030545,           UTC 时间   北京时间=UTC 时间+8小时=11:05:45  
			    break; 
			  case 2://3414.2522,        纬度       北纬34.142522度 
			    break; 
			  case 3://N,                纬度半球N(北半球)或S(南半球) 
			    break; 
			  case 4://10853.9838,       经度       东经108.539838度 
			    break; 
			  case 5://E,                经度半球E(东经)或W(西经) 
			    break; 
			  case 6://1,                GPS 状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算 
			    break; 
			  case 7://05,               正在使用解算位置的卫星数量(00~12)(前面的0 也将被传输) 
			    break; 
			  case 8://2.9,              HDOP水平精度因子(0.5~99.9) 
			    break; 
			  case 9://442.2,            海拔高度442.2公尺(-9999.9~99999.9) 
			    break; 
			  case 10://M,               海拔高度单位公尺 
			    break; 
			  case 11://-29.4,           地表平均高度-29.4公尺 
			    break; 
			  case 12://M,               地表平均高度单位公尺 
			    break; 
			  case 13: 
			    break; 
			  case 14: 
			    break; 
			} 
		    recno ++; 
		    count = 0; 
		  } 
		} 
		else {//防止\r\n死锁 
		  state = 0;// 
		} 
		break; 
      case 7://GPRMC/GPGGA语句校验分析状态 
	    if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) { 
	      str[count ++] = ch;//合法数据 
		} 
		else if (ch == '\r') { 
		  ch = str[count - 2]; 
		  if ((ch >= '0') && (ch <= '9')) ch -= '0'; 
		  else ch -= 'A' - 10; 
		  sum = ch << 4; 
		  ch = str[count - 1]; 
		  if ((ch >= '0') && (ch <= '9')) ch -= '0'; 
		  else ch -= 'A' - 10; 
		  sum |= ch; 
		  if (sum == crc) { 
		    state = 8;// 
		  } 
		  else { 
		    ch = crc >> 4; 
		    if (ch <= 9) ch += '0'; 
		    else ch += 'A' - 10; 
		    Uart.TxBuffer[Uart.TxCount ++] = ch; 
		    ch = crc & 0x0f; 
		    if (ch <= 9) ch += '0'; 
		    else ch += 'A' - 10; 
		    Uart.TxBuffer[Uart.TxCount ++] = ch; 
		    for (i = 0; prnstrb[i] != 0; i ++) { 
		      Uart.TxBuffer[Uart.TxCount ++] = prnstrb[i]; 
		    } 
            if (!Uart.TxBusy) {//发送器不忙可以立即发送 
              VIC->SoftInt = (1 << VICIntSel_UART0);//模拟51的TI=1来引发发送中断 
            } 
  		      state = 0;//校验失败!!! 
		    } 
		} 
		else { 
		  state = 0;// 
		} 
		break; 
	  case 8: 
	    if (ch == '\n') { 
		  for (i = 0; prnstrg[i] != 0; i ++) { 
		    Uart.TxBuffer[Uart.TxCount ++] = prnstrg[i]; 
		  } 
          if (!Uart.TxBusy) {//发送器不忙可以立即发送 
            VIC->SoftInt = (1 << VICIntSel_UART0);//模拟51的TI=1来引发发送中断 
          } 
		  state = 0;//成功解码 
		} 
	    break; 
	  default://其他状态出错 
	    state = 0; 
	} 
  } 
  VIC->SoftIntClr = (1 << VICIntSel_SoftInt22); 
  VIC->VectAddr = 0;		// 向量中断结束 
} 
 
void SystemInit(void) 
{ 
volatile unsigned int start; 
  for (start = 0; start < 10000; start ++); 
  if (SystemRamTest != 0x55aa) { 
    SystemRamTest = 0x55aa; 
  } 
  VicInit(); 
  PortInit(); 
  UartInit(); 
  RtcInit(); 
} 
 
void VicInit(void) 
{ 
unsigned int i; 
  VIC->IntEnable = 0; 
  VIC->SoftIntClr = 0xffffffff;//清除所有软中断标志 
  VIC->IntSelect   = 0;//全部中断为IRQ中断或默认中断 
  for(i = 0;i < 16;i++) { 
    VIC->VectCntls[i] = 0; 
	VIC->VectAddrs[i] = 0;  
  } 
} 
 
void PortInit(void) 
{ 
  PINSEL->PIN_SEL0 = 0x00000000;		// 设置管脚连接GPIO 
  PINSEL->PIN_SEL1 = 0x00000000;		// 设置管脚连接GPIO 
  PINSEL->PIN_SEL2 = 0x00000000;		// 设置管脚连接GPIO 
} 
 
void UartInit(void) 
{ 
unsigned int Fdiv; 
  Uart.TxCount = 0; 
  Uart.RxCount = 0; 
  Uart.TxdCount = 0; 
  Uart.RxdCount = 0; 
  Uart.TxBusy = 0; 
  PINSEL->PIN_SEL0 |= (P0_0_TXD0 << P0_0_PINSEL) | (P0_1_RXD0 << P0_1_PINSEL); //设置I/O连接到UART0 
 
  U0->LCR = 0x83;// DLAB=1,允许设置波特率 
  Fdiv  = (Fpclk / 16) / UART_BPS;// 设置波特率38400 
  U0->DLM = Fdiv / 256; 
  U0->DLL = Fdiv % 256; 
  U0->LCR = 0x03; 
  U0->FCR = 0xc7;/* 初始化FIFO 接收14个字节就中断*/ 
  U0->IER = 0x07;/* 允许接收发送中断 */ 
  VIC->VectAddrs[0] = (unsigned int)IRQ_BOD; 
  VIC->VectCntls[0]   = VICIntSel_Enable 
                      | VICIntSel_BOD; 
  VIC->VectAddrs[1] = (unsigned int)IRQ_UART0; 
  VIC->VectCntls[1]   = VICIntSel_Enable//使能IRQ中断 
                      | VICIntSel_UART0;//获取UART0的IRQ级别 
  VIC->IntEnable |= (1 << VICIntSel_UART0)//使能UART0中断 
                 |  (1 << VICIntSel_BOD); 
} 
 
void RtcInit(void) 
{ 
  POWER->P_CONP |= (1 << PCRTC); 
  RTC->RTC_CCR = 0;  
  RTC->RTC_CIIR = (1 << IMSEC);				    // 设置秒值的增量产生一次中断 
  RTC->RTC_ILR = (1 << RTCALF) | (1 << RTCCIF);	// 清除RTC增量和报警中断标志 
  RTC->RTC_CCR = (1 << CLKEN) | (1 << CLKSRC);				        // 启动RTC 
  VIC->VectAddrs[2] = (unsigned int)IRQ_RTC; 
  VIC->VectCntls[2]   = VICIntSel_Enable//使能RTC中断 
                      | VICIntSel_RTC;//获取RTC的IRQ级别 
  VIC->VectAddrs[3] = (unsigned int)IRQ_WriteRTC; 
  VIC->VectCntls[3]   = VICIntSel_Enable 
                      | VICIntSel_SoftInt22; 
  VIC->IntEnable  |= (1 << VICIntSel_RTC)//使能RTC中断 
                  |  (1 <<   VICIntSel_SoftInt22); 
  Rtc.Year	= RTC->RTC_YEAR; 
  Rtc.Month	= RTC->RTC_MONTH; 
  Rtc.Doy	= RTC->RTC_DOY; 
  Rtc.Hour	= RTC->RTC_HOUR; 
  Rtc.Min	= RTC->RTC_MIN; 
  Rtc.Sec	= RTC->RTC_SEC; 
} 
 
/*---------------------------------------------------------------------------------------- 
  0000年~9999年星期算法(菜农自创) 
-----------------------------------------------------------------------------------------*/ 
unsigned int GetDow(unsigned int y, unsigned int m, unsigned int d) 
{ 
unsigned int w, c; 
  if (m <= 2){ 
    m |= 4;//1月2月同5月六月表 
    y--; 
  } 
  c = y / 100; 
  c &= 0x03;//百年%4 
  y %= 100; 
  w = ((c | (c << 2)) + (y + (y >> 2)) + (13 * m + 8)/ 5 + d) % 7;//(星期=百年%4*5+年+年/4+(13*月+8)/5+日)%7 
  return w;//返回星期 
} 
 
/*---------------------------------------------------------------------------------------- 
  附赠0000年~9999年月最大天数算法(菜农自创) 
-----------------------------------------------------------------------------------------*/ 
int GetDom(unsigned int y, unsigned int m) 
{ 
int dn; 
  dn = GetDow(y, m + 1, 1) - GetDow(y, m, 1);//m+1=13表示明年的1月 
  if (dn < 0) dn += 7; 
  return dn + 28;//返回当月的最大天数 
} 
 
 
int main(void) 
{ 
  Disable();//关中断 
  SystemInit();//系统初始化 
  Enable();//开中断 
  while(1) {//本例主要是演示串口的FIFO,主循环不想做其他目的。 
    POWER->P_CON = (1 << IDL);//_idle_() 休眠,串口中断可以苏醒。    
  } 
}