这个程序完全没问题的,我做过实验。希望对你有帮助,,,,
//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度。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)