|
#include < reg51.h >
#include < intrins.h >
#define uchar unsigned char
#define uint unsigned int
#define lcddata P0
sbit LCDRS=P2^0; //液晶數據選擇命令端
sbit LCDRW=P2^1; //液晶讀寫命令端
sbit LCDEN=P2^2; //液晶使能端
uchar mos0,mos1;
sbit DQ = P1^2; //定義DS18B20端口DQ
sbit trig=P2^3; //超聲波測距模塊Trig
sbit echo=P3^2; //超聲波測距模塊Echo
sbit baojing=P1^0; //baojing
sbit baojing1=P3^7;
sbit baojing2=P3^6;
sbit baojing3=P3^5;
sbit baojing4=P3^4;
sbit baojing5=P3^3;
long int distance; //測量所得距離
uchar juli_CS[ ] = "000.0";
uchar juli_H[ ] = "000";
uchar juli_L[ ] = "000";
uchar count; //中斷累加變量
sbit key_H1=P1^7; //上限加
sbit key_H2=P1^6; //上限減
sbit key_L1=P1^5; //下限加
sbit key_L2=P1^4; //下限減
long int distance1=4000;//上限值
long int distance2=100;//下限值
bit presence; //ds18b20 DQ被拉低 信號0允許,1禁止
uint cc,cc2; //變量cc中保存讀出的溫度值
float cc1;
uchar flag; //flag為溫度值正負標志位,“1”表示溫度為復制,“0”表示為正值//flag為溫度值正負標志位,“1”表示溫度為復制,“0”表示為正值
void write_com(uchar com);
uchar code cdis0[ ] = {"Detection signal"};
uchar code cdis1[ ] = {"Plese wait . . ."};
uchar cdis2[ ] = "+00.00";
uchar code cdis3[ ] = " DS18B20 ERR0R " ;
uchar code cdis4[ ] = " Please check " ;
uchar code table[ ]={"0123456789"}; //定義字符數組顯示數字
unsigned char data temp_data[2] = {0x00,0x00} ; //存儲16位溫度
/**********************************lcd1602********************************************/
//----------------------------------
void delaylcd(uint z)
{uchar x,y;
for(x=z;x>0;x--)
{for(y=110;y>0;y--);
}
}
/*------------------------------------------------
延時函數
------------------------------------------------*/
void delayt(uint x)
{
uchar j;
while(x-- > 0)
{
for(j = 0;j < 125;j++)
{
;
}
}
}
/*lcd1602初始化 */
/**********************************/
void lcd_init(void)
{
write_com(0x38); //使用8位數據開關,顯示兩行,使用5*7字形
write_com(0x0c); //顯示器開,光標關,字符不閃爍 0x0e 光標開
write_com(0x06); //字符不動,光標自動右移動一位
write_com(0x01); //清屏
}
/*寫命令to lcd */
/**********************************/
void write_com(uchar com)//寫命令
{
LCDRW=0; //低電平為寫
LCDRS=0; //低電平為命令選擇
LCDEN=1;
lcddata=com;
delaylcd(5);
LCDEN=1;
delaylcd(5);
LCDEN=0;
}
/*寫數據to lcd */
/**********************************/
void write_data(uchar date)
{
LCDRW=0; //低電平為寫
LCDRS=1; //高電平為數據選擇
LCDEN=1;
lcddata=date;
delaylcd(5);
LCDEN=1;
delaylcd(5);
LCDEN=0;
}
/*設定顯示位置 */
/********************************/
void lcd_pos(uchar pos)
{ //第一行第幾列直接寫pos為幾,第二行pos從0x40開始
write_com(pos | 0x80) ; //數據指針=80+地址變量
}
void lcd_pos1(uchar pos1)
{ //第?行第幾列直接寫pos為幾,第二行pos從0x40開始
write_com(pos1 | 0xc0) ; //數據指針=80+地址變量
}
/*******************************ds18b20*******************************************/
/*ms級別 */
void ddelay(uint ms)
{
uint i;
uchar j;
for(i=0;i<ms;i++)
for(j=0;j<250;j++)
{
_nop_(); //一個機器周期,1us
_nop_(); //適用于精度高的
_nop_();
_nop_();
}
}
/*********us級延時**********/
void Delayus(uchar i)
{
while(--i);
}
/*復位,每次讀寫之前都要進行復位*/
/**********************************/
bit ow_reset(void)
{
DQ = 0; //拉低約600us
Delayus(150);
Delayus(150);
DQ = 1;//產生上升沿,延時約15~60us
Delayus(30);
if(DQ==0) {presence=0;}
else presence=1;
return(presence); //等待應答信號 0允許,1禁止
}
/*讀取數據一位 */
//---------------------------------
bit Read_bit()
{
uint i = 0;
bit b = 0;
DQ = 0; //產生讀時隙
i++; //維持低電平至少1us
DQ = 1; //1us以上后拉高
Delayus(2); //延時8us,DO下降沿15內ds18b20輸出的數據才有效
b = DQ; //讀取數據
Delayus(40); //每個讀時隙至少持續60us
return(b);
}
/*讀取一個字節 */
//------------------------------------
uchar Read_byte()
{
uchar byte_read = 0;
uchar i, j;
for(i=0; i<8; i++)
{
j = Read_bit();
byte_read = (j<<i) | byte_read; //低位讀起
}
return(byte_read);
}
//-----------------------------------------
/*寫一個字節 */
void Write_byte(uchar byte_to_write)
{
uchar i = 0;
uchar j = 0;
bit write_bit = 0;
for(j=0; j<8; j++)
{
write_bit = (byte_to_write & 0x01);
if(write_bit == 1) //寫1
{
DQ = 0; //產生寫時隙
Delayus(3); //延時15us
DQ = 1; //寫1
Delayus(40); //延時,寫時隙不得低于60us
}
else
{
DQ = 0; //產生寫時隙
Delayus(50); //延時,保持低約60us~120us
DQ = 1;
i++;
}
byte_to_write = byte_to_write >> 1;
}
}
//-----------------------------------
/*讀取溫度,啟動溫度轉換*/
/*啟動溫度轉換*/
void start_convert()
{
ow_reset(); // 發出復位脈沖,每次操作都從復位開始
ddelay(1);
Write_byte(0xcc); //skip room命令,跳過序列號命令字
Write_byte(0x44); //啟動溫度轉換命令
}
/*讀取溫度值*/
void read_tempreture()
{
ow_reset(); // 發出復位脈沖,每次操作都從復位開始
ddelay(1);
Write_byte(0xcc); //skip room命令
Write_byte(0xbe); //讀取暫存器命令
temp_data[0] = Read_byte(); //存儲溫度低字節值 (整數部分低四位和小數部分) 先從低字節讀取
temp_data[1] = Read_byte(); //存儲溫度高字節值 (其中高五位為符號位)
}
//--------------------------------------
/* Detection...顯示 */
void lcd_display()
{
uchar m ;
lcd_pos(0) ; //設置顯示位置為第一行的第1個字符
m = 0 ;
while(cdis0[m] != '\0')
{ //顯示字符
write_data(cdis0[m]) ;
m++ ;
}
lcd_pos1(0) ; //設置顯示位置為第一行的第1個字符
m = 0 ;
while(cdis1[m] != '\0')
{ //顯示字符
write_data(cdis1[m]) ;
m++ ;
}
}
//-----------------------------------
/* ERR0R */
/*PLEASE CHECK 顯示 */
void Error_Menu ()
{
uchar m ;
lcd_init() ; //初始化LCD
lcd_pos(0) ; //設置顯示位置為第一行的第1個字符
m = 0 ;
while(cdis3[m] != '\0')
{
write_data(cdis3[m]) ; //顯示字符
m++ ;
}
lcd_pos(0x40) ; //設置顯示位置為第二行第1個字符
m = 0 ;
while(cdis4[m] != '\0')
{
write_data(cdis4[m]) ; //顯示字符
m++ ;
}
}
//------------------------------------
/* ℃顯示 */
void temp_c()
{
lcd_pos(6);
write_data(0xdf);//
lcd_pos(7);
write_data('C');
}
//------------------------------------
/*溫度顯示 */
void temperature_display()
{
uchar m;
flag=0;
ddelay(2);
EA=0; //DS18B20讀寫數據按照嚴格的時序,最好不要被打斷,故把所有中斷關閉
start_convert(); //啟動溫度轉換
ddelay(250);
read_tempreture(); //讀取溫度
EA=1;
cc=temp_data[1]*256.0+temp_data[0];
if(temp_data[1]>0xF8) {flag=1;cc=~cc+1;} else flag=0;
cc1=cc*0.0625;
cc2=cc1*100;
cdis2[1]=cc2/1000+0x30;
if(cdis2[1]==0x30)
{cdis2[1]=0x20;}
cdis2[2]=cc2/100%10+0x30;
cdis2[4]=cc2%100/10+0x30;
cdis2[5]=cc2%10+0x30;
if(flag==1)
cdis2[0]='-';
else
cdis2[0]='+';
lcd_pos(0) ; //設置顯示位置為第一行的第6個字符
m=0;
while(cdis2[m]!='\0')
{ //顯示字符
write_data(cdis2[m]) ;
m++;
}
}
/*--------------------------------------------
------------------超聲波函數-----------------
-------------------------------------------*/
/*------------------------------------------------
1602顯示固定字符函數
------------------------------------------------*/
void lcd_xianshi( )
{
lcd_pos1(0);
write_data('H');
lcd_pos1(1);
write_data('=');
lcd_pos1(9);
write_data('L');
lcd_pos1(10);
write_data('=');
lcd_pos(12);
write_data('.');
lcd_pos(14);
write_data('c');
lcd_pos(15);
write_data('m');
}
void init_t0()
{
PCON=0x00;
SCON=0x50;
TMOD=0x21;
TL0=0x66;
TH0=0xfc; //1ms
TH1=0xfd;
TL1=0xfd;
TR1=1;
ET0=1;
EA=1;
}
/*------------------------------------------------
超聲波模塊觸發信號
------------------------------------------------*/
void trigger()
{
trig=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
trig=1;
}
/*------------------------------------------------
超聲波模塊相應端口初始化函數
------------------------------------------------*/
void init_measuring()
{
trig=1;
echo=1;
count=0;
}
/*------------------------------------------------
超聲波模塊距離測試函數
------------------------------------------------*/
void measuring()
{
uchar l;
uint h,y;
while(echo==0);
TR0 = 1;
while(echo==1);
TR0 = 0;
l = TL0;
h = TH0;
y = (h << 8) + l;
y = y - 0xfc66;//us部分
distance = y + 1000 * count;//計算總時間,單位是微秒
TL0 = 0x66;
TH0 = 0xfc;
delayt(30);
distance = 3453* distance / 20000;//算出來毫米,原始為:(0.34毫米/us)*時間/2//
}
/*------------------------------------------------
超聲波模塊測量結果顯示函數
------------------------------------------------*/
void display(uint x)
{
uchar bai,shi,ge,xiaoshu;
bai=x/1000;
shi=(x/100)%10;
ge=(x/10)%10;
xiaoshu=x%10;
juli_CS[0]=bai+0x30;
juli_CS[1]=shi+0x30;
juli_CS[2]=ge+0x30;
juli_CS[4]=xiaoshu+0x30;
lcd_pos(9);//單位是厘米//
write_data(table[bai]);//百位顯示
write_data(table[shi]);//十位顯示
write_data(table[ge]);//各位顯示
lcd_pos(13);
write_data(table[xiaoshu]);//小數點后一位顯示
}
/*------------------------------------------
延時函數1ms
-------------------------------------------*/
void delay_key(uchar m)
{
uchar i,j;
for(i=0;i<m;i++)
for(j=0;j<24;j++);
}
void key()
{
key_H1=1; //上限加
key_H2=1; //上限減
key_L1=1; //下限加
key_L2=1;
if(key_H1==0)
{
delay_key(1);
if(key_H1==0)
{
distance1 = distance1+10;
}
}
if(key_H2==0)
{
delay_key(1);
if(key_H2==0)
{
distance1 = distance1-10;
}
}
if(key_L1==0)
{
delay_key(1);
if(key_L1==0)
{
distance2 = distance2+10;
}
}
if(key_L2==0)
{
delay_key(1);
if(key_L2==0)
{
distance2 = distance2-10;
if(distance2<0)
{
distance2=0;
}
}
}
}
/*-----------------------------------------------*/
/*--------------上下限顯示----------------------*/
void display_H_L()
{
uchar H_bai,H_shi,H_ge;
uchar L_bai,L_shi,L_ge;
key();
H_bai=distance1/1000;
H_shi=(distance1/100)%10;
H_ge=(distance1/10)%10;
juli_H[0] = H_bai+0X30;
juli_H[1] = H_shi+0X30;
juli_H[2] = H_ge+0X30;
L_bai=distance2/1000;
L_shi=(distance2/100)%10;
L_ge=(distance2/10)%10;
juli_L[0] = L_bai+0X30;
juli_L[1] = L_shi+0X30;
juli_L[2] = L_ge+0X30;
lcd_pos1(2);//單位是厘米//
write_data(table[H_bai]);//百位顯示
write_data(table[H_shi]);//十位顯示
write_data(table[H_ge]);//各位顯示
write_data('c');//各位顯示
write_data('m');//各位顯示
lcd_pos1(11);//單位是厘米//
write_data(table[L_bai]);//百位顯示
write_data(table[L_shi]);//十位顯示
write_data(table[L_ge]);//各位顯示
write_data('c');//各位顯示
write_data('m');//各位顯示
}
/////////////////////////////////////////////
/* 串口 */
////////////////////////////////////////////
void comm(uchar *parr) //串口發送;
{
do
{
SBUF=*parr++;
while(!TI);
TI=0;
}while(*parr!='\0');
}
//-------------------------------------------
/*主函數 */
void main()
{
baojing=0;
baojing1=0;//由于此單片機驅動電流太小
baojing2=0;//所以用空閑的I/O口作并聯
baojing3=0;//以提高輸出電流
baojing4=0;
baojing5=0;
lcd_init(); //初始化LCD
init_t0(); //定時器0初始化
init_measuring(); //超聲波相應端口初始化
lcd_display(); //顯示Detection
ddelay(1000); //顯示Detection1s
ddelay(1000); //顯示Detection1s
ddelay(1000); //顯示Detection1s
write_com(0x01);//清屏
ow_reset();//DS18B20復位
while(1)
{
comm(cdis2);
comm("\r\n");
comm(juli_CS);
comm("\r\n");
comm(juli_H);
comm("\r\n");
comm(juli_L);
comm("\r\n");
comm("\r\n");
if(presence==0)
{
temperature_display();//溫度顯示
temp_c();//顯示℃
}
else
{
Error_Menu ();//顯示字符串DS18B20 ERR0R Please check
while(1)
{
ow_reset();//DS18B20復位
if(presence==0)
{
temperature_display();//溫度顯示
}
}
}
lcd_xianshi( ) ; //液晶顯示特定字符
trigger(); //觸發超聲波啟動
measuring(); //進行距離測量
display_H_L();//顯示上下限
if(distance>distance1||distance<distance2)
{
baojing=1;
baojing1=1;//由于此單片機驅動電流太小
baojing2=1;//所以用空閑的I/O口作并聯
baojing3=1;//以提高輸出電流
baojing4=1;
baojing5=1;
}
else
{
baojing=0;
baojing1=0;//由于此單片機驅動電流太小
baojing2=0;//所以用空閑的I/O口作并聯
baojing3=0;//以提高輸出電流
baojing4=0;
baojing5=0;
}
display(distance); //對測量結果進行顯示
init_measuring(); //超聲波相應端口初始化
}
}
//……………………………………………中斷服務函數……
void T_0()interrupt 1
{
TL0 = 0x66;
TH0 = 0xfc;
count++;
if(count==39)
{
TR0 =0;
TL0 = 0x66;
TH0 = 0xfc;
count = 0;
}
}
|
評分
-
查看全部評分
|