STC单片机模拟串口与上位机通信,并发送扫描18B20得到的温度值。

STC单片机模拟串口与上位机通信,并发送扫描18B20得到的温度值。,第1张

你定时器1-18B20那段程序在中断里面进行的吗?

给你个建议,程序要有节奏进行:

比如首先进行18B20的数据读取,然后就串口发送数据,再等待时间,时间到了再循环读数,发送,等待。让读数、发送都有规律进行,读数期间不发送,发送期间不读数,读数发送要固定一个刷新频率。你要是要LCD显示出来的话,刷新周期100ms已经足够了。

测温,并和上位机通讯,你可以删掉上位机通讯部分。

#include < intrinsh >

#include <reg51h>

sbit DQ = P3^3; //定义DS18B20端口DQ

bit flash=0; //显示开关标记

//sbit BEEP=P3^7 ;

unsigned char presence,temp=0x00 ;//初始化标志

unsigned char ac=0,bc=1,cc=0,ff=0;

unsigned char data temp_save[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//存储8个传感器数据

unsigned char data yihuo_save[14] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00};//存储命令数据

unsigned char code ditab[16] = {0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,

0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};

char code RomCode[8][8] = { 0x28,0xd3,0x3e,0xeb,0x01,0x00,0x00,0xd3, //n1

0x28,0x55,0x35,0xeb,0x01,0x00,0x00,0xfb, //n2

0x28,0x82,0x2d,0xeb,0x01,0x00,0x00,0xf8, //n3

0x28,0xe9,0x2f,0xeb,0x01,0x00,0x00,0x40, //n4

0x28,0xe5,0x67,0xeb,0x01,0x00,0x00,0xea, //n5

0x28,0x2f,0x52,0xeb,0x01,0x00,0x00,0xec, //n6

0x28,0xf1,0x3b,0xeb,0x01,0x00,0x00,0xd9, //n7

0x28,0xa8,0x44,0xeb,0x01,0x00,0x00,0x63 //n8

};//////温度传感器发生损坏需替换时,需更改对应传感器的RomCode////

char str1[] ={0x40,0x30,0x46,0x30,0x32,'\0'};//字头,标志等 传送两个字符

unsigned char Data_buf_ASCII[]={0x00,0x00};//拆分中使用

//

void hctoa(unsigned char buf_char) ; //拆分函数 一字节数据转换成两字节ASCII码

//void beep();

//

void Delay(unsigned int num)//延时函数

{

while( --num );

}

//

// 二、 18b20相关函数

// 1 初始化 2 读字节 3 写字节 4 读序列码 5 读取温度

/ 设想,讲DQ的定义,制成单独的函数,

对标准变量X0的访问,改为写入,根据写入的数据不同,选择不同的管脚,

从而实现程序复用和点数的扩展

//

Init_DS18B20(void) //初始化ds1820

{

DQ = 1; //DQ复位

Delay(8); //稍做延时

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

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

DQ = 1; //拉高总线

Delay(8);

presence = DQ; //如果=0则初始化成功 =1则初始化失败

Delay(100);

DQ = 1;

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

}

//

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;

}

}

//

Read_Temperature() //读取温度 unsigned char n

{

unsigned char i,j,k,m=0,temp0=0,temp1=0; // m-第几个温度传感器 i-序列号的第几个字节

Init_DS18B20();

if(presence==1)

{ flash=1;} // DS18B20不正常,蜂鸣器报警

else

{

flash=0;

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

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

while(m<8) // 8个温度传感器18B20

{

unsigned char x=0;

Init_DS18B20();

WriteOneChar(0x55); // 匹配ROM命令

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

{

WriteOneChar(RomCode[m][i]); // 8个传感器中某一个的8个字节的ID号

}

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

temp0 = ReadOneChar(); // 温度低8位

temp1 = ReadOneChar(); // 温度高8位

/将温度保存到temp_save[]对应位置/

j=2m;

k=temp0&0x0f; // 温度低8位的低4位(小数部分)

x=ditab[k]; //查表得小数位的值

temp_save[j]=(temp0&0xf0)|x; // 将温度低8位的高4位和转换后的小数位存入-温度的第1字节

j++;

temp_save[j]=temp1; // 将温度高8位存入温度的第2字节

m++; // 下一个温度传感器

} // end while

} // end else

ff=1; // 测温成功标志 先存低字节

}

//

// 三、 串口 *** 作函数 1 发送字符 2 发送字符串

//

void send_char(unsigned char txd) // 1 传送一个字符

{

SBUF = txd;

while(!TI); // 等特数据传送

TI = 0; // 清除数据传送标志

}

//

void send_str() // 2 传送字符串之1 用于发送字符串

{

unsigned char i=0;

while(str1[i] != '\0')

{

SBUF = str1[i];

while(!TI); // 等特数据传送

TI = 0; // 清除数据传送标志

i++; // 下一个字符

}

}

//

void send_str0() // 3 传送字符串之2 传送Data_buf_ASCII[i]

{

unsigned char i;

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

{

SBUF =Data_buf_ASCII[i];

while(!TI); // 等特数据传送

TI = 0; // 清除数据传送标志

}

}

//

void delayms(unsigned char ms)

// 延时子程序

{

unsigned char i;

while(ms--)

{

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

}

}

//

// 四、 通信协议函数 发送1 发送2 拆分函数

//

void send_1() // 发送下位机发送数据的第1部分 40(字头) 30 46(设备地址15) 30 32(表示将发送两个字节的数据)

{

send_str(); // 发送数据位前的字符串 40(字头) 30 46(设备地址15) 30 32(表示将发送两个字节的数据)

}

//

void send_2(unsigned char a) //发送数据之 2

{

unsigned char x,i,j,k,s=0;

unsigned long m;

unsigned char xor=0x74; // 除去传送数据外的异或值

//// temp_save[] 先存的是低字节

k=temp_save[a]&0x0f; // 低8位的低4位(小数部分) ,查表后值

j=temp_save[a]&0xf0; // 低8位的高4位(整数部分的低4位+0000),原正整数部分 0010 0001 取

j=j/16; // 比实际数值大了16倍,所以要除以16

a++;

i=temp_save[a]&0x0f; // 高8位的低4位(0000+整数部分的高4位),比实际数值小了16倍

x=i16+j; // x为温度整数部分的实际值

m=x10+k; // 十倍数据,为避免给上位机传小数,将整数部分乘10倍,再加上小数。即测温375度,实际传375

// 在组态软件的变量中针对I/O变量,通过设置(最大原始值10000/原始值1000)=10的方式变换回375

// m=375 需要用2个字节表示 00000001 01110111

j=m/256; // 得到高字节的值 1

k=m%256; // 得到低字节的值 119

s=j; // 先传高位 00000001

hctoa(s); // 0000 0001 转换成ASCII码 30 31 实际在串口中传输的是两个字节二进制数 00110000 00110001

send_str0(); // 传送温度数据

xor^=Data_buf_ASCII[0];

xor^=Data_buf_ASCII[1];

s=k; // 再传低位 01110111

hctoa(s); // 0111 0111 转换成ASCII码 37 37 实际在串口中传输的是两个字节二进制数 00110000 00110001

send_str0(); // 传送温度数据

xor^=Data_buf_ASCII[0];

xor^=Data_buf_ASCII[1];

hctoa(xor); // 求异或位的ASC码

send_str0(); // 发送异或校验位

send_char(0x0d); // 发送结束字符0d

}

////////////////////////////////////////////

void hctoa(unsigned char buf_char) // 拆分函数,组态王传输协议决定的

//一字节十六进制数据转换成两字节ASCII码 例:00000001拆分成 0000和0001 再分别求两部分的ASCII码

{

unsigned char count,c;

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

{

if(count==0)

{

c = buf_char>>4; // 循环右移四位,使高4位移到低4位的位置,

}

else

{

c = buf_char; // 后取低4位

}

c &= 0x0f; // 高4位置0+取低4位 *** 作

if(c>=0&&c<=9)

Data_buf_ASCII[count] = '0' + c;

else

Data_buf_ASCII[count] = 'A' + c - 10;

}

}

//

//

/

void get_number()//计算发送数据的个数

{

num=16(str1[3]-30)+str1[4]-30;

}

//

//

void main(void)

{

TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率

TH1 = 0xF4; // 波特率2400 注意110592的晶振为F4,12M晶振为F3

TL1 = 0xF4;

SCON = 0x50; // 设定串行口工作方式

PCON &= 0xef; // 波特率不倍增

TR1 = 1; // 启动定时器1

IE = 0x0; // 禁止任何中断

while(1)

{

unsigned char aa=0,bb=0; //a 通讯标志

if(RI) // 是否有数据到来,有数据到来时,RI被单片机自动置1,一个字节的数据被暂存在缓存器SUBF中

{

temp = SBUF; // 暂存接收到的数据

yihuo_save[cc]= SBUF;

if(temp==0x40)

ac=0x8f; // 标志一次命令的读入ac: 0-1

if(cc==8) // cc从0~8,共读入前9个字节

// [字头40,设备地址30 46,标志40 30,数据地址30 30 30 46]

{

bc=0;

if(yihuo_save[8]==0x30) // 每次新一轮测温都需要用组态王发送读I/O变量en的值来启动

// yihuo_save[8]==0x30 代表寄存器X0,即组态王中的变量en

{ff=2;} // ff=2表示启动测温 ff:0--2 标志着要进行温度测量

else

{

bc=yihuo_save[8]-0x31; // bc<9之前yihuo_save[8]依次为 31 33,35,37,39

// 此时yihuo_save[8]-0x31的值依次为 0,2,4,6,8

ff=1; // 为前5个温度传感器的值在temp_save[16]中的位置

}

if(bc>9) bc=bc-7; // 当寄存器地址为30 30 30 42时(组态王自动跳过40,40为字头),x42-x31=66-49=17

} // 17-7=10

cc++;

RI = 0; // 准备接收下一字节

} //end RI ,此循环接收组态王发送过来的读命令,共14个字节

//

if(temp==0x0d) // 如果缓存器SBUF中是0d,表示上位机的读命令的14个字节已经正确接收

{

delayms(5); // 短暂延时

//

if(ac>0)

{

if(ff==2) // 只有当组态王发读I/O变量en(寄存器X0)的命令时 ff==2,才发送此设定好的字节

{

send_char(0x40);

send_char(0x30);

send_char(0x46);

send_char(0x30);

send_char(0x31);

send_char(0x30);

send_char(0x30);

send_char(0x37);

send_char(0x37);

send_char(0x0d);

ac=0;

Read_Temperature();

}

if(ff==1&&ac>0) // ff=1表示测温成功

{

send_1(); // 发送数据位前的字符串40(字头)30 46(设备地址15)30 32(表示将发送两个字节的数据)

send_2(bc); // 上传1个传感器温度(bc指定是那个温度传感器的温度)

// bc的数值用来选择temp_save[ ]中存储的某个18B20的温度

// 如bc=0和bc=1为分别传送temp_save[ ]中的第1字节和第2字节。

// 发送温度值(30 32 37 37),异或值,结束符(0d)

ac=0; // 准备接收下一条读命令,进而发送指定温度传感器的温度

}

// 将变量置零,重新进入下一循环的读写 *** 作

cc=0x00; // cc代表命令数据的第几个字节,此处置0,将重新开始接收上位机的读命令。

temp=0x00; // temp暂存缓存器中的数据,此处清零

bc=0;

}//end if(ac==1)

}//end if (temp==0d)

}//end while

}//end main

/

send_char(temp_save[1]);

send_char(temp_save[0]);

send_char(temp_save[3]);

send_char(temp_save[2]);

send_char(temp_save[5]);

send_char(temp_save[4]);

send_char(temp_save[7]);

send_char(temp_save[6]);

send_char(temp_save[9]);

send_char(temp_save[8]);

send_char(temp_save[11]);

send_char(temp_save[10]);

send_char(temp_save[13]);

send_char(temp_save[12]);

send_char(temp_save[15]);

send_char(temp_save[14]);

//

先把18B20程序取出来,显示部分自己编,给你个参考18B20读出的温度值要先经过转换分成单个的数,然后再调用显示

/转换显示/

void zhuan_huan(uint temp) //转换显示数据

{

uchar qian,bai,shi,ge;

qian=temp/1000;

bai=temp%1000/100;

shi=temp%100/10;

ge=temp%100%10;

mah[3]=qian;

mah[2]=bai;

mah[1]=shi;

mah[0]=ge;

}

void display() //显示函数

{

DPY1=0;

P0=table[mah[3]];

delay_ms(5);

P0=0xFF;

DPY1=1;

DPY2=0;

P0=table1[mah[2]];

delay_ms(5);

P0=0xFF;

DPY2=1;

DPY3=0;

P0=table[mah[1]];

delay_ms(5);

P0=0xFF;

DPY3=1;

DPY4=0;

P0=table[mah[0]];

delay_ms(5);

P0=0xFF;

DPY4=1;

}

一下程序是51单片机的程序。P0口是八段数码管,wela、dula分别是数码管位选和段选。 DS18S20接在P2^2口。

//安装目录下的EXE文件打开后可在电脑上显示当前温度值

#include <reg52h>

#define uchar unsigned char

#define uint unsigned int

sbit DS=P2^2; //define interface of DS18B20

sbit dula=P2^6;

sbit wela=P2^7;

uint pre_temp=0; //储存当前温度值,以减少串口工作频率

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,

0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

unsigned char code table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,

0x87,0xff,0xef};

void delay(uint count) //delay

{

uint i;

while(count)

{

i=200;

while(i>0)

i--;

count--;

}

}

///////功能:串口初始化,波特率9600,方式1///////

void Init_Com(void)

