51單片機課設,比賽計分器


本來是用匯編寫的,但是匯編屬實學的不怎么好,於是自學用C來寫,效果還不錯

比賽計分器

一、 需求分析(從用戶角度 UML

1.1 設計內容

本項目設計開發一款個比賽計分器,在重競技比賽項目中(拳擊,跆拳道),由3個裁判員對運動員評判。當一方運動員有效攻擊后,裁判員立刻給這個運動員加分。如果有2個或2個以上裁判同時(一秒內)按鍵,則給該方運動員加一分。比賽期間(2分鍾)得分多判定為勝利方。

 

1.2 設計目標

比賽計分器要實現的功能如下:

(1)能夠提供三個裁判的評分按鍵,當一秒鍾內有2個或者3個裁判按鍵,則有效分加1。 

(2)顯示1分鍾倒計時,並可以按鍵控制實踐走停,開始和結束時候有蜂鳴器響聲,時間開始響1s,時間結束響1s

(3)按下按鍵可以對兩隊進行警告,同時記錄警告次數。

(4)對誤判可以進行減分。

(5)數碼管顯示時間,得分,警告次數。

1.3實驗平台和工具

實驗平台為:keil

 

 

 

 

 

實驗工具為:89c51單片機

 

 

 

 

1.3 設計的功能分析

 單片機實現比賽計分器功能。使用單片機數碼管,獨立按鍵,蜂鳴器以及矩陣鍵盤四個模塊。數碼管用來顯示時間倒計時,雙方警告次數以及得分。蜂鳴器在開始時以及快結束前五秒時響1s。獨立按鍵k1按下開始,k2按下暫停,k3按下第一隊警告次數加1k4按下第二隊警告次數加1。矩陣按鍵s1s2s3,一秒內按下任意兩個或三個,第一隊得分加1,按下s4得分減1。矩陣按鍵s5s6s7,一秒內按下任意兩個或三個,第二隊得分加1,按下s8得分減1

1.5 設計的非功能性分析

通過本程序的設計可設計出一個簡易的比賽計分器,應用於實際生活中也是非常簡易方便的。

 

二、 總體設計

2.1總體方案設計

1)裁判按鍵設置

S1:提供裁判1對第一隊的評分按鍵

S2:提供裁判2對第一隊的評分按鍵

S3:提供裁判3對第一隊的評分按鍵

S5:提供裁判1對第二隊的評分按鍵

S6:提供裁判2對第二隊的評分按鍵

S7:提供裁判3對第二隊的評分按鍵

 

2)評分判斷設置

通過啟動定時器T0來判斷1s之內有幾個裁判按鍵,設計一個50ms的定時器,中斷20次后即為1s,若一秒鍾內有2個或者3個裁判按鍵,則有效分加1;否則,不加分。

(3) 分數顯示設置

通過P0口將分數顯示至數碼管。

(4) 減分設置

按下S4或S5第一隊或第二隊分數減1。

(5) 警告次數顯示設置

按下K3或K4,第一隊或第二隊警告次數加1。

(6) 開始,暫停設置

按下K1開始,按下K2暫停

2.2 演示支持方案(如何利用開發板資源或外接模塊,實現功能演示的方案,傳感器(或模擬)演示方案)

在單片機下載完成后,51單片機的8位動態數碼管全部顯示為0,

一二個顯示時間,三四個分別顯示兩隊警告次數,五六個顯示第一隊得分,七八個顯示第二隊得分。

在按下獨立按鍵K1后,第一二個數碼管顯示60並開始倒計時,同時蜂鳴器響1s,若按下獨立按鍵K2便暫停並且要再次按下K1才能開始。當倒計時為5s時,蜂鳴器也再次響1s。在這60s期間,矩陣按鍵s1,s2,s3在1秒內按下任意兩個第一隊得分加一,若出現誤判,按下矩陣按鍵s4使得分減一,若第一隊出現犯規可按下獨立按鍵K3便使警告次數加1。同理第二隊矩陣按鍵s5,s6,s7在1秒內按下任意兩個第二隊得分加一,若出現誤判,按下矩陣按鍵s8使得分減一,若第二隊出現犯規可按下獨立按鍵K4便使警告次數加1。

2.3 單片機資源分配設計(包括RAM資源分配,I/O資源分配)

沒有具體的要求。

三、 模塊設計與實現(介紹本課設主要模塊的設計思路,實現方法,可以通過流程圖,狀態圖,關鍵代碼,顯示效果等多種手段說明)

 

 

 

 

1.獨立按鍵模塊:

 

 

 

 

由圖可知k1對應的為p3.1口,k2對應的為p3.0口,k3對應的為p3.2口,k4對應的為p3.3口;本課設中使用到的是k1和k2按鍵,由上圖知按鍵的一端已經連接到GND,而在另一端則是通過按下來檢測,當未被按下時p3口的前四位默認為高電平,即1。按下后即為0,其中的抖動可使用延時來消除;代碼如圖:

 

 

 

 

 

  1. 動態數碼管:

 

 

 

 

首先是數碼管的片選,本次課設采用的52單片機使用的是38譯碼器,即如上圖中:通過p2.2、p2.3、p2.4三位2^3=8位來判斷使用哪一個數碼管工作(亮);例如當p2.2=1;p2.3=1;p2.4=0時,對應的十六進制數值為6,則從右往左數的第七個數碼管會亮,即圖中的LED7;具體對應關系如下圖:

P2.2

P2.3

P2.4

LED(位)

0

0

0

LED1

0

0

1

LED2

0

1

0

LED3

0

1

1

LED4

1

0

0

LED5

1

0

1

LED6

1

1

0

LED7

1

1

1

LED8

然后是數碼管模塊的數字顯示,如下圖:

 

 

 

 

數碼管電路的接法有共陰和共陽兩種,本次用的單片機里的數碼管采用的是共陰接法。
從其中取出一個數碼管進行分析

 

 

 

 


單個數碼管

此處為一個8位的數碼管,想要數碼管顯示出想要的數字,則需要對數碼管進行高低電平的設置1為高電平,0為低電平,分別對 a,b,c,d,e,f,g,dp進行1和0的編寫;

 

 

 

如圖中所示,數字2的 八位二進制就可以表示為 0101 1011,讀數為從dp依次讀到a,轉化為十六進制則是0x5b。

  1. 定時器中斷:

 

 

 

由該圖可知定時器T0的中斷入口為0BH,將中斷的子程序入口設為0BH即可。由於本課設整體就是基於時間的累加,因此核心也是定時器的計時功能。在使用定時器0工作於方式1,中斷使用定時器的溢出中斷,設置TH0、TL0初值為0D8H、0F0H,即可產生每10ms一次的溢出中斷,又定義R0為100,通過DJNZ指令達到使每過10ms*100=1s才執行對應的計時計費操作來實現功能。如圖:

 

 

 

 

  1. 蜂鳴器模塊:

 

 

 

 

 

 

蜂鳴器發聲原理是電流通過電磁線圈,使電磁線圈產生磁場來驅動振動膜發聲的,因此需要一定的電流才能驅動它,單片機IO引腳輸出的電流較小,單片機輸出的TTL電平基本上驅動不了蜂鳴器,因此需要增加一個電流放大的電路。S51增強型單片機實驗板通過一個三極管C8550來放大驅動蜂鳴器。蜂鳴器的正極接到VCC(+5V)電源上面,蜂鳴器的負極接到三極管的發射極E,三極管的基級B經過限流電阻R1后由單片機的P1.5引腳控制,當P1.5輸出高電平電磁式有源蜂鳴器,電磁式有源蜂鳴器產品質量好時,三極管T1截止,沒有電流流過線圈,蜂鳴器不發聲;當P1.5輸出低電平時,三極管導通,這樣蜂鳴器的電流形成回路,發出聲音。因此,我們可以通過程序控制P1.5腳的電平來使蜂鳴器發出聲音和關閉.程序中改變單片機P1.5引腳輸出波形的頻率,就可以調整控制蜂鳴器音調,產生各種不同音色、音調的聲音。

四、 系統集成設計(與其它系統通信、連接,和相互作用設計,參考結構,根據項目增減)

沒有使用。

五、  系統測試

5.1 系統測試

 

 

 

 

5.2 單元測試

 

 

 

 

 

 

 

 

 

 

 

 5.3非功能性測試

 

開始前;

 

 

 

 

 

 

 

 

 

 

 

開始時:

 

 

具體介紹:

 

 

 

 

六、 收獲與總結

通過本次單片機課程設計,我更加理解了實踐出真知的重要性,不僅要擁有足夠的理論知識,同時也應該懂得用於實踐,只有通過不斷反復的測試與失敗,才能獲得成功。當然,這其中也有很多問題,第一、由於對課本理論的不熟悉導致編程出現錯誤。第二,這次課設是對我的學習態度的一次檢驗。這次課設所遇到的多半問題多數都是由於我們不夠嚴謹,考慮問題全部全面,周不周到。第三,我認識到,無論做什么事情,只要你足夠堅強,有足夠的毅力與決心,有足夠的挑戰困難的勇氣,就沒有什么辦不到的。

 

附錄1原理圖

 

 

 

 

 

 

 

 

 

 

 

 

 

 

附錄2 源程序清單

#include <reg51.h>

#define uint unsigned int   //無符號化

#define uchar unsigned char

 

uchar num = 0;

sbit led0 = P2^0;   //位定義

sbit led2 = P2^2;

sbit led3 = P2^3;

sbit led4 = P2^4;

sbit beep = P1^5;

sbit K1 = P3^1;

sbit K2 = P3^0;

sbit K3 = P3^2;

sbit K4 = P3^3;

 

 

uchar  DisplayData[8];

#define GPIO_KEY P1

uchar KeyValue1=0xff; //存放讀取到的鍵值

uchar KeyValue2=0xff;

uchar KeyValue=0xff;

uint time_jsq1=0;

uint time_jsq2=0;

uchar flag_start1=0;    //記錄當前時間

uchar flag_start2=0;

uint time_start1=0;    //記錄加分開始時間

uint time_start11=0; //記錄減分開始時間

uint time_start111=0;//記錄警告開始時間

uint time_start2=0;

uint time_start22=0;

uint time_start222=0;

uint time_end1=0;      //記錄結束時間

uint time_end2=0;

 

uchar key_num1=-1;           //記錄第一次讀取到的鍵值

uchar key_num11=-1;          //記錄第二次讀取到的鍵值

uchar key_num2=-1;

uchar key_num22=-1;

uchar  num_fenshu1=0;               //記錄分數

uchar  num_fenshu2=0;

uint i=0,time=0;

uint j=0,k=0,A=0;

uint A1=0;

uint jinggao1=0,jinggao2=0;

void KeyDown(void);

uchar code duanxuan[] = {0x3f,0x06,0x5b,0x4f,   //0,1,2,3

0x66,0x6d,0x7d,0x07,   //4,5,6,7

0x7f,0x6f,0x77,0x7c,   //8,9,A,B

0x39,0x5e,0x79,0x71};   //C,D,E,F

 

 

/*******************************************************************************

* 函數名:      : fp

* 功能    : 蜂鳴器延時

*******************************************************************************/

void fp(uint i)       //蜂鳴器延時

{

while(i--);

}

 

/*******************************************************************************

* 函數名:      : delay

* 功能    : 延時函數,i=1大概1us

*******************************************************************************/

void delay(uint i)

{

while(i--);

}

 

/*******************************************************************************

* 函數名:      : Display

* 功能    : 顯示數碼管

*******************************************************************************/

void Display(int j,int k,uchar m,uchar n,int a,int b) //xianshi

{

uchar ii;

DisplayData[0]=duanxuan[j]; //duanxuan[j];

DisplayData[1]=duanxuan[k]; //duanxuan[k];

DisplayData[2]=duanxuan[m%100/10]; //duanxuan[m%100/10];

DisplayData[3]=duanxuan[m%10]; //duanxuan[m%10];

DisplayData[4]=duanxuan[n%100/10];

DisplayData[5]=duanxuan[n%10];

DisplayData[6]=duanxuan[a];

DisplayData[7]=duanxuan[b];

for(ii=0;ii<8;ii++)

{

switch(ii)//位選點亮的燈管

{

case(0):led2=1,led3=1,led4=1;break;   //1

case(1):led2=0,led3=1,led4=1;break;   //2

case(2):led2=1,led3=1,led4=0;break; //5  

case(3):led2=0,led3=1,led4=0;break;   //6

case(4):led2=1,led3=0,led4=0;break;   //7

case(5):led2=0,led3=0,led4=0;break;   //8

case(6):led2=1,led3=0,led4=1;break; //3

case(7):led2=0,led3=0,led4=1;break;   //4

}

P0=DisplayData[ii];//送到P0

delay(50); //延時

P0=0x00;//消影

 }

}

 

void main()

{

 

TMOD = 0X01;

TH0 = (65536-45872)/256; //高八位

TL0 = (65536-45872)%256; //低八位

EA = 1;          //總開關

ET0 = 1;           //定時器0

TR0 = 1;

led0 = 0;                 

if(K1==0)

time=60;

while(time!=0)

{

KeyDown();

if(num == 20)

{

num = 0;

time--;

j=time/10,k=time%10;

}

if(led0 == 0&&(time==60||time==5))

{

beep = ~beep;

fp(1);

}

Display(j,k,num_fenshu1,num_fenshu2,jinggao1,jinggao2);

 

 

 if(KeyValue1!=0xff) //按鍵是否按下

 {

   if((KeyValue1==0||KeyValue1==1||KeyValue1==2)&&flag_start1==0&&A==0&&TR0==1)

 {

   flag_start1=1;

 time_start1=time_jsq1;

 key_num1=KeyValue1;  

 KeyValue1=0xff;

 KeyValue=0xff;

 }

 if((KeyValue1==0||KeyValue1==1||KeyValue1==2)&&flag_start1==1&&key_num1!=KeyValue1&&key_num11==-1&&time_start1!=0&&TR0==1)

 {

 num_fenshu1=num_fenshu1+1;   //分數加一

 key_num11=KeyValue1;

 }

 

 if(KeyValue1==7&&time_jsq1-time_start11>=5&&num_fenshu1>0&&TR0==1)

 {

 time_start11=time_jsq1;

 num_fenshu1=num_fenshu1-1;  //減分

 KeyValue1=0xff;

 KeyValue=0xff;

 }

 }

 if(time_jsq1-time_start1>20||TR0==0)//大於1s全部恢復初值進行下一次

 {

 A=0;

   time_start1=0;

 time_end1=0;

 flag_start1=0;

 key_num11=-1;

 key_num1=-1;

 KeyValue1=0xff;

 KeyValue=0xff;

 }  

 

 if(KeyValue2!=0xff) //同上

 {

   if((KeyValue2==3||KeyValue2==4||KeyValue2==5)&&flag_start2==0&&A1==0&&TR0==1)

 {

   flag_start2=1;

 time_start2=time_jsq2;

 key_num2=KeyValue2;  

 KeyValue2=0xff;

 }

 if((KeyValue2==3||KeyValue2==4||KeyValue2==5)&&flag_start2==1&&key_num2!=KeyValue2&&key_num22==-1&&time_start2!=0&&TR0==1)

 {

 num_fenshu2=num_fenshu2+1;   

 key_num22=KeyValue2;

 }

 if(KeyValue2==6&&time_jsq2-time_start22>=5&&num_fenshu2>0&&TR0==1)

 {

 time_start22=time_jsq2;

 num_fenshu2=num_fenshu2-1;

 KeyValue2=0xff;

 }

 }

 if(time_jsq2-time_start2>20||TR0==0)

 {

 A1=0;

   time_start2=0;

 time_end2=0;

 flag_start2=0;

 key_num22=-1;

 key_num2=-1;

 KeyValue2=0xff;

 }

 

 if(K2==0)

 {

 beep = ~beep;

 fp(10);

 TR0=0;

 }

  if(K1==0)

 {

 beep = ~beep;

 fp(10);

 TR0=1;

 }

 

 

 if(K3==0&&time_jsq1-time_start111>=5&&TR0==1)  //A隊警告

 {

 time_start111=time_jsq1;

 jinggao1=jinggao1+1;

 if(jinggao1>9)

 {

 jinggao1=15;

 break;

 }

 }

 

 if(K4==0&&time_jsq2-time_start222>=5&&TR0==1)  //B隊警告

 {

   time_start222=time_jsq2;

 jinggao2=jinggao2+1;

 if(jinggao2>9)

 {

 jinggao2=15;

 break;

 }

 }

 

}

 

 

for(i=1;i>=0;i++)    //結束后顯示

{

Display(j,k,num_fenshu1,num_fenshu2,jinggao1,jinggao2);

if(K1==0)

break;

}

 

 

}

 

 

/*******************************************************************************

* 函數名:      : TR0_time

* 功能    : 定時器中斷,每溢出一次0.05s

*******************************************************************************/

void TR0_time() interrupt 1 //dingshiqizhongduan

{

TH0 = (65536-45872)/256;

TL0 = (65536-45872)%256;

num++;

  time_jsq1++;

  time_jsq2++;

}

 

/*******************************************************************************

* 函數名        : KeyDown

* 功能    : 判斷按下哪個按鍵

*******************************************************************************/

void KeyDown(void)

{

char a=0;

GPIO_KEY=0x0f;

if(GPIO_KEY!=0x0f)//判斷是否按下

{

delay(10);//延時消抖

if(GPIO_KEY!=0x0f)//再次判斷是否按下

{

//

GPIO_KEY=0X0F;

switch(GPIO_KEY)

{

case(0X07): KeyValue=0;break;

case(0X0b): KeyValue=1;break;

case(0X0d): KeyValue=2;break;

case(0X0e): KeyValue=7;break;

}

//

GPIO_KEY=0XF0;

switch(GPIO_KEY)

{

case(0X70): KeyValue1=KeyValue;break;

}

 

}

 

if(GPIO_KEY!=0x0f)//同上

{

delay(10);

if(GPIO_KEY!=0x0f)

{

 

GPIO_KEY=0X0F;//低四位全置1

switch(GPIO_KEY)

{

case(0X07): KeyValue2=0;break;

case(0X0b): KeyValue2=1;break;

case(0X0d): KeyValue2=2;break;

case(0X0e): KeyValue2=3;break;

}

GPIO_KEY=0XF0;

switch(GPIO_KEY)

{

case(0Xb0): KeyValue2=KeyValue2+3;break;

}

 

}

}

 

}

while((a<50)&&(GPIO_KEY!=0xf0))  //判斷是否松開

{

a++;

}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM