導航:首頁 > 操作系統 > 測海拔關於氣壓的51單片機程序

測海拔關於氣壓的51單片機程序

發布時間:2024-04-09 21:09:42

『壹』 bmp180 怎麼接到51單片機上測氣壓

可以用行慧BMP085或BMP180,支持IIC通信敬帶茄 單片機程序通過IO口模擬IIC通信,直接可以讀取到亮察大氣壓的信息

『貳』 51單片機如何控制超聲波感測器 求C語言程序(一定要能用)100追加

//超聲波模塊ME007顯示程序
//晶振=8M
//MCU=STC10F04XE
//P0.0-P0.6共陽數碼管引腳
//Trig = P1^0
//Echo = P3^2
#include <reg52.h> //包括一個52標准內核的頭文件
#define uchar unsigned char //定義一下方便使用
#define uint unsigned int
#define ulong unsigned long
//***********************************************
sfr CLK_DIV = 0x97; //為STC單片機定義,系統時鍾分頻
//為STC單片機的IO口設置地址定義
sfr P0M1 = 0X93;
sfr P0M0 = 0X94;
sfr P1M1 = 0X91;
sfr P1M0 = 0X92;
sfr P2M1 = 0X95;
sfr P2M0 = 0X96;
//***********************************************
sbit Trig = P1^0; //產生脈沖引腳
sbit Echo = P3^2; //回波引腳
sbit test = P1^1; //測試用引腳

uchar code SEG7[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//數碼管0-9
uint distance[4]; //測距接收緩沖區
uchar ge,shi,,temp,flag,outcomeH,outcomeL,i; //自定義寄存器
bit succeed_flag; //測量成功標志
//********函數聲明
void conversion(uint temp_data);
void delay_20us();
//void pai_xu();

void main(void) // 主程序
{ uint distance_data,a,b;
uchar CONT_1;
CLK_DIV=0X03; //系統時鍾為1/8晶振(pdf-45頁)
P0M1 = 0; //將io口設置為推挽輸出
P1M1 = 0;
P2M1 = 0;
P0M0 = 0XFF;
P1M0 = 0XFF;
P2M0 = 0XFF;
i=0;
flag=0;
test =0;
Trig=0; //首先拉低脈沖輸入引腳
TMOD=0x11; //定時器0,定時器1,16位工作方式
TR0=1; //啟動定時器0
IT0=0; //由高電平變低電平,觸發外部中斷
ET0=1; //打開定時器0中斷
//ET1=1; //打開定時器1中斷
EX0=0; //關閉外部中斷
EA=1; //打開總中斷0

while(1) //程序循環
{
EA=0;
Trig=1;
delay_20us();
Trig=0; //產生一個20us的脈沖,在Trig引腳
while(Echo==0); //等待Echo回波引腳變高電平
succeed_flag=0; //清測量成功標志
EX0=1; //打開外部中斷
TH1=0; //定時器1清零
TL1=0; //定時器1清零
TF1=0; //
TR1=1; //啟動定時器1
EA=1;

while(TH1 < 30);//等待測量的結果,周期65.535毫秒(可用中斷實現)
TR1=0; //關閉定時器1
EX0=0; //關閉外部中斷

if(succeed_flag==1)
{
distance_data=outcomeH; //測量結果的高8位
distance_data<<=8; //放入16位的高8位
distance_data=distance_data|outcomeL;//與低8位合並成為16位結果數據
distance_data*=12; //因為定時器默認為12分頻
distance_data/=58; //微秒的單位除以58等於厘米
} //為什麼除以58等於厘米, Y米=(X秒*344)/2
// X秒=( 2*Y米)/344 ==》X秒=0.0058*Y米 ==》厘米=微秒/58
if(succeed_flag==0)
{
distance_data=0; //沒有回波則清零
test = !test; //測試燈變化
}

/// distance[i]=distance_data; //將測量結果的數據放入緩沖區
/// i++;
/// if(i==3)
/// {
/// distance_data=(distance[0]+distance[1]+distance[2]+distance[3])/4;
/// pai_xu();
/// distance_data=distance[1];

a=distance_data;
if(b==a) CONT_1=0;
if(b!=a) CONT_1++;
if(CONT_1>=3)
{ CONT_1=0;
b=a;
conversion(b);
}
/// i=0;
/// }
}
}
//***************************************************************
//外部中斷0,用做判斷回波電平
INTO_() interrupt 0 // 外部中斷是0號
{
outcomeH =TH1; //取出定時器的值
outcomeL =TL1; //取出定時器的值
succeed_flag=1; //至成功測量的標志
EX0=0; //關閉外部中斷
}
//****************************************************************
//定時器0中斷,用做顯示
timer0() interrupt 1 // 定時器0中斷是1號
{
TH0=0xfd; //寫入定時器0初始值
TL0=0x77;
switch(flag)
{case 0x00:P0=ge; P2=0xfd;flag++;break;
case 0x01:P0=shi;P2=0xfe;flag++;break;
case 0x02:P0=;P2=0xfb;flag=0;break;
}
}
//*****************************************************************
/*
//定時器1中斷,用做超聲波測距計時
timer1() interrupt 3 // 定時器0中斷是1號
{
TH1=0;
TL1=0;
}
*/
//******************************************************************
//顯示數據轉換程序
void conversion(uint temp_data)
{
uchar ge_data,shi_data,_data ;
_data=temp_data/100 ;
temp_data=temp_data%100; //取余運算
shi_data=temp_data/10 ;
temp_data=temp_data%10; //取余運算
ge_data=temp_data;

_data=SEG7[_data];
shi_data=SEG7[shi_data];
ge_data =SEG7[ge_data];

EA=0;
= _data;
shi = shi_data;
ge = ge_data ;
EA=1;
}
//******************************************************************
void delay_20us()
{ uchar bt ;
for(bt=0;bt<100;bt++);
}
/*
void pai_xu()
{ uint t;
if (distance[0]>distance[1])
{t=distance[0];distance[0]=distance[1];distance[1]=t;} /*交換值
if(distance[0]>distance[2])
{t=distance[2];distance[2]=distance[0];distance[0]=t;} /*交換值
if(distance[1]>distance[2])
{t=distance[1];distance[1]=distance[2];distance[2]=t;} /*交換值
}
*/

我的一個超聲波程序
有問題,請問~~

//超聲波模塊顯示程序
#include <reg52.h> //包括一個52標准內核的頭文件
#include<intrins.h> //包含_nop_()函數定義的頭文件
#define uchar unsigned char //定義一下方便使用
#define uint unsigned int
#define ulong unsigned long
sbit Tx = P3^3; //產生脈沖引腳
sbit Rx = P3^2; //回波引腳
sbit RS=P2^0; //寄存器選擇位,將RS位定義為P2.0引腳
sbit RW=P2^1; //讀寫選擇位,將RW位定義為P2.1引腳
sbit E=P2^2; //使能信號位,將E位定義為P2.2引腳
sbit BF=P0^7; //忙碌標志位,,將BF位定義為P0.7引腳
unsigned char code string[ ]= {"CHAO SHENG BO"};
//unsigned char code string1[ ]={"QUICK STUDY MCU"};
unsigned char code digit[ ]={"0123456789"}; //定義字元數組顯示數字
//uchar code SEG7[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//數碼管0-9
uint distance[4]; //測距接收緩沖區
uchar ge,shi,,temp,flag,outcomeH,outcomeL,i; //自定義寄存器
bit succeed_flag; //測量成功標志
//********函數聲明
void conversion(uint temp_data);
void delay_20us();
void pai_xu();

/*****************************************************
函數功能:延時1ms
(3j+2)*i=(3×33+2)×10=1010(微秒),可以認為是1毫秒
***************************************************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/*****************************************************
函數功能:延時若干毫秒
入口參數:n
***************************************************/
void delay(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/*****************************************************
函數功能:判斷液晶模塊的忙碌狀態
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
unsigned char BusyTest(void)
{
bit result;
RS=0; //根據規定,RS為低電平,RW為高電平時,可以讀狀態
RW=1;
E=1; //E=1,才允許讀寫
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四個機器周期,給硬體反應時間
result=BF; //將忙碌標志電平賦給result
E=0; //將E恢復低電平
return result;
}
/*****************************************************
函數功能:將模式設置指令或顯示地址寫入液晶模塊
入口參數:dictate
***************************************************/
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根據規定,RS和R/W同時為低電平時,可以寫入指令
RW=0;
E=0; //E置低電平(根據表8-6,寫指令時,E為高脈沖,
// 就是讓E從0到1發生正跳變,所以應先置"0"
_nop_();
_nop_(); //空操作兩個機器周期,給硬體反應時間
P0=dictate; //將數據送入P0口,即寫入指令或地址
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四個機器周期,給硬體反應時間
E=1; //E置高電平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四個機器周期,給硬體反應時間
E=0; //當E由高電平跳變成低電平時,液晶模塊開始執行命令
}
/*****************************************************
函數功能:指定字元顯示的實際地址
入口參數:x
***************************************************/
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80); //顯示位置的確定方法規定為"80H+地址碼x"
}
/*****************************************************
函數功能:將數據(字元的標准ASCII碼)寫入液晶模塊
入口參數:y(為字元常量)
***************************************************/
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS為高電平,RW為低電平時,可以寫入數據
RW=0;
E=0; //E置低電平(根據表8-6,寫指令時,E為高脈沖,
// 就是讓E從0到1發生正跳變,所以應先置"0"
P0=y; //將數據送入P0口,即將數據寫入液晶模塊
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四個機器周期,給硬體反應時間
E=1; //E置高電平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四個機器周期,給硬體反應時間
E=0; //當E由高電平跳變成低電平時,液晶模塊開始執行命令
}
/*****************************************************
函數功能:對LCD的顯示模式進行初始化設置
***************************************************/
void LcdInitiate(void)
{
delay(15); //延時15ms,首次寫指令時應給LCD一段較長的反應時間
WriteInstruction(0x38); //顯示模式設置:16×2顯示,5×7點陣,8位數據介面
delay(5); //延時5ms,給硬體一點反應時間
WriteInstruction(0x38);
delay(5);
WriteInstruction(0x38); //連續三次,確保初始化成功
delay(5);
WriteInstruction(0x0c); //顯示模式設置:顯示開,無游標,游標不閃爍
delay(5);
WriteInstruction(0x06); //顯示模式設置:游標右移,字元不移
delay(5);
WriteInstruction(0x01); //清屏幕指令,將以前的顯示內容清除
delay(5);
}