{

TMOD = 0x20;

PCON = 0x00;

SCON = 0x50;

TH1 = 0xFd;

TL1 = 0xFd;

TR1 = 1;

}

void dsreset(void) //send reset and initialization command 18B20复位,初始化函数

{

uint i;

DS=0;

i=103;

while(i>0)i--;

DS=1;

i=4;

while(i>0)i--;

}

bit tmpreadbit(void) //read a bit 读1位数据函数

{

uint i;

bit dat;

DS=0;i++; //i++ for delay

DS=1;i++;i++;

dat=DS;

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

return (dat);

}

uchar tmpread(void) //read a byte date 读1字节函数

{

uchar i,j,dat;

dat=0;

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

{

j=tmpreadbit();

dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里

}

return(dat);

}

void tmpwritebyte(uchar dat) //write a byte to ds18b20 向1820写一个字节数据函数

{

uint i;

uchar j;

bit testb;

for(j=1;j<=8;j++)

{

testb=dat&0x01;

dat=dat>>1;

if(testb) //write 1

{

DS=0;

i++;i++;

DS=1;

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

}

else

{

DS=0; //write 0

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

DS=1;

i++;i++;

}

}

}

void tmpchange(void) //DS18B20 begin change 开始获取数据并转换

{

dsreset();

delay(1);

tmpwritebyte(0xcc); // address all drivers on bus 写跳过读ROM指令

tmpwritebyte(0x44); // initiates a single temperature conversion 写温度转换指令

}

uint tmp() //get the temperature 读取寄存器中存储的温度数据

{

float tt;

uchar a,b;

uint temp; // variable of temperature

dsreset();

delay(1);

tmpwritebyte(0xcc);

tmpwritebyte(0xbe);

a=tmpread(); //读低8位

b=tmpread(); //读高8位

temp=b;

temp<<=8; //two byte compose a int variable 两个字节组合为1个字

temp=temp|a;

tt=temp00625; //温度在寄存器中是12位,分辨率是00625

temp=tt10+05; //乘10表示小数点后只取1位,加05是四折五入

return temp;

}

// 读 DS18B20 的rom,本程序没有调用该函数,保留以保证程序的完整性

// void readrom() //read the serial

// {

// uchar sn1,sn2;

// dsreset();

// delay(1);

// tmpwritebyte(0x33);

// sn1=tmpread();

// sn2=tmpread();

// }

void display(uint temp) //显示程序

{

uchar A1,A2,A2t,A3,ser;

uchar serial_flag = 0; //每当产生新温度时通过串口进行更新,此为标志位

if ( temp != pre_temp )

{

serial_flag = 1;

pre_temp = temp;

}

A1=temp/100;

A2t=temp%100;

A2=A2t/10;

A3=A2t%10;

dula=0;

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

if ( serial_flag )

{

ser = temp/256; //发送串口数据高位

SBUF = ser;

}

dula=1;

dula=0;

wela=0;

P0=0x7e;

wela=1;

wela=0;

delay(1);

dula=0;

P0=table1[A2]; //显示十位

if ( serial_flag )

{

ser = temp%256; //发送串口数据低位

SBUF = ser;

}

dula=1;

dula=0;

wela=0;

P0=0x7d;

wela=1;

wela=0;

delay(1);

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

if ( serial_flag )

{

ser = 0xff; //发送串口同步标志信号,后跟着的高位信号不可能达到此值,除非是在孙悟空在八卦炉里

SBUF = ser;

}

dula=1;

dula=0;

P0=0x7b;

wela=1;

wela=0;

delay(1);

}

void main()

{

uchar a;

Init_Com();

do

{

tmpchange();

// delay(200);

for(a=10;a>0;a--)

{

display(tmp());

}

}while(1);

}

DS18B20一线总线数字式传感器的原理与使用

________________________________________

DS18B20、 DS1822 “一线总线”数字化温度传感器是DALLAS最新单线数字温度传感器, 同DS1820一样,DS18B20也 支持“一线总线”接口,测量温度范围为 -55°C~+125°C,在-10~+85°C范围内,精度为±05°C。DS1822的精度较差为± 2°C 。现场温度直接以“一线总线”的数字方式传输,大大提高了系统的抗干扰性。适合于恶劣环境的现场温度测量,与前一代产品不同,新的产品支持3V~55V的电压范围,使系统设计更灵活、方便。而且新一代产品更便宜,体积更小。

DS18B20可以程序设定9~12位的分辨率,精度为±05°C。可选更小的封装方式,更宽的电压适用范围。分辨率设定,及用户设定的报警温度存储在EEPROM中,掉电后依然保存。DS18B20的性能是新一代产品中最好的!性能价格比也非常出色! DS1822与 DS18B20软件兼容,是DS18B20的简化版本。省略了存储用户定义报警温度、分辨率参数的EEPROM,精度降低为±2°C,适用于对性能要求不高,成本控制严格的应用,是经济型产品。 继“一线总线”的早期产品后,DS1820开辟了温度传感器技术的新概念。DS18B20和DS1822使电压、特性及封装有更多的选择,让我们可以构建适合自己的经济的测温系统。

DS18B20的内部结构

DS18B20内部结构主要由四部分组成:64位光刻ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。DS18B20的管脚排列如下:

15元/只

DQ为数字信号输入/输出端;GND为电源地;VDD为外接供电电源输入端(在寄生电源接线方式时接地)。

光刻ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码。64位光刻ROM的排列是:开始8位(28H)是产品类型标号,接着的48位是该DS18B20自身的序列号,最后8位是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。

DS18B20中的温度传感器可完成对温度的测量,以12位转化为例:用16位符号扩展的二进制补码读数形式提供,以00625℃/LSB形式表达,其中S为符号位。

这是12位转化后得到的12位数据,存储在18B20的两个8比特的RAM中,二进制中的前面5位是符号位,如果测得的温度大于0,这5位为0,只要将测到的数值乘于00625即可得到实际温度;如果温度小于0,这5位为1,测到的数值需要取反加1再乘于00625即可得到实际温度。

例如+125℃的数字输出为07D0H,+250625℃的数字输出为0191H,-250625℃的数字输出为FF6FH,-55℃的数字输出为FC90H。

DS18B20温度传感器的存储器

DS18B20温度传感器的内部存储器包括一个高速暂存RAM和一个非易失性的可电擦除的E2RAM,后者存放高温度和低温度触发器TH、TL和结构寄存器。

暂存存储器包含了8个连续字节,前两个字节是测得的温度信息,第一个字节的内容是温度的低八位,第二个字节是温度的高八位。第三个和第四个字节是TH、TL的易失性拷贝,第五个字节是结构寄存器的易失性拷贝,这三个字节的内容在每一次上电复位时被刷新。第六、七、八个字节用于内部计算。第九个字节是冗余检验字节。

该字节各位的意义如下:

TM R1 R0 1 1 1 1 1

低五位一直都是1 ,TM是测试模式位,用于设置DS18B20在工作模式还是在测试模式。在DS18B20出厂时该位被设置为0,用户不要去改动。R1和R0用来设置分辨率,如下表所示:(DS18B20出厂时被设置为12位)

分辨率设置表:

R1 R0 分辨率 温度最大转换时间

0 0 9位 9375ms

0 1 10位 1875ms

1 0 11位 375ms

1 1 12位 750ms

根据DS18B20的通讯协议,主机控制DS18B20完成温度转换必须经过三个步骤:每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的 *** 作。复位要求主CPU将数据线下拉500微秒,然后释放,DS18B20收到信号后等待16~60微秒左右,后发出60~240微秒的存在低脉冲,主CPU收到此信号表示复位成功。

DS1820使用中注意事项

DS1820虽然具有测温系统简单、测温精度高、连接方便、占用口线少等优点,但在实际应用中也应注意以下几方面的问题:

(1)较小的硬件开销需要相对复杂的软件进行补偿,由于DS1820与微处理器间采用串行数据传送,因此,在对DS1820进行读写编程时,必须严格的保证读写时序,否则将无法读取测温结果。在使用PL/M、C等高级语言进行系统程序设计时,对DS1820 *** 作部分最好采用汇编语言实现。

(2)在DS1820的有关资料中均未提及单总线上所挂DS1820数量问题,容易使人误认为可以挂任意多个DS1820,在实际应用中并非如此。当单总线上所挂DS1820超过8个时,就需要解决微处理器的总线驱动问题,这一点在进行多点测温系统设计时要加以注意。

(3)连接DS1820的总线电缆是有长度限制的。试验中,当采用普通信号电缆传输长度超过50m时,读取的测温数据将发生错误。当将总线电缆改为双绞线带屏蔽电缆时,正常通讯距离可达150m,当采用每米绞合次数更多的双绞线带屏蔽电缆时,正常通讯距离进一步加长。这种情况主要是由总线分布电容使信号波形产生畸变造成的。因此,在用DS1820进行长距离测温系统设计时要充分考虑总线分布电容和阻抗匹配问题。

(4)在DS1820测温程序设计中,向DS1820发出温度转换命令后,程序总要等待DS1820的返回信号,一旦某个DS1820接触不好或断线,当程序读该DS1820时,将没有返回信号,程序进入死循环。这一点在进行DS1820硬件连接和软件设计时也要给予一定的重视。

测温电缆线建议采用屏蔽4芯双绞线,其中一对线接地线与信号线,另一组接VCC和地线,屏蔽层在源端单点接地。

本站实验板实验程序:

;这是关于DS18B20的读写程序,数据脚P22,晶振12MHZ

;温度传感器18B20汇编程序,采用器件默认的12位转化,最大转化时间750微秒

;可以将检测到的温度直接显示到AT89C51开发实验板的两个数码管上

;显示温度00到99度,很准确哦~~无需校正!

ORG 0000H

;单片机内存分配申明!

TEMPER_L EQU 29H;用于保存读出温度的低8位

TEMPER_H EQU 28H;用于保存读出温度的高8位

FLAG1 EQU 38H;是否检测到DS18B20标志位

a_bit equ 20h ;数码管个位数存放内存位置

b_bit equ 21h ;数码管十位数存放内存位置

MAIN:

LCALL GET_TEMPER;调用读温度子程序

;进行温度显示,这里我们考虑用网站提供的两位数码管来显示温度

;显示范围00到99度,显示精度为1度

;因为12位转化时每一位的精度为00625度,我们不要求显示小数所以可以抛弃29H的低4位

;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度

MOV A,29H

MOV C,40H;将28H中的最低位移入C

RRC A

MOV C,41H

RRC A

MOV C,42H

RRC A

MOV C,43H

RRC A

MOV 29H,A

LCALL DISPLAY;调用数码管显示子程序

CPL P10

AJMP MAIN

; 这是DS18B20复位初始化子程序

INIT_1820:

SETB P35

NOP

CLR P35

;主机发出延时537微秒的复位低脉冲

MOV R1,#3

TSR1:MOV R0,#107

DJNZ R0,$

DJNZ R1,TSR1

SETB P35;然后拉高数据线

NOP

NOP

NOP

MOV R0,#25H

TSR2:

JNB P35,TSR3;等待DS18B20回应

DJNZ R0,TSR2

LJMP TSR4 ; 延时

TSR3:

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

CLR P17;检查到DS18B20就点亮P17LED

LJMP TSR5

TSR4:

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

CLR P11;点亮P1。1脚LED表示温度传感器通信失败

LJMP TSR7

TSR5:

MOV R0,#117

TSR6:

DJNZ R0,TSR6 ; 时序要求延时一段时间

TSR7:

SETB P35

RET

; 读出转换后的温度值

GET_TEMPER:

SETB P35

LCALL INIT_1820;先复位DS18B20

JB FLAG1,TSS2

CLR P12

RET ; 判断DS1820是否存在若DS18B20不存在则返回

TSS2:

CLR P13;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!

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

LCALL WRITE_1820

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

LCALL WRITE_1820

;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒

LCALL DISPLAY

LCALL INIT_1820;准备读温度前先复位

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

LCALL WRITE_1820

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

LCALL WRITE_1820

LCALL READ_18200; 将读出的温度数据保存到35H/36H

CLR P14

RET

;写DS18B20的子程序(有具体的时序要求)

WRITE_1820:

MOV R2,#8;一共8位数据

CLR C

WR1:

CLR P35

MOV R3,#6

DJNZ R3,$

RRC A

MOV P35,C

MOV R3,#23

DJNZ R3,$

SETB P35

NOP

DJNZ R2,WR1

SETB P35

RET

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

READ_18200:

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

MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)

RE00:

MOV R2,#8;数据一共有8位

RE01:

CLR C

SETB P35

NOP

NOP

CLR P35

NOP

NOP

NOP

SETB P35

MOV R3,#9

RE10:

DJNZ R3,RE10

MOV C,P35

MOV R3,#23

RE20:

DJNZ R3,RE20

RRC A

DJNZ R2,RE01

MOV @R1,A

DEC R1

DJNZ R4,RE00

RET

;显示子程序

display: mov a,29H;将29H中的十六进制数转换成10进制

mov b,#10 ;10进制/10=10进制

div ab

mov b_bit,a ;十位在a

mov a_bit,b ;个位在b

mov dptr,#numtab ;指定查表启始地址

mov r0,#4

dpl1: mov r1,#250 ;显示1000次

dplop: mov a,a_bit ;取个位数

MOVC A,@A+DPTR ;查个位数的7段代码

mov p0,a ;送出个位的7段代码

clr p20 ;开个位显示

acall d1ms ;显示1ms

setb p20

mov a,b_bit ;取十位数

MOVC A,@A+DPTR ;查十位数的7段代码

mov p0,a ;送出十位的7段代码

clr p21 ;开十位显示

acall d1ms ;显示1ms

setb p21

djnz r1,dplop ;100次没完循环

djnz r0,dpl1 ;4个100次没完循环

ret

;1MS延时(按12MHZ算)

D1MS: MOV R7,#80

DJNZ R7,$

RET

;实验板上的7段数码管0~9数字的共阴显示代码

numtab: DB 0F3H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H

end

以下是第二种采集和处理程序供网友参考

;温度传感器18B20汇编程序,采用器件默认的12位转化,最大转化时间750微秒

;将温度数据通过串口发送出去,波特率2400

;本程序专为AT89C51实验开发板编写适合12晶振

;本程序经过验证,可以显示温度+/-和两位整数温度和两位小数温度数据

DOT EQU 30H

ZHENGSHU EQU 31H

FLAG1 EQU 38H ;是否检测到DS18B20的标志位

;定义温度数据

DIS_1 EQU 32H ;符号

DIS_2 EQU 33H ;十位

DIS_3 EQU 34H ;个位

DIS_4 EQU 35H ;小数点后第一位

DIS_5 EQU 36H ;小数点后第二位

WDDATA BIT P22 ;定义DS18B20的数据脚为P22端口

ORG 0000H

;以下为主程序进行CPU中断方式设置

CLR EA ;关闭总中断

MOV SCON,#50H ;设置成串口1方式

MOV TMOD,#20H ;波特率发生器T1工作在模式2上

MOV TH1,#0F3H ;预置初值(按照波特率2400BPS预置初值)

MOV TL1,#0F3H ;预置初值(按照波特率2400BPS预置初值)

SETB TR1 ;启动定时器T1

;以上完成串口2400通讯初始化设置

;-------------------------

; 主程序

;-------------------------

MAIN:

LCALL INIT_1820 ;调用复位DS18B20子程序

MAIN1:

LCALL GET_TEMPER;调用读温度子程序

LCALL FORMULA ;通过公式计算,小数点后显示两位

LCALL BCD

LCALL DISPLAY ;调用串口显示子程序

LCALL DELAY500 ;延时05秒

LCALL DELAY500 ;延时05秒

LCALL DELAY500 ;延时05秒

AJMP MAIN1

;-------------------------

; DS18B20复位初始化程序

;-------------------------

INIT_1820:

SETB WDDATA

NOP

CLR WDDATA

;主机发出延时540微秒的复位低脉冲

MOV R0,#36

LCALL DELAY

SETB WDDATA;然后拉高数据线

NOP

NOP

MOV R0,#36

TSR2:

JNB WDDATA,TSR3;等待DS18B20回应

DJNZ R0,TSR2

LJMP TSR4 ; 延时

TSR3:

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

LJMP TSR5

TSR4:

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

LJMP TSR7

TSR5:

MOV R0,#06BH

TSR6:

DJNZ R0,TSR6 ;复位成功!时序要求延时一段时间

TSR7:

SETB WDDATA

RET

;-------------------

; 读出转换后的温度值

;-------------------

GET_TEMPER:

SETB WDDATA ; 定时入口

LCALL INIT_1820 ;先复位DS18B20

JB FLAG1,TSS2

RET ; 判断DS1820是否存在若DS18B20不存在则返回

TSS2:

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

LCALL WRITE_1820

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

LCALL WRITE_1820

MOV R0,#50 ;等待AD转换结束,12位的话750微秒

LCALL DELAY

LCALL INIT_1820 ;准备读温度前先复位

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

LCALL WRITE_1820

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

LCALL WRITE_1820

LCALL READ_18200; 将读出的九个字节数据保存到60H-68H

RET

;----------------------------------

;写DS18B20的子程序(有具体的时序要求)

;----------------------------------

WRITE_1820:

MOV R2,#8 ;一共8位数据

CLR C

WR1:

CLR WDDATA

MOV R3,#6

DJNZ R3,$

RRC A

MOV WDDATA,C

MOV R3,#24

DJNZ R3,$

SETB WDDATA

NOP

DJNZ R2,WR1

SETB WDDATA

RET

;--------------------------------------------------

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

;--------------------------------------------------

READ_18200:

MOV R4,#9

MOV R1,#60H ; 存入60H开始的九个单元

RE00:

MOV R2,#8

RE01:

CLR C

SETB WDDATA

NOP

NOP

CLR WDDATA

NOP

NOP

NOP

SETB WDDATA

MOV R3,#09

RE10:

DJNZ R3,RE10

MOV C,WDDATA

MOV R3,#23

RE20:

DJNZ R3,RE20

RRC A

DJNZ R2,RE01

MOV @R1,A

INC R1

DJNZ R4,RE00

RET

;------------------------

;温度计算子程序

;------------------------

FORMULA: ; 按公式:T实际=(T整数-025)+( M每度-M剩余)/ M每度

;计算出实际温度,整数部分和小数部分分别存于ZHENGSHU单元和DOT单元

;将61H中的低4位移入60H中的高4位,得到温度的整数部分,并存于ZHENGSHU单元

MOV 29H,61H

MOV A,60H

MOV C,48H

RRC A

MOV C,49H

RRC A

MOV C,4AH

RRC A

MOV C,4BH

RRC A

MOV ZHENGSHU,A

; ( M每度-M剩余)/ M每度,小数值存于A中

MOV A,67h

SUBB A,66h

MOV B,#64H

MUL AB

MOV R4,B

MOV R5,A

MOV R7,67H

LCALL DIV457

MOV A,R3

;再减去025,实际应用中减去25

SUBB A,#19H

MOV DOT,A ;小数部分存于DOT中

MOV A,ZHENGSHU

SUBB A,#00H ;整数部分减去来自小数部分的借位

MOV ZHENGSHU,A

MOV C,4BH

JNC ZHENG ;是否为负数

CPL A

INC A

MOV DIS_1,#2DH ; 零度以下时,第一位显示"-"号

MOV ZHENGSHU,A

ZHENG:

MOV DIS_1,#2BH ; 零度以上时,第一位显示"+"号

RET

;------------------------

;双字节除以单字节子程序

;------------------------

DIV457: CLR C

MOV A,R4

SUBB A,R7

JC DV50

SETB OV ;商溢出

RET

DV50: MOV R6,#8 ;求平均值(R4R5/R7-→R3)

DV51: MOV A,R5

RLC A

MOV R5,A

MOV A,R4

RLC A

MOV R4,A

MOV F0,C

CLR C

SUBB A,R7

ANL C,/F0

JC DV52

MOV R4,A

DV52: CPL C

MOV A,R3

RLC A

MOV R3,A

DJNZ R6,DV51

MOV A,R4 ;四舍五入

ADD A,R4

JC DV53

SUBB A,R7

JC DV54

DV53: INC R3

DV54: CLR OV

RET

;---------------------

;转换成非压缩的BCD码

;---------------------

BCD: MOV A,ZHENGSHU

MOV B,#0AH

DIV AB

ORL A,#00110000B ;转换成ASCII码

MOV DIS_2,A

MOV DIS_3,B

MOV A,DIS_3

ORL A,#00110000B ;转换成ASCII码

mov DIS_3,A

MOV A,DOT

MOV B,#0AH

DIV AB

ORL A,#00110000B ;转换成ASCII码

MOV DIS_4,A

MOV DIS_5,B

MOV A,DIS_5

ORL A,#00110000B ;转换成ASCII码

mov DIS_5,A

RET

;----------------------

;串口显示数据子程序

;----------------------

DISPLAY:

CLR TI

MOV A,DIS_1

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示+/-

CLR TI

MOV A,DIS_2

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示整数第一位

CLR TI

MOV A,DIS_3

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示整数第二位

CLR TI

MOV A,#2EH

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示小数点

CLR TI

MOV A,DIS_4

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示小数第一位

CLR TI

MOV A,DIS_5

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示小数第一位

CLR TI

MOV A,#0DH;换行

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示

CLR TI

MOV A,#0AH;换行

MOV SBUF,A

JNB TI,$ ;发送给PC,通过串口调试助手显示

RET

;----------------------

;延时子程序

;----------------------

;为保证DS18B20的严格I/O时序,需要做较精确的延时

;在DS18B20 *** 作中,用到的延时有15 μs,90 μs,270 μs,540 μs

;因这些延时均为15 μs的整数倍,因此可编写一个DELAY15(n)函数

DELAY: ;1105962M晶振

LOOP: MOV R1,#06H

LOOP1: DJNZ R1,LOOP1

DJNZ R0,LOOP

RET

;500毫秒延时子程序,占用R4、R5

DELAY500:MOV R4,#248

DA222:MOV R5,#248

DJNZ R5,$

DJNZ R4,DA222

RET

END

以上就是关于STC单片机模拟串口与上位机通信,并发送扫描18B20得到的温度值。全部的内容,包括:STC单片机模拟串口与上位机通信,并发送扫描18B20得到的温度值。、基于AT89C51单片机和DS18B20温度传感器、LCD1602液晶显示的高精度数字温度计程序、以单片机AT89S52为核,使用并口两位共阳数显做显示,DS18B20做温度传感器,来制作一个温度器等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址:https://54852.com/zz/10047440.html

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

发表评论

登录后才能评论

评论列表(0条)

    保存