S3F9454/94C4/94C8通用ADC检测NTC热敏电阻温度转换显示例程
文章来源: 本站原创   更新时间: 2014-06-23
;--------------------------------------
;程序中所有分号后面的都是注释语句
;#号表示一个常量名字或数据
;-----------------------------------------------------
.include "s3c9454.reg" ;必须加入寄存器定义文件,这个文件是OPENICE自带的
;-----------------------------------------------------
;以下为程序运行所用变量定义
DIGIT1 EQU 00H ;LED-A位数据定义
DIGIT2 EQU 01H ;LED-B位数据定义
DIGIT3 EQU 02H ;LED-C位数据定义
DIGIT4 EQU 03H ;LED-D位数据定义
SEG1 EQU 04H ;SEG-A位显示码
SEG2 EQU 05H ;SEG-B位显示码
SEG3 EQU 06H ;SEG-C位显示码
SEG4 EQU 07H ;SEG-D位显示码

TMRFLAG EQU 08H ;定时标志寄存器
LED_LOOP EQU 09H ;显示循环计数器
TMR_05S EQU 0AH ;0.5S计时器

NTC_TEMP EQU 0BH ;温度值
ADC_H EQU 0CH ;ADC数据高位
ADC_L EQU 0DH ;ADC数据低位
;--------------------------------------------
;位操作定义
CK_164 BIT P0.0 ;P0.0是164时钟驱动线
DT_164 BIT P0.1 ;P0.1是164数据驱动线

SMG_D1 BIT P0.5 ;P0.5是数码管驱动位线1
SMG_D2 BIT P0.4 ;P0.4是数码管驱动位线2
SMG_D3 BIT P0.3 ;P0.3是数码管驱动位线3
SMG_D4 BIT P0.2 ;P0.2是数码管驱动位线4

NTC_IN BIT P2.6 ;NTC热敏电阻接在P26

FLAG_05S BIT TMRFLAG.0 ;0.5S定时标志

ADC_NTC .EQU 10000001B ;NTC ADC转换启动设定值

MIN_TEMP .EQU -30 ;查表最低温度为-30度
MAX_TEMP .EQU 99 ;查表最高温度为99度
;--------------------------------------------------------
         ;9454只有一个中断向量地址,在0000H,这里设置中断服务程序INT_9454
        ORG 0000H ;ORG表示定义一个绝对的ROM地址,0000H地址
        .VECTOR $,INT_9454 ;一个向量地址占用2个字节,$表示是在当前地址处定义,也可以采用直接的绝地址定义,
                                ;如:.VECTOR 0000H,INT_9454,两者效果相同
;------------------------------------------------------------
;显示编码予定义
DIGIT_CODE: ;表格开始地址是0000H
       DB 03fh ;0
       DB 006h ;1
       DB 05bh ;2
       DB 04fh ;3
       DB 066h ;4
       DB 06dh ;5
       DB 07dh ;6
       DB 007h ;7
       DB 07fh ;8
       DB 06fh ;9
       DB 077h ;A
       DB 07Ch ;B
       DB 039h ;C
       DB 05Eh ;D
       DB 079h ;E
       DB 071h ;F
       DB 040H ;-号
       DB 0FFH ;全显示
       DB 00H ;不显示(黑屏)
       
_CODE .EQU 10H
LED_OFF .EQU 12H
LED_ON .EQU 11H
;-----------------------------------------------------------
;SMART OPTION
;有关这几个数据设置,请详细参阅9454手册的ADDRESS SPACE部分的SMART OPTION说明
;SMART OPTION定义4个字节数据在003CH--003FH这4个ROM地址
        ORG 003CH
        DB 00H
        DB 00H
        DB 0E7H ;设置内部LVR使能,用内部复位,LVR电平为2.3V
        DB 03H ;00H定义外部晶振,03H定义内部OSC
;-----------------------------------------------------------
;-------<>
        ORG 0100H