void main(void) // 主程序
{ uint distance_data,a,b;
uchar CONT_1;
uchar k; //定義變數i指向字元串數組元素
LcdInitiate(); //調用LCD初始化函數
delay(10); //延時10ms,給硬體一點反應時間
WriteAddress(0x01); // 從第1行第3列開始顯示
k = 0; //指向字元數組的第1個元素
while(string[k] != '\0')
{
WriteData(string[k]);
k++; //指向下字元數組一個元素
}
i=0;

flag=0;
Tx=0; //首先拉低脈沖輸入引腳
TMOD=0x10; //定時器0,定時器1,16位工作方式
// TR0=1; //啟動定時器0
IT0=0; //由高電平變低電平,觸發外部中斷
//ET0=1; //打開定時器0中斷
EX0=0; //關閉外部中斷
EA=1; //打開總中斷0

while(1) //程序循環
{
WriteAddress(0x41); // 從第2行第6列開始顯示
WriteData('J'); //將萬位數字的字元常量寫入LCD
WriteData('U'); //將萬位數字的字元常量寫入LCD
WriteData('L'); //將萬位數字的字元常量寫入LCD
WriteData('I'); //將萬位數字的字元常量寫入LCD
WriteData(':'); //將萬位數字的字元常量寫入LCD
WriteData(digit[]); //將萬位數字的字元常量寫入LCD
WriteData(digit[shi]); //將千位數字的字元常量寫入LCD
WriteData('.'); //將萬位數字的字元常量寫入LCD
WriteData(digit[ge]); //將百位數字的字元常量寫入LCD
WriteData(' '); //將百位數字的字元常量寫入LCD
WriteData('C'); //將萬位數字的字元常量寫入LCD
WriteData('M'); //將萬位數字的字元常量寫入LCD
EA=0;
Tx=1;
delay_20us();
Tx=0; //產生一個20us的脈沖,在Tx引腳
while(Rx==0); //等待Rx回波引腳變高電平
succeed_flag=0; //清測量成功標志
EX0=1; //打開外部中斷
TH1=0; //定時器1清零
TL1=0; //定時器1清零
TF1=0; //
TR1=1; //啟動定時器1
EA=1;

while(TH1 < 30);//等待測量的結果,周期65.535毫秒(可用中斷實現)
TR1=0; //關閉定時器1
EX0=0; //關閉外部中斷

if(succeed_flag==1)
{
distance_data=outcomeH; //測量結果的高8位
distance_data<<=8; //放入16位的高8位
distance_data=distance_data|outcomeL;//與低8位合並成為16位結果數據
distance_data*=12; //因為定時器默認為12分頻
distance_data/=58; //微秒的單位除以58等於厘米
} //為什麼除以58等於厘米, Y米=(X秒*344)/2
// X秒=( 2*Y米)/344 ==》X秒=0.0058*Y米 ==》厘米=微秒/58
if(succeed_flag==0)
{
distance_data=0; //沒有回波則清零

}

distance[i]=distance_data; //將測量結果的數據放入緩沖區
i++;
if(i==3)
{
distance_data=(distance[0]+distance[1]+distance[2]+distance[3])/4;

pai_xu();
distance_data=distance[1];

a=distance_data;
if(b==a) CONT_1=0;
if(b!=a) CONT_1++;
if(CONT_1>=3)
{ CONT_1=0;
b=a;
conversion(b);
}
i=0;
}
}
}
//***************************************************************
//外部中斷0,用做判斷回波電平
INTO_() interrupt 0 // 外部中斷是0號
{
outcomeH =TH1; //取出定時器的值
outcomeL =TL1; //取出定時器的值
succeed_flag=1; //至成功測量的標志
EX0=0; //關閉外部中斷
}
//****************************************************************
//定時器0中斷,用做顯示
timer0() interrupt 1 // 定時器0中斷是1號
{
// TH0=0xfd; //寫入定時器0初始值
// TL0=0x77;

}

