单片机交流
直播中

张桂英

7年用户 1545经验值
私信 关注
[问答]

如何去实现一种基于51单片机的电子秒表设计呢

如何去实现一种基于51单片机电子秒表设计呢?
如何对基于51单片机的电子秒表设计进行仿真呢?

回帖(1)

张倩

2021-11-8 09:14:51
  设计要求:
  最多可记录十组数据
  可删除其中多组数据
  可上下查阅所记录的数据
  数据通过lcd1602显示
  计时精度到0.01s
  由于并没有使用24c02,导致程序去数据较大,仿真可能不行。实际验证通过
  程序界面如图:
  
  仿真界面如图:
  
  如果编译出错,将keil按如图参数设置:
  
  以下为程序代码:
  包括两个文件,主程序里面是:
  #include《1602.h》
  #include《reg52.h》
  #ifndef uchar
  #define uchar unsigned char
  #endif
  #ifndef uint
  #define uint unsigned int
  #endif
  /*按键定义*/
  /*开始键,计数键,停止计数键或者清零键,上下查阅键,删除数据键*/
  ***it key_start=P1^0;
  ***it key_count=P1^1;
  ***it key_stop=P1^2;
  ***it key_up=P1^3;
  ***it key_down=P1^4;
  /*变量定义*/
  int count=0;//计数器
  uint i,j,state,k=0,countnum,m,delete;
  /*设置标志位*/
  char flag;
  char maxflag;
  char clearflag;
  char turnflag; //
  char upflag; //为1时可以继续上翻
  char minflag=0; //为0时可以继续下翻
  char downflag;
  /*定义数组 */
  unsigned char str[] = “time:”;
  unsigned char str2[]= “num:”;
  unsigned char str3[;
  unsigned char str4[;
  unsigned char str5[;
  unsigned char str6[;
  unsigned char str7[;
  int number[10]=0;
  int num2[5]=0;
  void keyscan();
  void init();
  void main()
  {
  InitLcd1602();
  init();
  /*以下为调试程序段*/
  LcdShowStr(0,0,str3);
  // LcdShowStr(0,1,str2);
  // LcdWriteCom(0x91);
  // LcdWriteData(‘0’+1);
  // LcdWriteCom(0x90);
  // LcdWriteData(‘0’+1);
  /*以上为调试程序段*/
  while(1)
  { //LcdShowStr(0,1,str4); //测试
  keyscan();
  Lcd1602_Delay1ms(50);
  }
  }
  void init()
  {
  IT0=0;
  EX0=0;
  TMOD=0x01;
  TH0=(65536-10000)/256;
  TL0=(65536-10000)%256;
  EA=0; //开总中断
  // key_count=0;
  // key_stop=0;
  // key_up=0;
  // key_down=0;
  // key_delete=0;
  flag=0; //标志位为0时代表未计时状态,为1时代表为计时状态
  i=0;
  maxflag=0;//定时标志位,为1时代表定时已满
  clearflag=0;//清除标志位
  turnflag=0;//为1时可以上下翻页显示
  downflag=0;
  upflag=1;
  }
  void keyscan()
  {
  if((key_start==0)&&(flag==0)) //防抖处理
  {
  Lcd1602_Delay1ms(10); //防抖处理
  if((key_start==0)&&(flag==0))//防抖处理
  {
  while((!(key_start==0)&&(flag==0)));//防抖处理
  InitLcd1602();
  EA=1;//检测到开始按键按下后,启动定时器
  ET0=1; //计时器0开启
  TR0=1; //计时器打开
  flag=1;//设置标志位为计时状态
  LcdShowStr(0,0,str4);
  LcdShowStr(0,1,str5);
  }
  }
  if((key_count==0)&&(flag==1)&&(maxflag==0))
  {
  Lcd1602_Delay1ms(50);
  if((key_count==0)&&(flag==1)&&(maxflag==0))
  {
  while(!((key_count==0)&&(flag==1)&&(maxflag==0)));
  InitLcd1602();
  LcdShowStr(0,0,str);
  LcdShowStr(0,1,str2);
  number=count;
  LcdWriteCom(0xC7);
  LcdWriteData(‘0’+i+1);
  LcdWriteCom(0xC6);
  LcdWriteData(‘0’);
  if(i==9)
  {
  LcdWriteCom(0xC7);
  LcdWriteData(‘0’);
  LcdWriteCom(0xC6);
  LcdWriteData(‘0’+1);
  }
  num2[0]=number/10000;
  num2[1]=number/1000%10;
  num2[2]=number/100%10;
  num2[3]=number/10%10;
  num2[4]=number%10;
  LcdWriteCom(0x86);
  LcdWriteData(‘0’+num2[0]);
  LcdWriteCom(0x87);
  LcdWriteData(‘0’+num2[1]);
  LcdWriteCom(0x88);
  LcdWriteData(‘0’+num2[2]);
  LcdWriteCom(0x89);
  LcdWriteData(‘。’);
  LcdWriteCom(0x8A);
  LcdWriteData(‘0’+num2[3]);
  LcdWriteCom(0x8B);
  LcdWriteData(‘0’+num2[4]);
  LcdWriteCom(0x8D);
  LcdWriteData(‘S’);
  i++;
  state=i;
  if(i==10)
  {
  maxflag=1;
  }
  }
  }
  if(key_stop==0)
  {
  Lcd1602_Delay1ms(50);
  if(key_stop==0)
  {
  while(!(key_stop==0));
  if(clearflag==0)
  {
  TR0=0; //关定时器,查阅时定时就停止
  EX0=1; //开外部中断,保证只有在上下翻阅时才能触发外部中断
  count=0;//计数清零
  clearflag=1;//清除标志位打开,也就是说再按一下这个按键所有制清零
  turnflag=1;
  minflag=0;
  }
  else if(clearflag==1)//此块执行清除任务
  {
  InitLcd1602();
  number[10]=0;
  clearflag=0;
  LcdShowStr(0,0,str3);
  turnflag=0;
  maxflag=0;
  flag=0;
  i=0;//将数组计数给清零
  }
  }
  }
  if(key_up==0)
  {
  Lcd1602_Delay1ms(50);
  if(key_up==0)
  {
  while(!(key_up==0));
  if(upflag==0)
  {
  InitLcd1602();
  LcdShowStr(0,0,str);
  LcdShowStr(0,1,str2);
  minflag=0;//只要上翻过后都可以下翻
  state++;
  if(state==10)
  {
  LcdWriteCom(0xC7);
  LcdWriteData(‘0’);
  LcdWriteCom(0xC6);
  LcdWriteData(‘0’+1);
  }
  else
  {
  LcdWriteCom(0xC7);
  LcdWriteData(‘0’+state);
  LcdWriteCom(0xC6);
  LcdWriteData(‘0’);
  }
  m=state-1;
  delete=m;
  /*显示时间*/
  num2[0]=number[m]/10000;
  num2[1]=number[m]/1000%10;
  num2[2]=number[m]/100%10;
  num2[3]=number[m]/10%10;
  num2[4]=number[m]%10;
  LcdWriteCom(0x86);
  LcdWriteData(‘0’+num2[0]);
  LcdWriteCom(0x87);
  LcdWriteData(‘0’+num2[1]);
  LcdWriteCom(0x88);
  LcdWriteData(‘0’+num2[2]);
  LcdWriteCom(0x89);
  LcdWriteData(‘。’);
  LcdWriteCom(0x8A);
  LcdWriteData(‘0’+num2[3]);
  LcdWriteCom(0x8B);
  LcdWriteData(‘0’+num2[4]);
  LcdWriteCom(0x8D);
  LcdWriteData(‘S’);
  if(state==10)
  {
  upflag=1;
  }
  }
  }
  }
  if(key_down==0)
  {
  Lcd1602_Delay1ms(50);
  if(key_down==0)
  {
  while(!(key_down==0));
  if((turnflag==1)&&(minflag==0))
  {
  InitLcd1602();
  LcdShowStr(0,0,str);
  LcdShowStr(0,1,str2);
  /*显示组号*/
  state--;
  LcdWriteCom(0xC7);
  LcdWriteData(‘0’+state);
  LcdWriteCom(0xC6);
  LcdWriteData(‘0’);
  k=state-1;
  delete=k;
  /*显示时间*/
  num2[0]=number[k]/10000;
  num2[1]=number[k]/1000%10;
  num2[2]=number[k]/100%10;
  num2[3]=number[k]/10%10;
  num2[4]=number[k]%10;
  LcdWriteCom(0x86);
  LcdWriteData(‘0’+num2[0]);
  LcdWriteCom(0x87);
  LcdWriteData(‘0’+num2[1]);
  LcdWriteCom(0x88);
  LcdWriteData(‘0’+num2[2]);
  LcdWriteCom(0x89);
  LcdWriteData(‘。’);
  LcdWriteCom(0x8A);
  LcdWriteData(‘0’+num2[3]);
  LcdWriteCom(0x8B);
  LcdWriteData(‘0’+num2[4]);
  LcdWriteCom(0x8D);
  LcdWriteData(‘S’);
  if(state==1)
  {
  minflag=1;
  }
  upflag=0;
  }
  }
  }
  }
  void timer0() interrupt 1
  {
  TH0=(65536-10000)/256;
  TL0=(65536-10000)%256;
  count++;
  if(count==6000)
  {
  count=0;
  ET0=0; //计时器0关闭
  TR0=0; //计时器关闭
  turnflag=1;
  EX0=1;
  InitLcd1602();
  LcdShowStr(0,0,str6);
  LcdShowStr(0,1,str7);
  }
  }
  void counter0(void) interrupt 0 using 1
  {
  number[delete]=0;
  LcdWriteCom(0x86);
  LcdWriteData(‘0’);
  LcdWriteCom(0x87);
  LcdWriteData(‘0’);
  LcdWriteCom(0x88);
  LcdWriteData(‘0’);
  LcdWriteCom(0x89);
  LcdWriteData(‘。’);
  LcdWriteCom(0x8A);
  LcdWriteData(‘0’);
  LcdWriteCom(0x8B);
  LcdWriteData(‘0’);
  LcdWriteCom(0x8D);
  LcdWriteData(‘S’);
  }
  然后是lcd的驱动程序:
  #include《1602.h》
  void Read_Busy() //忙检测函数,判断bit7是0,允许执行;1禁止
  {
  unsigned char sta; //
  LCD1602_DB = 0xff;
  LCD1602_RS = 0;
  LCD1602_RW = 1;
  do
  {
  LCD1602_EN = 1;
  sta = LCD1602_DB;
  LCD1602_EN = 0; //使能,用完就拉低,释放总线
  }while(sta & 0x80);
  }
  void Lcd1602_Write_Cmd(unsigned char cmd) //写命令
  {
  Read_Busy();
  LCD1602_RS = 0;
  LCD1602_RW = 0;
  LCD1602_DB = cmd;
  LCD1602_EN = 1;
  LCD1602_EN = 0;
  }
  void Lcd1602_Write_Data(unsigned char dat) //写数据
  {
  Read_Busy();
  LCD1602_RS = 1;
  LCD1602_RW = 0;
  LCD1602_DB = dat;
  LCD1602_EN = 1;
  LCD1602_EN = 0;
  }
  void LcdSetCursor(unsigned char x,unsigned char y) //坐标显示
  {
  unsigned char addr;
  if(y == 0)
  addr = 0x00 + x;
  else
  addr = 0x40 + x;
  Lcd1602_Write_Cmd(addr|0x80);
  }
  void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str) //显示字符串
  {
  LcdSetCursor(x,y); //当前字符的坐标
  while(*str != ‘’)
  {
  Lcd1602_Write_Data(*str++);
  }
  }
  void InitLcd1602() //1602初始化
  {
  Lcd1602_Write_Cmd(0x38); //打开,5*8,8位数据
  Lcd1602_Write_Cmd(0x0c);
  Lcd1602_Write_Cmd(0x06);
  Lcd1602_Write_Cmd(0x01); //清屏
  }
  void Lcd1602_Delay1ms(uint c) //误差 0us
  {
  uchar a,b;
  for (; c》0; c--)
  {
  for (b=199;b》0;b--)
  {
  for(a=1;a》0;a--);
  }
  }
  }
  /*******************************************************************************
  * 函 数 名 : LcdWriteCom
  * 函数功能 : 向LCD写入一个字节的命令
  * 输 入 : com
  * 输 出 : 无
  *******************************************************************************/
  #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
  void LcdWriteCom(uchar com) //写入命令
  {
  LCD1602_EN = 0; //使能
  LCD1602_RS = 0; //选择发送命令
  LCD1602_RW = 0; //选择写入
  LCD1602_DB = com; //放入命令
  Lcd1602_Delay1ms(1); //等待数据稳定
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5); //保持时间
  LCD1602_EN = 0;
  }
  #else
  void LcdWriteCom(uchar com) //写入命令
  {
  LCD1602_EN = 0; //使能清零
  LCD1602_RS = 0; //选择写入命令
  LCD1602_RW = 0; //选择写入
  LCD1602_DB = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  Lcd1602_Delay1ms(1);
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5);
  LCD1602_EN = 0;
  // Lcd1602_Delay1ms(1);
  LCD1602_DB = com 《《 4; //发送低四位
  Lcd1602_Delay1ms(1);
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5);
  LCD1602_EN = 0;
  }
  #endif
  /*******************************************************************************
  * 函 数 名 : LcdWriteData
  * 函数功能 : 向LCD写入一个字节的数据
  * 输 入 : dat
  * 输 出 : 无
  *******************************************************************************/
  #ifndef LCD1602_4PINS
  void LcdWriteData(uchar dat) //写入数据
  {
  LCD1602_EN = 0; //使能清零
  LCD1602_RS = 1; //选择输入数据
  LCD1602_RW = 0; //选择写入
  LCD1602_DB = dat; //写入数据
  Lcd1602_Delay1ms(1);
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5); //保持时间
  LCD1602_EN = 0;
  }
  #else
  void LcdWriteData(uchar dat) //写入数据
  {
  LCD1602_EN = 0; //使能清零
  LCD1602_RS = 1; //选择写入数据
  LCD1602_RW = 0; //选择写入
  LCD1602_DB = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  Lcd1602_Delay1ms(1);
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5);
  LCD1602_EN = 0;
  LCD1602_DB = dat 《《 4; //写入低四位
  Lcd1602_Delay1ms(1);
  LCD1602_EN = 1; //写入时序
  Lcd1602_Delay1ms(5);
  LCD1602_EN = 0;
  }
  #endif
  还有一个1602.h文件:
  #include《reg52.h》
  #ifndef uchar
  #define uchar unsigned char
  #endif
  #ifndef uint
  #define uint unsigned int
  #endif
  #define LCD1602_DB P0
  ***it LCD1602_RS = P2^6;
  ***it LCD1602_RW = P2^5;
  ***it LCD1602_EN = P2^7;
  void InitLcd1602(); //初始化lcd1602
  void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);//写入一个字符串
  void LcdWriteData(uchar dat1);//写入一个单个字
  void LcdWriteCom(uchar com);//写入地址
  void Lcd1602_Delay1ms(uint c);
  void InitLcd1602();
举报

更多回帖

发帖
×
20
完善资料,
赚取积分