求一个51单片机控制的温度计显示程序

求一个51单片机控制的温度计显示程序,第1张

这个程序完全没问题的,我做过实验。希望对你有帮助,,,,

//DS18B20的读写程序,数据脚P33 //

//温度传感器18B20汇编程序,采用器件默认的12位转化 //

//最大转化时间750微秒,显示温度-55到+125度,显示精度 //

//为01度,显示采用4位LED共阳显示测温值 //

//P0口为段码输入,P24~P27为位选 //

//

#include "reg51h"

#include "intrinsh" //_nop_();延时函数

#define Disdata P0 //段码输出口

#define discan P2 //扫描口

#define uchar unsigned char

#define uint unsigned int

sbit DQ=P3^3; //温度输入口

sbit DIN=P0^7; //LED小数点控制

uint h;

uchar flag;

//温度小数部分用查表法//

uchar code ditab[16]=

{0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};

//

uchar code dis_7[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};

//共阳LED段码表 "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "不亮" "-"

uchar code scan_con[4]={0x7f,0xbf,0xdf,0xef}; //列扫描控制字

uchar data temp_data[2]={0x00,0x00}; //读出温度暂放

uchar data display[5]={0x00,0x00,0x00,0x00,0x00}; //显示单元数据,共4个数据和一个运算暂用

//

//

//

/11微秒延时函数/

//

void delay(uint t)

{

for(;t>0;t--);

}

//

/显示扫描函数/

scan()

{

char k;

for(k=0;k<4;k++) //四位LED扫描控制

{

Disdata=0xff;

Disdata=dis_7[display[k]];

if(k==1){DIN=0;}

discan=scan_con[k];delay(90);

discan=0xff;

}

}

//

//

/18B20复位函数/

ow_reset(void)

{

char presence=1;

while(presence)

{

while(presence)

{

DQ=1;_nop_();_nop_();

DQ=0; //

delay(50); // 550us

DQ=1; //

delay(6); // 66us

presence=DQ; // presence=0继续下一步

}

delay(45); //延时500us

presence = ~DQ;

}

DQ=1;

}

//

//

/18B20写命令函数/

//向 1-WIRE 总线上写一个字节

void write_byte(uchar val)

{

uchar i;

for (i=8; i>0; i--) //

{

DQ=1;_nop_();_nop_();

DQ = 0;_nop_();_nop_();_nop_();_nop_();_nop_();//5us

DQ = val&0x01; //最低位移出

delay(6); //66us

val=val/2; //右移一位

}

DQ = 1;

delay(1);

}

//

/18B20读1个字节函数/

//从总线上读取一个字节

uchar read_byte(void)

{

uchar i;

uchar value = 0;

for (i=8;i>0;i--)

{

DQ=1;_nop_();_nop_();

value>>=1;

DQ = 0; //

_nop_();_nop_();_nop_();_nop_(); //4us

DQ = 1;_nop_();_nop_();_nop_();_nop_(); //4us

if(DQ)value|=0x80;

delay(6); //66us

}

DQ=1;

return(value);

}

//

/读出温度函数/

//

read_temp()

{

ow_reset(); //总线复位

write_byte(0xCC); // 发Skip ROM命令

write_byte(0xBE); // 发读命令

temp_data[0]=read_byte(); //温度低8位

temp_data[1]=read_byte(); //温度高8位

ow_reset();

write_byte(0xCC); // Skip ROM

write_byte(0x44); // 发转换命令

}

//

/温度数据处理函数/

void work_temp()

{

uchar n=0;

uchar doth,dotl;

uchar flag3=1,flag2=1; //数字显示修正标记

if((temp_data[1]&0xf8)!=0x00)

{

temp_data[1]=~(temp_data[1]);

temp_data[0]=~(temp_data[0])+1;

n=1;

flag=1;

}//负温度求补码

if(temp_data[0]>255)

{

temp_data[1]++;

}

display[4]=temp_data[0]&0x0f;

display[0]=ditab[display[4]];

doth=display[0]/10;

dotl=display[0]%10;

display[4]=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x07)<<4);

display[3]=display[4]/100;

display[2]=display[4]/10%10;

display[1]=display[4]%10;

if(!display[3])

{

display[3]=0;

flag3=0;

if(!display[2])

{

display[2]=0;

flag2=0;

}

}//最高位为0时都不显示

if(n)

{

display[3]=0x0b;//负温度时最高位显示"-"

flag3=0;

}

}

//

//

/主函数/

main()

{

Disdata=0xff; //初始化端口

discan=0xff;

for(h=0;h<4;h++){display[h]=8;}//开机显示8888

ow_reset(); // 开机先转换一次

write_byte(0xCC); // Skip ROM

write_byte(0x44); // 发转换命令

for(h=0;h<500;h++)

{scan();} //开机显示"8888"2秒

while(1)

{

read_temp(); //读出18B20温度数据

work_temp(); //处理温度数据

scan(); //显示温度值2秒

}

}

