|
IMG_20150510_184709.jpg (1.58 MB, 下載次數: 180)
下載附件
初始值
2015-5-10 18:50 上傳
我的超聲波測距儀有個設置報警距離功能,當測得的距離小于設定時蜂鳴器報警。問題是更改報警距離后,再開機,報警距離就又是初始化的值,不是更改后的值,不知道哪里出了問題。
以下是源程序:
#include <reg52.h> //調用單片機頭文件
#define uchar unsigned char //無符號字符型 宏定義 變量范圍0~255
#define uint unsigned int //無符號整型 宏定義 變量范圍0~65535
#include <intrins.h>
sbit c_send = P1^5; //超聲波發射
sbit c_recive = P3^2; //超聲波接收
//這三個引腳參考資料
sbit rs=P1^0; //1602數據/命令選擇引腳 H:數據 L:命令
sbit rw=P1^1; //1602讀寫引腳 H:數據寄存器 L:指令寄存器
sbit e =P2^5; //1602使能引腳 下降沿觸發
uchar code table_num[]="0123456789abcdefg";
/***********************語音模塊控制IO口的定義************************/
sbit VBUSY= P2^0;
sbit VSDA = P2^1;
sbit VCS = P2^2;
sbit VSCL = P2^6;
sbit VRST = P2^4;
uchar yujing[3];
sbit beep = P2^3; //蜂鳴器IO口定義
bit flag_300ms ;
long distance; //距離
uint set_d; //距離
bit flag_csb_juli; //超聲波超出量程
uint flag_time0; //用來保存定時器0的時候的
// 按鍵的IO變量的定義
uchar key_can; //按鍵值的變量
uchar menu_1; //菜單設計的變量
uchar a_a;
#define RdCommand 0x01 //定義ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x07 //定義CPU的等待時間
sfr ISP_DATA=0xe6; //寄存器申明
sfr ISP_ADDRH=0xe5;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe3;
sfr ISP_TRIG=0xe2;
sfr ISP_CONTR=0xe1;
/* ================ 打開 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
EA = 0; /* 關中斷 */
ISP_CONTR = ISP_CONTR & 0x18; /* 0001,1000 */
ISP_CONTR = ISP_CONTR | WaitTime; /* 寫入硬件延時 */
ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */
}
/* =============== 關閉 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
ISP_TRIG = 0x00;
EA = 1; /* 開中斷 */
}
/* ================ 公用的觸發代碼 ==================== */
void ISPgoon(void)
{
ISP_IAP_enable(); /* 打開 ISP,IAP 功能 */
ISP_TRIG = 0x46; /* 觸發ISP_IAP命令字節1 */
ISP_TRIG = 0xb9; /* 觸發ISP_IAP命令字節2 */
_nop_();
}
/* ==================== 字節讀 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
EA = 0;
ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址賦值 */
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
ISP_CMD = ISP_CMD & 0xf8; /* 清除低3位 */
ISP_CMD = ISP_CMD | RdCommand; /* 寫入讀命令 */
ISPgoon(); /* 觸發執行 */
ISP_IAP_disable(); /* 關閉ISP,IAP功能 */
EA = 1;
return (ISP_DATA); /* 返回讀到的數據 */
}
/* ================== 扇區擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
iSectorAddr = (sector_addr & 0xfe00); /* 取扇區地址 */
ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
ISP_ADDRL = 0x00;
ISP_CMD = ISP_CMD & 0xf8; /* 清空低3位 */
ISPgoon(); /* 觸發執行 */
ISP_IAP_disable(); /* 關閉ISP,IAP功能 */
}
/* ==================== 字節寫 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
EA = 0;
SectorErase(byte_addr);
ISP_ADDRH = (unsigned char)(byte_addr >> 8); /* 取地址 */
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
ISP_CMD = ISP_CMD & 0xf8; /* 清低3位 */
ISP_DATA = original_data; /* 寫入數據準備 */
ISPgoon(); /* 觸發執行 */
ISP_IAP_disable(); /* 關閉IAP功能 */
EA =1;
}
/***********************1ms延時函數*****************************/
void delay_1ms(uint q)
{
uint i,j;
for(i=0;i<q;i++)
for(j=0;j<120;j++);
}
void delay_us (unsigned int us)
{
while(us--)
{
_nop_();
}
}
/***********************三線發碼子程序************************/
void Send_threelines(unsigned char addr)
{
unsigned char i;
VRST=0;
delay_1ms(5);
VRST=1;
delay_1ms(20); /* 復位拉高20ms*/
VCS=0;
delay_1ms(5); /* 片選拉低5ms */
for(i=0;i<8;i++)
{
VSCL=0;
if(addr&0x01)
{
VSDA=1;
}
else
VSDA=0;
addr<<=1;
delay_us(150); /* 150us */
VSCL=1;
delay_us(150); /* 150us */
}
VCS=1;
}
/********************************************************************
* 名稱 : delay_uint()
* 功能 : 小延時。
* 輸入 : 無
* 輸出 : 無
***********************************************************************/
void delay_uint(uint q)
{
while(q--);
}
/********************************************************************
* 名稱 : write_com(uchar com)
* 功能 : 1602命令函數
* 輸入 : 輸入的命令值
* 輸出 : 無
***********************************************************************/
void write_com(uchar com)
{
e=0;
rs=0;
rw=0;
P0=com;
delay_uint(25);
e=1;
delay_uint(100);
e=0;
}
/********************************************************************
* 名稱 : write_data(uchar dat)
* 功能 : 1602寫數據函數
* 輸入 : 需要寫入1602的數據
* 輸出 : 無
***********************************************************************/
void write_data(uchar dat)
{
e=0;
rs=1;
rw=0;
P0=dat;
delay_uint(25);
e=1;
delay_uint(100);
e=0;
}
/********************************************************************
* 名稱 : write_string(uchar hang,uchar add,uchar *p)
* 功能 : 改變液晶中某位的值,如果要讓第一行,第五個字符開始顯示"ab cd ef" ,調用該函數如下
write_string(1,5,"ab cd ef;")
* 輸入 : 行,列,需要輸入1602的數據
* 輸出 : 無
***********************************************************************/
void write_string(uchar hang,uchar add,uchar *p)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
while(1)
{
if(*p == '\0') break;
write_data(*p);
p++;
}
}
/***********************lcd1602上顯示兩位十進制數************************/
void write_sfm3(uchar hang,uchar add,uint date)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
write_data(0x30+date/100%10);
write_data('.');
write_data(0x30+date/10%10);
write_data(0x30+date%10);
}
/********************************************************************
* 名稱 : init_1602()
* 功能 : 初始化1602液晶
* 輸入 : 無
* 輸出 : 無
***********************************************************************/
void init_1602() //1602初始化
{
write_com(0x38);
write_com(0x0c);
write_com(0x06);
delay_uint(1000);
write_string(1,0," juli:0.00m ");
write_string(2,0," set:0.00m ");
}
/******************把數據保存到單片機內部eepom中******************/
void write_eeprom() //保存數據
{
SectorErase(0x2000);
byte_write(0x2000, set_d % 256);
byte_write(0x2001, set_d / 256);
byte_write(0x2058, a_a);
}
/******************把數據從單片機內部eepom中讀出來*****************/
void read_eeprom() //讀出保存數據
{
set_d = byte_read(0x2001);
set_d <<= 8;
set_d |= byte_read(0x2000);
a_a = byte_read(0x2058);
}
///**************開機自檢eeprom初始化*****************/
void init_eeprom() ////開始初始化保存的數據
{
read_eeprom(); //讀出保存數據
if(a_a != 15) //新的單片機初始單片機內問EEPOM
{
set_d = 50;
a_a = 15;
write_eeprom(); //保存數據
}
}
/********************獨立按鍵程序*****************/
uchar key_can; //按鍵值
void key() //獨立按鍵程序
{
static uchar key_new;
key_can = 20; //按鍵值還原
P3 |= 0xf0;
if((P3 & 0xf0) != 0xf0) //按鍵按下
{
delay_1ms(1); //按鍵消抖動
if(((P3 & 0xf0) != 0xf0) && (key_new == 1))
{ //確認是按鍵按下
key_new = 0;
switch(P3 & 0xf0)
{
//case 0xb0: key_can = 3; break; //得到k3鍵值
case 0xb0: key_can = 3; break;
//case 0x70: key_can = 2; break; //得到k2鍵值
case 0xd0: key_can = 2; break;
//case 0x30: key_can = 1; break; //得到k4鍵值
case 0x70: key_can = 1; break;
}
}
}
else
key_new = 1;
}
/****************按鍵處理顯示函數***************/
void key_with()
{
if(key_can == 1) //設置鍵
{
menu_1 ++;
if(menu_1 >= 2)
{
menu_1 = 0;
init_1602() ; //1602初始化
write_sfm3(2,7,set_d); //顯示設置的距離
}
}
if(menu_1 == 1) //設置距離報警
{
if(key_can == 2)
{
set_d ++ ; //加1
if(set_d > 500)
set_d = 500;
}
if(key_can == 3)
{
set_d -- ; //減1
if(set_d <= 1)
set_d = 1;
}
write_sfm3(2,7,set_d); //顯示設置的距離
write_com(0x80+0x40+6); //將光標顯示地址
write_com(0x0f); //顯示光標并且閃爍
write_eeprom(); //保存數據
}
}
/**************10us延時函數***************/
void delay()
{
_nop_(); //執行一條_nop_()指令就是1us
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/*********************超聲波測距程序*****************************/
void send_wave()
{
c_send = 1; //10us的高電平觸發
delay();
c_send = 0;
TH0 = 0; //給定時器0清零
TL0 = 0;
TR0 = 0; //關定時器0定時
while(!c_recive); //當c_recive為零時等待
TR0=1;
while(c_recive) //當c_recive為1計數并等待
{
flag_time0 = TH0 * 256 + TL0;
if((flag_time0 > 40000)) //當超聲波超過測量范圍時,顯示3個888
{
TR0 = 0;
distance = 888;
break ;
}
else
{
flag_csb_juli = 1;
}
}
if(flag_csb_juli == 1)
{
TR0=0; //關定時器0定時
distance =flag_time0; //讀出定時器0的時間
distance *= 0.017; // 0.017 = 340M / 2 = 170M = 0.017M 算出來是米
if((distance > 600)) //距離 = 速度 * 時間
{
distance = 888; //如果大于3.8m就超出超聲波的量程
}
}
}
/*********************定時器0、定時器1初始化******************/
void time_init()
{
EA = 1; //開總中斷
TMOD = 0X11; //定時器0、定時器1工作方式1
ET0 = 0; //關定時器0中斷
TR0 = 1; //允許定時器0定時
ET1 = 1; //開定時器1中斷
TR1 = 1; //允許定時器1定時
}
/****************報警函數***************/
void clock_h_l()
{
static uchar value;
if(distance <= set_d)
{
value ++; //消除實際距離在設定距離左右變化時的干擾
if(value >= 2)
{
beep = ~beep; //蜂鳴器報警
}
}
else
{
value = 0;
beep = 1; //取消報警
}
}
/***************主函數*****************/
void main()
{
static uchar value = 5;
beep = 0; //開機蜂鳴器響一下
delay_1ms(200);
P0 = P1 = P2 = P3 = 0xff; //初始化單片機IO口為高電平
init_eeprom(); //開機自檢eeprom初始化
init_1602(); //1602初始化
time_init();
send_wave(); //測距離函數
write_sfm3(2,7,set_d); //顯示設置的距離
while(1)
{
if(flag_300ms == 1)
{
flag_300ms = 0;
if((beep == 1))
send_wave(); //測距離函數
if(menu_1 == 0)
write_sfm3(1,7,distance); //顯示距離
yujing[0] = distance % 10;
yujing[1] = distance / 10 % 10;
yujing[2] = distance / 100 % 10;
value ++;
if(value > 10) //3秒鐘自動播放一次
{
value = 0;
if(distance == 888)
{
Send_threelines(0x0d); //語音播放已超出量程
}
else
{
Send_threelines(yujing[2]); //語音播放
Send_threelines(0x0b);
Send_threelines(yujing[1]);
Send_threelines(yujing[0]);
Send_threelines(0x0c);
}
}
}
key(); //按鍵函數
if(key_can < 10)
{
key_with(); //按鍵處理函數
}
}
}
/*********************定時器1中斷服務程序************************/
void time1_int() interrupt 3
{
static uchar value; //定時10ms中斷一次
TH1 = 0xf8;
TL1 = 0x30; //2ms
value++;
if(value >= 150)
{
value = 0;
flag_300ms = 1;
clock_h_l(); //報警函數
}
}
|
|