📄 gps.asm
字号:
RS EQU P3.5
RW EQU P3.6
E EQU P3.7
ORG 0000H
JMP START ; 程序开始
ORG 0023H
JMP Serial_RX_ISR ; 串口中断向量
START:
MOV SP,#60H ; 设置堆栈
LCALL Init ; 进行有关的初始化
MOV R1,#20H ; 初始化内存空间
MOV R2,#30H
CLR_CYC:
MOV @R1,#0
DJNZ R2,CLR_CYC
MOV R4,#0
SETB 20H.0 ; 将GPS工作状态位设为1,表示正在搜索中
LCALL LCD_INIT ; 刷新启动进行LCD
MAIN:
MOV C,20H.0
JC WAIT ; 20H.0 为 1时,进入等待
LCALL COUNT_NS ; 计算纬度
LCALL COUNT_EW ; 计算经度
LCALL DISPLAY_NS ; 显示纬度
LCALL DISPLAY_EW ; 显示经度
LCALL DELAY1 ; 延时
JMP MAIN
WAIT:
LCALL DISPLAY_SEARCH ; 显示搜索状态
LCALL DELAY1 ; 延时
JMP MAIN
Init:
;---------------------------------
; 程序初始化,包括串口、定时器T1、中断的初始化
;---------------------------------
MOV SCON,#10010000B ; 串口控制寄存器初始化
ORL PCON,#10000000B ; 把SMOD位置1
SETB EA ; 中断允许总控制位使能
SETB ES ; 串口中断使能
SETB PS ; 把串口中断设为高优先级
CALL Timer1_Init ; 进行定时器T1的初始化
RET
Timer1_Init:
;-------------------------
; 定时器T1作为串口的波特率发生器
; (2^SMOD)*fosc/32*12*(256-th1)=9600
;-------------------------
MOV TMOD,#00100000B ; 定时器T1工作在方式2
MOV TCON,#01000000B ; 定时器T1使能
MOV TH1,#0FAH ; 设定定时器T1的初始值
RET
COUNT_NS:
;----------------------------------
;- 计算纬度的值,并将纬度的十位,个位,十分位分别放入相应的内存空间
;----------------------------------
MOV A,55 ; 读取纬度的最高位数据
ANL A,#80H ; 测试符号位,1为北纬,0为南纬
JZ S ; 跳到南纬的处理
MOV DPTR,#TABLE2
MOV A,#0
MOVC A,@A+DPTR
MOV 61,A ; 将N所对应的代码写进内存61
MOV A,55
ANL A,7FH ; 去掉最高位
JMP NEXT
S:
MOV DPTR,#TABLE2
MOV A,#1
MOVC A,@A+DPTR
MOV 61,A ; 将S对应的代码写进内存61
MOV A,55
NEXT:
MOV B,#90
MUL AB ; 最高字节乘以90
MOV 37,B ; 结果的高位存在内存37
MOV 38,A ; 结果的低位存在内存38
MOV A,56 ; 读取次高字节
MOV B,#90
MUL AB ; 次高字节乘以90
MOV A,38 ; 读取纬度高字节乘以90所得结果的低字节
ADDC A,B ; 用纬度次高字节乘以90所得结果的高字节修正上述数据
JNC NEXT1
MOV B,37 ; 读取纬度高字节乘以90所得结果的高字节
INC B ; 修正上述数据
MOV 37,B ; 纬度计算结果高位存在37
MOV 38,A ; 纬度计算结果低位存在38
NEXT1:
; 处理整数部分,将整数的十位部分和个位部分分别储存
RLC A ; 将低位的最高位左移到C中
MOV A,37 ; 处理高位
RL A ; 高位乘2
ADDC A,#0 ; 加上低位的最高位,这就是纬度的整数部分
MOV B,#10
DIV AB ; 整数部分除以10,得到十位部分和个位部分
MOV 62,A ; 十位部分
MOV 63,B ; 个位部分
; 以下处理小数部分
MOV A,38 ; 读入纬度的低字节部分
ANL A,#7FH ; 去掉最高位得到小数部分
MOV B,#10 ; 小数部分乘以10
MUL AB
RLC A ; 以下将小数部分乘以10的结果除以2^7,去商作为第一位小数
MOV A,B
RLC A
MOV 64,A
RET
COUNT_EW:
;----------------------------------
;- 计算经度的值,并将经度的十位,个位,十分位分别放入相应的内存空间
;----------------------------------
MOV A,59 ; 读取经度的最高位数据
ANL A,#80H ; 测试符号位,1为西经,0为东经
JZ EAST ; 跳到东经的处理
MOV DPTR,#TABLE2
MOV A,#3
MOVC A,@A+DPTR
MOV 65,A ; 将W所对应的代码写进内存61
MOV A,55
ANL A,7FH ; 去掉最高位
EAST:
MOV DPTR,#TABLE2
MOV A,#2
MOVC A,@A+DPTR
MOV 65,A ; 将E对应的代码写进内存65
MOV A,55
NEXT2:
MOV B,#180
MUL AB ; 最高字节乘以180
MOV 39,B ; 结果的高位存在内存39
MOV 40,A ; 结果的低位存在内存40
MOV A,60 ; 读取次高字节
MOV B,#180
MUL AB ; 次高字节乘以180
MOV A,40 ; 读取经度度高字节乘以180所得结果的低字节
ADDC A,B ; 用经度次高字节乘以180所得结果的高字节修正上述数据
JNC NEXT3
MOV B,39 ; 读取经度高字节乘以180所得结果的高字节
INC B ; 修正上述数据
MOV 39,B ; 经度计算结果高位存在39
MOV 40,A ; 经度计算结果低位存在40
NEXT3:
; 处理整数部分,将整数的十位部分和个位部分分别储存
RLC A ; 将低位的最高位左移到C中
MOV A,37 ; 处理高位
RL A ; 高位乘2
ADDC A,#0 ; 加上低位的最高位,这就是经度的整数部分
MOV B,#10
DIV AB ; 整数部分除以10,得到十位部分和个位部分
MOV 66,A ; 十位部分
MOV 67,B ; 个位部分
; 以下处理小数部分
MOV A,40 ; 读入经度度的低字节部分
ANL A,#7FH ; 去掉最高位得到小数部分
MOV B,#10 ; 小数部分乘以10
MUL AB
RLC A ; 以下将小数部分乘以10的结果除以2^7,取商作为第一位小数
MOV A,B
RLC A
MOV 68,A
RET
DISPLAY_NS:
;------------------
;- 显示纬度
;------------------
CALL LCD_INIT
MOV P1,#80H ; 显示位置
ACALL ENABLE ; 传送命令
MOV P1,#01H
CALL ENABLE
MOV R0,#61 ; 显示N或S
MOV A,@R0
CALL WRITE2
INC R0
MOV DPTR,#TABLE1
MOV A,@R0 ; 显示纬度的十位
MOVC A,@A+DPTR
CALL WRITE2
INC R0
MOV A,@R0 ; 显示纬度的个位
MOVC A,@A+DPTR
CALL WRITE2
INC R0
MOV A,#2EH ; 显示小数点 .
CALL WRITE2
INC R0
MOV A,@R0 ; 显示纬度的十分位
MOVC A,@A+DPTR
CALL WRITE2
RET
DISPLAY_EW:
;------------------
;- 显示经度
;------------------
MOV P1,#80H ; 显示位置
ACALL ENABLE
MOV P1,#0C0H ; 写入显示起始地址(第二行第一个位置)
CALL ENABLE ; 调用写入命令子程序
MOV R0,#65 ; 显示E或W
MOV A,@R0
CALL WRITE2
INC R0
MOV DPTR,#TABLE1
MOV A,@R0 ; 显示经度的十位
MOVC A,@A+DPTR
CALL WRITE2
INC R0
MOV A,@R0 ; 显示纬度的个位
MOVC A,@A+DPTR
CALL WRITE2
INC R0
MOV A,#2EH ; 显示小数点 .
CALL WRITE2
INC R0
MOV A,@R0 ; 显示纬度的十分位
MOVC A,@A+DPTR
CALL WRITE2
RET
DISPLAY_SEARCH:
;------------------
;- 显示搜索状态
;------------------
CALL LCD_INIT
MOV P1,#80H ; 显示位置
ACALL ENABLE
MOV P1,#01H
CALL ENABLE
MOV DPTR,#TABLE0
CALL WRITE1
RET
LCD_INIT:
mov p3,#0ffh
MOV P1,#01H ; 清除屏幕
ACALL ENABLE
MOV P1,#38H ; 8位点阵
ACALL ENABLE
MOV P1,#0FH ; 开显示
ACALL ENABLE
MOV P1,#06H ; 移动光标
ACALL ENABLE
RET
ENABLE: ;送命令
CLR RS
CLR RW
CLR E
ACALL DELAY
SETB E
RET
WRITE1: ; 送字符串
MOV R1,#00h
A1:
MOV A,R1
MOVC A,@A+DPTR
CALL WRITE2
INC R1
CJNE A,#00h,A1 ; 以00H做字符串结束标志
RET
WRITE2: ; 送单个字符
MOV P1,A
SETB RS
CLR RW
CLR E
CALL delay
SETB E
RET
delay: ; 延时子程序
mov r7,#255
d1:mov r6,#255
d2:djnz r6,d2
djnz r7,d1
ret
delay1:
mov r7,#255
delay2:
mov r6,#255
djnz r6,$
djnz r7,delay2
ret
Serial_RX_ISR:
;-----------------------------------
; 串口接收中断服务程序,需要在程序开始时在2FH处写入缓存区首地址
;-----------------------------------
PUSH PSW ; 程序状态字压栈
PUSH 1 ; R1压栈
CJNE R4,#0,ISR_1 ; 判断第0字节是否为0FFH
MOV A,SBUF
CJNE A,#0FFH,ISR_OUT
INC R4
ISR_1:
CJNE R4,#1,ISR_2 ; 判断第1字节是否为81H
MOV A,SBUF
CJNE A,#81H,ISR_OUT
INC R4
ISR_2:
CJNE R4,#2,ISR_3 ; 判断第2字节是否为0E8H
MOV A,SBUF
CJNE A,#0E8H,ISR_OUT
INC R4
ISR_3:
CJNE R4,#3,ISR_4 ; 判断第3字节是否为03H
MOV A,SBUF
CJNE A,#03H,ISR_OUT
INC R4
ISR_4:
CJNE R4,#4,ISR_22 ; 判断第4字节是否为31H
MOV A,SBUF
CJNE A,#31H,ISR_OUT
INC R4
ISR_22:
CJNE R4,#22,ISR_NEXT ; 判断搜索到卫星的数量是否大于4
MOV A,SBUF
SUBB A,#4
JNC ISR_OK
SETB 20H.0 ; 20h.0为1时表示GPS搜索卫星数小于4,GPS无法准确定位
ISR_OK:
CLR 20H.0
ISR_NEXT:
MOV A,R4
SUBB A,#53 ; 将经度和纬度数据存入内存空间53-60
JC ISR_OTHER
MOV A,R4
SUBB A,#61
JNC ISR_OTHER
MOV A,R4
MOV R1,A
MOV @R1,SBUF
INC R4
JMP ISR_OUT2
ISR_OTHER:
INC R4
CJNE R4,#55,ISR_OUT ; 判断是否到一帧结束
JMP ISR_OUT2
ISR_OUT:
CLR RI ; 软件清除串口接收中断标志
MOV R4,#0 ; 将R4清零
ISR_OUT2:
POP 1 ; R1 出栈
POP PSW ; 程序状态字出栈
RETI
;--S,E,A,R,C,H,I,N,G
TABLE0: DB 53H,45H,41H,52H,43H,48H,49H,4EH,47H,00H
;-- 0,1,2,3,4,5,6,7,8,9
TABLE1: DB 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h
;-- N,S,E,W
TABLE2: DB 4EH,53H,45H,57H
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -