1.基本知识
ADC0809是带有8位A/D转换器、8路多路开关以及微处理机兼容的控制逻辑的CMOS组件。它是逐次逼近式A/D转换器,可以和单片机直接接口。
(1).ADC0809的内部逻辑结构
由上图可知,ADC0809由一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用A/D转换器进行转换。三态输出锁器用于锁存A/D转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。
(2).
IN0-IN7:8条模拟量输入通道
引脚结构
ADC0809对输入模拟量要求:信号单极性,电压范围是0-5V,若信号太小,必须进行放大;输入的模拟量在转换过程中应该保持不变,如若模拟量变化太快,则需在输入前增加采样保持电路。
地址输入和控制线:4条
ALE为地址锁存允许输入线,高电平有效。当ALE线为高电平时,地址锁存与译码器将A,B,C三条地址线的地址信号进行锁存,经译码后被选中的通道的模拟量进转换器进行转换。A,B和C为地址输入线,用于选通IN0-IN7上的一路模拟量输入。通道选择表如下表所示。C00001111
B00110011
A01010101
选择的通道IN0IN1IN2IN3IN4IN5IN6IN7
数字量输出及控制线:11条
ST为转换启动信号。当ST上跳沿时,所有内部寄存器清零;下跳沿时,开始进行A/D转换;在转换期间,ST应保持低电平。EOC为转换结束信号。当EOC为高电平时,表明转换结束;否则,表明正在进行A/D转换。OE为输出允许信号,用于控制三条输出锁存器向单片机输出转换得到的数据。OE=1,输出转换得到的数据;OE=0,输出数据线呈高阻状态。D7-D0为数字量输出线。
CLK为时钟输入信号线。因ADC0809的内部没有时钟电路,所需时钟信号必须由外界提供,通常使用频率为500KHZ,VREF(+),VREF(-)为参考电压输入。2.ADC0809应用说明
(1).ADC0809内部带有输出锁存器,可以与AT89S51单片机直接相连。(2).初始化时,使ST和OE信号全为低电平。(3).送要转换的哪一通道的地址到A,B,C端口上。(4).在ST端给出一个至少有100ns宽的正脉冲信号。(5).是否转换完毕,我们根据EOC信号来判断。
(6).当EOC变为高电平时,这时给OE为高电平,转换的数据就输出给单
片机了。3.实验任务
如下图所示,从ADC0809的通道IN3输入0-5V之间的模拟量,通过ADC0809转换成数字量在数码管上以十进制形成显示出来。ADC0809的VREF接+5V电压。4.电路原理图
图1.27.1
5.系统板上硬件连线
(1).把“单片机系统板”区域中的P1端口的P1.0-P1.7用8芯排线连
接到“动态数码显示”区域中的ABCDEFGH端口上,作为数码管的笔段驱动。(2).把“单片机系统板”区域中的P2端口的P2.0-P2.7用8芯排线连
接到“动态数码显示”区域中的S1S2S3S4S5S6S7S8端口上,作为数码管的位段选择。(3).把“单片机系统板”区域中的P0端口的P0.0-P0.7用8芯排线连
接到“模数转换模块”区域中的D0D1D2D3D4D5D6D7端口上,A/D转换完毕的数据输入到单片机的P0端口
(4).把“模数转换模块”区域中的VREF端子用导线连接到“电源模块”
区域中的VCC端子上;(5).把“模数转换模块”区域中的A2A1A0端子用导线连接到“单片机
系统”区域中的P3.4P3.5P3.6端子上;(6).把“模数转换模块”区域中的ST端子用导线连接到“单片机系统”
区域中的P3.0端子上;(7).把“模数转换模块”区域中的OE端子用导线连接到“单片机系统”
区域中的P3.1端子上;(8).把“模数转换模块”区域中的EOC端子用导线连接到“单片机系统”
区域中的P3.2端子上;(9).把“模数转换模块”区域中的CLK端子用导线连接到“分频模块”
区域中的/4端子上;(10).把“分频模块”区域中的CKIN端子用导线连接到“单片机系统”
区域中的ALE端子上;(11).把“模数转换模块”区域中的IN3端子用导线连接到“三路可调
压模块”区域中的VR1端子上;6.程序设计内容
(1).进行A/D转换时,采用查询EOC的标志信号来检测A/D转换是
否完毕,若完毕则把数据通过P0端口读入,经过数据处理之后在数码管上显示。(2).进行A/D转换之前,要启动转换的方法:
ABC=110选择第三通道
ST=0,ST=1,ST=0产生启动转换的正脉冲信号
7.汇编源程序CHEQU30HDPCNTEQU31HDPBUFEQU33HGDATAEQU32HSTBITP3.0OEBITP3.1EOCBITP3.2ORG00H
LJMPSTARTORG0BHLJMPT0XORG30H
START:MOVCH,#0BCHMOVDPCNT,#00HMOVR1,#DPCNTMOVR7,#5MOVA,#10MOVR0,#DPBUFLOP:MOV@R0,AINCR0
DJNZR7,LOPMOV@R0,#00HINCR0
MOV@R0,#00HINCR0
MOV@R0,#00HMOVTMOD,#01H
MOVTH0,#(65536-4000)/256MOVTL0,#(65536-4000)MOD256SETBTR0SETBET0SETBEAWT:CLRSTSETBSTCLRST
WAIT:JNBEOC,WAITSETBOE
MOVGDATA,P0CLROE
MOVA,GDATAMOVB,#100DIVABMOV33H,AMOVA,BMOVB,#10DIVABMOV34H,AMOV35H,BSJMPWTT0X:NOP
MOVTH0,#(65536-4000)/256MOVTL0,#(65536-4000)MOD256
MOVDPTR,#DPCDMOVA,DPCNTADDA,#DPBUFMOVR0,AMOVA,@R0
MOVCA,@A+DPTRMOVP1,A
MOVDPTR,#DPBTMOVA,DPCNTMOVCA,@A+DPTRMOVP2,AINCDPCNTMOVA,DPCNTCJNEA,#8,NEXTMOVDPCNT,#00HNEXT:RETI
DPCD:DB3FH,06H,5BH,4FH,66HDB6DH,7DH,07H,7FH,6FH,00HDPBT:DB0FEH,0FDH,0FBH,0F7HDB0EFH,0DFH,0BFH,07FHEND
8.C语言源程序
#include unsignedcharcodedispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00}; unsignedchardispbuf[8]={10,10,10,10,10,0,0,0};unsignedchardispcount;sbitST=P3^0;sbitOE=P3^1;sbitEOC=P3^2; unsignedcharchannel=0xbc;//IN3unsignedchargetdata;voidmain(void){ TMOD=0x01; TH0=(65536-4000)/256;TL0=(65536-4000)%256;TR0=1;ET0=1; EA=1;P3=channel; while(1){ST=0;ST=1;ST=0; while(EOC==0);OE=1; getdata=P0;OE=0; dispbuf[2]=getdata/100;getdata=getdata%10;dispbuf[1]=getdata/10;dispbuf[0]=getdata%10;}} voidt0(void)interrupt1using0{ TH0=(65536-4000)/256;TL0=(65536-4000)%256; P1=dispcode[dispbuf[dispcount]];P2=dispbitcode[dispcount];dispcount++;if(dispcount==8){ dispcount=0;}} 28.数字电压表 1.实验任务 利用单片机AT89S51与ADC0809设计一个数字电压表,能够测量0-5V之间的直流电压值,四位数码显示,但要求使用的元器件数目最少。2.电路原理图 图1.28.1 3.系统板上硬件连线 a)把“单片机系统”区域中的P1.0-P1.7与“动态数码显示”区域中的 ABCDEFGH端口用8芯排线连接。b)把“单片机系统”区域中的P2.0-P2.7与“动态数码显示”区域中的 S1S2S3S4S5S6S7S8端口用8芯排线连接。 c)把“单片机系统”区域中的P3.0与“模数转换模块”区域中的ST端子 用导线相连接。d)把“单片机系统”区域中的P3.1与“模数转换模块”区域中的OE端子 用导线相连接。e)把“单片机系统”区域中的P3.2与“模数转换模块”区域中的EOC端子 用导线相连接。f)把“单片机系统”区域中的P3.3与“模数转换模块”区域中的CLK端子 用导线相连接。g)把“模数转换模块”区域中的A2A1A0端子用导线连接到“电源模块”区 域中的GND端子上。h)把“模数转换模块”区域中的IN0端子用导线连接到“三路可调电压模 块”区域中的VR1端子上。i)把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“模数转换模 块”区域中的D0D1D2D3D4D5D6D7端子上。4.程序设计内容 i.由于ADC0809在进行A/D转换时需要有CLK信号,而此时的ADC0809 的CLK是接在AT89S51单片机的P3.3端口上,也就是要求从P3.3输出CLK信号供ADC0809使用。因此产生CLK信号的方法就得用软件来产生了。ii.由于ADC0809的参考电压VREF=VCC,所以转换之后的数据要经过 数据处理,在数码管上显示出电压值。实际显示的电压值(D/256*VREF) 5.汇编源程序(略) 6.C语言源程序 #include unsignedcharcodedispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00}; unsignedchardispbuf[8]={10,10,10,10,0,0,0,0};unsignedchardispcount;unsignedchargetdata;unsignedinttemp; unsignedchari;sbitsbitsbitsbit ST=P3^0;OE=P3^1;EOC=P3^2;CLK=P3^3; voidmain(void){ST=0;OE=0;ET0=1;ET1=1;EA=1; TMOD=0x12;TH0=216;TL0=216; TH1=(65536-4000)/256;TL1=(65536-4000)%256;TR1=1;TR0=1;ST=1;ST=0;while(1){ if(EOC==1){OE=1; getdata=P0;OE=0; temp=getdata*235;temp=temp/128;i=5; dispbuf[0]=10;dispbuf[1]=10;dispbuf[2]=10;dispbuf[3]=10;dispbuf[4]=10;dispbuf[5]=0;dispbuf[6]=0;dispbuf[7]=0;while(temp/10){ dispbuf[i]=temp%10;temp=temp/10;i++;} dispbuf[i]=temp;ST=1;ST=0;}}} voidt0(void)interrupt1using0{ CLK=~CLK;} voidt1(void)interrupt3using0{ TH1=(65536-4000)/256;TL1=(65536-4000)%256; P1=dispcode[dispbuf[dispcount]];P2=dispbitcode[dispcount];if(dispcount==7){ P1=P1|0x80;} dispcount++;if(dispcount==8){ dispcount=0;}} 29.两点间温度控制 1.实验任务 用可调电阻调节电压值作为模拟温度的输入量,当温度低于30℃时,发出长嘀报警声和光报警,当温度高于60℃时,发出短嘀报警声和光报警。测量的温度范围在0-99℃。2.电路原理图 图4.29.1 3.系统板上硬件连线 a)把“单片机系统”区域中的P1.0-P1.7与“动态数码显示”区域中的 ABCDEFGH端口用8芯排线连接。b)把“单片机系统”区域中的P2.0-P2.7与“动态数码显示”区域中的 S1S2S3S4S5S6S7S8端口用8芯排线连接。c)把“单片机系统”区域中的P3.0与“模数转换模块”区域中的ST端子 用导线相连接。d)把“单片机系统”区域中的P3.1与“模数转换模块”区域中的OE端子 用导线相连接。e)把“单片机系统”区域中的P3.2与“模数转换模块”区域中的EOC端子 用导线相连接。f)把“单片机系统”区域中的P3.3与“模数转换模块”区域中的CLK端子 用导线相连接。g)把“模数转换模块”区域中的A2A1A0端子用导线连接到“电源模块”区 域中的GND端子上。h)把“模数转换模块”区域中的IN0端子用导线连接到“三路可调电压模 块”区域中的VR1端子上。i)把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“模数转换模 块”区域中的D0D1D2D3D4D5D6D7端子上。j)把“单片机系统”区域中的P3.6、P3.7用导线分别连接到“八路发光二 极管指示模块”区域中的L1、L2上。k)把“单片机系统”区域中的P3.5用导线连接到“音频放大模块”区域中 的SPKIN端口上。l)把“音频放大模块“区域中的SPKOUT插入音频喇叭。4.汇编源程序(略) 5.C语言源程序 #include unsignedcharcodedispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00}; unsignedchardispbuf[8]={10,10,10,10,10,10,0,0}; unsignedunsignedunsignedunsignedchardispcount;chargetdata;inttemp;chari; sbitST=P3^0;sbitOE=P3^1;sbitEOC=P3^2;sbitCLK=P3^3;sbitLED1=P3^6;sbitLED2=P3^7;sbitSPK=P3^5;bitlowflag;bithighflag; unsignedintcnta;unsignedintcntb;bitalarmflag; voidmain(void){ST=0;OE=0; TMOD=0x12;TH0=0x216;TL0=0x216; TH1=(65536-500)/256;TL1=(65536-500)%256;TR1=1;TR0=1;ET0=1;ET1=1;EA=1;ST=1;ST=0;while(1){ if((lowflag==1)&&(highflag==0)){ LED1=0;LED2=1;} elseif((highflag==1)&&(lowflag==0)){ LED1=1;LED2=0;}else{ LED1=1;LED2=1;}}} voidt0(void)interrupt1using0{ CLK=~CLK;} voidt1(void)interrupt3using0{ TH1=(65536-500)/256;TL1=(65536-500)%256;if(EOC==1){OE=1; getdata=P0;OE=0; temp=getdata*25;temp=temp/64;i=6; dispbuf[0]=10;dispbuf[1]=10;dispbuf[2]=10;dispbuf[3]=10;dispbuf[4]=10;dispbuf[5]=10;dispbuf[6]=0;dispbuf[7]=0;while(temp/10){ dispbuf[i]=temp%10;temp=temp/10;i++;} dispbuf[i]=temp;if(getdata<77){ lowflag=1;highflag=0;} elseif(getdata>153){ lowflag=0;highflag=1;}else{ lowflag=0;highflag=0;}ST=1;ST=0;} P1=dispcode[dispbuf[dispcount]];P2=dispbitcode[dispcount];dispcount++;if(dispcount==8){ dispcount=0;} if((lowflag==1)&&(highflag==0)){ cnta++; if(cnta==800){ cnta=0; alarmflag=~alarmflag;} if(alarmflag==1){ SPK=~SPK;}} elseif((lowflag==0)&&(highflag==1)){ cntb++; if(cntb==400){ cntb=0; alarmflag=~alarmflag;} if(alarmflag==1){ SPK=~SPK;}}else{ alarmflag=0;cnta=0;cntb=0;}} 30.四位数数字温度计 1.温度传感器AD590基本知识 AD590产生的电流与绝对温度成正比,它可接收的工作电压为4V-30V,检测的温度范围为-55℃-+150℃,它有非常好的线性输出性能,温度每增加1℃,其电流增加1uA。 AD590温度与电流的关系如下表所示摄氏温度0℃10℃20℃30℃40℃50℃60℃100℃AD590引脚图2.实验任务 利用AD590温度传感器完成温度的测量,把转换的温度值的模拟量送入ADC0809的其中一个通道进行A/D转换,将转换的结果进行温度值变换之后送入数码管显示。3.电路原理图 AD590电流273.2uA283.2uA293.2uA303.2uA313.2uA323.2uA333.2uA373.2uA 经10KΩ电压2.732V2.832V2.932V3.032V3.132V3.232V3.332V3.732V 图4.30.1 4.系统板上硬件连线 (1).把“单片机系统”区域中的P1.0-P1.7与“动态数码显示”区域 中的ABCDEFGH端口用8芯排线连接。(2).把“单片机系统”区域中的P2.0-P2.7与“动态数码显示”区域 中的S1S2S3S4S5S6S7S8端口用8芯排线连接。(3).把“单片机系统”区域中的P3.0与“模数转换模块”区域中的ST 端子用导线相连接。(4).把“单片机系统”区域中的P3.1与“模数转换模块”区域中的OE 端子用导线相连接。(5).把“单片机系统”区域中的P3.2与“模数转换模块”区域中的EOC 端子用导线相连接。 (6).把“单片机系统”区域中的P3.3与“模数转换模块”区域中的CLK 端子用导线相连接。(7).把“模数转换模块”区域中的A2A1A0端子用导线连接到“电源模 块”区域中的GND端子上。(8).把“模数转换模块”区域中的IN0端子用导线连接到自制的AD590 电路上。(9).把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“模数 转换模块”区域中的D0D1D2D3D4D5D6D7端子上。5.程序设计内容 (1).ADC0809的CLK信号由单片机的P3.3管脚提供 (2).由于AD590的温度变化范围在-55℃-+150℃之间,经过10KΩ之 后采样到的电压变化在2.182V-4.232V之间,不超过5V电压所表示的范围,因此参考电压取电源电压VCC,(实测VCC=4.70V)。由此可计算出经过A/D转换之后的摄氏温度显示的数据为: 如果(D*2350/128)<2732,则显示的温度值为-(2732-(D*2350/128)) 如果(D*2350/128)≥2732,则显示的温度值为+((D*2350/128)-2732) 6.汇编源程序(略) 7.C语言源程序 #include unsignedcharcodedispbitcode[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40}; unsignedchardispbuf[8]={10,10,10,10,10,10,0,0};unsignedchardispcount;unsignedchargetdata;unsignedlongtemp;unsignedchari;bitsflag;sbitST=P3^0; sbitsbitsbitsbitsbitsbitOE=P3^1;EOC=P3^2;CLK=P3^3;LED1=P3^6;LED2=P3^7;SPK=P3^5; voidmain(void){ST=0;OE=0; TMOD=0x12;TH0=0x216;TL0=0x216; TH1=(65536-4000)/256;TL1=(65536-4000)%256;TR1=1;TR0=1;ET0=1;ET1=1;EA=1;ST=1;ST=0; getdata=148;while(1){;}} voidt0(void)interrupt1using0{ CLK=~CLK;} voidt1(void)interrupt3using0{ TH1=(65536-4000)/256;TL1=(65536-4000)%256;if(EOC==1){ OE=1; getdata=P0;OE=0; temp=(getdata*2350);temp=temp/128;if(temp<2732){ temp=2732-temp;sflag=1;}else{ temp=temp-2732;sflag=0;}i=3; dispbuf[0]=10;dispbuf[1]=10;dispbuf[2]=10;if(sflag==1){ dispbuf[7]=11;}else{ dispbuf[7]=10;} dispbuf[3]=0;dispbuf[4]=0;dispbuf[5]=0;dispbuf[6]=0;while(temp/10){ dispbuf[i]=temp%10;temp=temp/10;i++;} dispbuf[i]=temp;ST=1;ST=0;} P1=dispcode[dispbuf[dispcount]];P2=dispbitcode[dispcount]; dispcount++;if(dispcount==8){ dispcount=0;}} 31.6位数显频率计数器 1.实验任务 利用AT89S51单片机的T0、T1的定时计数器功能,来完成对输入的信号进行频率计数,计数的频率结果通过8位动态数码管显示出来。要求能够对0-250KHZ的信号频率进行准确计数,计数误差不超过±1HZ。2.电路原理图 图4.31.1 3.系统板上硬件连线 (1).把“单片机系统”区域中的P0.0-P0.7与“动态数码显示”区域中的 ABCDEFGH端口用8芯排线连接。(2).把“单片机系统”区域中的P2.0-P2.7与“动态数码显示”区域中的 S1S2S3S4S5S6S7S8端口用8芯排线连接。 (3).把“单片机系统”区域中的P3.4(T0)端子用导线连接到“频率产生 器”区域中的WAVE端子上。4.程序设计内容 (1).定时/计数器T0和T1的工作方式设置,由图可知,T0是工作在计数状 态下,对输入的频率信号进行计数,但对工作在计数状态下的T0,最大计数值为fOSC/24,由于fOSC=12MHz,因此:T0的最大计数频率为250KHz。对于频率的概念就是在一秒只数脉冲的个数,即为频率值。所以T1工作在定时状态下,每定时1秒中到,就停止T0的计数,而从T0的计数单元中读取计数的数值,然后进行数据处理。送到数码管显示出来。(2).T1工作在定时状态下,最大定时时间为65ms,达不到1秒的定时,所 以采用定时50ms,共定时20次,即可完成1秒的定时功能。5.C语言源程序 #include unsignedcharcodedispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40}; unsignedchardispbuf[8]={0,0,0,0,0,0,10,10};unsignedchartemp[8];unsignedchardispcount;unsignedcharT0count;unsignedchartimecount;bitflag; unsignedlongx;voidmain(void){ unsignedchari;TMOD=0x15;TH0=0;TL0=0; TH1=(65536-4000)/256;TL1=(65536-4000)%256;TR1=1;TR0=1;ET0=1;ET1=1;EA=1;while(1) { if(flag==1){ flag=0; x=T0count*65536+TH0*256+TL0;for(i=0;i<8;i++){ temp[i]=0;}i=0; while(x/10){ temp[i]=x%10;x=x/10;i++;} temp[i]=x; for(i=0;i<6;i++){ dispbuf[i]=temp[i];} timecount=0;T0count=0;TH0=0;TL0=0;TR0=1;}}} voidt0(void)interrupt1using0{ T0count++;} voidt1(void)interrupt3using0{ TH1=(65536-4000)/256;TL1=(65536-4000)%256;timecount++; if(timecount==250){ TR0=0; timecount=0;flag=1; } P0=dispcode[dispbuf[dispcount]];P2=dispbit[dispcount];dispcount++;if(dispcount==8){ dispcount=0;}} 32.电子密码锁设计 1.实验任务 根据设定好的密码,采用二个按键实现密码的输入功能,当密码输入正确之后,锁就打开,如果输入的三次的密码不正确,就锁定按键3秒钟,同时发现报警声,直到没有按键按下3种后,才打开按键锁定功能;否则在3秒钟内仍有按键按下,就重新锁定按键3秒时间并报警。2.电路原理图 图4.32.1 3.系统板上硬件连线 (1).把“单片机系统”区域中的P0.0/AD0用导线连接到“音频放大模块”区域中的SPKIN端子上; (2).把“音频放大模块”区域中的SPKOUT端子接喇叭和; (3).把“单片机系统”区域中的P2.0/A8-P2.7/A15用8芯排线连接到“四路静态数码显示”区域中的任一个ABCDEFGH端子上; (4).把“单片机系统“区域中的P1.0用导线连接到“八路发光二极管模块”区域中的L1端子上; (5).把“单片机系统”区域中的P3.6/WR、P3.7/RD用导线连接到“独立式键盘”区域中的SP1和SP2端子上;4.程序设计内容 (1).密码的设定,在此程序中密码是固定在程序存储器ROM中,假设预设的密码为“12345”共5位密码。(2).密码的输入问题: 由于采用两个按键来完成密码的输入,那么其中一个按键为功能键,另一个按键为数字键。在输入过程中,首先输入密码的长度,接着根据密码的长度输入密码的位数,直到所有长度的密码都已经输入完毕;或者输入确认功能键之后,才能完成密码的输入过程。进入密码的判断比较处理状态并给出相应的处理过程。(3).按键禁止功能:初始化时,是允许按键输入密码,当有按键按下并开始进入按键识别状态时,按键禁止功能被激活,但启动的状态在3次密码输入不正确的情况下发生的。5.C语言源程序 #include unsignedcharcodeps[]={1,2,3,4,5}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};unsignedcharpslen=9;unsignedchartemplen;unsignedchardigit;unsignedcharfuncount;unsignedchardigitcount;unsignedcharpsbuf[9];bitcmpflag;bithibitflag;biterrorflag;bitrightflag; unsignedintsecond3;unsignedintaa;unsignedintbb;bitalarmflag;bitexchangeflag;unsignedintcc; unsignedintdd;bitokflag; unsignedcharoka;unsignedcharokb;voidmain(void){ unsignedchari,j; P2=dispcode[digitcount];TMOD=0x01; TH0=(65536-500)/256;TL0=(65536-500)%256;TR0=1;ET0=1;EA=1; while(1){ if(cmpflag==0){ if(P3_6==0)//functionkey{ for(i=10;i>0;i--)for(j=248;j>0;j--);if(P3_6==0){ if(hibitflag==0){ funcount++; if(funcount==pslen+2){ funcount=0;cmpflag=1;} P1=dispcode[funcount];}else{ second3=0;} while(P3_6==0);}} if(P3_7==0)//digitkey{ for(i=10;i>0;i--)for(j=248;j>0;j--);if(P3_7==0){ if(hibitflag==0){ digitcount++; if(digitcount==10){ digitcount=0;} P2=dispcode[digitcount];if(funcount==1){ pslen=digitcount;templen=pslen;} elseif(funcount>1){ psbuf[funcount-2]=digitcount;}}else{ second3=0;} while(P3_7==0);}}}else{ cmpflag=0; for(i=0;i hibitflag=1;i=pslen;errorflag=1;rightflag=0;cmpflag=0; second3=0;gotoa;}}cc=0; errorflag=0;rightflag=1;hibitflag=0;a:cmpflag=0;}}} voidt0(void)interrupt1using0{ TH0=(65536-500)/256;TL0=(65536-500)%256; if((errorflag==1)&&(rightflag==0)){bb++; if(bb==800){ bb=0; alarmflag=~alarmflag;} if(alarmflag==1){ P0_0=~P0_0;} aa++; if(aa==800){aa=0; P0_1=~P0_1;} second3++; if(second3==6400){ second3=0;hibitflag=0;errorflag=0;rightflag=0; cmpflag=0;P0_1=1; alarmflag=0;bb=0;aa=0;}} if((errorflag==0)&&(rightflag==1)){ P0_1=0;cc++; if(cc<1000){ okflag=1;} elseif(cc<2000){ okflag=0;}else{ errorflag=0;rightflag=0;hibitflag=0;cmpflag=0;P0_1=1;cc=0;oka=0;okb=0;okflag=0;P0_0=1;} if(okflag==1){ oka++;if(oka==2){ oka=0; P0_0=~P0_0;}}else{ okb++;if(okb==3){ okb=0; P0_0=~P0_0;}}}} 33.4×4键盘及8位数码管显示构成的电子密码锁 1.实验任务 用4×4组成0-9数字键及确认键。 用8位数码管组成显示电路提示信息,当输入密码时,只显示“8.”,当密码位数输入完毕按下确认键时,对输入的密码与设定的密码进行比较,若密码正确,则门开,此处用LED发光二极管亮一秒钟做为提示,同时发出“叮咚”声;若密码不正确,禁止按键输入3秒,同时发出“嘀、嘀”报警声;若在3秒之内仍有按键按下,则禁止按键输入3秒被重新禁止。2.电路原理图 图4.33.1 3.系统板上硬件连线 (1).把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“动态数码显示”区域中的ABCDEFGH端子上。 (2).把“单片机系统“区域中的P2.0-P2.7用8芯排线连接到“动态数码显示”区域中的S1S2S3S4S5S6S7S8端子上。 (3).把“单片机系统”区域中的P3.0-P3.7用8芯排线连接到“4×4行列 式键盘”区域中的R1R2R3R4C1C2C3C4端子上。(4).把“单片机系统”区域中的P1.0用导线连接到“八路发光二极管模块” 区域中的L2端子上。(5).把“单片机系统”区域中的P1.7用导线连接到“音频放大模块”区域 中的SPKIN端子上。(6).把“音频放大模块”区域中的SPKOUT接到喇叭上。4.程序设计内容 (1).4×4行列式键盘识别技术:有关这方面内容前面已经讨论过,这里不 再重复。(2).8位数码显示,初始化时,显示“P”,接着输入最大6位数的 密码,当密码输入完后,按下确认键,进行密码比较,然后给出相应的信息。在输入密码过程中,显示器只显示“8.”。当数字输入超过6个时,给出报警信息。在密码输入过程中,若输入错误,可以利用“DEL”键删除刚才输入的错误的数字。(3).4×4行列式键盘的按键功能分布图如图4.33.2所示: 图4.33.2 5.C语言源程序 #include unsignedcharps[]={1,2,3,4,5}; unsignedcharcodedispbit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedispcode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, 0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40,0x73,0xff}; unsignedchardispbuf[8]={18,16,16,16,16,16,16,16};unsignedchardispcount;unsignedcharflashcount;unsignedchartemp;unsignedcharkey; unsignedcharkeycount;unsignedcharpslen=5;unsignedchargetps[6];bitkeyoverflag;biterrorflag;bitrightflag; unsignedintsecond3;unsignedintaa,bb;unsignedintcc;bitokflag;bitalarmflag;bithibitflag; unsignedcharoka,okb;voidmain(void){ unsignedchari,j;TMOD=0x01; TH0=(65536-500)/256;TL0=(65536-500)%256;TR0=1;ET0=1;EA=1; while(1){ P3=0xff;P3_4=0;temp=P3; temp=temp&0x0f;if(temp!=0x0f) { for(i=10;i>0;i--)for(j=248;j>0;j--);temp=P3; temp=temp&0x0f;if(temp!=0x0f){ temp=P3; temp=temp&0x0f;switch(temp){ case0x0e:key=7;break; case0x0d:key=8;break; case0x0b:key=9;break; case0x07:key=10;break;} temp=P3;P1_1=~P1_1; if((key>=0)&&(key<10)){ if(keycount<6){ getps[keycount]=key;dispbuf[keycount+2]=19;} keycount++;if(keycount==6){ keycount=6;} elseif(keycount>6){ keycount=6; keyoverflag=1;//keyoverflow}} elseif(key==12)//deletekey{ if(keycount>0){ keycount--; getps[keycount]=0; dispbuf[keycount+2]=16;}else{ keyoverflag=1;}} elseif(key==15)//enterkey{ if(keycount!=pslen){ errorflag=1;rightflag=0;second3=0;}else{ for(i=0;i i=keycount;errorflag=1;rightflag=0;second3=0;gotoa;}} errorflag=0;rightflag=1;a:i=keycount;}} temp=temp&0x0f;while(temp!=0x0f){ temp=P3; temp=temp&0x0f; } keyoverflag=0;//?????????}} P3=0xff;P3_5=0;temp=P3; temp=temp&0x0f;if(temp!=0x0f){ for(i=10;i>0;i--)for(j=248;j>0;j--);temp=P3; temp=temp&0x0f;if(temp!=0x0f){ temp=P3; temp=temp&0x0f;switch(temp){ case0x0e:key=4;break; case0x0d:key=5;break; case0x0b:key=6;break; case0x07:key=11;break;} temp=P3;P1_1=~P1_1; if((key>=0)&&(key<10)){ if(keycount<6){ getps[keycount]=key;dispbuf[keycount+2]=19;} keycount++;if(keycount==6) { keycount=6;} elseif(keycount>6){ keycount=6; keyoverflag=1;//keyoverflow}} elseif(key==12)//deletekey{ if(keycount>0){ keycount--; getps[keycount]=0; dispbuf[keycount+2]=16;}else{ keyoverflag=1;}} elseif(key==15)//enterkey{ if(keycount!=pslen){ errorflag=1;rightflag=0;second3=0;}else{ for(i=0;i i=keycount;errorflag=1;rightflag=0;second3=0;gotoa4;}} errorflag=0; rightflag=1;a4:i=keycount;}} temp=temp&0x0f;while(temp!=0x0f){ temp=P3; temp=temp&0x0f;} keyoverflag=0;//?????????}} P3=0xff;P3_6=0;temp=P3; temp=temp&0x0f;if(temp!=0x0f){ for(i=10;i>0;i--)for(j=248;j>0;j--);temp=P3; temp=temp&0x0f;if(temp!=0x0f){ temp=P3; temp=temp&0x0f;switch(temp){ case0x0e:key=1;break; case0x0d:key=2;break; case0x0b:key=3;break; case0x07:key=12;break;} temp=P3; P1_1=~P1_1; if((key>=0)&&(key<10)){ if(keycount<6){ getps[keycount]=key;dispbuf[keycount+2]=19;} keycount++;if(keycount==6){ keycount=6;} elseif(keycount>6){ keycount=6; keyoverflag=1;//keyoverflow}} elseif(key==12)//deletekey{ if(keycount>0){ keycount--; getps[keycount]=0; dispbuf[keycount+2]=16;}else{ keyoverflag=1;}} elseif(key==15)//enterkey{ if(keycount!=pslen){ errorflag=1;rightflag=0;second3=0;}else{ for(i=0;i i=keycount;errorflag=1;rightflag=0;second3=0;gotoa3;}} errorflag=0;rightflag=1;a3:i=keycount;}} temp=temp&0x0f;while(temp!=0x0f){ temp=P3; temp=temp&0x0f;} keyoverflag=0;//?????????}} P3=0xff;P3_7=0;temp=P3; temp=temp&0x0f;if(temp!=0x0f){ for(i=10;i>0;i--)for(j=248;j>0;j--);temp=P3; temp=temp&0x0f;if(temp!=0x0f){ temp=P3; temp=temp&0x0f;switch(temp){ case0x0e:key=0;break; case0x0d: key=13;break; case0x0b:key=14;break; case0x07:key=15;break;} temp=P3;P1_1=~P1_1; if((key>=0)&&(key<10)){ if(keycount<6){ getps[keycount]=key;dispbuf[keycount+2]=19;} keycount++;if(keycount==6){ keycount=6;} elseif(keycount>6){ keycount=6; keyoverflag=1;//keyoverflow}} elseif(key==12)//deletekey{ if(keycount>0){ keycount--; getps[keycount]=0; dispbuf[keycount+2]=16;}else{ keyoverflag=1;}} elseif(key==15)//enterkey{ if(keycount!=pslen){ errorflag=1;rightflag=0;second3=0;}else{ for(i=0;i i=keycount;errorflag=1;rightflag=0;second3=0;gotoa2;}} errorflag=0;rightflag=1;a2:i=keycount;}} temp=temp&0x0f;while(temp!=0x0f){ temp=P3; temp=temp&0x0f;} keyoverflag=0;//?????????}}}} voidt0(void)interrupt1using0{ TH0=(65536-500)/256;TL0=(65536-500)%256;flashcount++;if(flashcount==8){ flashcount=0; P0=dispcode[dispbuf[dispcount]];P2=dispbit[dispcount];dispcount++;if(dispcount==8){ dispcount=0;}} if((errorflag==1)&&(rightflag==0)){bb++; if(bb==800){bb=0; alarmflag=~alarmflag;} if(alarmflag==1)//soundalarmsignal{ P1_7=~P1_7;} aa++; if(aa==800)//lightalarmsignal{aa=0; P1_0=~P1_0;} second3++; if(second3==6400){ second3=0;errorflag=0;rightflag=0;alarmflag=0;bb=0;aa=0;}} elseif((errorflag==0)&&(rightflag==1)){ P1_0=0;cc++; if(cc<1000) { okflag=1;} elseif(cc<2000){ okflag=0;}else{ errorflag=0;rightflag=0;P1_7=1;cc=0;oka=0;okb=0;okflag=0;P1_0=1;} if(okflag==1){ oka++; if(oka==2){ oka=0; P1_7=~P1_7;}}else{ okb++; if(okb==3){ okb=0; P1_7=~P1_7;}}} if(keyoverflag==1){ P1_7=~P1_7;}} 34.带有存储器功能的数字温度计-DS1624技术应用 1.DS1624基本原理 DS1624是美国DALLAS公司生产的集成了测量系统和存储器于一体的芯片。数字接口电路简单,与I2C总线兼容,且可以使用一片控制器控制多达8片的DS1624。其数字温度输出达13位,精度为0.03125℃。DS1624可工作在最低2.7V电压下,适用于低功耗应用系统。 (1).DS1624基本特性◆ 无需外围元件即可测量温度 ◆测量范围为-55℃~+125℃,精度为0.03125℃◆测量温度的结果以13位数字量(两字节传输)给出◆测量温度的典型转换时间为1秒◆集成了256字节的E2PROM非易性存储器 ◆数据的读出和写入通过一个2-线(I2C)串行接口完成◆采用8脚DIP或SOIC封装,如图2.34.1 2.34.1 (2).引脚描述及功能方框图其引脚描述如表1所示: DS1624的功能结构图如图4.34.2所示: 图 图4.34.2 (3).DS1624工作原理温度测量 图4.34.3是温度测量的原理结构图 图4.34.3温度测量的原理结构图 DS1624在测量温度时使用了独有的在线温度测量技术。它通过在一个由对温度高度敏感的振荡器决定的计数周期内对温度低敏感的振荡器时钟脉冲的计数值的计算来测量温度。DS1624在计数器中预置了一个初值,它相当于-55℃。如果计数周期结束之前计数器达到0,已预置了此初值的温度寄存器中的数字就会增加,从而表明温度高于-55℃。 与此同时,计数器斜坡累加电路被重新预置一个值,然后计数器重新对时钟计数,直到计数值为0。 通过改变增加的每1℃内的计数器的计数,斜坡累加电路可以补偿振荡器的非线性误差,以提高精度,任意温度下计数器的值和每一斜坡累加电路的值对应的计数次数须为已知。 DS1624通过这些计算可以得到0.03125℃的精度,温度输出为13位,在发出读温度值请求后还会输出两位补偿值。表2给出了所测的温度和输出数据的关系。这些数据可通过2线制串行口连续输出,MSB在前,LSB在后。 表2 温度+125℃+25.0625℃+0.5℃+0℃-0.5℃-25.0625℃-55℃ 温度与输出数据关系表 数字量输出(十六进制)7D00H1910H0080H0000HFF80HE6F0HC900H 数字量输出(二进制)0111,1101,0000,00000001,1001,0001,00000000,0000,1000,00000000,0000,0000,00001111,1111,1000,00001110,0110,1111,00001100,1001,0000,0000 由于数据在总线上传输时MSB在前,所以DS1624读出的数据可以是一个字节(分辨率为1℃),也可以是两个字节,第二个字节包含的最低位为0.03125℃。表2是13位温度寄存器中存储温度值的数据格式 高八位字节 低八位字节S B14B13B12B11B10B9 表3 B8 B7 B6 B5 B4 B3 0 0 0 温度值的数据存储格式 其中S-为符号位,当S=0时,表示当前的测量的温度为正的温度;当S=1时,表示当前的测量的温度为负的温度。B14-B3为当前测量的温度值。最低三位被设置为0。DS1624工作方式 DS1621的工作方式是由片上的配置/状态寄存器来决定的,如表4,该寄存器的定义如下: 表4 DONE 1 0 配置/状态寄存器格式0 1 0 1 1SHOT 其中DONE为转换完成位,温度转换结束时置1,正在进行转换时为0;1SHOT为温度转换模式选择。1SHOT为1时为单次转换模式,DS1624在收到启动温度转换命令EEH后进行一次温度转换。1SHOT为0时为连续转换模式,此时DS1624将连续进行温度转换,并将最近一次的结果保存在温度寄存器中。该位为非易失性的。 片内256字节存储器操作 控制器对DS1624的存储器编程有两种模式:一种是字节编程模式,另一种是页编程模式。 在字节编程模式中,主控制器发送地址和一个字节的数据到DS1624。在主器件发出开始(START)信号以后,主器件发送写控制字节即1001A2A1A00(其中R/W控制位为低电平“0”)。指示从接收器被寻址,DS1624接收后应答,再由主器件发送访问存储器指令(17H)后,DS1624接收后应答,接着由主器件发送的下一个字节字地址将被写入到DS1624的地址指针。主器件接收到来自DS1624的另一个确认信号以后,发送数据字节,并写入到寻址的存储地址。DS1624再次发出确认信号,同时主器件产生停止条件STOP,启动内部写周期。在内部写周期DS1624将不产生确认信号。 在页编程模式中,如同字节写方式,先将控制字节、访问存储器指令(17H)、字地址发送到DS1624,接着发N个数据字节,其中以8个字节为一个页面。主器件发送不多于一个页面字节的数据字节到DS1624,这些数据字节暂存在片内页面缓存器中,在主器件发送停止信号以后写入到存储器。接收每一个字节以后,低位顺序地址指针在内部加1。高位顺序字地址保持为常数。如果主器件在产生停止条件以前要发送多于一页字的数据,地址计数器将会循环,并且先接收到的数据将被覆盖。像字节写操作一样,一旦停止条件被接收到,则内部写周期将开始。 存储器的读操作 在这种模式下,主器件可以从DS1624的EEPROM中读取数据。主器件在发送开始信号之后,主器件首先发送写控制字节1001A2A1A00,主器件接收到DS1624应答之后,发送访问存储器的指令(17H),收到DS1624的应答之后,接着发送字地址将被被写入到DS1624的地址指针。这时DS1624发送应答信号之后,主器件并没有发送停止信号,而是重新发送START开始信号,接着又发送读控制字节1001A2A1A01,主器件接收到DS1624应答之后,开始接收DS1624送出来的数据,主器件每接收完一个字节的数据之后,都要发送一个应答信号给DS1624,直到主器件发送一个非应答信号或停止条件来结束DS1624的数据发送过程。DS1624的指令集 数据和控制信息的写入读出是以表5和表6所示的方式进行的。在写入信息时,主器件输出从器件(即DS1624)的地址,同时R/W位置0。接收到响应位后, 总线上的主器件发出一个命令地址,DS1624接收此地址后,产生响应位,主器件就向它发送数据。如果要对它进行读操作,主器件除了发出命令地址外,还要产生一个重复的启动条件和命令字节,此时R/W位为1,读操作开始。下面对它们的命令进行说明。 访问存储器指令[17H]:该指令是对DS1624的EEPROM进行访问,发送该指令之后,下一个字节就是被访问存储器的字地址数据。 访问设置寄存器指令[ACH]:如果R/W位置0,将写入数据到设置寄存器。发出请求后,接下来的一个字节被写入。如果R/W位置1,将读出存在寄存器中的值。 读温度值指令[AAH]:即读出最后一个测温结果。DS1624产生两个字节,即为寄存器内的结果。 开始测温指令[EEH]:此命令将开始一次温度的测量,不需再输入数据。在单次测量模式下,可在进行转换的同时使DS1624保持闲置状态。在连续模式下,将启动连续测温。 停止测温指令[22H]:该命令将停止温度的测量,不需再输入数据。此命令可用来停止连续测温模式。发出请求后,当前温度测量结束,然后DS1624保持闲置状态。直到下一个开始测温的请求发出才继续进行连续测量。 表5 I2C通信开始 主器件发送控制字节(DS1624地址和写操作)表6 I2C通信开始 主器件发送控制字节(DS1624地址和写操作) 主机对DS1624写操作通信格式DS1624应答 主器件发送访问DS1624的指令 DS1624应答 主器件发送的数据字节 DS1624应答 I2C通信停止 主机对DS1624读操作通信格式DS1624应答 主器件发送访问DS1624的指令 DS1624应答 I2C通信开始 主器件发送控制字节(DS1624地址和读操作) DS1624应答 数据字节0 主机应答 数据字节1 主机非应答 I2C通信停止 2.实验任务 用一片DS1624完成本地数字温度的测量,并通过8位数码管显示出测量的温度值。其硬件电路图如图4.34.4所示3.电路原理图 图4.34.4 4.系统板上硬件连线 (1).把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“动态 数码显示”区域中的ABCDEFGH端子上。(2).把“单片机系统”区域中的P2.0-P2.7用8芯排线连接到“动态 数码显示”区域中的S1S2S3S4S5S6S7S8端子上。(3).把DS1624芯片插入到“二线总线模块”区域中的8脚集成座上, 注意芯片不插反。(4).把“二线总线模块”区域中的PIN1PIN2分别用导线连接到“单片 机系统”区域中的P1.6和P1.7端子上。(5).把“二线总线模块”区域中的PIN4PIN5 “电源模块”区域中的GND端子上。 PIN6分别用导线连接到 5.程序设计内容 (1).由于DS1624是I2C总线结构的串行数据传送,它只需要SDA和SCL 两根线完成数据的传送过程。因此,我们在进行程序设计的时候,也得按着I2C协议来对DS1624芯片数据访问。有关I2C协议参看有关资料,这里不详述。对于AT89S51单片机本身没有I2C硬件资源,所以必须用软件来模拟I2C协议过程。(2).要从DS1624中读取温度值,首先启动DS1624的内部温度A/D开始 转换,对应着有相应的命令用来启动开始温度转换,有关DS1624的指令集参考前面的叙述。一般情况下,DS1624经过一次温度的变换,需要经过1秒钟左右的时间,所以等待1秒钟后,即可读取内部的温度值,对于读取的温度值,仍然通过DS1624的指令集来完成温度的读取。但所有有数据的传送过程必须遵循I2C协议。6.C语言源程序 #include unsignedcharcodedisplaybit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedisplaycode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsignedcharcodedotcode[32]={0,3,6,9,12,16,19,22,25,28,31,34,38,41,44,48,50,53,56,59,63,66,69,72,75,78,81,84,88,91,94,97};sbitSDA=P1^6;sbitSCL=P1^7; unsignedchardisplaybuffer[8]={0,1,2,3,4,5,6,7};unsignedchareepromdata[8];unsignedchartemperdata[2];unsignedchartimecount;unsignedchardisplaycount;bitsecondflag=0; unsignedcharsecondcount=0;unsignedcharretn;unsignedintresult;unsignedcharx;unsignedintk; unsignedintks; voiddelay(void);voiddelay10ms(void);voidi_start(void);voidi_stop(void);voidi_init(void);voidi_ack(void);biti_clock(void); biti_send(unsignedchari_data);unsignedchari_receive(void);bitstart_temperature_T(void); bitread_temperature_T(unsignedchar*p);voiddelay(void){ _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();} voiddelay10ms(void){ unsignedinti;for(i=0;i<1000;i++){ delay();}} voidi_start(void){ SCL=1;delay();SDA=0;delay();SCL=0;delay();} voidi_stop(void){ SDA=0;delay();SCL=1;delay();SDA=1;delay();SCL=0;delay();} voidi_init(void){ SCL=0;i_stop();} voidi_ack(void){ SDA=0; i_clock();SDA=1;} biti_clock(void){ bitsample;SCL=1;delay();sample=SDA;_nop_();_nop_();SCL=0;delay(); return(sample);} biti_send(unsignedchari_data){ unsignedchari; for(i=0;i<8;i++){ SDA=(bit)(i_data&0x80);i_data=i_data<<1; i_clock();} SDA=1; return(~i_clock());} unsignedchari_receive(void){ unsignedchari_data=0;unsignedchari;for(i=0;i<8;i++){ i_data*=2; if(i_clock())i_data++;} return(i_data);} bitstart_temperature_T(void){ i_start(); if(i_send(0x90)){ if(i_send(0xee)){ i_stop();delay();return(1);}else{ i_stop();delay();return(0);}}else{ i_stop();delay();return(0);}} bitread_temperature_T(unsignedchar*p){ i_start(); if(i_send(0x90)){ if(i_send(0xaa)){ i_start(); if(i_send(0x91)){ *(p+1)=i_receive();i_ack(); *p=i_receive();i_stop();delay();return(1);}else{ i_stop();delay();return(0);}}else{ i_stop();delay();return(0);}}else{ i_stop();delay();return(0);}} voidmain(void){ P1=0xff; timecount=0;displaycount=0; TMOD=0x21;TH1=0x06;TL1=0x06;TR1=1;ET1=1;ET0=1;EA=1; if(start_temperature_T())//向DS1624发送启动A/D温度转换命令,成功则启动T0定时1s。{ secondflag=0;secondcount=0;TH0=55536/256;TL0=55536%256;TR0=1;} while(1){ if(secondflag==1){ secondflag=0;TR0=0; if(read_temperature_T(temperdata))//T0定时1s时间到,读取DS1624的温度值{ for(x=0;x<8;x++){ displaybuffer[x]=16;}x=2; result=temperdata[1];//将读取的温度值进行数据处理,并送到显示缓冲区 while(result/10){ displaybuffer[x]=result%10;result=result/10;x++;} displaybuffer[x]=result;result=temperdata[0];result=result>>3; displaybuffer[0]=(dotcode[result])%10;displaybuffer[1]=(dotcode[result])/10; if(start_temperature_T())//温度值数据处理完毕,重新启动DS1624开始温度转换{ secondflag=0;secondcount=0;TH0=55536/256;TL0=55536%256;TR0=1;}}}}} voidt0(void)interrupt1using0//T0用于定时1s时间到{ secondcount++; if(secondcount==100){ secondcount=0;secondflag=1;} TH0=55536/256;TL0=55536%256;} voidt1(void)interrupt3using0//T1定时1ms用数码管的动态刷新{ timecount++; if(timecount==4)//T1定时1ms到{ timecount=0; if(displaycount==5){ P0=(displaycode[displaybuffer[7-displaycount]]|0x80);//在该位同时还要显示小数点}else{ P0=displaycode[displaybuffer[7-displaycount]];} P2=displaybit[displaycount];displaycount++;if(displaycount==8){ displaycount=0; }}} 35.DS18B20数字温度计使用 1.DS18B20基本知识 DS18B20数字温度计是DALLAS公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。 1、DS18B20产品的特点 (1)、只要求一个端口即可实现通信。 (2)、在DS18B20中的每个器件上都有独一无二的序列号。(3)、实际应用中不需要外部任何元器件即可实现测温。(4)、测量温度范围在-55。C到+125。C之间。(5)、数字温度计的分辨率用户可以从9位到12位选择。(6)、内部有温度上、下限告警设置。2、DS18B20的引脚介绍 TO-92封装的DS18B20的引脚排列见图1,其引脚功能描述见表1。 (底视图)图1 表1序号123 DS18B20详细引脚功能描述名称GNDDQVDD 引脚功能描述 地信号 数据输入/输出引脚。开漏单总线接口引脚。当被用着在寄生电源下,也可以向器件提供电源。 可选择的VDD引脚。当工作于寄生电源时,此引脚必须接地。 3.DS18B20的使用方法 由于DS18B20采用的是1-Wire总线协议方式,即在一根数据线实现数据的双向传输,而对AT89S51单片机来说,硬件上并不支持单总线协议,因此,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。 由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。 DS18B20的复位时序 DS18B20的读时序 对于DS18B20的读时序分为读0时序和读1时序两个过程。 对于DS18B20的读时隙是从主机把单总线拉低之后,在15秒之内就得释放单总线,以让DS18B20把数据传输到单总线上。DS18B20在完成一个读时序过程,至少需要60us才能完成。 DS18B20的写时序 对于DS18B20的写时序仍然分为写0时序和写1时序两个过程。 对于DS18B20写0时序和写1时序的要求不同,当要写0时序时,单总线要被拉低至少60us,保证DS18B20能够在15us到45us之间能够正确地采样IO总线上的“0”电平,当要写1时序时,单总线被拉低之后,在15us之内就得释放单总线。 4.实验任务 用一片DS18B20构成测温系统,测量的温度精度达到0.1度,测量的温度的范围在-20度到+100度之间,用8位数码管显示出来。5.电路原理图 6.系统板上硬件连线 (1).把“单片机系统”区域中的P0.0-P0.7用8芯排线连接到“动态 数码显示”区域中的ABCDEFGH端子上。(2).把“单片机系统”区域中的P2.0-P2.7用8芯排线连接到“动态 数码显示”区域中的S1S2S3S4S5S6S7S8端子上。(3).把DS18B20芯片插入“四路单总线”区域中的任一个插座中,注意 电源与地信号不要接反。(4).把“四路单总线”区域中的对应的DQ端子连接到“单片机系统” 区域中的P3.7/RD端子上。 7.C语言源程序 #include unsignedcharcodedisplaybit[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedcharcodedisplaycode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00,0x40}; unsignedcharcodedotcode[32]={0,3,6,9,12,16,19,22,25,28,31,34,38,41,44,48,50,53,56,59,63,66,69,72,75,78,81,84,88,91,94,97};unsignedchardisplaycount; unsignedchardisplaybuf[8]={16,16,16,16,16,16,16,16};unsignedchartimecount;unsignedcharreaddata[8];sbitDQ=P3^7;bitsflag; bitresetpulse(void){ unsignedchari;DQ=0; for(i=255;i>0;i--);DQ=1; for(i=60;i>0;i--);return(DQ); for(i=200;i>0;i--);} voidwritecommandtods18b20(unsignedcharcommand){ unsignedchari;unsignedcharj;for(i=0;i<8;i++){ if((command&0x01)==0){DQ=0; for(j=35;j>0;j--); DQ=1;}else{DQ=0; for(j=2;j>0;j--);DQ=1; for(j=33;j>0;j--);} command=_cror_(command,1);}}unsigned{ unsignedunsignedunsigned charreaddatafromds18b20(void)chari;charj;chartemp; temp=0; for(i=0;i<8;i++){ temp=_cror_(temp,1);DQ=0;_nop_();_nop_();DQ=1; for(j=10;j>0;j--);if(DQ==1){ temp=temp|0x80;}else{ temp=temp|0x00;} for(j=200;j>0;j--);} return(temp);} voidmain(void){ TMOD=0x01; TH0=(65536-4000)/256;TL0=(65536-4000)%256;ET0=1;EA=1; while(resetpulse()); writecommandtods18b20(0xcc);writecommandtods18b20(0x44);TR0=1;while(1){;}} voidt0(void)interrupt1using0{ unsignedcharx;unsignedintresult; TH0=(65536-4000)/256;TL0=(65536-4000)%256;if(displaycount==2){ P0=displaycode[displaybuf[displaycount]]|0x80;}else{ P0=displaycode[displaybuf[displaycount]];} P2=displaybit[displaycount];displaycount++;if(displaycount==8){ displaycount=0;} timecount++; if(timecount==150){ timecount=0; while(resetpulse()); writecommandtods18b20(0xcc);writecommandtods18b20(0xbe); readdata[0]=readdatafromds18b20();readdata[1]=readdatafromds18b20();for(x=0;x<8;x++){ displaybuf[x]=16;} sflag=0; if((readdata[1]&0xf8)!=0x00){ sflag=1; readdata[1]=~readdata[1];readdata[0]=~readdata[0];result=readdata[0]+1;readdata[0]=result;if(result>255){ readdata[1]++;}} readdata[1]=readdata[1]<<4;readdata[1]=readdata[1]&0x70;x=readdata[0];x=x>>4;x=x&0x0f; readdata[1]=readdata[1]|x;x=2; result=readdata[1];while(result/10){ displaybuf[x]=result%10;result=result/10;x++;} displaybuf[x]=result;if(sflag==1){ displaybuf[x+1]=17;} x=readdata[0]&0x0f;x=x<<1; displaybuf[0]=(dotcode[x])%10;displaybuf[1]=(dotcode[x])/10;while(resetpulse()); writecommandtods18b20(0xcc); writecommandtods18b20(0x44);}} 因篇幅问题不能全部显示,请点此查看更多更全内容