1. 程式人生 > >C51微控制器利用LCD1602設計時鐘

C51微控制器利用LCD1602設計時鐘

-設計思路 -知識積累 -編寫程式碼 -總結

1. 設計思路 第一行顯示年月日,第二行顯示時間 上電之後計時開始,K2控制分秒設定,按第一次計時停止秒針閃爍,按第二次分針閃爍,按第三次計時繼續,K3,K4分別控制加減(只有在按鍵K2按下後生效),在計時過程中可以實現整分報時,K1轉換成60秒倒計時

2. 知識積累

  1. LCD1602

(1)LCD1602介面訊號說明

VSS:電源地訊號引腳; VDD:電源訊號引腳; VEE:液晶對比度調節引腳,接0~5V以調節液晶的顯示對比度; RS:暫存器選擇引腳: RS = 1時為資料暫存器; RS = 0時為指令暫存器; RW:讀寫選擇引腳: RW = 1時,選擇讀操作; RW = 0時,選擇寫操作; E

:讀寫操作選擇引腳,下降沿時,資料被寫入1602液晶,E= 1時,對1602液晶進行讀資料操作; D0~D7:資料匯流排引腳; LEDA:背光電源引腳; LEDK:背光電源地引腳;

(2)LCD1602的基本操作分為四種:

1)讀狀態:輸入RS=0,RW=1,E=高脈衝。輸出:D0—D7為狀態字。 2)讀資料:輸入RS=1,RW=1,E=高脈衝。輸出:D0—D7為資料。 3)寫命令:輸入RS=0,RW=0,E=高脈衝。輸出:無。 4)寫資料:輸入RS=1,RW=0,E=高脈衝。輸出:無。

(3)初始化設定

  1. 定時器

3.編寫程式碼

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
sbit Key0=P3^1;                       //轉換模式
sbit Key1=P3^0;                       //設定分秒
sbit Key2=P3^2;                      //分秒加
sbit Key3=P3^3;                       //分秒減
sbit beep=P1^5;
char code line3[]="   2018-11-6";
char code line4[]="     00:00";
uchar flag1=1,flag2=0;
char  sec=0,min=0,count=0,i;
uchar sec_shi,sec_ge,min_shi,min_ge;
void delay(int n)
{
 int i,j;
 for(i=0;i<n;i++)
 for(j=0;j<110;j++);
}
void W_LCD_Com(uchar com)
{
 LCD_EN=0;
 LCD_RS=0;
 LCD_RW=0;
  P0=com;
 delay(1);
  LCD_EN=1;
  delay(1);
  LCD_EN=0;
}
void W_LCD_Dat(uchar Dat)
{
 LCD_EN=0;
 LCD_RS=1;
 LCD_RW=0;
  P0=Dat;
 delay(1);
 LCD_EN=1;
 delay(1);
 LCD_EN=0;
}
void LCD_Init()
{
 W_LCD_Com(0x38);
 delay(5);
 W_LCD_Com(0x38);
 delay(5);
 W_LCD_Com(0x38);
 W_LCD_Com(0x38);
 
 W_LCD_Com(0x08);
 W_LCD_Com(0x01);
 W_LCD_Com(0x06);
 W_LCD_Com(0x0c);
 W_LCD_Com(0x80);
 for(i=0;i<12;i++)
 {
  W_LCD_Dat(line3[i]);
  delay(5);
 }
 W_LCD_Com(0x80+0x40);
 for(i=0;i<10;i++)
 {
  W_LCD_Dat(line4[i]);
  delay(5);
 }
}
void Time_Init()
{
 TMOD=0x01;
 TH0=(65536-50000)/256;
 TL0=(65536-50000)%256;
 EA=1;
 ET0=1;
 TR0=1;
}
void display()                       //顯示
{
 sec_shi=sec/10;
 sec_ge=sec%10;
 W_LCD_Com(0x80+0x48);                        //+48,是因為只能顯示ASCII碼      
 W_LCD_Dat(sec_shi+48);
  W_LCD_Dat(sec_ge+48);
 delay(1);
  min_shi=min/10;
 min_ge=min%10;
 W_LCD_Com(0x80+0x45);
 W_LCD_Dat(min_shi+48);
 delay(1);
 W_LCD_Dat(min_ge+48);
 delay(1);
}
void read_key()                                     //按鍵控制
{
 if(Key1==0)                                           
 {
  delay(5);
  if(Key1==0)
  {
   flag2++;
  while(!Key1);
   if(flag2==1)                    
   {
    TR0=0;                               // 計時關閉
    W_LCD_Com(0x80+0x49);
    W_LCD_Com(0x0f);
   }
  if(flag2==2)                   
  {
    W_LCD_Com(0x80+0x46);
  }
  if(flag2==3)                  
  {
   flag2=0;
   W_LCD_Com(0x0c);
   TR0=1;
  }
 }
 }
  if(flag2!=0)                  
 {
  if(Key2==0)                    
  {
   delay(5);
   if(Key2==0)                 
   {
    while(!Key2); 
    if(flag2==1)
       {
      sec++;
      sec%=60;
      display();
      W_LCD_Com(0x80+0x49); 
     }
         if(flag2==2)
      {
      min++;
      min%=60; 
      display();
     W_LCD_Com(0x80+0x46);
      }
    }   
  }   
  if(Key3==0)                    
  {
   delay(5);
   if(Key3==0)
   {
    while(!Key3);
    if(flag2==1)
    {
     sec--;
     if(sec==-1)
      sec=59;
     display();
     W_LCD_Com(0x80+0x49); 
    }
    if(flag2==2)
    {  
       min--;
     if(min==-1)
      min=59;
     display();
     W_LCD_Com(0x80+0x46); 
    }
   } 
   }
  }
}
void main()
{
 LCD_Init();
 Time_Init();
 while(1)
 {
   read_key();
  if(count==20)
  {
    count=0;   
   sec++;
  display();
  if(sec==59)
   {
    sec=0;
   beep=~beep;
   delay(200);
   min++;
   if(min==60)
   {
    min=0; 
   }
   }
  }
   if(Key0==0)        
 {
  delay(5);
  if(Key0==0)
  { 
   while(!Key0)
  sec=0;min=1;
   display();
  delay(1000);
   for(sec=59;sec>-1;sec--)
   { 
    min=0;
     display();
      delay(1000);
   }
   if(sec==0)
   {
    beep=~beep;
   }
  }
 }
 }
}
void Time0()interrupt 1
{
 TH0=(65536-50000)/256;
 TL0=(65536-50000)%256;
 count++;
}

4.總結 (1)當要用一個按鍵控制不用功能,並且一個按鍵必須作用於另一按鍵裡時,需熟練使用標誌位 這時應該構出整體框架,再細寫不同功能,例如

void read_key()                                  
{
 if(Key1==0)                                           
 {
  delay(5);
  if(Key1==0)
  {
   flag2++;
  while(!Key1);
   if(flag2==1)                    
   {  }
 if(flag2==2)                   
   {  }
  if(flag2==3)                  
   {  }
  }
 }
  if(flag2!=0)                  
  {
  if(flag2==1)
       {  }
  if(flag2==2)
      {  }
  } 
 }

詳細使用見程式碼。 這樣的好處是思路清晰,不容易搞混{} (2)常見錯誤 1)LCD顯示有問題 若LCD只顯示一排方塊,檢查引腳是否正確 若LCD一直頻閃,可能是初始化寫在while(1)裡,所以一進入迴圈就清屏 2)數字亂跳,檢查按鍵是否消抖 (3)遺留問題 1)蜂鳴器只有“噠”的一聲 2)計時時秒針會出現60 (4)PCB佈線制板 1)分模組化,最好先畫電源,因為所有VCC和GND都來自電源,可確保其不遺漏 2)線不宜過細,焊盤和焊孔不宜過小