//

//结束//

显示函数有问题。。给你一个参考一下

void display(int bai,int shi,int ge)

{

x=get_temp();//读温度

bai=x%1000/100;//显示百位

shi=x%100/10;//显示十位

ge=x%10;//显示个位

P2=0Xdf; //显示小数点

P0=0X7f; //显示小数点

delay(150);//显示小数点

P2=0x7f;

P0=table[0];//显示千位

delay(300);//一小段延时动态显示

P2=0xbf;

P0=table[bai];//显示百位

delay(300);

P2=0xdf;

P0=table[shi]|0x80;//显示十位

delay(300);

P2=0xef;

P0=table[ge];//显示个位

delay(300);

}不过你的程序真够麻烦,给你一个看看。

/××××××××××××××××××××××××××××××××××××××××××××/

#include<reg52h>

#include <intrinsh>

#define uchar unsigned char

#define uint unsigned int

sbit DATA = P3^7; //DS18B20接入口

uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};

char bai,shi,ge; //定义变量

/延时子函数/

void delay(uint num)

{

while(num--) ;

}

/DS18b20温度传感器函数/

void Init_DS18B20(void) //传感器初始化

{

uchar x;

DATA = 1; //DQ复位

delay(10); //稍做延时

DATA = 0; //单片机将DQ拉低

delay(80); //精确延时 大于 480us //450

DATA = 1; //拉高总线

delay(20); //初始化成功的话S18b20返回一个信号 DATA

x=DATA; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败

delay(30);

}

//读一个字节 从低位到高位

ReadOneChar(void)

{

uchar i=0;

uchar dat = 0;

for (i=8;i>0;i--)

{

DATA = 0; // 给脉冲信号

dat>>=1;

DATA = 1; // 给脉冲信号

if(DATA)

dat|=0x80;

delay(8);

}

return(dat);

}

//写一个字节

void WriteOneChar(uchar dat)

{

uchar i=0;

for (i=8; i>0; i--)

{

DATA = 0;

DATA = dat&0x01;

delay(10);

DATA = 1;

dat>>=1;

}

delay(8);

}

//读取温度

int ReadTemperature(void)

{

uchar a=0;

uchar b=0;

int t=0;

float tt=0;

Init_DS18B20(); //初始化

WriteOneChar(0xCC); // 跳过读序号列号的 *** 作

WriteOneChar(0x44); // 启动温度转换

Init_DS18B20();

WriteOneChar(0xCC); //跳过读序号列号的 *** 作

WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

a=ReadOneChar();//低位

b=ReadOneChar();//高位

t=b;

t<<=8;

t=t|a;

tt=t00625;

t= tt10+05;

return(t);

}

/显示子函数/

void display(int bai,int shi,int ge)

{

P2=0Xdf; //显示小数点

P0=0X7f; //显示小数点

delay(150);//显示小数点

P2=0x7f;

P0=table[0];//显示千位

delay(100);//一小段延时动态显示

P2=0xbf;

P0=table[bai];//显示百位

delay(100);

P2=0xdf;

P0=table[shi]|0x80;//显示十位

delay(100);

P2=0xef;

P0=table[ge];//显示个位

delay(100);

}

void main()

{

int temp;

while(1)

{

temp=ReadTemperature();//读温度

bai=temp%1000/100;//显示百位

shi=temp%100/10;//显示十位

ge=temp%10;//显示个位

display(bai,shi,ge);//显示函数

}

}

TEMPER_L EQU 36H

TEMPER_H EQU 35H

TEMPER_d EQU 61H ;小数位

TEMPER_NUM EQU 60H

FLAG1 BIT 00H

DQ BIT P22

dula bit P26;

wela bit P27;

bai_c equ 37h

sh_c equ 38h

g_c equ 39h

MOV SP,#70H

AAA:LCALL GET_TEMPER

LCALL TEMPER_COV

mov a,TEMPER_NUM ;分开 TEMPER_NUM

anl a,#0f0h

swap a

mov bai_c,a

mov a,TEMPER_NUM

anl a,#0fh

mov sh_c,a

mov g_c,TEMPER_d

mov r2,#256

lplp:lcall display

djnz r2,lplp

LJMP AAA

NOP

;------------------读出转换后的温度值

GET_TEMPER: LCALL INIT_1820 ;初始化程序

SETB DQ ; 定时入口

BCD:

JB FLAG1,S22

LJMP BCD ; 若DS18B20不存在则返回

S22:LCALL DELAY1

MOV A,#0CCH ; 跳过ROM匹配------0CC

LCALL WRITE_1820

MOV A,#44H ; 发出温度转换命令

LCALL WRITE_1820

NOP

LCALL DELAY

LCALL DELAY

CBA:LCALL INIT_1820

JB FLAG1,ABC

LJMP CBA

ABC:LCALL DELAY1

MOV A,#0CCH ; 跳过ROM匹配

LCALL WRITE_1820

MOV A,#0BEH ; 发出读温度命令

LCALL WRITE_1820

LCALL READ_18200 ;或者 READ_1820

RET

;------------------读DS18B20的程序,从DS18B20中读出一个字节的数据

READ_1820:

MOV R2,#8

RE1:

CLR C

SETB DQ

NOP

NOP

CLR DQ

NOP

NOP

NOP

SETB DQ

MOV R3,#7

DJNZ R3,$

MOV C,DQ

MOV R3,#23

DJNZ R3,$

RRC A

DJNZ R2,RE1

RET

;-------------------写DS18B20的程序

WRITE_1820:

MOV R2,#8

CLR C

WR1:

CLR DQ

MOV R3,#6

DJNZ R3,$

RRC A

MOV DQ,C

MOV R3,#23

DJNZ R3,$

SETB DQ

NOP

DJNZ R2,WR1

SETB DQ

RET

;-------------------读DS18B20的程序,从DS18B20中读出两个字节的温度数据

READ_18200:

MOV R4,#2 ; 将温度高位和低位从DS18B20中读出

MOV R1,#36H ; 低位存入36H(TEMPER_L),高位存入35H(TEMPER_H)

RE00:

MOV R2,#8

RE01:

CLR C

SETB DQ

NOP

NOP

CLR DQ

NOP

NOP

NOP

SETB DQ

MOV R3,#7

DJNZ R3,$

MOV C,DQ

MOV R3,#23

DJNZ R3,$

RRC A

DJNZ R2,RE01

MOV @R1,A

DEC R1

DJNZ R4,RE00

RET

;-------------------将从DS18B20中读出的温度数据进行转换

TEMPER_COV:

MOV A,#0F0H

ANL A,TEMPER_L ; 舍去温度低位中小数点后的四位温度数值

SWAP A

MOV TEMPER_NUM,A

MOV A,TEMPER_L

JNB ACC3,TEMPER_COV1 ; 四舍五入去温度值

INC TEMPER_NUM

TEMPER_COV1:

MOV A,TEMPER_H

ANL A,#07H

SWAP A

ORL A,TEMPER_NUM

MOV TEMPER_NUM,A ; 保存变换后的温度数据

mov a,#0fh

ANL A,TEMPER_L

mov TEMPER_d,a

clr c

subb a,#10

jc jianlo

mov TEMPER_d,a

inc TEMPER_NUM

jianlo:

LCALL BIN_BCD

RET

;-------------------将16进制的温度数据转换成压缩BCD码

BIN_BCD:

MOV DPTR,#TEMP_TAB

MOV A,TEMPER_NUM

MOVC A,@A+DPTR

MOV TEMPER_NUM,A

RET

TEMP_TAB:

DB 00H,01H,02H,03H,04H,05H,06H,07H

DB 08H,09H,10H,11H,12H,13H,14H,15H

DB 16H,17H,18H,19H,20H,21H,22H,23H

DB 24H,25H,26H,27H,28H,29H,30H,31H

DB 32H,33H,34H,35H,36H,37H,38H,39H

DB 40H,41H,42H,43H,44H,45H,46H,47H

DB 48H,49H,50H,51H,52H,53H,54H,55H

DB 56H,57H,58H,59H,60H,61H,62H,63H

DB 64H,65H,66H,67H,68H,69H,70H,71H

DB 72H,73H,74H,75H,76H,77H,78H,79H

DB 80H,81H,82H,83H,84H,85H,86H,87H

DB 88H,89H,90H,91H,92H,93H,94H,95H

DB 96H,97H,98H,99H

;-------------------DS18B20初始化程序

INIT_1820:

SETB DQ

NOP

CLR DQ

MOV R0,#80H

TSR1:

DJNZ R0,TSR1 ; 延时

SETB DQ

MOV R0,#25H ;96US-25H

TSR2:

DJNZ R0,TSR2

JNB DQ,TSR3

LJMP TSR4 ; 延时

TSR3:

SETB FLAG1 ; 置标志位,表示DS1820存在

LJMP TSR5

TSR4:

CLR FLAG1 ; 清标志位,表示DS1820不存在

LJMP TSR7

TSR5:

MOV R0,#06BH ;200US

TSR6:

DJNZ R0,TSR6 ; 延时

TSR7:

SETB DQ

RET

;------------------重新写DS18B20暂存存储器设定值

RE_CONFIG:

JB FLAG1,RE_CONFIG1 ; 若DS18B20存在,转RE_CONFIG1

RET

RE_CONFIG1:

MOV A,#0CCH ; 发SKIP ROM命令

LCALL WRITE_1820

MOV A,#4EH ; 发写暂存存储器命令

LCALL WRITE_1820

MOV A,#00H ; TH(报警上限)中写入00H

LCALL WRITE_1820

MOV A,#00H ; TL(报警下限)中写入00H

LCALL WRITE_1820

MOV A,#7FH ; 选择12位温度分辨率

LCALL WRITE_1820

RET

;------------------延时子程序

DELAY:MOV R7,#2H

MIN:DJNZ R7,YS500

RET

YS500:LCALL YS500US

LJMP MIN

YS500US:MOV R6,#200

DJNZ R6,$

RET

DELAY1:MOV R7,#20H

DJNZ R7,$

RET

display: ;显示程序

MOV DPTR,#TABLE

clr dula;

mov a,bai_c

MOVC a,@A+DPTR

mov p0,a ;显示百位

setb dula;

clr dula;

clr wela;

mov P0,#7eh;

setb wela;

clr wela;

mov 50h,#5h

call delayxms

clr dula;

mov a,sh_c

MOVC a,@A+DPTR

orl a,#80h ;显示小数点

mov p0,a ; ;显示十位

setb dula;

clr dula;

clr wela;

mov P0,#7dh;

setb wela;

clr wela;

mov 50h,#5h

call delayxms

mov a,g_c

MOVC a,@A+DPTR

mov p0,a ; ;显示个位

setb dula;

clr dula;

mov P0,#7bh;

setb wela;

clr wela;

mov 50h,#5h

call delayxms

ret

delayxms:mov 52h,#1 ;50h,51h,52h用于延时 50h为参数x 延时1x ms

delaya: mov 51h,#125

djnz 51h,$

djnz 52h,delaya

djnz 50h,delayxms

ret ;延时返回

table:db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,

db 7fh,6fh,77h,7ch,39h,5eh,79h,71h

/

读取DS18B20温度,通过数码管显示出来

/

/头文件/

#include <reg52h>

#include <intrinsh>

#define uint unsigned int

#define uchar unsigned char

#define _Nop() _nop_()

sbit DQ =P3^5; //定义DS18B20通信端口

sbit LED_EN_PORT = P2^5;

sbit DAC_ADC_EN_PORT = P3^7;/定义发光二极管及ADC、DAC、时钟的锁存器有效脚LE/

#define sled_dm_port P0 /定义数码管段码的控制脚/

#define sled_wm_port P2 /定义数码管位码的控制脚/

/定义数码管显示字符跟数字的对应数组关系/

uchar code sled_mun_to_char[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};

/ 0 1 2 3 4 5 6 7 8 9 a b c d e f /

/定义需要点亮的数码管/

uchar code sled_bit_table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

uchar data sled_data[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /0-7号SLED缓冲值/

uchar data led_lighten_bit=0 ; /LED灯点亮标志位0-7/

//////////////////以下是DS18B20驱动程序////////////////

//延时函数

void delay(unsigned int i)

{

while(i--);

}

//初始化函数

Init_DS18B20(void)

{

unsigned char x=0;

DQ = 1; //DQ复位

delay(8); //稍做延时

DQ = 0; //单片机将DQ拉低

delay(80); //精确延时 大于 480us

DQ = 1; //拉高总线

delay(14);

x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败

delay(20);

}

//读一个字节

ReadOneChar(void)

{

unsigned char i=0;

unsigned char dat = 0;

for (i=8;i>0;i--){

DQ = 0; // 给脉冲信号

dat>>=1;

DQ = 1; // 给脉冲信号

if(DQ) dat|=0x80;

delay(4);

}

return(dat);

}

//写一个字节

WriteOneChar(unsigned char dat)

{

unsigned char i=0;

for (i=8; i>0; i--){

DQ = 0;

DQ = dat&0x01;

delay(5);

DQ = 1;

dat>>=1;

}

}

//读取温度

ReadTemperature(void)

{

unsigned char a=0;

unsigned char b=0;

unsigned int t=0;

float tt=0;

Init_DS18B20();

WriteOneChar(0xCC); // 跳过读序号列号的 *** 作

WriteOneChar(0x44); // 启动温度转换

Init_DS18B20();

WriteOneChar(0xCC); //跳过读序号列号的 *** 作

WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

a=ReadOneChar();

b=ReadOneChar();

t=b;

t<<=8;

t=t|a;

tt=t00625; //将温度的高位与低位合并

t= tt10+05; //对结果进行4舍5入

return(t);

}

//////////////////以上是DS18B20驱动程序////////////////

/1MS为单位的延时程序/

void delay_1ms(uchar x)

{

uchar j;

while(x--){

for(j=0;j<125;j++)

{;}

}

}

main()

{

uint temp_buff;

uchar i;

LED_EN_PORT = 0; /关闭发光二极管显示/

DAC_ADC_EN_PORT = 0; /关闭数码管以为的所有通道/

while(1){

temp_buff=ReadTemperature(); /读取当前温度/

sled_data[5] = sled_mun_to_char[temp_buff/100];

sled_data[6] = sled_mun_to_char[temp_buff%100/10];

sled_data[7] = sled_mun_to_char[temp_buff%10];

for(i=0;i<8;i++){

sled_wm_port = 0xff; /关闭显示/

_Nop();

_Nop();

_Nop();

sled_dm_port = sled_data[i]; /输出段码数据到数码管/

if(i==6) sled_dm_port = sled_dm_port&0x7f; /显示小数点/

sled_wm_port = sled_bit_table[i]; /输出位码数据到数码管/

delay_1ms(1);

}

}

}

我看了一些你的程序,没看到什么问题。

显示不正常可能是因为:

1、硬件问题,ds18b20出现故障,可能性不大!

2、软件问题。18b20对时序要求非常严格,我要求学生练习时序的时候,就拿18b20作为实例

18b20对时序要求非常严格,我想问几个问题。你选用的晶振是多少?你严格按照说明书说的时序了吗?

我没有测试你的程序,只是结合我以前的程序给你一些建议

///////DS18B20初始化子程序////////

void DS18B20_rst(void)

{

DQ = 1;

Delay(2);

DQ = 0;

Delay(30); //精确延时 480~960us

DQ = 1;

Delay(8);

}

unsigned int DS18B20_Read(void)

{

int i=0;

unsigned int u=0;

for (i=0;i<16;i++)

{

DQ=0;

u>>=1;

DQ=1;

if(DQ) u|=0x8000;

Delay(4);

}

return (u);

}

void DS18B20_Write(unsigned char ku)

{

int i=0;

for (i=0;i<8;i++)

{

DQ=0;

DQ =ku&0x01;

Delay(3);

DQ=1;

ku>>=1;

}

}

void Display(void)

{

unsigned int tp;

DS18B20_rst();

DS18B20_Write(0xCC);

DS18B20_Write(0x44);

DS18B20_rst();

DS18B20_Write(0xCC);

DS18B20_Write(0xBE);

tp=DS18B20_Read(); //取得DS18B20读的温度值

tp=(unsigned int)(tp625);

}

我的晶振是110592,单片机用的是普通12分频的STC89C51

你对照改一下

OK希望对你能有帮助

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

sbit DQ = P3^7; //定义DQ引脚为P37

/ds18b20延迟子函数(晶振12MHz )/

/DS18B20对时间要求很严,但只能长不能短

在110592M下也行,因为时间长些/

void delay_18B20(unsigned int i)

{

while(i--);

}

/ds18b20初始化函数/

void Init_DS18B20(void)

{

 unsigned char x=0;

 DQ = 0;          //单片机将DQ拉低

 delay_18B20(80); //精确延时 大于 480us

 DQ = 1;          //拉高总线

 delay_18B20(14);

 x=DQ;            //稍做延时后 如果x=0则初始化成功 x=1则初始化失败

 delay_18B20(20);

}

/ds18b20读一个字节/

unsigned char ReadOneChar(void)

{

unsigned char i=0;

unsigned char dat = 0;

for (i=8;i>0;i--)

 {

  DQ = 0; // 给脉冲信号

  dat>>=1;

  DQ = 1; // 给脉冲信号

  if(DQ)

  dat|=0x80;

  delay_18B20(4);

 }

return(dat);

}

/ds18b20写一个字节/

void WriteOneChar(unsigned char dat)

{

unsigned char i=0;

for (i=8; i>0; i--)

{

DQ = 0;

DQ = dat&0x01;

delay_18B20(5);

DQ = 1;

dat>>=1;

}

}

/设置DS18B20工作状态

TH和TL分别是上限报警和下限报警温度,RS是显示分辨率的设置

/

void setds18b20(unsigned char TH,unsigned char TL,unsigned char RS)

{

Init_DS18B20();

WriteOneChar(0xCC);     // 跳过读序号列号的 *** 作

WriteOneChar(0x4E);  // //写入"写暂存器"命令,修改TH和TL和分辩率配置寄存器

//先写TH,再写TL,最后写配置寄存器

WriteOneChar(TH); //写入想设定的温度报警上限

WriteOneChar(TL); //写入想设定的温度报警下限

WriteOneChar(RS); //写配置寄存器,格式为0 R1 R0 1,1 1 1 1

//R1R0=00分辨率娄9位,R1R0=11分辨率为12位

}

/读取ds18b20当前温度/

unsigned char ReadTemperature(void)

{ unsigned char tt[2];

Init_DS18B20();

WriteOneChar(0xCC);     // 跳过读序号列号的 *** 作

WriteOneChar(0x44);  // 启动温度转换

delay_18B20(70);       // 温度转化要一段时间

Init_DS18B20();

WriteOneChar(0xCC);  //跳过读序号列号的 *** 作

WriteOneChar(0xBE);  //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

//delay_18B20(70);

tt[0]=ReadOneChar();     //读取温度值低位

tt[1]=ReadOneChar();    //读取温度值高位

return(tt);

}

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

#include <intrinsh>//此函数为库函数,里面有_nop_函数,相当于汇编中的NOP

//Port Definitions

sbit LcdRs = P2^0;

sbit LcdRw = P2^1;

sbit LcdEn   = P2^2;

sfr  DBPort  = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0数据端口

//内部等待函数

void LCD_Wait(void)

{

LcdRs=0; //RS=0表示选择指令寄存器

LcdRw=1; _nop_();//RW=1表示进行读 *** 作

LcdEn=1; _nop_();//在EN为下降沿的时候锁存数据

while(DBPort&0x80)

{

LcdEn=0;

_nop_();

    _nop_();

LcdEn=1;

_nop_();

    _nop_();

}

LcdEn=0;

}

//向LCD写入命令或数据

#define LCD_COMMAND 0      // Command

#define LCD_DATA 1      // Data

#define LCD_CLEAR_SCREEN 0x01      // 清屏

#define LCD_HOMING   0x02      // 光标返回原点

void LCD_Write(bit style, unsigned char input)

{

LcdEn=0;

LcdRs=style;

LcdRw=0; _nop_();

DBPort=input; _nop_();//注意顺序

LcdEn=1; _nop_();//注意顺序

LcdEn=0; _nop_();

LCD_Wait();

}

//设置显示模式

#define LCD_SHOW 0x04    //显示开

#define LCD_HIDE 0x00    //显示关

#define LCD_CURSOR 0x02  //显示光标

#define LCD_NO_CURSOR 0x00    //无光标

#define LCD_FLASH 0x01    //光标闪动

#define LCD_NO_FLASH 0x00    //光标不闪动

void LCD_SetDisplay(unsigned char DisplayMode)

{

LCD_Write(LCD_COMMAND, 0x08|DisplayMode);

}

//设置输入模式

#define LCD_AC_UP 0x02

#define LCD_AC_DOWN 0x00      // default

#define LCD_MOVE 0x01      // 画面可平移

#define LCD_NO_MOVE 0x00      //default

void LCD_SetInput(unsigned char InputMode)

{

LCD_Write(LCD_COMMAND, 0x04|InputMode);

}

//初始化LCD

void LCD_Initial()

{

LcdEn=0;

LCD_Write(LCD_COMMAND,0x38);           //8位数据端口,2行显示,57点阵

LCD_Write(LCD_COMMAND,0x38);

LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);    //开启显示, 无光标

LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏

LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);       //AC递增, 画面不动

}

//

void GotoXY(unsigned char x, unsigned char y)

{

if(y==0)

LCD_Write(LCD_COMMAND,0x80|x);

if(y==1)

LCD_Write(LCD_COMMAND,0x80|(x-0x40));

}

void Print(unsigned char str)

{

while(str!='\0')

{

LCD_Write(LCD_DATA,str);

str++;

}

}

void LCD_Print(unsigned char x, unsigned char y, unsigned char str)

{

GotoXY(x,y);

Print(str);

}

#include <reg52h>

//#include <at89x52h>

//unsigned char code BCD[]={0x3f,0x06,0x5b,0x4f, //此处是将0-F转换成相应的BCD码

//                          0x66,0x6d,0x7d,0x07,

//                          0x7f,0x6f,0x77,0x7c,

//                          0x39,0x5e,0x79,0x71};

//unsigned char code KEY[]={0x00,0x00,0x01,0x02,0x03,//此处是为使程序通用,当键值不是按

//       0x04,0x05,0x06,0x07,//这个排列时,把此表更改即可

//    0x08,0x09,0,0x0b,//最前面的那个0x00是为了查表方便,

//    0x0c,0x0d,0x0e,0x0f};//因为键值是从1开始的

sfr key_port=0x90;     //定义P1口为键盘扫描口

//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0数据端口

bit key_ok=0;        //有键按下的标志

/延时子程序

调用一次用时18微秒,t每加1,用时增加6微秒/

void delay(unsigned char t)

{

while(t--);

}

unsigned char r_left(unsigned char x)//循环左移一位

{

x<<=1;

x++;

return(x);

}

/粗判有无键按下

有键按下则将key_ok置1/

void scan_full(void)

{

unsigned char temp;

key_port=0xf0;  //低半字节为行线,高半字节为列线

temp=P1;

if(temp!=0xf0)

key_ok=1;

else key_ok=0;

}

/键盘扫描程序

功能:返回键值,当无键按下时,返回0/

unsigned char key_scan(void)

{

unsigned char temp,count=0x01,key_value;//按键返回值

unsigned char x_scan=0xfe,y_scan=0xef;//行、列扫描码

unsigned char i,j,y; //行数和列数

while(1)

{

scan_full();   //粗判是否有键按下

if(key_ok==1)

{

key_ok=0;

delay(200); //延时去抖动

scan_full(); //再次粗判是否有键按下

if(key_ok==1)

{

for(i=0;i<4;i++) //扫描4行

{

  key_port=x_scan;

for(j=0;j<4;j++) //每行4列

{

temp=key_port;

   temp=temp&0xf0;

   y=y_scan&0xf0;

   if(temp==y)

   {

while(key_ok!=0)//等待按键松开

{

scan_full();

}

    key_value=count;

    return(key_value);//找到键值,马上返回

   }

   else

   {

    count++;

    y_scan=r_left(y_scan);

   }

  }

y_scan=0xef; //扫描完一列,重新对列扫描量赋初值

  x_scan=r_left(x_scan);//行扫描码左移一位,扫描下一行  

}

}

}

return(key_value);//没键按下,返回0

}

}

//unsigned char key(void)

//{

// unsigned char x;

// unsigned char y;

// x=key_scan();

// return(x);

//y=KEY[x];

//return y;

//}

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

//#include <absacch>

//#include <ctypeh>

//#include <mathh>

//#include <stdioh>

//#include <stringh>

#include <DS18B20h> //测温头文件

#include <LCD1602h> //液晶显示头文件

#include <keyscanh> //键盘扫描头文件

sbit alarm=P2^6; //报警信号

//sbit DQ = P3^7; //定义DQ引脚为P37

unsigned char key_value;            //存放键盘扫描值

bit up_one,down_one;  //加1和减1标志

bit alarm_up_flag,alarm_down_flag; //上限报警和下限报警设置标志

bit set_temper_flag; //设置控制标志温度标志

bit alarm_switch; //报警开关

unsigned char user_temper;  //用户标定温度

unsigned char TH=110,TL=-20,RS=0x3f; //上限温度110,下限-20,分辨率10位,也就是025C

unsigned char t[2],pt; //用来存放温度值,测温程序就是通过这个数组与主函数通信的

unsigned char  TempBuffer1[17]={0x2b,0x20,0x30,0x30,0x2e,0x30,0x30,0x20,

0x53,0x45,0x54,0x2b,0x20,0x30,0x30,0x43,'\0'};

//显示实时温度,上电时显示+ 0000 SET+ 00C

unsigned char  TempBuffer0[17]={0x54,0x48,0x3a,0x2b,0x20,0x30,0x30,0x20,

0x54,0x4c,0x3a,0x2b,0x20,0x30,0x30,0x43,'\0'};

//显示温度上下限,上电时显示TH:+ 00 TL:+ 00C

unsigned char code dotcode[4]={0,25,50,75};

/因显示分辨率为025,但小数运算比较麻烦,故采用查表的方法

再将表值分离出十位和个位后送到十分位和百分位/

/用户设定温度转换为LCD显示数据

功能:将用户设定温度user_temper,分离出符号位,百、十、个位

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void user_temper_LCD(unsigned char temper)

{

if(temper>0x7f) //判断正负,如果为负温,将其转化为其绝对值

{

TempBuffer1[11]=0x2d; //0x2d为"-"的ASCII码

temper=~temper; //将负数的补码转换成绝对值

temper++;

}

else TempBuffer1[11]=0x2b; ////0x2B为"+"的ASCII码

TempBuffer1[12]=temper/100+0x30;              //分离出temper的百十个位

if( TempBuffer1[12]==0x30) TempBuffer1[12]=0xfe;     //百位数消隐

TempBuffer1[13]=(temper%100)/10+0x30;      //分离出十位

TempBuffer1[14]=(temper%100)%10+0x30;        //分离出个位

}

/温度上下限转换为LCD显示数据

功能:将上下限报警温度,分离出符号位,百、十、个位

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void alarm_LCD( unsigned char TH, unsigned char TL)

{

if(TH>0x7F)                    //判断正负,如果为负温,将其转化为其绝对值

{

TempBuffer0[3]=0x2d;      //0x2d为"-"的ASCII码

TH=~TH;  //将负数的补码转换成绝对值

TH++;

}

else TempBuffer0[3]=0x2b; //0x2B为"+"的ASCII码

if(TL>0x7f)

{

TempBuffer0[11]=0x2d;      //0x2d为"-"的ASCII码

TL=~TL+1;

}

else TempBuffer0[11]=0x2b; //0x2B为"+"的ASCII码

TempBuffer0[4]=TH/100+0x30;              //分离出TH的百十个位

if( TempBuffer0[4]==0x30) TempBuffer0[4]=0xfe; //百位数消隐

TempBuffer0[5]=(TH%100)/10+0x30; //分离出十位

TempBuffer0[6]=(TH%100)%10+0x30;   //分离出个位

TempBuffer0[12]=TL/100+0x30;              //分离出TL的百十个位

if( TempBuffer0[12]==0x30) TempBuffer0[12]=0xfe; //百位数消隐

TempBuffer0[13]=(TL%100)/10+0x30; //分离出十位

TempBuffer0[14]=(TL%100)%10+0x30;   //分离出个位

}

/温度转换为LCD显示数据

功能:将两个字节的温度值,分离出符号位,整数及小数

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void temper_LCD(void)

