最新传感器proteus虚拟实验.docx
《最新传感器proteus虚拟实验.docx》由会员分享,可在线阅读,更多相关《最新传感器proteus虚拟实验.docx(26页珍藏版)》请在冰豆网上搜索。
最新传感器proteus虚拟实验
传感器proteus虚拟实验
《传感器原理与应用》实验指导书
Proteus-V1.0版本
实验1:
基于DS18B20传感器温度测量实验
步骤:
(1)在Proteus软件画出电路图
(2)用keilC软件写出C程序,并生成.hex文件,导入到单片机当中,进行仿真,观察结果。
包括:
2个头文件LCD1602.h和DS18B20.h;1个源文件LCD_18b20.c;代码如下
LCD1602.h:
#include//用AT89C51时就用这个头文件
//#include//用华邦W78E58B时必须用这个头文件
#include
//注意那个LCD_Wait()函数,它是判"忙"标志的,在实际硬件要把注掉的那种打开
//PortDefinitions**********************************************************
sbitLcdRs=P2^0;
sbitLcdRw=P2^1;
sbitLcdEn=P2^2;
sfrDBPort=0x80;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
//内部等待函数**************************************************************************
unsignedcharLCD_Wait(void)
{
LcdRs=0;
LcdRw=1;_nop_();
LcdEn=1;_nop_();
//while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,
//可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80
//实际硬件时打开此语句
LcdEn=0;
returnDBPort;
}
//向LCD写入命令或数据************************************************************
#defineLCD_COMMAND0//Command
#defineLCD_DATA1//Data
#defineLCD_CLEAR_SCREEN0x01//清屏
#defineLCD_HOMING0x02//光标返回原点
voidLCD_Write(bitstyle,unsignedcharinput)
{
LcdEn=0;
LcdRs=style;
LcdRw=0;_nop_();
DBPort=input;_nop_();//注意顺序
LcdEn=1;_nop_();//注意顺序
LcdEn=0;_nop_();
LCD_Wait();
}
//设置显示模式************************************************************
#defineLCD_SHOW0x04//显示开
#defineLCD_HIDE0x00//显示关
#defineLCD_CURSOR0x02//显示光标
#defineLCD_NO_CURSOR0x00//无光标
#defineLCD_FLASH0x01//光标闪动
#defineLCD_NO_FLASH0x00//光标不闪动
voidLCD_SetDisplay(unsignedcharDisplayMode)
{
LCD_Write(LCD_COMMAND,0x08|DisplayMode);
}
//设置输入模式************************************************************
#defineLCD_AC_UP0x02
#defineLCD_AC_DOWN0x00//default
#defineLCD_MOVE0x01//画面可平移
#defineLCD_NO_MOVE0x00//default
voidLCD_SetInput(unsignedcharInputMode)
{
LCD_Write(LCD_COMMAND,0x04|InputMode);
}
//初始化LCD************************************************************
voidLCD_Initial()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,0x38);//8位数据端口,2行显示,5*7点阵
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递增,画面不动
}
//************************************************************************
voidGotoXY(unsignedcharx,unsignedchary)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
voidPrint(unsignedchar*str)
{
while(*str!
='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
}
voidLCD_Print(unsignedcharx,unsignedchary,unsignedchar*str)
{
GotoXY(x,y);
Print(str);
}
DS18b20.h
#include//用AT89C51时就用这个头文件
//#include//用华邦W78E58B时必须用这个头文件
sbitDQ=P3^4;//定义DQ引脚为P3.4
/***********ds18b20延迟子函数(晶振12MHz)*******/
/************DS18B20对时间要求很严,但只能长不能短
*************在11.0592M下也行,因为时间长些********/
voiddelay_18B20(unsignedinti)
{
while(i--);
}
/**********ds18b20初始化函数**********************/
voidInit_DS18B20(void)
{
unsignedcharx=0;
DQ=1;//DQ复位
delay_18B20(8);//稍做延时
DQ=0;//单片机将DQ拉低
delay_18B20(80);//精确延时大于480us
DQ=1;//拉高总线
delay_18B20(14);
x=DQ;//稍做延时后如果x=0则初始化成功x=1则初始化失败
delay_18B20(20);
}
/***********ds18b20读一个字节**************/
unsignedcharReadOneChar(void)
{
unsignedchari=0;
unsignedchardat=0;
for(i=8;i>0;i--)
{
DQ=0;//给脉冲信号
dat>>=1;
DQ=1;//给脉冲信号
if(DQ)
dat|=0x80;
delay_18B20(4);
}
return(dat);
}
/*************ds18b20写一个字节****************/
voidWriteOneChar(unsignedchardat)
{
unsignedchari=0;
for(i=8;i>0;i--)
{
DQ=0;
DQ=dat&0x01;
delay_18B20(5);
DQ=1;
dat>>=1;
}
}
/**************读取ds18b20当前温度************/
unsignedchar*ReadTemperature(charTH,charTL,unsignedcharRS)
{unsignedchartt[2];
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x4E);////写入"写暂存器"命令,修改TH和TL和分辩率配置寄存器
//先写TH,再写TL,最后写配置寄存器
WriteOneChar(TH);//写入想设定的温度报警上限
WriteOneChar(TL);//写入想设定的温度报警下限
WriteOneChar(RS);//写配置寄存器,格式为0R1R01,1111
//R1R0=00分辨率娄9位,R1R0=11分辨率为12位
delay_18B20(80);//thismessageisweryimportant
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x44);//启动温度转换
delay_18B20(80);//thismessageisweryimportant
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0xBE);//读取温度寄存器等(共可读9个寄存器)前两个就是温度
delay_18B20(80);
tt[0]=ReadOneChar();//读取温度值低位
tt[1]=ReadOneChar();//读取温度值高位
return(tt);
}
LCD_18b20.c
#include//用AT89C51时就用这个头文件
//#include//用华邦W78E58B时必须用这个头文件
#include
#include
#include
#include
#include
#include
#include"LCD1602.h"////液晶显示头文件
//sbitDQ=P3^4;//定义DQ引脚为P3.4
unsignedchart[2],*pt;//用来存放温度值,测温程序就是通过这个数组与主函数通信的
unsignedcharTempBuffer1[9]={0x2b,0x31,0x32,0x32,0x2e,0x30,0x30,0x43,'\0'};
//显示实时温度,上电时显示+125.00C
unsignedcharTempBuffer0[17]={0x54,0x48,0x3a,0x2b,0x31,0x32,0x35,0x20,
0x54,0x4c,0x3a,0x2b,0x31,0x32,0x34,0x43,'\0'};
//显示温度上下限,上电时显示TH:
+125TL:
+124C
unsignedcharcodedotcode[4]={0,25,50,75};
/***因显示分辨率为0.25,但小数运算比较麻烦,故采用查表的方法*******
再将表值分离出十位和个位后送到十分位和百分位********************/
voidcovert0(unsignedcharTH,unsignedcharTL)//将温度上下限转换为LCD显示的数据
{
if(TH>0x7F)//判断正负,如果为负温,将其转化为其绝对值
{
TempBuffer0[3]=0x2d;//0x2d为"-"的ASCII码
TH=~TH;
TH++;
}
elseTempBuffer0[3]=0x2b;//0x2B为"+"的ASCII码
if(TL>0x7f)
{
TempBuffer0[11]=0x2d;//0x2d为"-"的ASCII码
TL=~TL+1;
}
elseTempBuffer0[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;//分离出个位
}
voidcovert1(void)//将温度转换为LCD显示的数据
{
unsignedcharx=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]++;/*********************/
}
elseTempBuffer1[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~9ASCII码
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;//分离出百分位
}
voiddelay(unsignedchari)
{
while(i--);
}
main()
{
unsignedcharTH=110,TL=-20;//下一步扩展时可能通过这两个变量,调节上下限
//测温函数返回这个数组的头地址
while
(1)
{
pt=ReadTemperature(TH,TL,0x3f);//上限温度-22,下限-24,分辨率10位,也就是0.25C
//读取温度,温度值存放在一个两个字节的数组中,
delay(100);
covert1();
covert0(TH,TL);
LCD_Initial();//第一个参数列号,第二个为行号,为0表示第一行
//为1表示第二行,第三个参数为显示数据的首地址
LCD_Print(0,0,TempBuffer0);
LCD_Print(0,1,TempBuffer1);
}
}
实验2:
基于MPX4115传感器温度测量实验
步骤:
(1)在Proteus软件画出电路图
(2)用keilC软件写出C程序,并生成.hex文件,导入到单片机当中,进行仿真,观察结果。
压力测试仪
系统描述;输入15--115kPA压力信号
输出00h--ffh数字信号(adc0832)
在LCD上显示实际的压力值,如果超限则报警
线性区间标度变换公式:
y=(115-15)/(243-13)*X+15kpa
作者:
单位:
日期:
2008.3.7
********************************************************/
#include
#include"intrins.h"
#defineuintunsignedint
#defineucharunsignedchar
//ADC0832的引脚
sbitADCS=P2^0;//ADC0832chipseclect
sbitADDI=P3^7;//ADC0832kin
sbitADDO=P3^7;//ADC0832kout
sbitADCLK=P3^6;//ADC0832clocksignal
unsignedchardispbitcode[8]={0xf7,0xfb,0xfd,0xfe,0xef,0xdf,0xbf,0x7f};//位扫描
unsignedchardispcode[11]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};//共阳数码管字段码
unsignedchardispbuf[4];
uinttemp;
uchargetdata;//获取ADC转换回来的值
voiddelay_1ms(void)//12mhzdelay1.01ms
{
unsignedcharx,y;
x=3;
while(x--)
{
y=40;
while(y--);
}
}
voiddisplay(void)//数码管显示函数
{
chark;
for(k=0;k<4;k++)
{
P1=dispbitcode[k];
P0=dispcode[dispbuf[k]];
if(k==1)//加上数码管的dp小数点
P0&=0x7f;
delay_1ms();
}
}
/************
读ADC0832函数
************/
//采集并返回
unsignedintAdc0832(unsignedcharchannel)//AD转换,返回结果
{
uchari=0;
ucharj;
uintdat=0;
ucharndat=0;
if(channel==0)channel=2;
if(channel==1)channel=3;
ADDI=1;
_nop_();
_nop_();
ADCS=0;//拉低CS端
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿1
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=channel&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿2
_nop_();
_nop_();
ADCLK=1;//拉高CLK端
ADDI=(channel>>1)&0x1;
_nop_();
_nop_();
ADCLK=0;//拉低CLK端,形成下降沿3
ADDI=1;//控制命令结束
_nop_();
_nop_();
dat=0;
for(i=0;i<8;i++)
{
dat|=ADDO;//收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0;//形成一次时钟脉冲
_nop_();
_nop_();
dat<<=1;
if(i==7)dat|=ADDO;
}
for(i=0;i<8;i++)
{
j=0;
j=j|ADDO;//收数据
ADCLK=1;
_nop_();
_nop_();
ADCLK=0;//形成一次时钟脉冲
_nop_();
_nop_();
j=j<<7;
ndat=ndat|j;
if(i<7)ndat>>=1;
}
ADCS=1;//拉低CS端
ADCLK=0;//拉低CLK端
ADDO=1;//拉高数据端,回到初始状态
dat<<=8;
dat|=ndat;
return(dat);//returnadk
}
voidmain(void)
{
while
(1)
{unsignedinttemp;
f