⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 基于LPC213X的GPS应用及使用状态机解码。全面替代LPC213x.h, 展示结构指针在ARM之特殊寄存器应用,特殊寄存器变量可在WATCH窗口中显示,为软件仿真提供最大的方便。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*--------------------------------------------------------------------------
             LPCARM之GPS应用及使用状态机解码祥解


#include <string.h>
#include <stdio.h>
#include "LPC213xdef.h"	//
#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')) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -