;/*---------------------------------------------------------------------*/
;/* --- STC MCU Limited ------------------------------------------------*/
;/* --- STC 1T Series MCU Demo Programme -------------------------------*/
;/* --- Mobile: (86)13922805190 ----------------------------------------*/
;/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
;/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
;/* --- Web: www.STCMCU.com --------------------------------------------*/
;/* --- Web: www.STCMCUDATA.com ----------------------------------------*/
;/* --- QQ:  800003751 -------------------------------------------------*/
;/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
;/*---------------------------------------------------------------------*/

;/************* 功能说明    **************

;本例程基于STC32G为主控芯片的实验箱进行编写测试。

;使用Keil C251编译器，Memory Model推荐设置XSmall模式，默认定义变量在edata，单时钟存取访问速度快。

;edata建议保留1K给堆栈使用，空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

;从P2.3(PWM8)输出16位的PWM, 输出的PWM经过RC滤波成直流电压送P1.1做ADC并用数码管显示出来.

;串口2配置为115200bps, 8,n, 1, 切换到P4.6 P4.7, 下载后就可以直接测试. 通过串口2设置占空比.

;串口命令使用ASCII码的数字，比如： 10，就是设置占空比为10/256， 100： 就是设置占空比为100/256。

;可以设置的值为0~256, 0为连续低电平, 256为连续高电平.

;左边4位数码管显示PWM的占空比值，右边4位数码管显示ADC值。

;下载时, 选择时钟 22.1184MHz (用户可自行修改频率).

;******************************************/

$include (../../comm/STC32G.INC)

;/****************************** 用户定义宏 ***********************************/

Fosc_KHZ    EQU 22118   ;22118KHZ

STACK_POIRTER   EQU     0D0H    ;堆栈开始地址

Timer0_Reload   EQU     (65536 - Fosc_KHZ)  ; Timer 0 中断频率, 1000次/秒

DIS_DOT         EQU     020H
DIS_BLACK       EQU     010H
DIS_            EQU     011H

;UART2_Baudrate EQU     (-4608) ;   600bps @ 11.0592MHz
;UART2_Baudrate EQU     (-2304) ;  1200bps @ 11.0592MHz UART2_Baudrate = 65536UL - ((MAIN_Fosc / 4) / Baudrate)
;UART2_Baudrate EQU     (-1152) ;  2400bps @ 11.0592MHz
;UART2_Baudrate EQU     (-576)  ;  4800bps @ 11.0592MHz
;UART2_Baudrate EQU     (-288)  ;  9600bps @ 11.0592MHz
;UART2_Baudrate EQU     (-144)  ; 19200bps @ 11.0592MHz
;UART2_Baudrate EQU     (-72)   ; 38400bps @ 11.0592MHz
;UART2_Baudrate EQU     (-48)   ; 57600bps @ 11.0592MHz
;UART2_Baudrate EQU     (-24)   ;115200bps @ 11.0592MHz

;UART2_Baudrate EQU     (-7680) ;   600bps @ 18.432MHz
;UART2_Baudrate EQU     (-3840) ;  1200bps @ 18.432MHz
;UART2_Baudrate EQU     (-1920) ;  2400bps @ 18.432MHz
;UART2_Baudrate EQU     (-960)  ;  4800bps @ 18.432MHz
;UART2_Baudrate EQU     (-480)  ;  9600bps @ 18.432MHz
;UART2_Baudrate EQU     (-240)  ; 19200bps @ 18.432MHz
;UART2_Baudrate EQU     (-120)  ; 38400bps @ 18.432MHz
;UART2_Baudrate EQU     (-80)   ; 57600bps @ 18.432MHz
;UART2_Baudrate EQU     (-40)   ;115200bps @ 18.432MHz

;UART2_Baudrate EQU     (-9216) ;   600bps @ 22.1184MHz
;UART2_Baudrate EQU     (-4608) ;  1200bps @ 22.1184MHz
;UART2_Baudrate EQU     (-2304) ;  2400bps @ 22.1184MHz
;UART2_Baudrate EQU     (-1152) ;  4800bps @ 22.1184MHz
;UART2_Baudrate EQU     (-576)  ;  9600bps @ 22.1184MHz
;UART2_Baudrate EQU     (-288)  ; 19200bps @ 22.1184MHz
;UART2_Baudrate EQU     (-144)  ; 38400bps @ 22.1184MHz
;UART2_Baudrate EQU     (-96)   ; 57600bps @ 22.1184MHz
UART2_Baudrate  EQU     (-48)   ;115200bps @ 22.1184MHz

;UART2_Baudrate EQU     (-6912) ; 1200bps @ 33.1776MHz
;UART2_Baudrate EQU     (-3456) ; 2400bps @ 33.1776MHz
;UART2_Baudrate EQU     (-1728) ; 4800bps @ 33.1776MHz
;UART2_Baudrate EQU     (-864)  ; 9600bps @ 33.1776MHz
;UART2_Baudrate EQU     (-432)  ;19200bps @ 33.1776MHz
;UART2_Baudrate EQU     (-216)  ;38400bps @ 33.1776MHz
;UART2_Baudrate EQU     (-144)  ;57600bps @ 33.1776MHz
;UART2_Baudrate EQU     (-72)   ;115200bps @ 33.1776MHz


RX2_Lenth       EQU     32      ; 串口接收缓冲长度

;*******************************************************************
;*******************************************************************

;*************  IO口定义    **************/


;*************  本地变量声明    **************/
B_1ms           BIT     20H.0   ;   1ms标志

LED8            DATA    30H     ;   显示缓冲 30H ~ 37H
display_index   DATA    38H     ;   显示位索引
msecond         DATA    39H     ; 2 byte

B_TX2_Busy      BIT     20H.1   ; 发送忙标志
B_RX2_OK        BIT     20H.2   ; 接收结束标志
TX2_Cnt         DATA    3BH     ; 发送计数
RX2_Cnt         DATA    3CH     ; 接收计数
RX2_TimeOut     DATA    3DH     ; 超时计数
RX2_Buffer      DATA    40H     ;40 ~ 5FH 接收缓冲

;*******************************************************************
;*******************************************************************
        ORG     0000H               ;程序复位入口，编译器自动定义到 0FF0000H 地址
        LJMP    F_Main

        ORG     000BH               ;1  Timer0 interrupt
        LJMP    F_Timer0_Interrupt

        ORG     0043H               ;8  UART2 interrupt
        LJMP    F_UART2_Interrupt


;******************** 主程序 **************************/
        ORG     0100H       ;编译器自动定义到 0FF0100H 地址
F_Main:
    MOV     WTST, #00H     ;设置指令周期
    MOV     CKCON,#00H     ;提高访问XRAM速度
    ORL     P_SW2,#080H    ;使能访问XFR

    MOV     P0M1, #30H     ;设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P0M0, #30H
    MOV     P1M1, #32H     ;设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V), P1.1 为 ADC 高阻输入口
    MOV     P1M0, #30H
    MOV     P2M1, #3cH     ;设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P2M0, #3cH
    MOV     P3M1, #50H     ;设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P3M0, #50H
    MOV     P4M1, #3cH     ;设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P4M0, #3cH
    MOV     P5M1, #0cH     ;设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P5M0, #0cH
    MOV     P6M1, #0ffH    ;设置为漏极开路(实验箱加了上拉电阻到3.3V)
    MOV     P6M0, #0ffH
    MOV     P7M1, #00H     ;设置为准双向口
    MOV     P7M0, #00H
    
    MOV     SP, #STACK_POIRTER
    MOV     PSW, #0
    USING   0       ;选择第0组R0~R7

;================= 用户初始化程序 ====================================

    MOV     display_index, #0
    MOV     R0, #LED8
    MOV     R2, #8
L_ClearLoop:
    MOV     @R0, #DIS_BLACK     ;上电消隐
    INC     R0
    DJNZ    R2, L_ClearLoop
    
    CLR     TR0
    ORL     AUXR, #(1 SHL 7)    ; Timer0_1T();
    ANL     TMOD, #NOT 04H      ; Timer0_AsTimer();
    ANL     TMOD, #NOT 03H      ; Timer0_16bitAutoReload();
    MOV     TH0, #Timer0_Reload / 256   ;Timer0_Load(Timer0_Reload);
    MOV     TL0, #Timer0_Reload MOD 256
    SETB    ET0         ; Timer0_InterruptEnable();
    SETB    TR0         ; Timer0_Run();
    SETB    EA          ; 打开总中断
    
    LCALL   F_ADC_config    ; ADC初始化
    LCALL   F_PWM_Init      ; PWM初始化

    MOV     LED8+7, #1  ;   //显示PWM默认值
    MOV     LED8+6, #2  ;
    MOV     LED8+5, #8  ;
    MOV     LED8+4, #DIS_BLACK  ;   //这位不显示

    MOV     A, #2
    LCALL   F_UART2_config  ; 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.

    MOV     DPTR, #StringText1  ;Load string address to DPTR
    LCALL   F_SendString2       ;Send string

;=================== 主循环 ==================================
L_Main_Loop:
    JNB     B_1ms,  L_Main_Loop     ;1ms未到
    CLR     B_1ms
    
    MOV     A, RX2_TimeOut
    JNZ     L_CheckRx2TimeOut   ;串口空闲超时计数非0, 
L_QuitCheckRxTimeOut:
    LJMP    L_QuitProcessUart2  ;串口空闲超时计数为0, 退出
L_CheckRx2TimeOut:
    DJNZ    RX2_TimeOut, L_QuitCheckRxTimeOut   ;串口空闲超时计数-1非0退出

    SETB    B_RX2_OK            ;串口空闲超时, 接收结束, 做标志
    MOV     A, RX2_Cnt
    JNZ     L_RxCntNotZero      ;接收到字符数非空, 则处理
    LJMP    L_QuitProcessUart2  ;接收到字符数空, 则退出

L_RxCntNotZero:
    ANL     A, #NOT 3   ;限制为3位数字
    JZ      L_NumberLengthOk
    MOV     DPTR, #StringError3 ;Load string address to DPTR    "错误! 输入字符过多! 输入占空比为0~256!"
    LCALL   F_SendString2       ;Send string
    LJMP    L_QuitCalculatePWM  ;退出
    
L_NumberLengthOk:
    MOV     R2, #0
    MOV     R3, #0
    MOV     R0, #RX2_Buffer
    MOV     R1, RX2_Cnt

L_GetUartPwmLoop:
    MOV     A, @R0
    CLR     C
    SUBB    A, #'0'             ;计算是否小于ASCII数字0
    JNC     L_RxdataLargeThan0
    MOV     DPTR, #StringError1 ;Load string address to DPTR    "错误! 接收到小于0的数字字符! 占空比为0~256!"
    LCALL   F_SendString2       ;Send string
    LJMP    L_QuitCalculatePWM
    
L_RxdataLargeThan0:
    MOV     A, @R0
    CLR     C
    SUBB    A, #03AH            ;计算是否大于ASCII数字9
    JC      L_RxdataLessThan03A
    MOV     DPTR, #StringError4 ;Load string address to DPTR    "错误! 接收到大于9的数字字符! 占空比为0~256!"
    LCALL   F_SendString2       ;Send string
    LJMP    L_QuitCalculatePWM

L_RxdataLessThan03A:
    MOV     WR6, #10
    MUL     WR6, WR2     ;(R2,R3)* R7 -->(R4,R5,R6,R7)
    MOV     WR2, WR6

    MOV     A, @R0      ;计算 [R2 R3] = [R2 R3] * 10 + RX2_Buffer[i] - '0';
    CLR     C
    SUBB    A, #'0'
    MOVZ    WR6, R11
    ADD     WR2, WR6
    INC     R0
    DJNZ    R1, L_GetUartPwmLoop

    CMP     WR2, #256
    JLE     L_SetPWM_Right
    MOV     DPTR, #StringError2 ;Load string address to DPTR    错误! 输入占空比过大, 请不要大于256!
    LCALL   F_SendString2       ;Send string
    LJMP    L_QuitCalculatePWM