//顯示數據轉換程序
void conversion(uint temp_data)
{
uchar ge_data,shi_data,_data ;
_data=temp_data/100 ;
temp_data=temp_data%100; //取余運算
shi_data=temp_data/10 ;
temp_data=temp_data%10; //取余運算
ge_data=temp_data;

//_data=SEG7[_data];
//shi_data=SEG7[shi_data]&0x7f;
//ge_data =SEG7[ge_data];

EA=0;
= _data;
shi = shi_data;
ge = ge_data ;
EA=1;
}
//******************************************************************

void delay_20us()
{ uchar bt ;
for(bt=0;bt<60;bt++);
}
void pai_xu()
{ uint t;
if (distance[0]>distance[1])
{t=distance[0];distance[0]=distance[1];distance[1]=t;}
if(distance[0]>distance[2])
{t=distance[2];distance[2]=distance[0];distance[0]=t;}
if(distance[1]>distance[2])
{t=distance[1];distance[1]=distance[2];distance[2]=t;}
}

第一個需要修改,你還是試試這個吧!這個你先理解下,修改引腳……顯示為1602

『叄』 求C51單片機程序,關於超聲波測距儀

看下這個

原文http://www.elecfans.com/article/87/82/2009/20091219139294.html

基於單片機的倒車防撞預警系統設計和實現

0 引 言
汽車倒車防撞預警系統即是俗稱的倒車雷達,是汽車泊車輔助裝置。在汽車倒車時,倒車雷達採用超聲波測距原理探測汽車尾部離障礙物的距離,當汽車尾部離障礙物的距離達到探測范圍時,倒車雷達通過數碼管實時動態顯示距離。當汽車尾部離障礙物的距離達到設定的安全警告值時,倒車雷達發出報警聲,以警示駕駛員,輔助駕駛員安全倒車。現在生產的中高檔小轎車大多數都配置有倒車雷達,而出於節省成本等方面的考慮,經濟型小轎車、大客車等其他車輛都沒有配置倒車雷達。有市場需求的產品,必然會帶動產品的開發設計。倒車雷達電路種類較多,本文介紹基於單片機控制的倒車雷達系統,該系統採用通用型單片機作為控制電路,方便系統功能擴展。系統電路主要採用集成器件構成,外圍元件少,電路簡潔、調試方便、成本低,利於商品化生產。

1 系統組成及工作原理
倒車防撞預警系統由四路收發一體封閉(防水)型超聲波感測器及其超聲波發射與回波接收電路、超聲波電信號放大電路、單片機控制電路、LED數碼管顯示電路和蜂鳴器聲音報警電路組成。系統組成框圖如圖1所示。

當汽車倒車時由倒車換擋裝置自動接通系統電源,系統上電復位,進入工作狀態。單片機編程產生一串40 kHz的矩形脈沖電壓,經四選一模擬開關加到超聲波發射與回波接收電路,經放大驅動超聲波感測器發射出超聲波,同時單片機開始計時。發射出的超聲波碰到障礙物後形成反射波,部分反射波返回作用於超聲波感測器,經超聲波感測器的聲/電轉換,變成微弱的電信號,該微弱的電信號經放大、整形產生負跳變電壓,向單片機發出中斷申請。單片機收到中斷申請的信號後,立即響應中斷,執行外部中斷服務程序,停止計時,得到超聲波發送和返回的時間T,計算出發射點離障礙物的距離S,即:S=(C·T)/2。C是超聲波在空氣中的傳播速度,在常溫25℃時,C約為346 m/s。若發射出的超聲波在測距范圍內未遇到障礙物,直到單片機定時中斷產生,執行定時中斷服務程序,選擇下一路,依次按後左路、後左中路、後右中路、後右路的順序繼續發射和接收超聲波,並經過計算處理。四路探測處理完畢,選擇四路中測出的最小距離值通過LED數碼管顯示出來。當最小距離值小於預先設定的報警距離時,單片機接通蜂鳴器的電源,蜂鳴器發出報警聲。若四路探測無回波中斷申請,則顯示「-.--」,表明在安全距離內沒有障礙物,再繼續下一輪的循環探測處理。

2 系統硬體電路的設計
2.1 超聲波發射與回波接收電路
超聲波發射與回波接收電路的主要作用是提高驅動超聲波感測器的脈沖電壓幅值,有效地進行電/聲轉換,增大超聲波的發射距離,並通過收發一體的超聲波感測器將返回的超聲波轉變成微弱的電信號。超聲波發射與回波接收電路如圖2所示(畫出一路,其他三路與該路一樣)。

EFR40RS是收發一體封閉(防水)型超聲波感測器,其中心頻率f0=(40.0±1.0)kHz,-3 dB帶寬1 kHz。驅動電壓峰一峰值要求60~150 V。CD4052是雙路四選一模擬開關,單片機的P3.4和P3.5埠輸出選通信號,單片機的P3.3埠輸出一串40 kHz的脈沖電壓,通過CD4052的X路加到選通的開關三極體Q1基極,經脈沖變壓器T1升壓至100 VP-P左右,驅動超聲波感測器EFR40RS發射超聲波。發射時的脈沖電壓幅值大小直接影響測距的遠近,應採用超聲波專用的脈沖變壓器。反射回的超聲波經原收發一體封閉型超聲波感測器變成毫伏級的一串脈沖電信號。由於回波電信號的幅值小,VD3和VD4二極體截止,該信號不會通過T1變壓器副邊線圈形成短路。VD1和VD2二極體也截止,所以回波電信號經R1和C1,通過CD4052的Y路送到超聲波電信號放大與整形電路。R1和VD1,VD2組成雙向限幅電路,避免發射時的大信號造成超聲波放大與整形電路阻塞,甚至損壞電路。

2.2 超聲波電信號放大電路
超聲波電信號放大電路採用集成電路CX20106A構成。CX20106A是日本索尼公司生產的紅外遙控信號接收集成電路。通過外部所接電阻,將其內部帶通濾波電路的中心頻率f0設置為40 kHz,就可以接收放大超聲波電信號,並整形輸出負脈沖電壓。
應用電路如圖3所示。1腳是超聲波電信號輸入端,2腳與地之間連接RC串聯網路,是內部前置放大電路負反饋網路的組成部分。電阻R5的數值確定前置放大電路的增益。R5電阻值減小,負反饋減弱,放大倍數增大;反之,則放大倍數減小。3腳與地之間連接檢波電容C3,適當改變電容C3的大小,可以改變超聲波電信號放大和整形電路的靈敏度和抗干擾能力。C3電容量大,靈敏度低,抗干擾能力強;C3容量小,靈敏度高,抗干擾能力弱,易造成誤動作。5腳與電源間接入一個電阻,用以設置內部帶通濾波電路的中心頻率f0。

