用汇编语言写一个温度传感显示器程序

2023-01-13  

读ADC和测温度.

;用STC的MCU的IO方式控制74HC595驱动8位数码管。

;用户可以修改宏来选择时钟频率.

;用户可以在"用户定义宏"中选择共阴或共阳. 推荐尽量使用共阴数码管.

;使用Timer0的16位自动重装来产生1ms节拍,程序运行于这个节拍下, 用户修改MCU主时钟频率时,自动定时于1ms.

;左边4位数码管显示ADC2接的电压基准TL431的读数, 右边4位数码管显示温度值, 分辨率0.1度.

;NTC使用1%精度的MF52 10K@25度C.

;测温度时, 为了通用, 使用12位的ADC值, 使用对分查找表格来计算, 小数点后一位数是用线性插补来计算的.

;所以, 测温度的ADC3进行4次ADC连续采样, 变成12位的ADC来计算温度.

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

AUXR DATA 08EH

P4 DATA 0C0H

P5 DATA 0C8H

ADC_CONTR DATA 0BCH ;带AD系列

ADC_RES DATA 0BDH ;带AD系列

ADC_RESL DATA 0BEH ;带AD系列

P1ASF DATA 09DH

PCON2 DATA 097H

P0M1 DATA 0x93 ;

P0M0 DATA 0x94 ;

P1M1 DATA 0x91 ;

P1M0 DATA 0x92 ;

P2M1 DATA 0x95 ;

P2M0 DATA 0x96 ;

P3M1 DATA 0xB1 ;

P3M0 DATA 0xB2 ;

P4M1 DATA 0xB3 ;

P4M0 DATA 0xB4 ;

P5M1 DATA 0xC9 ;

P5M0 DATA 0xCA ;

P6M1 DATA 0xCB ;

P6M0 DATA 0xCC ;

P7M1 DATA 0xE1 ;

P7M0 DATA 0xE2 ;

P_HC595_SER BIT P4.0 ; //pin 14 SER data input

P_HC595_RCLK BIT P5.4 ; //pin 12 RCLk store (latch) clock

P_HC595_SRCLK BIT P4.3 ; //pin 11 SRCLK Shift data clock

Flag0 DATA 20H

B_1ms BIT Flag0.0 ; 1ms标志

LED8 DATA 30H ; 显示缓冲 30H ~ 37H

display_index DATA 38H ; 显示位索引

msecond_H DATA 39H ;

msecond_L DATA 3AH ;

min DATA 3BH

max DATA 3CH

ORG 0000H ;reset

LJMP F_Main

ORG 0003H ;0 INT0 interrupt

RETI

LJMP F_INT0_Interrupt

ORG 000BH ;1 Timer0 interrupt

LJMP F_Timer0_Interrupt

ORG 0013H ;2 INT1 interrupt

LJMP F_INT1_Interrupt

ORG 001BH ;3 Timer1 interrupt

LJMP F_Timer1_Interrupt

ORG 0023H ;4 UART1 interrupt

LJMP F_UART1_Interrupt

ORG 002BH ;5 ADC and SPI interrupt

LJMP F_ADC_Interrupt

ORG 0033H ;6 Low Voltage Detect interrupt

LJMP F_LVD_Interrupt

ORG 003BH ;7 PCA interrupt

LJMP F_PCA_Interrupt

ORG 0043H ;8 UART2 interrupt

LJMP F_UART2_Interrupt

ORG 004BH ;9 SPI interrupt

LJMP F_SPI_Interrupt

ORG 0053H ;10 INT2 interrupt

LJMP F_INT2_Interrupt

ORG 005BH ;11 INT3 interrupt

LJMP F_INT3_Interrupt

ORG 0063H ;12 Timer2 interrupt

LJMP F_Timer2_Interrupt

ORG 0083H ;16 INT4 interrupt

LJMP F_INT4_Interrupt

ORG 0100H ;reset

F_Main:

CLR A

MOV P0M1, A ;设置为准双向口

MOV P0M0, A

MOV P1M1, A ;设置为准双向口

MOV P1M0, A

MOV P2M1, A ;设置为准双向口

MOV P2M0, A

MOV P3M1, A ;设置为准双向口

MOV P3M0, A

MOV P4M1, A ;设置为准双向口

MOV P4M0, A

MOV P5M1, A ;设置为准双向口

MOV P5M0, A

MOV P6M1, A ;设置为准双向口

MOV P6M0, A

MOV P7M1, A ;设置为准双向口

MOV P7M0, A

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初始化

L_Main_Loop:

JNB B_1ms, L_Main_Loop ;1ms未到

CLR B_1ms

;检测300ms是否到

INC msecond_L ;msecond + 1

MOV A, msecond_L

JNZ $+4

INC msecond_H

CLR C

MOV A, msecond_L ;msecond - 300

SUBB A, #LOW 300

MOV A, msecond_H

SUBB A, #HIGH 300

JC L_Main_Loop ;if(msecond < 300), jmp

;300ms到

MOV msecond_L, #0 ;if(msecond >= 1000)

MOV msecond_H, #0

MOV A, #2

LCALL F_Get_ADC10bitResult ;ACC - 通道0~7, 查询方式做一次ADC, 返回值(R6 R7)就是ADC结果, == 1024 为错误

MOV A, R6

ANL A, #0FCH

JNZ L_Read_431_ADC_Err ; adc >= 1024, 错误

LCALL F_HEX2_DEC ;(R6 R7) HEX Change to DEC ---> (R3 R4 R5), use (R2~R7)

MOV A, R4

SWAP A

ANL A, #0x0F

MOV LED8, A ;显示Vref的ADC值

MOV A, R4

ANL A, #0x0F

MOV LED8+1, A

MOV A, R5

SWAP A

ANL A, #0x0F

MOV LED8+2, A

MOV A, R5

ANL A, #0x0F

MOV LED8+3, A

MOV A, LED8

JNZ L_QuitRead_431_ADC

MOV LED8, #DIS_BLACK ;千位为0则消隐

SJMP L_QuitRead_431_ADC

L_Read_431_ADC_Err: ;错误, 显示 ----

MOV LED8, #DIS_

MOV LED8+1, #DIS_

MOV LED8+2, #DIS_

MOV LED8+3, #DIS_

L_QuitRead_431_ADC:

MOV R2, #4

MOV R4, #0

MOV R5, #0

L_NTC_ADC_Loop:

MOV A, #3

LCALL F_Get_ADC10bitResult ;ACC - 通道0~7, 查询方式做一次ADC, 返回值(R6 R7)就是ADC结果, == 1024 为错误

MOV A, R7

ADD A, R5

MOV R5, A

MOV A, R6

ADDC A, R4

MOV R4, A

DJNZ R2, L_NTC_ADC_Loop ;连续做4次ADC, 加起来获得12位的ADC, 计算NTC温度需要12位的ADC.

MOV A, R4

ANL A, #0F0H

JNZ L_Read_NTC_ADC_Err ; (adc * 4) >= 4096, 错误

MOV AR6, R4

MOV AR7, R5

LCALL F_get_temperature ;计算温度值, (R6 R7)为12位ADC,

;返回温度为(R6 R7), 0对应-40.0度, 400对应0度, 625对应25.0度, 最大1600对应120.0度.

MOV A, R6

ANL A, #0xC0

JNZ L_Read_NTC_ADC_Err ; >= 16384, 错误

MOV A, R7

CLR C

SUBB A, #LOW 400

MOV A, R6

SUBB A, #HIGH 400

JC L_Temp_LowThan_0 ; (R6 R7) < 400, jmp

CLR F0 ; 温度 >= 0度

MOV R6, A ; (R6 R7) = (R6 R7) - 400

MOV A, R7

CLR C

SUBB A, #LOW 400

MOV R7, A

SJMP L_DisplayTemp

L_Temp_LowThan_0:

SETB F0 ; 温度 < 0度

MOV A, #LOW 400 ; (R6 R7) = 400 - (R6 R7)

CLR C

SUBB A, R7

MOV R7, A

MOV A, #HIGH 400

SUBB A, R6

MOV R6, A

L_DisplayTemp:

LCALL F_HEX2_DEC ;(R6 R7) HEX Change to DEC ---> (R3 R4 R5), use (R2~R7)

MOV A, R4

SWAP A

ANL A, #0x0F

MOV LED8+4, A ;显示温度值

MOV A, R4

ANL A, #0x0F

MOV LED8+5, A

MOV A, R5

SWAP A

ANL A, #0x0F

ADD A, #DIS_DOT

MOV LED8+6, A

MOV A, R5

ANL A, #0x0F

MOV LED8+7, A

MOV A, LED8+4

JNZ L_LED8_4_Not_0

MOV LED8+4, #DIS_BLACK ;千位为0则消隐

L_LED8_4_Not_0:

JNB F0, L_QuitRead_NTC_ADC

MOV LED8+4, #DIS_ ;负温度, 显示-

SJMP L_QuitRead_NTC_ADC

L_Read_NTC_ADC_Err: ;错误, 显示 ----

MOV LED8+4, #DIS_

MOV LED8+5, #DIS_

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。