L_SetPWM_Right:

    LCALL   F_UpdatePwm     ;更新占空比
    MOV     A, R2
    JZ      L_PWM_LessTan256
    MOV     LED8+7, #2      ;占空比为256,显示256
    MOV     LED8+6, #5
    MOV     LED8+5, #6
    SJMP    L_SetPWM_OK
L_PWM_LessTan256:
    MOV     A, R3
    MOV     B, #100     ;显示0~255占空比
    DIV     AB
    MOV     LED8+7, A
    MOV     A, B
    MOV     B, #10
    DIV     AB
    MOV     LED8+6, A
    MOV     LED8+5, B
    MOV     A, LED8+7
    JNZ     L_SetPWM_OK
    MOV     LED8+7, #DIS_BLACK    ;百位消0

L_SetPWM_OK:
    MOV     DPTR, #StringText2  ;Load string address to DPTR    "已更新占空比!"
    LCALL   F_SendString2       ;Send string
L_QuitCalculatePWM:
    MOV     RX2_Cnt, #0
    CLR     B_RX2_OK
L_QuitProcessUart2:

;=================== 检测300ms是否到 ==================================
    MOV     WR6, msecond
    INC     WR6, #1         ;msecond + 1
    MOV     msecond, WR6
    CMP     WR6, #300
    JNC     L_300msIsGood   ;if(msecond < 300), jmp
    LJMP    L_Main_Loop
L_300msIsGood:
    MOV     WR6, #0
    MOV     msecond, WR6    ;msecond = 0

    MOV     A, #01H
    LCALL   F_Get_ADC12bitResult    ; 读外部电压ADC, 查询方式做一次ADC, 返回值(R6 R7)就是ADC结果, == 4096 为错误

    MOV     WR4, #00000H    ;被除数
    ;MOV     WR6, WR6
    MOV     WR0, #00000H    ;除数
    MOV     WR2, #1000
    MOV     DMAIR, #04H     ;32位无符号除法
    MOV     A, R7           ;显示数值
    ANL     A, #0x0F
    MOV     LED8+3, A

    MOV     WR4, WR0        ;余数做被除数
    MOV     WR6, WR2
    MOV     WR0, #00000H
    MOV     WR2, #100
    MOV     DMAIR, #04H     ;32位无符号除法
    MOV     A, R7           ;显示数值
    ANL     A, #0x0F
    MOV     LED8+2, A

    MOV     WR4, WR0        ;余数做被除数
    MOV     WR6, WR2
    MOV     WR0, #00000H
    MOV     WR2, #10
    MOV     DMAIR, #04H     ;32位无符号除法
    MOV     A, R7           ;显示数值
    ANL     A, #0x0F
    MOV     LED8+1, A

    MOV     A, R3           ;显示数值
    ANL     A, #0x0F
    MOV     LED8+0, A

    MOV     A, LED8+3           ;显示消无效0
    JNZ     L_QuitProcessADC
    MOV     LED8+3, #DIS_BLACK
    MOV     A, LED8+2
    JNZ     L_QuitProcessADC
    MOV     LED8+2, #DIS_BLACK
    MOV     A, LED8+1
    JNZ     L_QuitProcessADC
    MOV     LED8+1, #DIS_BLACK
L_QuitProcessADC:

    LJMP    L_Main_Loop
;===================================================================