當R6=200 kΩ時,f0=40 kHz。6腳與地之間接一個積分電容,標准值為330 pF。如果該電容值取得太大,會使探測距離變短。7腳是電路集電極開路輸出端,R7是該引腳的上拉電阻。集成電路CX20106A無信號輸入時,7腳輸出高電平,當輸入的超聲波電信號經放大、整形後,7腳輸出一個負脈沖電壓。
2.3 單片機控制電路和顯示、報警電路
電路如圖4所示。由於系統用到單片機的輸入/輸出埠不多,在不考慮功能擴展時,從功能夠用和低成本的角度考慮,採用AT89C2051單片機作為控制電路的核心器件。AT89C2051單片機共有20個引腳,其中有15個I/O埠(P3.6無引出腳)。兩個16位定時器/計數器,其體積小、價格低。採用12 MHz高精度的晶振,以獲得較穩定的時鍾頻率,減小測量誤差。單片機的P3.3埠周期性的輸出一串40 kHz的矩形脈沖,通過雙路四選一模擬開關CD4052周期性地加到四路超聲波發射與回波接收電路。單片機的P3.4和P3.5埠輸出雙路四選一模擬開關CD4052的選通信號。單片機的P3.2埠為外部中斷0中斷申請信號輸入端。三位LED數碼管採用動態掃描顯示。U4的小數點常亮,U4的單位為m,U5的單位為dm,U6的單位為cm。採用有源蜂鳴器作為報警發音器件,一是器件成本低,二是便於動態掃描顯示的軟體編程。

3 系統軟體的設計
系統軟體採用模塊化設計,方便擴展移植。採用匯編語言編程。主要有主程序、T0中斷服務程序、外部中斷0服務程序、超聲波發生子程序。

3.1 主程序
本系統有四路測距通道,採用分時工作,按後左一後左中一後右中一後右順序循環測距。每一路發射超聲波後的等待外部中斷時間應大於超聲波在最大有效探測距離內往返時間。所以按最大有效探測距離可以估算出最短的循環間隔時間。因為超聲波在空氣中傳播能量會不斷衰減,所以超聲波測距存在最大有效探測距離。這最大有效探測距離與多種因數有關:
與超聲波感測器性能的好壞、與驅動超聲波感測器的脈沖電壓幅值(功率)的大小、障礙物大小和形狀、障礙物吸波特性以及反射波與入射波之間的夾角、與超聲波放大和整形電路的靈敏度等有關。設定最大有效探測距離為8 m(收發一體封閉型超聲波感測器比較難達到,實際上也沒有必要探測很遠的障礙物,只是設計留有裕量。由於顯示位數有限,也必須對最大探測距離做限制),則循環工作的間隔時間Tm=2S/C=2×8/346A46 ms,加上避免接收超聲波感測器余振的延時和程序執行時間,留足裕量,設定Tm△56 ms。
主程序流程圖如圖5所示。首先是對系統初始化。埠p1.0、P3.3置0;設置堆棧,中斷允許總控制位EA允許中斷(EA=1);允許外部中斷0中斷(EX0=1),採用邊沿觸發方式(IT0=1);設置定時器T0允許中斷(ET0=1),以16位工作方式定時約56 ms;設置定時器T1以16位工作方式定時/計數,計數初值0000H,然後啟動T0定時。設置顯示數據初值為三位BCD碼999(cm),對應字形段碼顯示「---」。四路探測處理完畢後,將四組數據中的最小值送入顯示緩沖區,通過LED數碼管顯示。同時該值與設定的100 cm值比較,若四組數據中的最小值小於100 cm,P3.7埠置0,Q2三極體導通,有源蜂鳴器得電發出報警聲。

由於單片機採用12 MHz的晶振,1個機器周期為1μs,所以計數器每計一個數就是1μs,定時器T1工作模式設置為16位定時/計數器模式,則其最大定時65.536 ms。由於定時器T0每56 ms產生中斷,執行T0中斷服務程序時停止T1計時,所以T1計時不會產生溢出中斷。一輪四路探測處理完畢所用時間大約是56 ms×4=224 ms,用時很短,而倒車速度又比較慢,所以可以做到實時動態顯示。
3.2 T0中斷服務程序
T0中斷服務程序流程圖如圖6所示。每隔56 ms分別按後左→後左中→後右中→後右順序選通下一路超聲波發射與回波接收電路,調用超聲波發生子程序,送出16個40 kHz的超聲波脈沖電壓,定時器T1開始計時,定時器T0開始定時56 ms,使每路工作56 ms。

為了避免接收到超聲波感測器余振的直射波產生的中斷申請,延時2.8 ms後,才允許外部中斷0中斷,等待接收返回的超聲波信號。所以,最小探測距離(盲區)Smin=Ct/2=346×0.002 8/2△0.48 m。四路探測處理完畢,將四路中最小值送入顯示緩沖區。若在四路探測中有些路在有效探測范圍內發射的超聲波未遇障礙物,無返回波,外部中斷0不產生中斷申請信號,或者是進入探測盲區,外部中斷0產生的中斷申請不被受理,則定時器T1計時到定時器T0產生中斷,在T0中斷服務程序中,用三位BCD碼999(三位十進制數最大值999 cm)置夠四組數據。若顯示緩沖區的四組數據都是999時,則對應字形段碼顯示「---」。倒車伊始,LED數碼顯示器就顯示「-.--」,表明在安全距離內沒有障礙物;若發出報警聲後,又顯示「-.--」,表明進入了探測盲區。
3.3 外部中斷0服務程序
外部中斷O服務程序流程圖如圖7所示。單片機一旦接收到返回超聲波信號(即INT0引腳由高電平跳變為低電平),立即進入外部中斷0服務程序。首先停止定時器T1計時,禁止外部中斷0中斷。然後將定時器T1中的數N,也即將超聲波往返所用的時間N(單位:μs),按式S=CT/2=(346 x N×10-6)/2=173×N÷10 000計算,即得被測物的距離(單位:cm),將計算結果以百位、十位、個位BCD碼方式送入比較大小的緩沖區,以備比較大小使用。然後等待定時器T0定時56 ms中斷的產生,繼續下一路的探測處理。

3.4 超聲波發生子程序
超聲波發生子程序通過P3.3埠發送16個周期是25μs(即頻率40 kHz,1個周期內高電平持續13μs、低電平持續12 μs)的矩形脈沖電壓。脈沖串個數在10~20個比較合適。脈沖個數太少,發射強度小,探測距離短;脈沖個數太多,發射持續時間長,在離障礙物距離近時,脈沖串尚未發射完畢,先發射出去的脈沖產生的回波就到達接收端,影響測距結果,造成測距盲區增大。

4 實現應用分析
本系統在實驗室條件下進行了可行性的研究設計,要實際應用中就必須考慮測量精度和工作穩定性的問題。因此,本系統可採取幾項措施來提高測量精度和工作穩定性。
(1)超聲波的傳播速度與溫度有關。為了適應不同環境溫度下的測距需要,提高測量精度,硬體電路上可增加檢測車外環境溫度的環節。單片機根據實測的溫度值,再計算確定超聲波的傳播速度,即C=331.4+0.6lt。t是環境溫度。或者在不增加硬體成本情況下,可考慮通過實驗數據分析,找到測量值與實際值偏差特點和規律,通過軟體編程對測量數據進行校正處理。
(2)軟體設計中採用數字濾波中的算術平均濾波程序對每個測距點進行連續多次測量,取平均值作為該測距點的測量數據,以提高數據采樣的可靠性。要盡量減小探測盲區,所設定的延時時間可根據實際所用超聲波感測器余振時間而定,可在實際調試中確定最小延時時間。
(3)倒車雷達安裝在車上,倒車雷達的工作環境非常惡劣,汽車倒車工作時,高壓點火產生很強的電磁輻射,會影響電路正常工作。所以在硬體及軟體方面要考慮採取抗干擾措施,提高系統工作的可靠性。如用金屬殼屏蔽電路,採用屏蔽線連接超聲波感測器;在滿足測量距離的情況下,可適當調大超聲波電信號放大和整形電路中檢波電容C3的容量。硬體上可增加「看門狗」電路,軟體設計添加指令冗餘、軟體陷阱、或設置軟體「看門狗」,防止程序「跑飛」或者進入死循環。對於駕駛員來說,倒車時主要關心的是車後方有無障礙物、以及障礙物離車大約有多遠等問題。由於車子制動時存在慣性,倒車遇到障礙物時,駕駛員總要提前制動。考慮性價比,倒車雷達測量精度不必很高。但從倒車安全考慮,此時的測量顯示值寧大勿小。

5 結 語
本系統充分利用了單片機的內部資源,用軟體編程產生超聲波矩形脈沖,代替硬體的超聲波發生電路,節省了硬體成本。採用一塊集成器件實現超聲波接收放大和整形,避免了採用多級集成運放組成高增益放大電路易產生自激等問題。實驗表明設計可行。在不增加硬體成本時,通過完善軟體設計,可提高系統測量精度和工作的可靠性,能夠滿足使用要求。在考慮功能擴展時,可以採用帶「看門狗」的AT89S52單片機,以增加擴展埠。在超聲波測距的基礎上,如可增加防盜報警功能、車載蓄電池電壓檢測功能等,若增加微型攝像頭和小型液晶顯示器,便成為可直接觀察車後方的可視倒車雷達。本系統實用性強,性價比高。

『肆』 求用51單片機控制ADXL345測量角度的程序,通過ADXL345感測器,用51單片機控制,測量傾角的程序!

//***************************************
// GY-29 ADXL345 IIC測試程序
// 使用單片機STC89C51
// 晶振:11.0592M
// 顯示:LCD1602
// 編譯環境 Keil uVision2
// 參考宏晶網站24c04通信程序
// 時間:2011年3月1日
// QQ:531389319
//****************************************
#include <REG51.H>
#include <math.h> //Keil library
#include <stdio.h> //Keil library
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
#define DataPort P0 //LCD1602數據埠
sbit SCL=P1^0; //IIC時鍾引腳定義
sbit SDA=P1^1; //IIC數據引腳定義
sbit LCM_RS=P2^0; //LCD1602命令埠
sbit LCM_RW=P2^1; //LCD1602命令埠
sbit LCM_EN=P2^2; //LCD1602命令埠
#define SlaveAddress 0xA6 //定義器件在IIC匯流排中的從地址,根據ALT ADDRESS地址引腳不同修改
//ALT ADDRESS引腳接地時地址為0xA6,接電源時地址為0x3A
typedef unsigned char BYTE;
typedef unsigned short WORD;
BYTE BUF[8]; //接收數據緩存區
uchar ge,shi,,qian,wan; //顯示變數
int dis_data; //變數
int data_xyz[3];

void delay(unsigned int k);
void InitLcd(); //初始化lcd1602
void Init_ADXL345(void); //初始化ADXL345
void WriteDataLCM(uchar dataW);
void WriteCommandLCM(uchar CMD,uchar Attribc);
void DisplayOneChar(uchar X,uchar Y,uchar DData);
void conversion(uint temp_data);
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //單個寫入數據
uchar Single_Read_ADXL345(uchar REG_Address); //單個讀取內部寄存器數據
void Multiple_Read_ADXL345(); //連續的讀取內部寄存器數據
//------------------------------------
void Delay5us();
void Delay5ms();
void ADXL345_Start();
void ADXL345_Stop();
void ADXL345_SendACK(bit ack);
bit ADXL345_RecvACK();
void ADXL345_SendByte(BYTE dat);
BYTE ADXL345_RecvByte();
void ADXL345_ReadPage();
void ADXL345_WritePage();
//-----------------------------------
//*********************************************************
void conversion(uint temp_data)
{
wan=temp_data/10000+0x30 ;
temp_data=temp_data%10000; //取余運算
qian=temp_data/1000+0x30 ;
temp_data=temp_data%1000; //取余運算
=temp_data/100+0x30 ;
temp_data=temp_data%100; //取余運算
shi=temp_data/10+0x30 ;
temp_data=temp_data%10; //取余運算
ge=temp_data+0x30;
}
/*******************************/
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}}
}
/*******************************/
void WaitForEnable(void)
{
DataPort=0xff;
LCM_RS=0;LCM_RW=1;_nop_();
LCM_EN=1;_nop_();_nop_();
while(DataPort&0x80);
LCM_EN=0;
}
/*******************************/
void WriteCommandLCM(uchar CMD,uchar Attribc)
{
if(Attribc)WaitForEnable();
LCM_RS=0;LCM_RW=0;_nop_();
DataPort=CMD;_nop_();
LCM_EN=1;_nop_();_nop_();LCM_EN=0;
}
/*******************************/
void WriteDataLCM(uchar dataW)
{
WaitForEnable();
LCM_RS=1;LCM_RW=0;_nop_();
DataPort=dataW;_nop_();
LCM_EN=1;_nop_();_nop_();LCM_EN=0;
}
/***********************************/
void InitLcd()
{
WriteCommandLCM(0x38,1);
WriteCommandLCM(0x08,1);
WriteCommandLCM(0x01,1);
WriteCommandLCM(0x06,1);
WriteCommandLCM(0x0c,1);
}
/***********************************/
void DisplayOneChar(uchar X,uchar Y,uchar DData)
{
Y&=1;
X&=15;
if(Y)X|=0x40;
X|=0x80;
WriteCommandLCM(X,0);
WriteDataLCM(DData);
}
/**************************************
延時5微秒(STC90C52RC@12M)
不同的工作環境,需要調整此函數,注意時鍾過快時需要修改
當改用1T的MCU時,請調整此延時函數
**************************************/
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
/**************************************
延時5毫秒(STC90C52RC@12M)
不同的工作環境,需要調整此函數
當改用1T的MCU時,請調整此延時函數
**************************************/
void Delay5ms()
{
WORD n = 560;
while (n--);
}
/**************************************
起始信號
**************************************/
void ADXL345_Start()
{
SDA = 1; //拉高數據線
SCL = 1; //拉高時鍾線
Delay5us(); //延時
SDA = 0; //產生下降沿
Delay5us(); //延時
SCL = 0; //拉低時鍾線
}
/**************************************
停止信號
**************************************/
void ADXL345_Stop()
{
SDA = 0; //拉低數據線
SCL = 1; //拉高時鍾線
Delay5us(); //延時
SDA = 1; //產生上升沿
Delay5us(); //延時
}
/**************************************
發送應答信號
入口參數:ack (0:ACK 1:NAK)
**************************************/
void ADXL345_SendACK(bit ack)
{
SDA = ack; //寫應答信號
SCL = 1; //拉高時鍾線
Delay5us(); //延時
SCL = 0; //拉低時鍾線
Delay5us(); //延時
}
/**************************************
接收應答信號
**************************************/
bit ADXL345_RecvACK()
{
SCL = 1; //拉高時鍾線
Delay5us(); //延時
CY = SDA; //讀應答信號
SCL = 0; //拉低時鍾線
Delay5us(); //延時
return CY;
}
/**************************************
向IIC匯流排發送一個位元組數據
**************************************/
void ADXL345_SendByte(BYTE dat)
{
BYTE i;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1; //移出數據的最高位
SDA = CY; //送數據口
SCL = 1; //拉高時鍾線
Delay5us(); //延時
SCL = 0; //拉低時鍾線
Delay5us(); //延時
}
ADXL345_RecvACK();
}
/**************************************
從IIC匯流排接收一個位元組數據
**************************************/
BYTE ADXL345_RecvByte()
{
BYTE i;
BYTE dat = 0;
SDA = 1; //使能內部上拉,准備讀取數據,
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1;
SCL = 1; //拉高時鍾線
Delay5us(); //延時
dat |= SDA; //讀數據
SCL = 0; //拉低時鍾線
Delay5us(); //延時
}
return dat;
}
//******單位元組寫入*******************************************
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
{
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(REG_Address); //內部寄存器地址,請參考中文pdf22頁
ADXL345_SendByte(REG_data); //內部寄存器數據,請參考中文pdf22頁
ADXL345_Stop(); //發送停止信號
}
//********單位元組讀取*****************************************
uchar Single_Read_ADXL345(uchar REG_Address)
{ uchar REG_data;
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(REG_Address); //發送存儲單元地址,從0開始
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
REG_data=ADXL345_RecvByte(); //讀出寄存器數據
ADXL345_SendACK(1);
ADXL345_Stop(); //停止信號
return REG_data;
}
//*********************************************************
//
//連續讀出ADXL345內部加速度數據,地址范圍0x32~0x37
//
//*********************************************************
void Multiple_read_ADXL345(void)
{ uchar i;
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(0x32); //發送存儲單元地址,從0x32開始
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
for (i=0; i<6; i++) //連續讀取6個地址數據,存儲中BUF
{
BUF[i] = ADXL345_RecvByte(); //BUF[0]存儲0x32地址中的數據
if (i == 5)
{
ADXL345_SendACK(1); //最後一個數據需要回NOACK
}
else
{
ADXL345_SendACK(0); //回應ACK
}
}
ADXL345_Stop(); //停止信號
Delay5ms();
}