{

unsigned char x=0x00,y=0x00;

t[0]=pt;

pt++;

t[1]=pt;

if(t[1]>0x07)                    //判断正负温度

{

TempBuffer1[0]=0x2d;      //0x2d为"-"的ASCII码

t[1]=~t[1];  /下面几句把负数的补码/

t[0]=~t[0];   / 换算成绝对值/

x=t[0]+1;  //

t[0]=x;  //

if(x>255)                //

t[1]++;  //

}

else TempBuffer1[0]=0x2b; //0xfe为变"+"的ASCII码

t[1]<<=4; //将高字节左移4位

t[1]=t[1]&0x70; //取出高字节的3个有效数字位

x=t[0]; //将t[0]暂存到X,因为取小数部分还要用到它

x>>=4; //右移4位

x=x&0x0f; //和前面两句就是取出t[0]的高四位

t[1]=t[1]|x; //将高低字节的有效值的整数部分拼成一个字节

TempBuffer1[1]=t[1]/100+0x30;              //+0x30 为变 0~9 ASCII码

if( TempBuffer1[1]==0x30) TempBuffer1[1]=0xfe; //百位数消隐

TempBuffer1[2]=(t[1]%100)/10+0x30; //分离出十位

TempBuffer1[3]=(t[1]%100)%10+0x30;   //分离出个位

t[0]=t[0]&0x0c; //取有效的两位小数

t[0]>>=2; //左移两位,以便查表

x=t[0];

y=dotcode[x]; //查表换算成实际的小数

TempBuffer1[5]=y/10+0x30; //分离出十分位

TempBuffer1[6]=y%10+0x30; //分离出百分位

}

/键盘命令处理函数

功能:把键盘值转化成相应的功能标志位

备注:为了提高程序的健壮性,在功能标志位无效时,

up_one和down_one都无效,并且各功能标志之间

采用互锁处理,虽然这样麻烦,特别是功能标志较多时

更是麻烦,但各功能标志之间是同级别的;

也可采用多重if else方法,虽然简单,

但各功能标志之间有了明显的优先级差别

/

void key_command(unsigned char x)     

{

switch(x)

{

case 1: up_one=1;break;

case 2: down_one=1;break;

case 5: alarm_up_flag=!alarm_up_flag;break;

case 6: alarm_down_flag=!alarm_down_flag;break;

case 7: set_temper_flag=!set_temper_flag;break;

case 8: alarm_switch=!alarm_switch;break;

default: break;

}

if(!(alarm_up_flag||alarm_down_flag||set_temper_flag))

{

up_one=0x00; //在没有相应功能标志有效时

down_one=0x00; //up_one和down_one都被锁定

}

if(alarm_up_flag&&(!alarm_down_flag)&&(!set_temper_flag))//设置上限报警

{

if(up_one)//上限报警加1

{

TH++;up_one=0;

if(TH>=100)//超过100度,回零到20度

TH=20;

}

if(down_one)//上限报警减1

{

TH--;down_one=0;

if(TH<=20)//小于20度,回零到20度

TH=20;

}

}

if((!alarm_up_flag)&&(alarm_down_flag)&&(!set_temper_flag))//设置下限报警

{

if(up_one)

{

TL++;up_one=0;

if(TL>=20)//高于20度,回零到0度

TL=0;

}

if(down_one)

{

TL--;down_one=0;

if(TL<=0)//低于0度,回零到0度

TL=0;

}

}

if((!alarm_up_flag)&&(!alarm_down_flag)&&(set_temper_flag))//设置用户标定温度

{

if(up_one)

{

user_temper++;up_one=0;

if(user_temper>=60)//高于60度,回零到0度

user_temper=0;

}

if(down_one)

{

user_temper--;down_one=0;

if(user_temper<=0)//低于0度,回零到0度

user_temper=0;

}

}

//if(alarm_switch)

}

main()

{

setds18b20(TH,TL,RS);     //设置上下限报警温度和分辨率

delay(100); 

while(1)

{

pt=ReadTemperature();    //测温函数返回这个数组的头地址

 //读取温度,温度值存放在一个两个字节的数组中,

temper_LCD();  //实测温度转化为ACSII码,并送液晶显示缓冲区

user_temper_LCD(user_temper);  //用户设定温度转化为ACSII码,并送液晶显示缓冲区

alarm_LCD(TH,TL);  //上下限报警温度转化为ASCII码,并送液晶显示缓冲区

LCD_Initial(); //第一个参数列号,第二个为行号,为0表示第一行

//为1表示第二行,第三个参数为显示数据的首地址

LCD_Print(0,0,TempBuffer0);

LCD_Print(0,1,TempBuffer1);

scan_full();                     //看有无键按下

if(key_ok) //如有键按下则看到底哪个键按下

{

key_value=key_scan();  //调用键盘扫描程序

key_command(key_value);  //键盘命令处理函数

}

}

}

觉得能运行,我试过了,自己看图

以上就是关于求一个51单片机控制的温度计显示程序全部的内容,包括:求一个51单片机控制的温度计显示程序、DS18B20 AT89S52单片机四位共阳数码管温度计怎么才能实现,各位大神下面是我的程序,主要显示函数不会弄、89s52单片机显示四位数码管汇编语言测温程序,,,,温度可显示范围在-20—+120度。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9332550.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存