;========================================================================
; 函数: F_PWM_Init
; 描述: PWM初始化程序.
; 参数: none
; 返回: none.
; 版本: V1.0, 2021-3-3
;========================================================================
F_PWM_Init:
    MOV     A, #00H              ;写 CCMRx 前必须先清零 CCxE 关闭通道
    MOV     WR6, #WORD0 PWMB_CCER2
    MOV     WR4, #WORD2 PWMB_CCER2
    MOV     @DR4, R11
    MOV     A, #060H             ;设置 CC8 为 PWM模式1 输出
    MOV     WR6, #WORD0 PWMB_CCMR4
    MOV     WR4, #WORD2 PWMB_CCMR4
    MOV     @DR4, R11
    MOV     A, #010H             ;使能 CC8 通道
    MOV     WR6, #WORD0 PWMB_CCER2
    MOV     WR4, #WORD2 PWMB_CCER2
    MOV     @DR4, R11

    MOV     A, #068H             ;开启PWMB_CCRx预转载功能(需要CCxE=1才可写)
    MOV     WR6, #WORD0 PWMB_CCMR4
    MOV     WR4, #WORD2 PWMB_CCMR4
    MOV     @DR4, R11

    MOV     A, #1                ;设置周期时间
    MOV     WR6, #WORD0 PWMB_ARRH
    MOV     WR4, #WORD2 PWMB_ARRH
    MOV     @DR4, R11
    MOV     A, #0
    MOV     WR6, #WORD0 PWMB_ARRL
    MOV     WR4, #WORD2 PWMB_ARRL
    MOV     @DR4, R11
    MOV     A, #0                ;设置占空比时间
    MOV     WR6, #WORD0 PWMB_CCR8H
    MOV     WR4, #WORD2 PWMB_CCR8H
    MOV     @DR4, R11
    MOV     A, #128
    MOV     WR6, #WORD0 PWMB_CCR8L
    MOV     WR4, #WORD2 PWMB_CCR8L
    MOV     @DR4, R11

    MOV     A, #40H              ;使能 PWM8 输出
    MOV     WR6, #WORD0 PWMB_ENO
    MOV     WR4, #WORD2 PWMB_ENO
    MOV     @DR4, R11
    MOV     A, #00H              ;高级 PWM 通道 8 输出脚选择位, 0x00:P2.3, 0x40:P3.4, 0x80:P0.3, 0xc0:P7.7
    MOV     WR6, #WORD0 PWMB_PS
    MOV     WR4, #WORD2 PWMB_PS
    MOV     @DR4, R11
    MOV     A, #080H             ;使能主输出
    MOV     WR6, #WORD0 PWMB_BKR
    MOV     WR4, #WORD2 PWMB_BKR
    MOV     @DR4, R11

    MOV     WR6, #WORD0 PWMB_CR1
    MOV     WR4, #WORD2 PWMB_CR1
    MOV     R11, @DR4
    ORL     A,#081H              ;使能ARR预装载,开始计时
    MOV     @DR4, R11
    RET

;======================================================================

;========================================================================
; 函数: F_UpdatePwm
; 描述: 更新PWM占空比值. 
; 参数: [R2 R3]: pwm占空比值.
; 返回: none.
; 版本: V1.0, 2021-3-3
;========================================================================
F_UpdatePwm:
    MOV     A, R2               ;设置占空比时间
    MOV     WR6, #WORD0 PWMB_CCR8H
    MOV     WR4, #WORD2 PWMB_CCR8H
    MOV     @DR4, R11
    MOV     A, R3
    MOV     WR6, #WORD0 PWMB_CCR8L
    MOV     WR4, #WORD2 PWMB_CCR8L
    MOV     @DR4, R11
    RET

;**********************************************/

F_ADC_config:
    MOV     A, #03FH            ; 设置 ADC 内部时序，ADC采样时间建议设最大值
    MOV     WR6, #WORD0 ADCTIM
    MOV     WR4, #WORD2 ADCTIM
    MOV     @DR4, R11

    MOV     ADCCFG, #02FH       ; 设置转换结果右对齐模式， ADC 时钟为系统时钟/2/16
    MOV     ADC_CONTR, #080H    ; 使能 ADC 模块
    RET

;========================================================================
; 函数: F_Get_ADC12bitResult
; 描述: 查询法读一次ADC结果.
; 参数: ACC: 选择要转换的ADC.
; 返回: (R6 R7) = 12位ADC结果.
; 版本: V1.0, 2020-11-09
;========================================================================
F_Get_ADC12bitResult:   ;ACC - 通道0~7, 查询方式做一次ADC, 返回值(R6 R7)就是ADC结果, == 4096 为错误
    MOV     R7, A           //channel
    MOV     ADC_RES,  #0;
    MOV     ADC_RESL, #0;

    MOV     A, ADC_CONTR        ;ADC_CONTR = (ADC_CONTR & 0xd0) | ADC_START | channel; 
    ANL     A, #0D0H
    ORL     A, #40H
    ORL     A, R7
    MOV     ADC_CONTR, A
    NOP
    NOP
    NOP
    NOP