//*****************************************************************
//初始化ADXL345,根據需要請參考pdf進行修改************************
void Init_ADXL345()
{
Single_Write_ADXL345(0x31,0x0B); //測量范圍,正負16g,13位模式
Single_Write_ADXL345(0x2C,0x08); //速率設定為12.5 參考pdf13頁
Single_Write_ADXL345(0x2D,0x08); //選擇電源模式 參考pdf24頁
Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中斷
Single_Write_ADXL345(0x1E,0x00); //X 偏移量 根據測試感測器的狀態寫入pdf29頁
Single_Write_ADXL345(0x1F,0x00); //Y 偏移量 根據測試感測器的狀態寫入pdf29頁
Single_Write_ADXL345(0x20,0x05); //Z 偏移量 根據測試感測器的狀態寫入pdf29頁
}
//***********************************************************************
//顯示x軸
void display_x()
{ float temp;
dis_data=(BUF[1]<<8)+BUF[0]; //合成數據
if(dis_data<0){
dis_data=-dis_data;
DisplayOneChar(2,0,'-'); //顯示正負符號位
}
else DisplayOneChar(2,0,' '); //顯示空格
temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
conversion(temp); //轉換出顯示需要的數據
DisplayOneChar(0,0,'X'); //第0行,第0列 顯示X
DisplayOneChar(1,0,':');
DisplayOneChar(3,0,qian);
DisplayOneChar(4,0,'.');
DisplayOneChar(5,0,);
DisplayOneChar(6,0,shi);
DisplayOneChar(7,0,'g');
}
//***********************************************************************
//顯示y軸
void display_y()
{ float temp;
dis_data=(BUF[3]<<8)+BUF[2]; //合成數據
if(dis_data<0){
dis_data=-dis_data;
DisplayOneChar(2,1,'-'); //顯示正負符號位
}
else DisplayOneChar(2,1,' '); //顯示空格
temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
conversion(temp); //轉換出顯示需要的數據
DisplayOneChar(0,1,'Y'); //第1行,第0列 顯示y
DisplayOneChar(1,1,':');
DisplayOneChar(3,1,qian);
DisplayOneChar(4,1,'.');
DisplayOneChar(5,1,);
DisplayOneChar(6,1,shi);
DisplayOneChar(7,1,'g');
}
//***********************************************************************
//顯示z軸
void display_z()
{ float temp;
dis_data=(BUF[5]<<8)+BUF[4]; //合成數據
if(dis_data<0){
dis_data=-dis_data;
DisplayOneChar(10,1,'-'); //顯示負符號位
}
else DisplayOneChar(10,1,' '); //顯示空格
temp=(float)dis_data*3.9; //計算數據和顯示,查考ADXL345快速入門第4頁
conversion(temp); //轉換出顯示需要的數據
/*
DisplayOneChar(10,0,'Z'); //第0行,第10列 顯示Z
DisplayOneChar(11,0,':');
DisplayOneChar(11,1,qian);
DisplayOneChar(12,1,'.');
DisplayOneChar(13,1,);
DisplayOneChar(14,1,shi);
DisplayOneChar(15,1,'g');
*/
}

//*********************************************************
//******主程序********
//*********************************************************
void main()
{
uchar devid;
float Roll,Pitch,Q,T,K;
delay(500); //上電延時
InitLcd(); //液晶初始化ADXL345
Init_ADXL345(); //初始化ADXL345
devid=Single_Read_ADXL345(0X00);//讀出的數據為0XE5,表示正確
while(1) //循環
{
Init_ADXL345(); //初始化ADXL345
Multiple_Read_ADXL345(); //連續讀出數據,存儲在BUF中
data_xyz[0]=(BUF[1]<<8)+BUF[0]; //合成數據
data_xyz[1]=(BUF[3]<<8)+BUF[2]; //合成數據
data_xyz[2]=(BUF[5]<<8)+BUF[4]; //合成數據
//分別是加速度X,Y,Z的原始數據,10位的
Q=(float)data_xyz[0]*3.9;
T=(float)data_xyz[1]*3.9;
K=(float)data_xyz[2]*3.9;
Q=-Q;
Roll=(float)(((atan2(K,Q)*180)/3.14159265)+180); //X軸角度值
Pitch=(float)(((atan2(K,T)*180)/3.14159265)+180); //Y軸角度值
conversion(Roll); //轉換出顯示需要的數據X軸,或者Y軸
DisplayOneChar(9,1,'A');
DisplayOneChar(10,1,':');
DisplayOneChar(11,1,);
DisplayOneChar(12,1,shi);
DisplayOneChar(13,1,ge);
delay(200); //延時
}
}

