📄 main.c
字号:
/*--------------------------------------------------------------------------
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 + -