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

📄 gps.asm

📁 单片机与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 + -