標(biāo)題: 單片機(jī)秒表 可以實(shí)現(xiàn)開始、暫停、復(fù)位功能 求指導(dǎo)記錄和查看功能 [打印本頁]

作者: 1556544    時(shí)間: 2023-11-12 17:22
標(biāo)題: 單片機(jī)秒表 可以實(shí)現(xiàn)開始、暫停、復(fù)位功能 求指導(dǎo)記錄和查看功能
多功能秒表系統(tǒng)設(shè)計(jì)
設(shè)計(jì)要求:
(1)兩位LED顯示,顯示時(shí)間為00~99秒。
(2)具有開始、暫停、復(fù)位功能。
(3)在秒表工作過程中能通過按鍵多次(不少于4次)記錄當(dāng)前的時(shí)間。
(4)可以通過按鈕查看記錄的時(shí)間 。
本人現(xiàn)在可以實(shí)現(xiàn)開始、暫停、復(fù)位功能,后面的記錄和查看功能有沒有哪位大佬可以幫忙改一下。求求了。
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit w0=P2^0;
sbit w1=P2^1;

sbit s1=P3^4;      //啟動(dòng)
sbit s2=P3^5;     //暫停
sbit s3=P3^6;     //清零
sbit s4=P3^7;     //記錄
sbit s5=P3^3;     //查詢

unsigned char recordTimes[4]; // 記錄的時(shí)間,長度為4
uchar count=0;        //對50ms定時(shí)時(shí)間進(jìn)行計(jì)數(shù)   
uchar miao=0;       //秒計(jì)數(shù)器
uchar j,k;
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//共陰極
void timedr0init()
{
  TMOD=0x01;
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        TR0=0;
        ET0=1;
        EA=1;
}
void delay(unsigned char i)
{
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}                           //延時(shí)
void display(uchar n)
{
   uchar c,d;
   c=n/10;
   d=n%10;
   P0=0x00;        //xiao
   P0=table[c];
   w0=0,w1=1;
   delay(5);

   P0=0x00;
   P0=table[d];
   w1=0,w0=1;
   delay(5);
                                              // P0=table[n/10];w0=0,w1=1;
                                        // P0=tabie[n%10];w0=1,w1=0;        
}
void scankeys()
{static bit recordFlag = 0;     //聲明了一個(gè)靜態(tài)的位變量 recordFlag,并將其初始化為 0
        static unsigned char recordIndex = 0;//靜態(tài)無字符變量

if(s1==0)//啟動(dòng)
{
TR0=1;                  
}
if(s2==0)//暫停
{
TR0=0;                  
}
if(s3==0)//清零
{
TR0=0,miao=count=0;                  
}

        if (s4 == 0) {  // 記錄
        if (!recordFlag && recordIndex < 4) {
            recordFlag = 1;

                recordTimes[recordIndex++] = miao;
                                                                while (s4 == 0);
                                                                delay(100); // 等待按鍵釋放,防止重復(fù)記錄

        }
    }
                else {
        recordFlag = 0;
    }

    if (s5 == 0) {  // 查看記錄
        if (recordIndex > 0)
                                        {
            uchar i;
            for (i = 0; i < recordIndex; i++)
                                        {
                display(recordTimes[ i]);
                delay(100);
                                        }
                                }
                        }                        
                }
void main()
{
       timedr0init();

        while(1)
        {
        display(miao);
                                        scankeys();

    }
}

void time0() interrupt 1
{       TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        count++;
        if(count==20)
        {
            count=0;
                                          miao++;
            if(miao==100)
            miao=0;        

        }

}

51hei.png (70.26 KB, 下載次數(shù): 50)

51hei.png

作者: wulin    時(shí)間: 2023-11-12 20:12
按下記錄鍵,緩存recordTimes[3]=recordTimes[2];recordTimes[2]=recordTimes[1];recordTimes[1]=recordTimes[0];全部后移,再將當(dāng)前秒數(shù)存在recordTimes[0]。始終保存最近4次的記錄
作者: 1556544    時(shí)間: 2023-11-12 21:03
wulin 發(fā)表于 2023-11-12 20:12
按下記錄鍵,緩存recordTimes[3]=recordTimes[2];recordTimes[2]=recordTimes[1];recordTimes[1]=recordTim ...

大佬,程序添加在哪里,求指導(dǎo),純新手,不是特別熟練

作者: 1556544    時(shí)間: 2023-11-12 21:27
wulin 發(fā)表于 2023-11-12 20:12
按下記錄鍵,緩存recordTimes[3]=recordTimes[2];recordTimes[2]=recordTimes[1];recordTimes[1]=recordTim ...

