找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5438|回复: 1
打印 上一主题 下一主题
收起左侧

超声波测距仪,设置的报警距离不能保存,求解答

[复制链接]
跳转到指定楼层
楼主
                我的超声波测距仪有个设置报警距离功能,当测得的距离小于设定时蜂鸣器报警。问题是更改报警距离后,再开机,报警距离就又是初始化的值,不是更改后的值,不知道哪里出了问题。
以下是源程序:
#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();    //报警函数
}
}


IMG_20150510_184742.jpg (1.52 MB, 下载次数: 186)

更改

更改

IMG_20150510_184759.jpg (1.73 MB, 下载次数: 185)

重启后 更改的数据没了

重启后 更改的数据没了
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:80976 发表于 2015-5-24 22:11 | 只看该作者
等待高手解答
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表