;--------------------------------------
;程序中所有分号后面的都是注释语句
;#号表示一个常量名字或数据
;-----------------------------------------------------
.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
|
相关备注: |
无 |
|