RESET: ;-------------------------
        ;follow must set
        DI ;disable interrupt
        LD BTCON,#10100011B ;Watch-dog disable
        LD CLKCON,#00011000B ;selet non-divided CPU clock
        LD SP,#0C0H ;Stack pointer must be set as 0C0H

        LD P0CONH,#00001010B
        LD P0CONL,#10101010B ;设置P00--P05作为输出
        
        LD P2CONH,#00110000B ;设置P26作为ADC输入
      
        LD T0CON,#01001010B ;TMR0输入时钟=FXX/8, 开启T0中断
        LD T0DATA,#50 ;若OSC=3.2MHZ,则T0每2MS产生一次中断,TIME= (3.2MHZ/256)*50= 4MS

        LD LED_LOOP,#00H
        EI
;----------------------------------------
MAIN:
        ;每0.5S检测一次温度
        TMBIT FLAG_05S
        JR Z,MAIN
        CLRBIT FLAG_05S
         
        CALL GET_NTC_TEMP ;检测得到温度值
        
        CALL DISPLAY_CONVERT ;转换温度数据到ABCD四位显示数据
        
        CALL DIGIT_CONVERT ;转换显示数据到显示码
        JR MAIN
 
;--------------------------------------------------------
;该进程检测ADC端口NTC热敏电阻状态并查表得到温度值
GET_NTC_TEMP:
        LD R0,#ADC_NTC
        CALL TEST_ADC
        
        ;LD ADC_H,#00H
        ;LD ADC_L,#0F0H
        ;转换得到的AD数据在ADC_H:ADC_L中存放
        ;查表得到实际的温度值
        ;从低温表值查起
        LD R10,#00H
        LD R11,#00H
        LD R2,ADC_H
        LD R3,ADC_L
        LD R4,#MIN_TEMP ;R4作为查表增量计数器,从最低温度开始查起(表头为-30度)
S_LOOP:
        LDC R0,#NTC_TABEL[RR10] ;得到高位数据
        ADD R11,#1 ;地址加1,得到低位数据
        ADC R10,#0
        LDC R1,#NTC_TABEL[RR10]
        ;通过减法来比较取得的表数据与实际测得的AD数据大小
        SUB R1,R3
        SBC R0,R2
        JR NC,S_BACK ;若当前值大于或等于测试值,则确认该数据
        ;小于,继续搜索下一个较大值
S_NEXT:
        ADD R11,#1 ;地址再加一个字节,准备读取下一个数据
        ADC R10,#0
        INC R4 ;R4作为增量计数器
        ;温度表格最大到100度
        CP R4,#0
        JR LT,S_LOOP
        CP R4,#MAX_TEMP ;最大130个列表项目 (-30--100)
        JR ULT,S_LOOP
        ;超出最大温度,则直接计为最大值
S_BACK:
        LD NTC_TEMP,R4
        RET
;--------------------------------------------------------
;该模块把温度值转换为ABCD四位显示数据
DISPLAY_CONVERT:
        CP NTC_TEMP,#99 ;大于99度的数据在查表中实际为负温度
        JR UGT,F_CVT
;----------------
;正温度显示转换
S_CVT:
        LD DIGIT1,#LED_OFF
        LD DIGIT2,#LED_OFF
        LD R1,NTC_TEMP
        JR DCVT_BACK
;----------------
;负温显示转换
F_CVT:
        LD DIGIT1,#LED_OFF
        LD DIGIT2,#_CODE
        ;负值必须转换为补码得到正值
        LD R1,NTC_TEMP
        XOR R1,#0FFH
        ADD R1,#1
;-------------
DCVT_BACK:
        CALL CONVERT_DATA
        LD DIGIT3,R0
        LD DIGIT4,R1
        RET
;--------------------------------------------------------
;该进程把一个两位数据转换为十位和个位数据
;R1--要转换的两位数据,转换后为个位数据
;R0--转换后的十位数据
CONVERT_DATA:
        CP R1,#99
        JR ULE,CVT_ST
        LD R1,#99 ;最大限99
CVT_ST:
        LD R0,#00H
CVT_LOOP:
        CP R1,#10
        JR ULT,CVT_BACK
        SUB R1,#10
        INC R0
        JR CVT_LOOP
CVT_BACK:
        RET
;---------------------------------------------------------
;该进程把要数码管各位要显示的数据转换为显示码
DIGIT_CONVERT:
        LD R10,#00H ;调入显示码定义高位地址
        LD R11,#DIGIT_CODE ;调入显示码定义起始地址
        
        ;调入A位显示码
        LD R11,#DIGIT_CODE ;调入显示码定义起始地址
        ADD R11,DIGIT1 ;LED-A位数据定义
        LDC R0,@RR10 ;把RR10寄存器对中的地址所指向的ROM地址字节中的数据调入到R0
        LD SEG1,R0 ;把R0寄存器中的地址所指向的ROM地址字节中的数据调入到
                                        ;SEG-A位显示码
        
        ;调入B位显示码
        LD R11,#DIGIT_CODE ;调入显示码定义起始地址
        ADD R11,DIGIT2
        LDC R0,@RR10
        LD SEG2,R0
        
        ;调入C位显示码
        LD R11,#DIGIT_CODE ;调入显示码定义起始地址
        ADD R11,DIGIT3
        LDC R0,@RR10
        LD SEG3,R0
        
        ;调入D位显示码
        LD R11,#DIGIT_CODE ;调入显示码定义起始地址
        ADD R11,DIGIT4
        LDC R0,@RR10
        LD SEG4,R0
     
        RET
;--------------------------------------------------------
;该进程根据输入的ADC设置数据进行AD检测得到ADH,ADL数据
;连续测64次AD输入求平均值
;R0---输入的ADCON设置数据
;返回:ADC_H:ADC_L是平均值的高位和低位
TEST_ADC:
        PUSH R15 ;首先将用到的暂存器入栈
        PUSH R14
        PUSH R13
        PUSH R12
        PUSH R11 ;但如果主程序中未用到这些工作寄存器,也可以不用管这些
        PUSH R10
        PUSH R9
        
        
        LD R9,#64 ;16次计数
        CLR R10
        CLR R11
        CLR R12
        ;R10:R11:R12是用来存储16次检测值加法和
        ;R13:R14:R15用来暂存ADDATAH:ADDATAL的移位转换
ADC_LOOP:
        LD ADCON,R0
ADC_WAIT:
        TM ADCON,#08H ;ADCON.3是AD转换完成位标志
        JR Z,ADC_WAIT
        ;转换完成
        LD R15,ADDATAL
        LD R14,ADDATAH
        LD R13,#00H
           
        ;将AD数据加到加法和
        RCF
        RLC R14 ;通过左移2位方式将ADDATAH的高2位移入到R12
        RLC R13 ;并腾出低2位以便加入ADDATAL的低2位
        RLC R14
        RLC R13
        AND R14,#11111100B ;低2位必须先行清零,以消除C标志移入的影响
        ADD R14,R15 ;加上低2位值
        ADC R13,#00H
        
        ADD R12,R14
        ADC R11,R13
        ADC R10,#00H
        
        DEC R9
        JR NZ,ADC_LOOP
        ;64次检测完毕,求平均值
        ;采用简单移位除法,将整个32位加法和右移4位即可得到
        ;除2
        RRC R10
        RRC R11
        RRC R12
        ;除4
        RRC R10
        RRC R11
        RRC R12
        ;除8
        RRC R10
        RRC R11
        RRC R12
        ;除16
        RRC R10
        RRC R11
        RRC R12
        ;除32
        RRC R10
        RRC R11
        RRC R12
        ;除64
        RRC R10
        RRC R11
        RRC R12
        
        ;低位R11是64次平均值
        LD ADC_H,R11
        LD ADC_L,R12
        ;如果只处理8位AD数据,则需要忽略低2位,则将数据右移2位即可
        ;RRC ADC_H
        ;RRC ADC_L
        ;RRC ADC_H
        ;RRC ADC_L
        ;ADTL是实际得到的AD测试平均值数据
        
        POP R9
        POP R10 ;将暂存器出栈,注意先进先出原则
        POP R11
        POP R12
        POP R13
        POP R14
        POP R15
        RET

        RET
;---------------------------------------------------------
;R0---要发送到164输出的数据
SENDTO164:
        PUSH R1
        CLRBIT CK_164
        CLRBIT DT_164
        LD R1,#08H
;----------
LOOP_164:
        ;必须先根据数据状态予置好DATA线状态
        CLRBIT DT_164
        RRC R0
        JR C,SET_1
SET_0:
        CLRBIT DT_164
        JR SEND_CLK
SET_1:
        SETBIT DT_164
;---------
;发送一个时钟信号
SEND_CLK:
        SETBIT CK_164
        NOP
        NOP
        NOP
        CLRBIT CK_164
        
        DEC R1
        JR NZ,LOOP_164
;---------
SEND_BACK:
        POP R1
        RET
;---------------------------------------------------------
;该进程通过轮询方式来分时扫描数码管的A,B,C,D各位显示
LED_SCAN:
        INC LED_LOOP
        ;注意在每次送数据到LED显示前,必须先关闭全部位线
        CLRBIT SMG_D1
        CLRBIT SMG_D2
        CLRBIT SMG_D3
        CLRBIT SMG_D4
         
        CP LED_LOOP,#01H
        JR EQ,SCAN_1
        CP LED_LOOP,#02H
        JR EQ,SCAN_2
        CP LED_LOOP,#03H
        JR EQ,SCAN_3
        CP LED_LOOP,#04H
        JR EQ,SCAN_4
        
        LD LED_LOOP,#00H
SCAN_1:
        LD R0,SEG1 ;调入A位显示码
        CALL SENDTO164
        SETBIT SMG_D1 ;打开1位线显示
        JR SCAN_BACK
SCAN_2:
        LD R0,SEG2 ;调入B位显示码
        CALL SENDTO164
        SETBIT SMG_D2 ;打开2位线显示
        JR SCAN_BACK
SCAN_3:
        LD R0,SEG3 ;调入C位显示码
        CALL SENDTO164
        SETBIT SMG_D3 ;打开3位线显示
        JR SCAN_BACK
SCAN_4:
        LD R0,SEG4 ;调入D位显示码
        CALL SENDTO164
        SETBIT SMG_D4 ;打开4位线显示
SCAN_BACK:
        RET
;---------------------------------------------------------
;TMR0-2MS中断一次
INT_9454:
        AND T0CON,#0FEH ;清T0中断标志位
        OR T0CON,#08H ;清T0CNT,这个是芯片手册规定的
        
        CALL LED_SCAN ;扫描LED显示
        
        INC TMR_05S
        CP TMR_05S,#250
        JR ULT,INT_BACK
        ;定时1S时间到
        SETBIT FLAG_05S
        CLR TMR_05S
INT_BACK:
        IRET
;---------------------------------------------------------------
;---------------------------------------------------
;热敏电阻分压值转换为ADC数据表格
;转换方式:设相应温度时的热敏电阻在电路中实际分压值为TV,
;则计算公式为 TV*1023
;因数据可能会大于8位,表格中所有数据均定义为字格式(双字节数据)
NTC_TABEL:
        dw 54,58,61,65,69,72,77,81,86,90;//-30 ~ -21
        dw 95,100,106,111,117,123,129,136,142,149;// -20 ~ -11
        dw 156,164,171,179,187,195,204,212,221,230;//-10 ~ -1
        dw 240,249,259,269,279,289,299,310,320,331;// 0 ~ 9
        dw 342,353,364,375,387,398,409,421,432,444;//10 ~ 19
        dw 455,467,478,489,501,512,523,534,545,556;//20 ~ 29
        dw 567,578,589,599,610,620,630,640,650,659;//30 ~ 39
        dw 669,678,687,696,705,713,722,730,738,746;//40 ~ 49
        dw 754,761,768,776,783,789,796,802,809,815;//50 ~ 59
        dw 821,827,832,838,843,848,853,858,863,868;//60 ~ 69
        dw 872,877,881,885,889,893,896,900,904,907;//70 ~ 79
        dw 910,914,917,920,923,926,928,931,934,936;//80 ~ 89
        dw 939,941,943,946,948,950,952,954,956,958;//90 ~ 99
;--------------------------------------------------------------

.END ;Programer is end

相关备注:
 
三星单片机开发网首页