L_WaitAdcLoop:
    MOV     A, ADC_CONTR
    JNB     ACC.5, L_WaitAdcLoop

    ANL     ADC_CONTR, #NOT 020H    ;清除完成标志

    MOV     A, ADC_RES      ;12位AD结果的高4位放ADC_RES的低4位，低8位在ADC_RESL。
    ANL     A, #0FH
    MOV     R6, A
    MOV     R7, ADC_RESL

L_QuitAdc:
    RET

;====================================================================================
StringText1:
    DB  "PWM和ADC测试程序, 输入占空比为 0~256!",0DH,0AH,0
StringText2:
    DB  "已更新占空比!",0DH,0AH,0
StringError1:
    DB  "错误! 接收到小于0的字符! 占空比为0~256!",0DH,0AH,0
StringError2:
    DB  "错误! 输入占空比太大, 请不要大于256!",0DH,0AH,0
StringError3:
    DB  "错误! 输入字符太多! 输入占空比为0~256!",0DH,0AH,0
StringError4:
    DB  "错误! 接收到大于9的字符! 占空比为0~256!",0DH,0AH,0


;========================================================================
; 函数: F_SendString2
; 描述: 串口2发送字符串函数。
; 参数: DPTR: 字符串首地址.
; 返回: none.
; 版本: VER1.0
; 日期: 2014-11-28
; 备注: 
;========================================================================
F_SendString2:
    CLR     A
    MOVC    A, @A+DPTR      ;Get current char
    JZ      L_SendEnd2      ;Check the end of the string
    SETB    B_TX2_Busy      ;标志发送忙
    MOV     S2BUF, A        ;发送一个字节
    JB      B_TX2_Busy, $   ;等待发送完成
    INC     DPTR            ;increment string ptr
    SJMP    F_SendString2       ;Check next
L_SendEnd2:
    RET

;========================================================================
; 函数: F_SetTimer2Baudraye
; 描述: 设置Timer2做波特率发生器。
; 参数: DPTR: Timer2的重装值.
; 返回: none.
; 版本: VER1.0
; 日期: 2014-11-28
; 备注: 
;========================================================================
F_SetTimer2Baudraye:    ; 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
    ANL     AUXR, #NOT (1 SHL 4)    ; Timer stop    波特率使用Timer2产生
    ANL     AUXR, #NOT (1 SHL 3)    ; Timer2 set As Timer
    ORL     AUXR, #(1 SHL 2)        ; Timer2 set as 1T mode
    MOV     T2H, DPH
    MOV     T2L, DPL
    ANL     IE2, #NOT (1 SHL 2)     ; 禁止中断
    ORL     AUXR, #(1 SHL 4)        ; Timer run enable
    RET

;========================================================================
; 函数: F_UART2_config
; 描述: UART2初始化函数。
; 参数: ACC: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
; 返回: none.
; 版本: VER1.0
; 日期: 2014-11-28
; 备注: 
;========================================================================
F_UART2_config:
    CJNE    A, #2, L_Uart2NotUseTimer2
    MOV     DPTR, #UART2_Baudrate
    LCALL   F_SetTimer2Baudraye

    MOV     A, #0X01            ; 使用串口2时，W1位必需设置为1，否则可能会产生不可预期的错误
    MOV     WR6, #WORD0 S2CFG
    MOV     WR4, #WORD2 S2CFG
    MOV     @DR4, R11

    ANL     S2CON, #0x3f
    ORL     S2CON, #0x40     ; UART2模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
    ORL     IE2,   #0X01            ; 允许中断
    ORL     S2CON, #(1 SHL 4)   ; 允许接收
