用温度芯片ds18b20编写简单的检测温度程序,可总是不能正常运行。数码管总是静止显示271,请大虾指点。

用温度芯片ds18b20编写简单的检测温度程序,可总是不能正常运行。数码管总是静止显示271,请大虾指点。,第1张

ds18b20加lcd1602加串口输出最近刚刚做的,调试成功了,lcddata口是P0

#include<intrinsh>

#include<stdioh>

#include"STC12C5AH"

#define XTAL 11059200 // CUP 晶振频率

#define baudrate 9600 // 通信波特率

#define uchar unsigned char

#define uint unsigned int

sbit DQ=P2^3; //DS18B20数据脚

sbit E=P2^7; //1602使能

sbit RW=P2^6; //1602读写

sbit RS=P2^5; //1602数据/命令选择

uchar data temp_data[2] = {0x00,0x00}; //高低8位数据缓存

uchar code num[]={'0','1','2','3','4','5','6','7','8','9'}; //lcd1602数字转ASCII表用于显示数字

uint DS[4]; //温度显示4位有效数字

uint dh;

uint dl;

uint DStemp; //16进制转10进制数据缓存

void Delay(unsigned int num) { // DS18B20及主程序延时函数 1=3us

unsigned int i;

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

}

void InitUART(void) //串口初始化

{

TMOD = 0x20;

SCON = 0x50;

TH1 = 0xFD;

TL1 = TH1;

PCON = 0x00;

EA = 1;

ES = 1;

TR1 = 1;

}

void SendOneByte(unsigned char c) //串口发送1字节

{

SBUF = c;

while(!TI);

TI = 0;

}

void delay() //lcd1602延迟

{

int i,j;

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

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

;

}

void wcmd(uchar del) //命令写入程序

{

P0 = del;

RS = 0;

RW = 0;

E = 0;

delay();

E = 1;

delay();

}

void write(uchar del) //写入一位数据

{

P0 = del;

RS = 1;

RW = 0;

E = 0;

delay();

E = 1;

delay();

}

void L1602_init(void) //lcd1602初始化

{

wcmd(0x01);

wcmd(0x38);

wcmd(0x0c);

wcmd(0x06);

wcmd(0xd0);

}

void L1602_char(uchar hang,uchar lie,char sign) //写入1个字符

{

uchar a;

if(hang == 1) a = 0x80;

if(hang == 2) a = 0xc0;

a = a + lie - 1;

wcmd(a);

write(sign);

}

void L1602_string(uchar hang,uchar lie,uchar p) //写入字符串

{

uchar a,b=0;

if(hang == 1) a = 0x80;

if(hang == 2) a = 0xc0;

a = a + lie - 1;

while(1)

{

wcmd(a++);

b++;

if((p == '\0')||(b==16)) break;

write(p);

p++;

}

}

uchar Init_DS18B20(void) { // 初始化ds1820

DQ=1; // DQ复位

Delay(22); // 稍做延时

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

Delay(160); // 精确延时 大于 480us

DQ=1; // 拉高总线

Delay(22);

while(DQ);

L1602_string(1,15,"ok"); //初始化成功在LCD1602上显示OK

Delay(166);

DQ=1;

return(1); // 返回信号,0=presence,1= no presence

}

uchar ReadOneChar(void) { // 读一个字节

uchar i;

uchar value=0;

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

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

value>>=1;

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

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

if(DQ) value|=0x80;

Delay(22); //66 us

}

DQ=1;

return(value);

}

void WriteOneChar(unsigned char dat) { // 写一个字节

unsigned char i=0;

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

DQ=0;

DQ=dat&0x01;

Delay(18);

DQ=1;

dat>>=1;

}

}

void Read_Temperature(void) { // 读取温度

Init_DS18B20();

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

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

Init_DS18B20();

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

WriteOneChar(0xBE); // 读取温度寄存器

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

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

}

void Main()

{

L1602_init(); //初始化LCD1602

Init_DS18B20(); //初始化DS18B20

InitUART(); //初始化串口通信

L1602_string(1,1,"DS18B20"); //lcd1602测试

L1602_string(2,15,"`c");

while(1)

{

Read_Temperature(); //读取高低8位数据

Delay(800000);

dl=temp_data[0];

dh=temp_data[1];

SendOneByte(dh); //串口发送高低8位数据

SendOneByte(dl);

DStemp=(dh256+dl)/10625/10; //16进制转换10进制 先除10否则会溢出

DS[0]=DStemp%10; //提取温度各个位数字

DS[1]=DStemp/10%10;

DS[2]=DStemp/100%10;

DS[3]=DStemp/1000;

L1602_char(1,3,''); //显示各个位数字

L1602_char(1,5,num[DS[0]]);

L1602_char(1,4,num[DS[1]]);

L1602_char(1,2,num[DS[2]]);

L1602_char(1,1,num[DS[3]]);

}

}

其实转ascii码只要加38就好了,当时没想到

ds18b20的原理就是一些控制指令。这些指令你可以上网找它的资料,里面有。至于连线,我只会51单片机。1端接地,3端接Vcc,2端接在I/O口上,可以接在P21上。另外2端还有外接一个10K的电阻,然后再连在Vcc上。。。写程序时,注意看时序图,一定要按时序图来写,ds18b20是单总线传输,一定要按时序来写。

#include<reg52h>

#include<defineh>

/延时函数/

void delay(uint n)

{uint i,j;

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

for(j=125;j>0;j--);

}

/报警函数/

void di()

{buzz=1;

delay(100);

buzz=0;

}

/液晶显示子函数/

void write_com(uchar com)//液晶写命令函数

{rs=0;

lcden=0;

P0=com;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void write_date(uchar date)// 液晶写数据函数

{rs=1;

lcden=0;

P0=date;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void write_sfm(uchar add,uchar date) //写时分秒,此处date定义char或uchar都行

{uchar shi,ge;

shi=date/10;

ge=date%10;

write_com(0x80+0x40+add);

write_date(0x30+shi);

write_date(0x30+ge);

}

void write_nyr(uchar add,char date) //写液晶年月日函数,注:年可以为0,则date可能去负值,所以用char型

{uchar shi,ge;

shi=date/10;

ge=date%10;

write_com(0x80+add);

write_date(0x30+shi);

write_date(0x30+ge);

}

void write_week(uchar week)

{write_com(0x80+12);

switch(week)

{case 1:write_date('M');//字母只能一个一个写,当然也可定义table,然后调用

delay(5);

write_date('O');

delay(5);

write_date('N');

break;//注:这里可不用延时

case 2:write_date('T');

delay(5);

write_date('U');

delay(5);

write_date('E');

break;

case 3:write_date('W');

delay(5);

write_date('E');

delay(5);

write_date('D');

break;

case 4:write_date('T');

delay(5);

write_date('H');

delay(5);

write_date('U');

break;

case 5:write_date('F');

delay(5);

write_date('R');

delay(5);

write_date('T');

break;

case 6:write_date('S');

delay(5);

write_date('A');

delay(5);

write_date('T');

break;

case 7:write_date('S');

delay(5);

write_date('U');

delay(5);

write_date('N');

break;

}

}

/初始化函数/

void init()

{uchar num;

EA=1;

EX1=1;//开外部中断1

IT1=1;//设置边沿触发方式

flag1=0;//闹钟开启控制,初始置0

t0_num=0;// 变量初始化

s1num=0;

// ch=0;//按键置低键

lcden=0;

/以下几行首次设置DS12C887时使用,以后不必再写入,但对于DS12c885这几行必须有/

write_ds(0,0x20);//

write_ds(0x0b,0x26);//设置24小时制,数据二进制格式,开启闹钟中断

set_time();//设置上电默认时间

//

write_com(0x38);//设置162

write_com(0x0c);//设置开显示

write_com(0x06);//写一个字符后地址加1

write_com(0x01);//显示清0,指针清0

write_com(0x80);//设置显示的初始化坐标,第一行

for(num=0;num<15;num++)

{write_date(table[num]);

delay(5);

}

write_com(0x80+0x40);//第二行

for(num=0;num<11;num++)

{write_date(table1[num]);

delay(5);

}

}

/键盘扫描函数/

void keyscan()

{if(flag_ri==1)

{if((s1==0)||(s2==0)||(s3==0)||(s4==0))

{delay(5);

if((s1==0)||(s2==0)||(s3==0)||(s4==0))

{while(!(s1&&s2&&s3&&s4));

di();

flag_ri=0;//清除报警标志

}

}

}

if(s1==0)

{ delay(5);

if(s1==0)

{s1num++;

if(flag1==1)//若闹钟的设置处于设置状态,再按下S1只能设置闹钟的时分秒

if(s1num==4)

s1num=1;

flag=1;//用来标志时钟现处于设置状态,既没有处于正常工作状态,处于正常工作状态时,flag=0,flag1=0

while(!s1);

di();

switch(s1num)//光标定位点

{case 1: write_com(0x80+0x40+10);//秒

write_com(0x0f);//光标开始闪烁,下次不必要此语句了, 因为计算的次数总是从1到2再到3的递增

break;

case 2: write_com(0x80+0x40+7);//分

break;

case 3: write_com(0x80+0x40+4);//时

break;

case 4: write_com(0x80+12);//星期

break;

case 5: write_com(0x80+9);//日

break;

case 6: write_com(0x80+6);//月

break;

case 7: write_com(0x80+3);//年

break;

case 8: s1num=0;

write_com(0x0c);//设置开显示,不显示光标,即恢复显示

flag=0;//解除设置状态,进入正常工作状态

write_ds(0,miao);//以下几句是把设置好的值送到DS12C887进行重新的时间调整

write_ds(2,fen);

write_ds(4,shi);

write_ds(6,week);

write_ds(7,day);

write_ds(8,month);

write_ds(9,year);

break;

}

}

}

if(s1num!=0)//只有当s1按下时,才检测s2和s3

{if(s2==0)

{delay(5);

if(s2==0)

{while(!s2);

di();

switch(s1num)//根据功能键的次数调节相应的值

{case 1: miao++;

if(miao==60)

miao=0;

write_sfm(10,miao);//每调节一下送液晶进行显示

write_com(0x80+0x40+10);//显示位置从新回到调节出

break;

case 2: fen++;

if(fen==60)

fen=0;

write_sfm(7,fen);//每调节一下送液晶进行显示

write_com(0x80+0x40+7);//显示位置从新回到调节出

break;

case 3: shi++;

if(shi==24)

shi=0;

write_sfm(4,shi);//每调节一下送液晶进行显示

write_com(0x80+0x40+4);//显示位置从新回到调节出

break;

case 4: week++;

if(week==8)

week=1;

write_week(week);//每调节一下送液晶进行显示

write_com(0x80+12);//显示位置从新回到调节出

break;

case 5: day++;

if(day==32)

day=1;

write_nyr(9,day);//每调节一下送液晶进行显示

write_com(0x80+9);//显示位置从新回到调节出

break;

case 6: month++;

if(month==13)

month=1;

write_nyr(6,month);//每调节一下送液晶进行显示

write_com(0x80+6);//显示位置从新回到调节出

break;

case 7: year++;

if(year==100)

year=0;

write_nyr(3,year);//每调节一下送液晶进行显示

write_com(0x80+3);//显示位置从新回到调节出

break;

}

}

}

if(s3==0)

{delay(5);

if(s3==0)

{while(!s3);

di();

switch(s1num)

{case 1: miao--;

if(miao==-1)

miao=59;

write_sfm(10,miao);//每调节一下送液晶进行显示

write_com(0x80+0x40+10);//显示位置从新回到调节出

break;

case 2: fen--;

if(fen==-1)

fen=59;

write_sfm(7,fen);//每调节一下送液晶进行显示

write_com(0x80+0x40+7);//显示位置从新回到调节出

break;

case 3: shi--;

if(shi==-1)

miao=23;

write_sfm(4,shi);//每调节一下送液晶进行显示

write_com(0x80+0x40+4);//显示位置从新回到调节出

break;

case 4: week--;

if(week==0)

week=7;

write_week(week);//每调节一下送液晶进行显示

write_com(0x80+12);//显示位置从新回到调节出

break;

case 5: day--;

if(day==0)

day=31;

write_nyr(9,day);//每调节一下送液晶进行显示

write_com(0x80+9);//显示位置从新回到调节出

break;

case 6: month--;

if(month==0)

month=12;

write_nyr(6,month);//每调节一下送液晶进行显示

write_com(0x80+6);//显示位置从新回到调节出

break;

case 7: year--;

if(year==-1)

year=99;

write_nyr(3,year);//每调节一下送液晶进行显示

write_com(0x80+3);//显示位置从新回到调节出

break;

}

}

}

}

if(s4==0)

{delay(5);

if(s4==0)

{flag1=~flag1;

while(!s4);

di();

if(flag1==0)

{flag=0;//确保进入正常工作状态

write_com(0x80+0x40);//设置写入的初始位置

write_date(' ');//关闭在进入闹钟设置状态显示的闹钟设置标志位

write_date(' ');//同上

write_com(0x0c);//设置开显示,不显示光标,即恢复显示

write_ds(1,miao);//设置的数据写入DS12C887

write_ds(3,fen);

write_ds(5,shi);

}

else //进入闹钟设置

{read_alarm();//读取原始数据

miao=amiao; //重新赋给LCD,以便按键调节

fen=afen;

shi=ashi;

write_com(0x80+0x40);

write_date('R');//设置闹钟进入设置状态的标志为Ri

write_date('i');

//write_com(0x80+0x40+3);//设置显示位置,此句可不要

write_sfm(4,shi); //送液晶显示闹钟时间,以便进行设置

write_sfm(7,fen);

write_sfm(10,miao);

}

}

}

}

/12C887函数程序/

void write_ds(uchar add,uchar date)//写12C887函数????

{dscs=0;//片选有效

dsas=1;//地址选通输入端,上升沿放地址/数据

dsds=1;//读允许输入引脚

dsrw=1;//写允许输入引脚,上升沿所存数据/地址

P0=add;//先写地址

dsas=0;

dsrw=0;

P0=date;//再写数据

dsrw=1;

dsas=1;

dscs=1;

}

uchar read_ds(uchar add)//读12C887函数?????

{uchar ds_date;

dsas=1;

dsds=1;

dsrw=1;

dscs=0;

P0=add;//先写地址

dsas=0;

dsds=0;

P0=0xff;//把P0置高,等待DS12C887在下一个上升沿放数据

ds_date=P0;//再读数据

dsds=1;

dsas=1;

dscs=1;

return ds_date;

}

/首次 *** 作DS12C887时给以寄存器初始化/

void set_time()

{ write_ds(0,0);

write_ds(1,0);

write_ds(2,0);

write_ds(3,0);

write_ds(4,0);

write_ds(5,0);

write_ds(6,1);

write_ds(7,0);

write_ds(8,0);

write_ds(9,10);// 初始化2010年

}

//

void read_alarm()//读取DS12C887闹钟值

{amiao=read_ds(1);

afen=read_ds(3);

ashi=read_ds(5);

}

/主函数/

void main()

{

init();

while(1)

{keyscan();

if(flag_ri==1)//当闹钟中断进入这里

{di();

delay(100);//时长时短的响

di();

delay(500);

}

if(flag==0&&flag1==0) //正常工作时进入这里

{keyscan();

//write_ds(6,week);

year=read_ds(9);//读取12C887数据

month=read_ds(8);

day=read_ds(7);

week=read_ds(6);

shi=read_ds(4);

fen=read_ds(2);

miao=read_ds(0);

write_sfm(10,miao);

write_sfm(7,fen);

write_sfm(4,shi);

write_week(week);

write_nyr(3,year);

write_nyr(6,month);

write_nyr(9,day);

}

}

}

/外部中断1的服务程序/

void exter()interrupt 2 //进入中断表示闹钟时间到

{uchar c;

flag_ri=1;//设置标志,用于大程序中的报警

c=read_ds(0x0c);//读取12C887的C寄存器表示响应了中断????

}

/代码定义/

以上就是关于用温度芯片ds18b20编写简单的检测温度程序,可总是不能正常运行。数码管总是静止显示271,请大虾指点。全部的内容,包括:用温度芯片ds18b20编写简单的检测温度程序,可总是不能正常运行。数码管总是静止显示271,请大虾指点。、DS18B20是如何测温的跟单片机如何连接、跪求ds18b20的程序 我写了1个多礼拜的ds18b20测温程序就是不好使。麻烦那位老师帮帮忙等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存