if (s4 == 0) {  // 記錄
        if (!recordFlag && recordIndex < 4) {
            recordFlag = 1;

            // 將記錄后移
            for ( i = 3; i > 0; i--) {
                recordTimes[ i] = recordTimes[i-1];
            }
            // 記錄當(dāng)前時(shí)間
            recordTimes[0] = miao;

            while (s4 == 0);
            delay(100); // 等待按鍵釋放,防止重復(fù)記錄
        }
    } else {
        recordFlag = 0;
    }
作者: 1556544    時(shí)間: 2023-11-12 21:38
wulin 發(fā)表于 2023-11-12 20:12
按下記錄鍵,緩存recordTimes[3]=recordTimes[2];recordTimes[2]=recordTimes[1];recordTimes[1]=recordTim ...

求大佬指導(dǎo),純萌新

作者: 大漠落日    時(shí)間: 2023-11-12 22:08
建產(chǎn)數(shù)組存儲(chǔ)數(shù)據(jù),再修改按鍵程序,上下翻看
作者: yzwzfyz    時(shí)間: 2023-11-14 09:50
本帖最后由 yzwzfyz 于 2023-11-15 09:36 編輯

1、建立一個(gè)二維數(shù)組【P,2】,P記錄你歷史上記錄的秒表數(shù)據(jù)是第幾個(gè)。2秒表讀數(shù)0-99。
2、建立三個(gè)指針P1\P2\P3:P1=當(dāng)前的秒表P號,P2=【記錄】按鍵指向的P號,P3=【查詢】按鍵指向的P號。
3、顯示程序,只從【P1,2】取數(shù)字顯示,也即只顯示P1所指向的數(shù)據(jù)。
鍵操作:
1、按下【記錄】鍵:P2=P2+1(表示進(jìn)行到第幾個(gè)記錄了),P1=P2(顯示指向新的P2記錄)。
2、按下【查詢】鍵:P3=P3+1(表示查詢到第幾個(gè)記錄了),P1=P3(對查詢到的記錄進(jìn)行顯示)。
3、按下【開始、清0、暫定】鍵:加一條 P1 = P2 (顯示改為【記錄】所指定的記錄號,并在此記錄上進(jìn)行操作,這樣保證【查詢】后,能回到之前的記錄號,不致混亂),其它操作與你的定義相同。
如此:
能讓你記錄到P組秒表數(shù)據(jù)(循環(huán)使用1-P),做到P組數(shù)據(jù)互不干擾,可查可詢,且查詢不影響當(dāng)前的操作,甚至在讀秒時(shí)查詢也不影響當(dāng)前的秒表計(jì)秒工作。

作者: 鵜鶘    時(shí)間: 2023-11-14 11:19
他已經(jīng)建立數(shù)組了,只是沒必要二維吧,序號就可以作為記錄的數(shù)據(jù)是第幾個(gè)。問題是他這個(gè)程序?qū)嵲谑翘銖?qiáng)了,直接驅(qū)動(dòng)數(shù)碼管不是這種方法,他的 display 函數(shù)這樣寫是不對的,只能在不按S4和S5的情況下正常,但也只是看似正常,這就是我說的“勉強(qiáng)”的意思,當(dāng)按下S4或S5時(shí),在按下的這段時(shí)間里有一個(gè)數(shù)碼管會(huì)滅,而亮的那個(gè)數(shù)碼管會(huì)保持,不會(huì)變化,尤其是S4,只要不抬起來一直保持這樣不變,這恐怕并不是你需要的功能吧,按下S5鍵情況就更復(fù)雜了,按下不動(dòng)基本上是亂顯示,這取決于你的delay函數(shù),delay(100)究竟會(huì)延遲多長時(shí)間,如果時(shí)間很短,那就是亂顯示,如果時(shí)間很長比如超過0.5秒,會(huì)看到兩個(gè)數(shù)碼管閃亮幾次,次數(shù)由記錄的次數(shù)決定,最多4次,閃亮的時(shí)間很短由display函數(shù)中的delay(5);決定,基本也看不清,如果按著S5不放就是這個(gè)過程反復(fù)循環(huán)。

由這個(gè)分析能夠猜出你的用意,想的是挺美,但這個(gè)程序做不到,僅僅是秒表勉強(qiáng)能用。要修改的話,量也不是很大,但框架就變了。。。
作者: 1556544    時(shí)間: 2023-11-14 21:19
鵜鶘 發(fā)表于 2023-11-14 11:19
他已經(jīng)建立數(shù)組了,只是沒必要二維吧,序號就可以作為記錄的數(shù)據(jù)是第幾個(gè)。問題是他這個(gè)程序?qū)嵲谑翘銖?qiáng)了 ...

大佬,可以幫忙修改一下嗎,新手不是特別懂
作者: 1556544    時(shí)間: 2023-11-14 21:26
1556544 發(fā)表于 2023-11-14 21:19
大佬,可以幫忙修改一下嗎,新手不是特別懂

上面呢位大佬講的二維數(shù)組沒有聽說過,剛學(xué)得新手
作者: 鵜鶘    時(shí)間: 2023-11-15 21:30
原理更重要吧,清楚了原理怎樣做是很自由的,我先把原理說下,一個(gè)修改方案提供給你,你也不必照搬的,可隨意修改試驗(yàn)。

這種LED數(shù)碼管的直接驅(qū)動(dòng)都是以掃描方式實(shí)現(xiàn)的,且掃描的頻率要穩(wěn)定不受其他程序部分的干擾,你的程序之所以僅在秒表時(shí)看起來正常,是因?yàn)樗褪窃诳焖僦貜?fù)掃描,但你這種掃描太易受到干擾而停頓,即在主函數(shù)的while中循環(huán),當(dāng)你不按按鍵或只按s1-s3時(shí),scankeys可以快速返回,顯示會(huì)連續(xù),但按下s4或者s5我上面那貼說過因?yàn)檠舆t和判斷是否抬起它就會(huì)延遲返回或者按著不放它就不返回,顯示就不正常。

所以這種數(shù)碼管的顯示一般都是分兩個(gè)部分,驅(qū)動(dòng)和賦值是分開的,驅(qū)動(dòng)部分只是將顯示緩沖區(qū)的內(nèi)容依次輪換送數(shù)碼管顯示,而向顯示緩沖區(qū)賦值是另一部分,可以在程序的任何地方、任何時(shí)候執(zhí)行(在這里顯示緩沖區(qū)就是c、d兩個(gè)無符號字符變量)。驅(qū)動(dòng)部分又必須等頻率不斷重復(fù)執(zhí)行,這樣數(shù)碼管才會(huì)看起來常亮且不受干擾而停頓,要做到這點(diǎn)驅(qū)動(dòng)部分就只能放在計(jì)時(shí)器的中斷程序里,這樣,你的display函數(shù)就要修改,把它分成兩部分,計(jì)算和賦值部分(實(shí)際只有兩句)留下,其余都移到中斷程序中。

但這還不夠,引起這個(gè)中斷的是計(jì)時(shí)器,而你啟停秒表是靠啟停這個(gè)計(jì)時(shí)器實(shí)現(xiàn)的,這又不行,因?yàn)橛?jì)時(shí)器一停中斷就消失,數(shù)碼管沒了驅(qū)動(dòng)就立即不亮了,所以這個(gè)也要改,計(jì)時(shí)器只要一上電初始化后就必須立即工作直到斷電,這樣才能使顯示驅(qū)動(dòng)不停地等間隔刷新數(shù)碼管,并且頻率要足夠高以使眼睛覺察不出閃爍。這又引來了一個(gè)問題,看你的程序參數(shù),你用的是12兆的晶振,計(jì)時(shí)器0,模式1,中斷頻率是20Hz,作為秒表用,這個(gè)沒問題,但兼作顯示驅(qū)動(dòng)頻率太低,數(shù)碼管肯定會(huì)閃,,,所以兼顧編程方便和人眼的視覺暫留特性,這個(gè)頻率應(yīng)該提高到100Hz,為此 timedr0init 函數(shù)中的50000應(yīng)改成10000,對應(yīng)的,中斷函數(shù)中的 if(count==20)改成 if(count==100),即每100次中斷為一秒到。由于計(jì)時(shí)器一上電初始化后就要立即工作,所以這個(gè)函數(shù)中的另一處TR0=0;要改成TR0=1;。既然TR0不能再=0了,那么啟停秒表就用更常規(guī)的辦法:設(shè)置一個(gè)全局的標(biāo)志位,比如Bit Stop_run,加在程序頭部的說明區(qū)中;而且作為顯示緩沖區(qū)的變量c、d也要全局化,因?yàn)橹骱瘮?shù)要向它賦值,中斷函數(shù)也要用到它,為此將他倆的定義從display函數(shù)中取出也放置在此處。啟停秒表就靠標(biāo)志位Stop_run被置1/清零來實(shí)現(xiàn),置1表示秒表啟動(dòng);清零表示暫停/停止,反過來當(dāng)然也可以,,,相應(yīng)的中斷程序中miao++;和下面的兩句改為:

if (Stop_run)
  {
     miao++;
     if(miao==100) miao=0;
  }

如果Stop_run的01定義與此相反的話前面加個(gè)非號就行了。Stop_run的置1/清零就用你的scankeys函數(shù)中的s1-s3處理語句來執(zhí)行,將TR0=0或1改成相應(yīng)的Stop_run=0或1。