;   ANL     P_SW2, #NOT 0x01    ; UART2 switch to P1.0 P1.1
    ORL     P_SW2, #0x01        ; UART2 switch to P4.6 P4.7
    CLR     B_TX2_Busy
    MOV     RX2_Cnt, #0;
    MOV     TX2_Cnt, #0;
L_Uart2NotUseTimer2:
    RET


;========================================================================
; 函数: F_UART2_Interrupt
; 描述: UART2中断函数。
; 参数: nine.
; 返回: none.
; 版本: VER1.0
; 日期: 2014-11-28
; 备注: 
;========================================================================
F_UART2_Interrupt:
    PUSH    PSW
    PUSH    ACC
    PUSH    AR0
    
    MOV     A, S2CON
    JNB     ACC.0, L_QuitUartRx
    ANL     S2CON, #NOT 1;
    MOV     RX2_TimeOut, #5
    MOV     A, #RX2_Buffer
    ADD     A, RX2_Cnt
    MOV     R0, A
    MOV     @R0, S2BUF  ;保存一个字节
    INC     RX2_Cnt
    MOV     A, RX2_Cnt
    CJNE    A, #RX2_Lenth, L_QuitUartRx
    MOV     RX2_Cnt, #0     ; 避免溢出处理
L_QuitUartRx:

    MOV     A, S2CON
    JNB     ACC.1, L_QuitUartTx
    ANL     S2CON, #NOT 2;
    CLR     B_TX2_Busy      ; 清除发送忙标志
L_QuitUartTx:

    POP     AR0
    POP     ACC
    POP     PSW
    RETI


; *********************** 显示相关程序 ****************************************
T_Display:                      ;标准字库
;    0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
DB  03FH,006H,05BH,04FH,066H,06DH,07DH,007H,07FH,06FH,077H,07CH,039H,05EH,079H,071H
;  black  -    H    J    K    L    N    o    P    U    t    G    Q    r    M    y
DB  000H,040H,076H,01EH,070H,038H,037H,05CH,073H,03EH,078H,03dH,067H,050H,037H,06EH
;    0.   1.   2.   3.   4.   5.   6.   7.   8.   9.   -1
DB  0BFH,086H,0DBH,0CFH,0E6H,0EDH,0FDH,087H,0FFH,0EFH,046H

T_COM:
DB  001H,002H,004H,008H,010H,020H,040H,080H     ;   位码


;//========================================================================
;// 函数: F_DisplayScan
;// 描述: 显示扫描子程序。
;// 参数: none.
;// 返回: none.
;// 版本: VER1.0
;// 日期: 2013-4-1
;// 备注: 除了ACCC和PSW外, 所用到的通用寄存器都入栈
;//========================================================================
F_DisplayScan:
    PUSH    DPH     ;DPH入栈
    PUSH    DPL     ;DPL入栈
    PUSH    00H     ;R0 入栈
    
    MOV     DPTR, #T_COM
    MOV     A, display_index
    MOVC    A, @A+DPTR
    CPL     A
    MOV     P7,A
    
    MOV     DPTR, #T_Display
    MOV     A, display_index
    ADD     A, #LED8
    MOV     R0, A
    MOV     A, @R0
    MOVC    A, @A+DPTR
    CPL     A
    MOV     P6,A

    INC     display_index
    MOV     A, display_index
    ANL     A, #0F8H            ; if(display_index >= 8)
    JZ      L_QuitDisplayScan
    MOV     display_index, #0;  ;8位结束回0
L_QuitDisplayScan:
    POP     00H     ;R0 出栈
    POP     DPL     ;DPL出栈
    POP     DPH     ;DPH出栈
    RET


;*******************************************************************
;**************** 中断函数 ***************************************************

F_Timer0_Interrupt: ;Timer0 1ms中断函数
    PUSH    PSW     ;PSW入栈
    PUSH    ACC     ;ACC入栈

    LCALL   F_DisplayScan   ; 1ms扫描显示一位
    SETB    B_1ms           ; 1ms标志
    

    POP     ACC     ;ACC出栈
    POP     PSW     ;PSW出栈
    RETI

    END