『伍』 51單片機程序編寫

/*這是用LCD顯示所測溫度的代碼,你參考一下,如果沒問題的話,其他的功能你再添加就好了,不難*/

#include<reg52.h>

#include<intrins.h>

#define uint unsigned int

#define uchar unsigned char

#define Nack_number 10

//**************埠定義**************************************************

uchar flag; //LCD控制線介面

sbit RS=P1^0; //RS端

sbit RW=P1^1; //讀寫端

sbit LCDE=P2^5; //使能端

//mlx90614埠定義

sbit SCK=P2^1; //時鍾線

sbit SDA=P2^2; //數據線

//************數據定義****************************************************

bdata uchar flag1; //可位定址數據

sbit bit_out=flag1^7;

sbit bit_in=flag1^0;

uchar tempH,tempL,err;


//************************** LCD1602 ***********************************

//向LCD寫入命令或數據*****************************************************

#define LCD_COMMAND 0 //命令

#define LCD_DATA 1 // 數據

#define LCD_CLEAR_SCREEN 0x01 // 清屏

#define LCD_HOMING 0x02 // 游標返回原點

//設置顯示模式******* 0x08+ *********************************************

#define LCD_SHOW 0x04 //顯示開

#define LCD_HIDE 0x00 //顯示關

#define LCD_CURSOR 0x02 //顯示游標

#define LCD_NO_CURSOR 0x00 //無游標

#define LCD_FLASH 0x01 //游標閃動

#define LCD_NO_FLASH 0x00 //游標不閃動

//設置輸入模式********** 0x04+ ********************************************

#define LCD_AC_UP 0x02 //游標右移 AC+

#define LCD_AC_DOWN 0x00 //默認 游標左移 AC-

#define LCD_MOVE 0x01 //畫面可平移

#define LCD_NO_MOVE 0x00 //默認 畫面不移動


//************************** mlx90614 ***********************************

//command mode 命令模式

#define RamAccess 0x00 //對RAM操作

#define EepomAccess 0x20 //對EEPRAM操作

#define Mode 0x60 //進入命令模式

#define ExitMode 0x61 //退出命令模式

#define ReadFlag 0xf0 //讀標志

#define EnterSleep 0xff //進入睡眠模式

//ram address read only RAM地址(只讀)

#define AbmientTempAddr 0x03 //周圍溫度

#define IR1Addr 0x04

#define IR2Addr 0x05

#define LineAbmientTempAddr 0x06 //環境溫度

/*0x0000 0x4074 16500 0.01/單元

-40 125*/

#define LineObj1TempAddr 0x07 //目標溫度,紅外溫度

/*0x27ad-0x7fff 0x3559 22610 0.02/單元

-70.01-382.19 0.01 452.2*/

#define LineObj2TempAddr 0x08

//eepom address EEPROM地址

#define TObjMaxAddr 0x00 //測量范圍上限設定

#define TObjMinAddr 0x01 //測量范圍下限設定

#define PWMCtrlAddr 0x02 //PWM設定

#define TaRangeAddr 0x03 //環境溫度設定

#define KeAddr 0x04 //頻率修正系數

#define ConfigAddr 0x05 //配置寄存器

#define SMbusAddr 0x0e //器件地址設定

#define Reserverd1Addr 0x0f //保留

#define Reserverd2Addr 0x19 //保留

#define ID1Addr 0x1c //ID地址1

#define ID2Addr 0x1d //ID地址2

#define ID3Addr 0x1e //ID地址3

#define ID4Addr 0x1f //ID地址4


//************函數聲明*****************************************************

void start(); //MLX90614發起始位子程序

void stop(); //MLX90614發結束位子程序

uchar ReadByte(void); //MLX90614接收位元組子程序

void send_bit(void); //MLX90614發送位子程序

void SendByte(uchar number); //MLX90614接收位元組子程序

void read_bit(void); //MLX90614接收位子程序

void delay(uint N); //延時程序

uint readtemp(void); //讀溫度數據

void init1602(void); //LCD初始化子程序

void busy(void); //LCD判斷忙子程序

void cmd_wrt(uchar cmd); //LCD寫命令子程序

void dat_wrt(uchar dat); //LCD寫數據子程序

void display(uint Tem); //顯示子程序

void Print(uchar *str); //字元串顯示程序


//*************主函數*******************************************

void main()

{

uint Tem; //溫度變數

SCK=1;

SDA=1;

delay(4);

SCK=0;

delay(1000);

SCK=1;

init1602(); //初始化LCD

while(1)

{

Tem=readtemp(); //讀取溫度

cmd_wrt(0x01); //清屏

Print(" Temperature: "); //顯示字元串 Temperature: 且換行

display(Tem); //顯示溫度

Print(" ^C"); //顯示攝氏度

delay(10000); //延時再讀取溫度顯示

}

}

void Print(uchar *str) //字元串顯示程序

{

while(*str!='') //直到字元串結束

{

dat_wrt(*str); //轉成ASCII碼

str++; //指向下一個字元

}

}


//*********輸入轉換並顯示*********

void display(uint Tem)

{

uint T,a,b;

T=Tem*2;

if(T>=27315) //溫度為正

{

T=T-27315; //

a=T/100; //溫度整數

b=T-a*100; //溫度小數

if(a>=100) //溫度超過100度

{

dat_wrt(0x30+a/100); //顯示溫度百位

dat_wrt(0x30+a%100/10); //顯示溫度十位

dat_wrt(0x30+a%10); //顯示溫度個位

}

else if(a>=10) //溫度超過10度

{

dat_wrt(0x30+a%100/10); //顯示溫度十位

dat_wrt(0x30+a%10); //顯示溫度個位

}

else //溫度不超過10度

{

dat_wrt(0x30+a); //顯示溫度個位

}

dat_wrt(0x2e); //顯示小數點

if(b>=10) //溫度小數點後第1位數不等於0

{

dat_wrt(0x30+b/10); //顯示溫度小數點後第1位數

dat_wrt(0x30+b%10); //顯示溫度小數點後第2位數

}

else //溫度小數點後第1位數等於0

{

dat_wrt(0x30); //顯示溫度小數點後第1位數0

dat_wrt(0x30+b); //顯示溫度小數點後第2位數

}

}

else //溫度為負

{

T=27315-T;

a=T/100;

b=T-a*100;

dat_wrt(0x2d); //顯示負號

if(a>=10) //溫度低於負10度

{

dat_wrt(0x30+a/10); //顯示溫度十位

dat_wrt(0x30+a%10); //顯示溫度個位

}

else //溫度高於負10度

{

dat_wrt(0x30+a); //顯示溫度個位

}

dat_wrt(0x2e); //顯示小數點

if(b>=10) //溫度小數點後第1位數不等於0

{

dat_wrt(0x30+b/10); //顯示溫度小數點後第1位數

dat_wrt(0x30+b%10); //顯示溫度小數點後第2位數

}

else //溫度小數點後第1位數等於0

{

dat_wrt(0x30); //顯示溫度小數點後第1位數0

dat_wrt(0x30+b); //顯示溫度小數點後第2位數

}

}

}

//************************************

void start(void) //停止條件是 SCK=1時,SDA由1到0

{

SDA=1;

delay(4);

SCK=1;

delay(4);

SDA=0;

delay(4);

SCK=0;

delay(4);

}

//------------------------------

void stop(void) //停止條件是 SCK=1時,SDA由0到1

{

SCK=0;

delay(4);

SDA=0;

delay(4);

SCK=1;

delay(4);

SDA=1;

}

//---------發送一個位元組---------

void SendByte(uchar number)

{

uchar i,n,dat;

n=Nack_number; //可以重發次數

Send_again:

dat=number;

for(i=0;i<8;i++) //8位依次發送

{

if(dat&0x80) //取最高位

{

bit_out=1; //發1

}

else

{

bit_out=0; //發0

}

send_bit(); //發送一個位

dat=dat<<1; //左移一位

}

read_bit(); //接收1位 應答信號

if(bit_in==1) //無應答時重發

{

stop();

if(n!=0)

{

n--; //可以重發Nack_number=10次

goto Repeat; //重發

}

else

{

goto exit; //退出

}

}

else

{

goto exit;

}

Repeat:

start(); //重新開始

goto Send_again; //重發

exit: ; //退出

}

//-----------發送一個位---------

void send_bit(void)

{

if(bit_out==1)

{

SDA=1; //發1

}

else

{

SDA=0; //發0

}

_nop_();

SCK=1; //上升沿

delay(4);delay(4);

SCK=0;

delay(4);delay(4);

}

//----------接收一個位元組--------

uchar ReadByte(void)

{

uchar i,dat;

dat=0; //初值為0

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

{

dat=dat<<1; //左移

read_bit(); //接收一位

if(bit_in==1)

{

dat=dat+1; //為1時對應位加1

}

}

SDA=0; //發送應答信號0

send_bit();

return dat; //帶回接收數據

}

//----------接收一個位----------

void read_bit(void)

{

SDA=1; //數據端先置1

bit_in=1;

SCK=1; //上升沿

delay(4);delay(4);

bit_in=SDA; //讀數據

_nop_();

SCK=0;

delay(4);delay(4);

}



//------------------------------

uint readtemp(void)

{

SCK=0;

start(); //開始條件

SendByte(0x00); //發送從地址00

SendByte(0x07); //發送命令

start(); //開始條件

SendByte(0x01); //讀從地址00

bit_out=0;

tempL=ReadByte(); //讀數據低位元組

bit_out=0;

tempH=ReadByte(); //讀數據高位元組

bit_out=1;

err=ReadByte(); //讀錯誤信息碼

stop(); //停止條件

return(tempH*256+tempL);

}

//******************LCD顯示子函數***********************

void init1602(void) //初始化LCD

{

cmd_wrt(0x01); //清屏

cmd_wrt(0x0c); //開顯示,不顯示游標,不閃爍

cmd_wrt(0x06); //完成一個字元碼傳送後,游標左移,顯示不發生移位

cmd_wrt(0x38); //16×2顯示,5×7點陣,8位數據介面

}

void busy(void) //LCD忙標志判斷

{

flag=0x80; //賦初值 高位為1 禁止

while(flag&0x80) //讀寫操作使能位禁止時等待 繼續檢測

{

P0=0xff;

RS=0; //指向地址計數器

RW=1; //讀

LCDE=1; //信號下降沿有效

flag=P0; //讀狀態位 高位為狀態

LCDE=0;

}

}

void cmd_wrt(uchar cmd) //寫命令子函數

{

LCDE=0;

busy(); //檢測 讀寫操作使能嗎

P0=cmd; //命令

RS=0; //指向命令計數器

RW=0; //寫

LCDE=1; //高電平有效

LCDE=0;

}

void dat_wrt(uchar dat) //寫數據子函數

{

busy(); //檢測 讀寫操作使能嗎

LCDE=0;

if(flag==16)

{

RS=0; //指向指令寄存器

RW=0; //寫

P0=0XC0; //指向第二行

LCDE=1; //高電平有效

LCDE=0;

}

RS=1; //指向數據寄存器

RW=0; //寫

P0=dat; //寫數據

LCDE=1; //高電平有效

LCDE=0;

}

//------------延時--------------

void delay(uint n)

{

uint j;

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

{

_nop_();

}

}


『陸』 51單片機C語言程序

//你原來的b2,b2都是死循環,這是不行的,只有主函數才可以死循環。
//你的主函數結構也有問題。
//為你增加了一個按鍵檢測的函數。
//下列程序通過了實驗測試。
//b1輸出的周期大約0.9s。
//b2輸出的周期大約0.6s。

//K為觸動開關,reg為紅燈,bice為綠燈,b1、b2 各為一個方波,
//按第一次觸動開關時紅燈亮寬態、b1輸出,
//按第二次綠燈亮、為b2輸出,
//按第三次都關閉.

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
uint a;
void b1();
void b2();
sbit t = P1^0;
sbit k = P3^5;
sbit reg = P3^3;
sbit bice = P3^2;

void delay(uchar z)
{
uint x,y;
for(x = z; x > 0; x--) for(y = 110; y > 0; y--);
}

bit key()
{
bit kkk;
kkk = k; //讀入按鍵.
if(kkk == 1) return 0;//沒有按下.
delay(5); //延時.
if(k == kkk) return 1;//兩次相等.
return 0;
}

void main()
{
while(1) {
P3 = 0xff;
while(!key()); //靜等按下第一次.
reg = 0;
bice = 1;
while(!key()) b1(); //沒有按下第二宴碰次就循環等待.
reg = 1;
bice = 0;
while(!key()) b2(); //沒有按下第三慎祥源次就循環等待.
}
}

void b1()
{
P1 = 0xfe; a = 50000; while(a--);
P1 = 0xff; a = 50000; while(a--);
}
void b2()
{
P1 = 0xfe; a = 30000; while(a--);
P1 = 0xff; a = 30000; while(a--);
}

閱讀全文

與測海拔關於氣壓的51單片機程序相關的資料

熱點內容
java課表 瀏覽:555
如何在pdf裡面修改 瀏覽:929
橙光製作器檔案框在哪個文件夾 瀏覽:991
php如何抓取網頁數據 瀏覽:642
計數器單片機 瀏覽:966
游戲aoi演算法 瀏覽:844
phpmysqlint 瀏覽:912
怎麼從appstore商城買東西 瀏覽:184
大秀直播平台源碼 瀏覽:424
java視屏 瀏覽:934
電腦中如何給程序加密 瀏覽:240
java排序容器 瀏覽:942
職稱證書在哪個app下載 瀏覽:362
四九演算法算男女 瀏覽:659
javawindows8 瀏覽:498
2021世界程序員節 瀏覽:485
php翼支付 瀏覽:884
盈通伺服器ip地址 瀏覽:791
3des演算法的c語言實現 瀏覽:875
網上怎樣購買伺服器地址 瀏覽:815