另外,你也沒說你想達(dá)到什么目的,秒表就不用說了,主要是回顯那幾個(gè)記錄值用什么方式、要達(dá)到什么效果,根據(jù)你貼出的程序看,你大概想以這樣的方式回顯:按下s5健,就立即在數(shù)碼管上依次顯示所有記錄值,每個(gè)記錄值顯示的時(shí)間由delay(100);控制。你的display函數(shù)在scankeys函數(shù)中的這種用法根本達(dá)不到目的,且邏輯還很混亂,并且delay函數(shù)的性能究竟怎樣,delay(100)究竟能延時(shí)多長時(shí)間這都不知道,直覺看它遠(yuǎn)不會(huì)達(dá)到1秒,如果你真想用這種方式回顯,那么每個(gè)記錄值顯示的時(shí)間怎么也應(yīng)該超過1秒吧。

根據(jù)這些條件我給你提供一個(gè)修改方案供你參考:

在變量聲明區(qū)后面再附加兩句:

bit stp_run=0;
uchar c,d,timer;



函數(shù)timedr0init改為:

void timedr0init()
{
  TMOD=0x01;
        TH0=(65536-10000)/256;
        TL0=(65536-10000)%256;
        TR0=1;
        ET0=1;
        EA=1;
}



增加一個(gè)延時(shí)函數(shù):

void wait(unsigned char t)//t單位為10ms,當(dāng)t=200時(shí),即延時(shí)2秒。
  {
    timer=0;
    while (timer<t);
   }



函數(shù)display改為:

void display(uchar n)
{
   c=n/10;
   d=n%10;
}



函數(shù)scankey改為:

void scankeys()
{static bit recordFlag = 0;     //聲明了一個(gè)靜態(tài)的位變量 recordFlag,并將其初始化為 0
        static unsigned char recordIndex = 0;//靜態(tài)無字符變量

if(s1==0)//啟動(dòng)
{
stp_run=1;                  
}
if(s2==0)//暫停
{
stp_run=0;                  
}
if(s3==0)//清零
{
stp_run=miao=count=0;                  
}

        if (s4 == 0) {  // 記錄
        if (!recordFlag && recordIndex < 4) {
            recordFlag = 1;

                recordTimes[recordIndex++] = miao;
                                                                while (s4 == 0);
                                                                delay(100); // 等待按鍵釋放,防止重復(fù)記錄

        }
    }
                else {
        recordFlag = 0;
    }

    if (s5 == 0) {  // 查看記錄
        if (recordIndex > 0)
                                        {
            uchar i;
            for (i = 0; i < recordIndex; i++)
                                        {
                display(recordTimes[ i]);
                wait(150);        //延時(shí)1.5秒,即每個(gè)數(shù)字顯示1.5秒。
                                        }
                                }
                        }                        
                }



中斷程序改動(dòng)比較大,但大部分代碼可以復(fù)制/粘貼過來:

void time0() interrupt 1
{
        static bit dp;
        TH0=(65536-10000)/256;
        TL0=(65536-10000)%256;
        P0=0x00;        //xiao
        timer++;
        count++;
        if(count==100)
        {
           count=0;
           if (stp_run)
             {
                miao++;
                if (miao==100) miao=0;
             }

        }
        if (dp=~dp)
          {
             P0=table[c];
             w0=0,w1=1;
          }
         else
         {
             P0=table[d];
             w1=0,w0=1;
         }
}


未提及的,就保留原文。
作者: 1556544    時(shí)間: 2023-11-16 10:47
鵜鶘 發(fā)表于 2023-11-15 21:30
原理更重要吧,清楚了原理怎樣做是很自由的,我先把原理說下,一個(gè)修改方案提供給你,你也不必照搬的,可隨 ...

太牛了,大佬
作者: 鵜鶘    時(shí)間: 2023-11-17 15:27
呵呵你試沒試,結(jié)果怎樣?你是不是這個(gè)意思,達(dá)沒達(dá)到目的?
另外,我的那個(gè)中斷程序中前半部分不甚合理,應(yīng)該把對stp_run的判斷放在最外層,還有就是count和miao的+1都沒不要單獨(dú)存在,都可以合并到條件判斷中,這樣程序就更簡潔清晰,也更符合C風(fēng)范:

void time0() interrupt 1
{
  static bit dp;
  TH0=(65536-10000)/256;
  TL0=(65536-10000)%256;
  P0=0x00;        //xiao
  timer++;
  if (stp_run)
    {
       if(++count==100)
         {
            count=0;
            if (++miao==100)
              {
                 miao=0;
              }
         }
    }
  if (dp=~dp)
    {
       P0=table[c];
       w0=0,w1=1;
    }
   else
    {
       P0=table[d];
       w1=0,w0=1;
    }
}
作者: 1556544    時(shí)間: 2023-11-21 13:33
鵜鶘 發(fā)表于 2023-11-17 15:27
呵呵你試沒試,結(jié)果怎樣?你是不是這個(gè)意思,達(dá)沒達(dá)到目的?
另外,我的那個(gè)中斷程序中前半部分不甚合理, ...

試了,符合我想的功能





歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1