專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機教程網(wǎng) >> MCU設(shè)計實例 >> 瀏覽文章

單片機開源項目之Stopwatch數(shù)碼管顯示-實用秒表

作者:寒竹子   來源:本站原創(chuàng)   點擊數(shù):  更新時間:2014年05月02日   【字體:

此程序是在51hei單片機開發(fā)板上面做的,如需要移植到自己的電路上,修改相應(yīng)的端口即可,開發(fā)板完整的電路圖下載:  點這里 (注意:只需要看相關(guān)部分即可,其他部分可以忽略)

/**
  ****************************************************************************************
  *file   :   main.c
  *author :   xr
  *date   :   2014年4月15日10:08:26 - 2014年4月15日12:40:51
  *version:   V1.2.3
  *brief  :   Stopwatch數(shù)碼管顯示-實用秒表   單片機STC89C52RC MCU 晶振 11.0592MHZ
  ****************************************************************************************
  */
#include <reg52.h>

//74HC138
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//矩陣按鍵
sbit KEY_IN_1 = P2^4;//列
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
//數(shù)碼管編碼
unsigned char code LedTable[] = {
    0xC0,  //"0"
                0xF9,  //"1"
                0xA4,  //"2"
                0xB0,  //"3"
                0x99,  //"4"
                0x92,  //"5"
                0x82,  //"6"
                0xF8,  //"7"
                0x80,  //"8"
                0x90,  //"9"
                0x88,  //"A"
                0x83,  //"B"
                0xC6,  //"C"
                0xA1,  //"D"
                0x86,  //"E"
                0x8E   //"F"
   };
//數(shù)碼管顯示緩沖區(qū)
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
bit flag10ms = 0;//10ms標(biāo)志位
bit stopwatchRunning = 0;//秒表啟動和停止標(biāo)志
unsigned char thr0, tlr0;//T0重載值的高低字節(jié)
unsigned char decimal = 0;//小數(shù)位
unsigned int  integer = 0;//整數(shù)位
static unsigned char volatile KeySta[4] = {1, 1, 1, 1}; //保存按鍵的當(dāng)前值(static 保存在靜態(tài)存儲區(qū),加上volatile關(guān)鍵字使KeySta[i]的值每次都從靜態(tài)存儲區(qū)讀取,避免讀取錯誤!)
/****************function definition**********************/
void Initial();
void ConfigTimer0(unsigned long xms);
void StopwatchDisplay();
void KeyAction();
/*主程序main()*/
void main(void)
{
 Initial();
 ConfigTimer0(1);//定時1ms
 while (1)
 {
  KeyAction();       //檢測按鍵動作
  if (flag10ms)      //10ms檢測秒表的運行狀態(tài),當(dāng)stopwatchRunning標(biāo)志=1時進行計時++,否則就停止計時
  {
   flag10ms = 0;
   if (stopwatchRunning)  //10ms刷新秒表計數(shù)
   {
    decimal++;
    if (decimal >= 100)
    {
     decimal = 0;
     integer++;
     if (integer >= 10000)
     {
      integer = 0;
     }
    }
    StopwatchDisplay();//分解decimal和integer,存入LedBuff數(shù)碼管緩沖區(qū) 
   }
  }
 }
}
/*程序初始化*/
void Initial()
{
 ADDR3 = 1;
 ENLED = 0;//選擇數(shù)碼管
 P2 = 0xFE;  //選擇第四行按鍵檢測(原理圖上是第四列)
 P0 = 0xFF;//默認(rèn)關(guān)閉段選
 LedBuff[0] = LedTable[decimal % 10];  //初始顯示0.00
 LedBuff[1] = LedTable[decimal / 10 % 10];
 LedBuff[2] = LedTable[integer % 10];
 LedBuff[2] &= 0x7F;//點亮小數(shù)點
}
/*配置定時器T0*/
void ConfigTimer0(unsigned long xms)
{
 unsigned long tmp;//32bit 注意:此處必須用unsigned long 數(shù)據(jù),因為11059200已經(jīng)超出了16位unsigned int
 tmp = 11059200/12;//單片機的機器周期頻率
 tmp = (tmp * xms) / 1000;//定時xms所需的頻率
 tmp = 65536-tmp;//定時xms的初始裝載值
 tmp += 18;  //補償值
 thr0 = (unsigned char)(tmp >> 8);
 tlr0 = (unsigned char)tmp;
 TMOD &= 0xF0;//清零T0控制位
 TMOD |= 0x01;//配置T0工作在方式1,16位可設(shè)定定時器
 TH0 = thr0;
 TL0 = tlr0;
 TR0 = 1;
 ET0 = 1;
 EA  = 1;  
}
/*數(shù)碼管刷新*/
void LedCharRefresh()
{
 static unsigned char j = 0;
 P0 = 0xFF;//消隱
 P1 = (P1 & 0xF8) | j;//先清零P1口低三位,再|(zhì)j
 P0 = LedBuff[j++];
 if (j > 5)
  j = 0;
}
/*分解decimal和integer,存入LedBuff數(shù)碼管緩沖區(qū)*/
void StopwatchDisplay()
{
 signed char i = 0;
 unsigned char buf[6];
 buf[0] = decimal % 10;
 buf[1] = decimal / 10 % 10;
 buf[2] = integer % 10;
 buf[3] = integer / 10 % 10;
 buf[4] = integer / 100 % 10;
 buf[5] = integer / 1000 % 10;
 for (i = 5; i >= 3; i--)    //去掉無效位
 {
  if (buf[i] == 0)
   buf[i] = 0xFF;
  else
   break;
 }
 //處理有效位
 for (; i >=0; i--)
 {
  buf[i] = LedTable[buf[i]]; //轉(zhuǎn)為實際的數(shù)字
 }
 //拷貝
 for (i = 0; i <= 5; i++)
 {
  LedBuff[i] = buf[i];//拷貝到顯示緩沖區(qū)
 }
 LedBuff[2] &= 0x7F;//點亮小數(shù)點
}
/*秒表啟動和停止*/
void StopwatchAction()
{
 if (stopwatchRunning)   //當(dāng)前狀態(tài)為運行
 {
  stopwatchRunning = 0;  //停止運行
 }
 else
 {
  stopwatchRunning = 1;  //啟動
 }
}
/*秒表復(fù)位*/
void StopwatchReset()
{
 stopwatchRunning = 0;//停止秒表計時
 decimal = 0;
 integer = 0;//清零
 StopwatchDisplay();//顯示
}
/*按鍵動作*/
void KeyAction()
{
    static unsigned char keybackup[4] = {1, 1, 1, 1};//按鍵的備份值(前一次按鍵值) 必須是靜態(tài)的
 unsigned char i = 0;
 for (i = 0; i < 4; i++)
 {
  if (keybackup[i] != KeySta[i])  //按鍵的上一次的狀態(tài)和當(dāng)前狀態(tài)不相同,即按鍵有動作
  {
   if (keybackup[i] != 0) //如果上一次按鍵的值是1,則此時按鍵是按下動作
   {
    switch (i)
    {
     case 1: StopwatchReset();  break;   //ESC鍵秒表復(fù)位
     case 2: StopwatchAction(); break; //Enter鍵控制秒表的啟動和停止
     default: break;
    }
   }
   keybackup[i] = KeySta[i];//備份當(dāng)前按鍵值
  }
 }
}
/*按鍵掃描函數(shù)*/
void KeyScan()
{
 static unsigned char KeyBuf[4] = {0xFF, 0xFF, 0xFF, 0xFF}; //按鍵掃描緩沖區(qū)
 unsigned char i = 0;
 
 //檢測一行按鍵的狀態(tài)并存入按鍵檢測緩沖區(qū)中
 KeyBuf[0] = (KeyBuf[0] << 1) | KEY_IN_1;
 KeyBuf[1] = (KeyBuf[1] << 1) | KEY_IN_2;
 KeyBuf[2] = (KeyBuf[2] << 1) | KEY_IN_3;
 KeyBuf[3] = (KeyBuf[3] << 1) | KEY_IN_4;
 //更新消抖后按鍵的值(1ms檢測一次,8ms檢測)
 for (i = 0; i < 4; i++)
 {
  if ((KeyBuf[i] & 0xFF) == 0x00)
   KeySta[i] = 0;//8次檢測按鍵狀態(tài)都是0,即按鍵穩(wěn)定按下
  else if ((KeyBuf[i] & 0xFF) == 0xFF)
   KeySta[i] = 1;//8次檢測按鍵的狀態(tài)都是1,即按鍵穩(wěn)定彈起
 }
}
/*定時器Timer0中斷服務(wù)*/
void Timer0_ISP() interrupt 1
{
 static unsigned char counter = 0;//計數(shù)器
 TH0 = thr0;
 TL0 = tlr0;//重新裝載定時器初值
 counter++;
 LedCharRefresh();//數(shù)碼管刷新
 KeyScan();   //按鍵掃描
 if (counter >= 10)
 {
  counter = 0;
  flag10ms = 1;
 }
}
關(guān)閉窗口

相關(guān)文章