基於STM32的八路搶答器仿真


              基於STM32的八路搶答器仿真

一、硬件說明:

  最小系統采用了STM32F4xx系列的,PB8~15分別連接了八個按鈕,八個按鈕模擬八位選手搶答,PE8~15連接了八盞LED燈,按鈕采用上拉電阻的,將按鈕作為中斷源,所有中斷全設置為同一優先級,設置的低電平觸發模式;觸發中斷后,對應的燈會閃爍。

二Proteus仿真原理圖:

 

 三、代碼部分:

3.1主函數:

 1 #include "stm32f4xx.h"
 2 #include "delay.h"
 3 #include "led.h"
 4 #include "exti.h"
 5 char led_status = 0;                                            //聲明一個表示LED燈狀態的變量
 6 int led_count = 0;                                                                                            //聲明一個表示LED按下次數的變量
 7 unsigned char led_now = 0;                                                                            //聲明一個當前按下的LED燈變量
 8 
 9 void main(void)
10 {
11   led_init();                                                   //初始化LED控制管腳
12   exti_init();                                                  //初始化按鍵檢測管腳
13   while(1){                                                     //循環體
14         if (led_count > 1){                                                                                    //判斷按鍵按下次數
15             continue;
16         }else if (led_count == 1){                                                                    //第一名
17             flash_4Hz(led_now);
18         }
19         
20   }
21 } 

3.2 led函數:

  1 #include "led.h"
  2 #include "delay.h"
  3 /*********************************************************************************************
  4 * 名稱:led_init
  5 * 功能:初始化LED對應的GPIO
  6 * 參數:無
  7 * 返回:無
  8 * 修改:
  9 * 注釋:
 10 *********************************************************************************************/
 11 void led_init(void)                                                            //初始化led
 12 {
 13   GPIO_InitTypeDef  GPIO_InitStructure;                    
 14   
 15   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);        //使能GPIO時鍾
 16   
 17   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_8 | GPIO_Pin_9 |
 18                                 GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_10 | GPIO_Pin_11;        //選中引腳
 19     
 20   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                 //輸出模式
 21   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                //推挽輸出
 22   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;              //輸出速度2MHz
 23   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;              //無上下拉
 24   GPIO_Init(GPIOE, &GPIO_InitStructure);                        //根據上述參數配置GPIOE0、GPIOE1、GPIOE2、GPIOE3
 25   GPIO_SetBits(GPIOE, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_8 | GPIO_Pin_9 |
 26                       GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_10 | GPIO_Pin_11);
 27 }
 28 
 29 /*********************************************************************************************
 30 * 名稱:turn_off
 31 * 功能:置引腳高電平,關閉LED
 32 * 參數:led
 33 * 返回:無
 34 * 修改:
 35 * 注釋:
 36 *********************************************************************************************/
 37 void turn_off(unsigned char led){                                //關閉led
 38   if(led & D1)                                                  //判斷LED選擇
 39     GPIO_SetBits(GPIOE, GPIO_Pin_8);                            //PE0置引腳高電平,關閉D1
 40   if(led & D2)
 41     GPIO_SetBits(GPIOE, GPIO_Pin_9);                            //PE1置引腳高電平,關閉D2
 42   if(led & D3)
 43     GPIO_SetBits(GPIOE, GPIO_Pin_10);                            //PE2置引腳高電平,關閉D3
 44   if(led & D4)
 45     GPIO_SetBits(GPIOE, GPIO_Pin_11);                            //PE3置引腳高電平,關閉D4
 46     
 47     if(led & D5)                                                  //判斷LED選擇
 48     GPIO_SetBits(GPIOE, GPIO_Pin_12);                            //PE0置引腳高電平,關閉D1
 49   if(led & D6)
 50     GPIO_SetBits(GPIOE, GPIO_Pin_13);                            //PE1置引腳高電平,關閉D2
 51   if(led & D7)
 52     GPIO_SetBits(GPIOE, GPIO_Pin_14);                            //PE2置引腳高電平,關閉D3
 53   if(led & D8)
 54     GPIO_SetBits(GPIOE, GPIO_Pin_15);                            //PE3置引腳高電平,關閉D4
 55 }
 56 
 57 /*********************************************************************************************
 58 * 名稱:turn_on
 59 * 功能:置引腳低電平,打開LED
 60 * 參數:led
 61 * 返回:無
 62 * 修改:
 63 * 注釋:
 64 *********************************************************************************************/
 65 void turn_on(unsigned char led){                                //打開led
 66   if(led & D1)                                                  //判斷LED選擇
 67     GPIO_ResetBits(GPIOE, GPIO_Pin_8);                          //PE0置引腳低電平,打開D1
 68   if(led & D2)
 69     GPIO_ResetBits(GPIOE, GPIO_Pin_9);                          //PE1置引腳低電平,打開D2
 70   if(led & D3)
 71     GPIO_ResetBits(GPIOE, GPIO_Pin_10);                          //PE2置引腳低電平,打開D3
 72   if(led & D4)
 73     GPIO_ResetBits(GPIOE, GPIO_Pin_11);                          //PE3置引腳低電平,打開D4
 74     
 75     if(led & D5)                                                  //判斷LED選擇
 76     GPIO_ResetBits(GPIOE, GPIO_Pin_12);                          //PE0置引腳低電平,打開D1
 77   if(led & D6)
 78     GPIO_ResetBits(GPIOE, GPIO_Pin_13);                          //PE1置引腳低電平,打開D2
 79   if(led & D7)
 80     GPIO_ResetBits(GPIOE, GPIO_Pin_14);                          //PE2置引腳低電平,打開D3
 81   if(led & D8)
 82     GPIO_ResetBits(GPIOE, GPIO_Pin_15);         
 83 }
 84 /*********************************************************************************************
 85 * 名稱:get_led_status
 86 * 功能:獲取LED狀態
 87 * 參數:
 88 * 返回:led_status--bit0-bit3分別表示4路LED燈的狀態,bit4-bit6分別表示RGB燈的狀態
 89 * 修改:
 90 * 注釋:
 91 *********************************************************************************************/
 92 unsigned char get_led_status(void){                            //獲取led狀態
 93   unsigned char led_status = 0;
 94   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_8))                 //判斷PE0引腳電平
 95     led_status |= D1;                                           //高電平將led_status bit0置1
 96   else
 97     led_status &= ~D1;                                          //低電平將led_status bit0置0
 98   
 99   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_9))                 //判斷PE1引腳電平
100     led_status |= D2;                                           //高電平將led_status bit1置1
101   else
102     led_status &= ~D2;                                          //低電平將led_status bit1置0
103   
104   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_10))                 //判斷PE2引腳電平
105     led_status |= D3;                                           //高電平將led_status bit2置1
106   else
107     led_status &= ~D3;                                          //低電平將led_status bit2置0
108   
109   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_11))                 //判斷PE3引腳電平
110     led_status |= D4;                                           //高電平將led_status bit3置1
111   else
112     led_status &= ~D4;                                          //低電平將led_status bit3置0
113     
114     if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_12))                 //判斷PE0引腳電平
115     led_status |= D5;                                           //高電平將led_status bit0置1
116   else
117     led_status &= ~D5;                                          //低電平將led_status bit0置0
118   
119   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_13))                 //判斷PE1引腳電平
120     led_status |= D6;                                           //高電平將led_status bit1置1
121   else
122     led_status &= ~D6;                                          //低電平將led_status bit1置0
123   
124   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_14))                 //判斷PE2引腳電平
125     led_status |= D7;                                           //高電平將led_status bit2置1
126   else
127     led_status &= ~D7;                                          //低電平將led_status bit2置0
128   
129   if(GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_15))                 //判斷PE3引腳電平
130     led_status |= D8;                                           //高電平將led_status bit3置1
131   else
132     led_status &= ~D8;                                          //低電平將led_status bit3置0
133   return led_status;                                            //返回led_status
134 }
135 
136 
137 void flash_4Hz(unsigned char led){                                //4Hz的閃爍
138     turn_on(led);
139     delay_count(900);                                                                                            //由計算可得,delay_count內的值為7200時,延時為1秒
140     turn_off(led);
141     delay_count(900);
142 }

3.3 key函數:

 1 #include "key.h"
 2 
 3 /*********************************************************************************************
 4 * 名稱:key_init
 5 * 功能:按鍵管腳初始化
 6 * 參數:無
 7 * 返回:無
 8 * 修改:無
 9 *********************************************************************************************/
10 void key_init(void)                                                                //初始化按鍵
11 {
12   GPIO_InitTypeDef GPIO_InitStructure;                          //定義一個GPIO_InitTypeDef類型的結構體
13   RCC_AHB1PeriphClockCmd( K1_CLK | K2_CLK |K3_CLK | K4_CLK |
14                           K5_CLK | K6_CLK |K7_CLK | K8_CLK , ENABLE);             //開啟KEY相關的GPIO外設時鍾
15   
16   GPIO_InitStructure.GPIO_Pin = K1_CLK | K2_CLK |K3_CLK | K4_CLK |
17                                                                 K5_CLK | K6_CLK |K7_CLK | K8_CLK;                //選擇要控制的GPIO引腳
18   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                //設置引腳的輸出類型為推挽輸出
19   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                  //設置引腳模式為輸入模式
20   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                  //設置引腳為上拉模式
21   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;              //設置引腳速率為2MHz
22   
23   GPIO_Init(K1_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
24   GPIO_Init(K2_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
25   GPIO_Init(K3_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
26   GPIO_Init(K4_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
27     
28       GPIO_Init(K5_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
29   GPIO_Init(K6_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
30   GPIO_Init(K7_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
31   GPIO_Init(K8_PORT, &GPIO_InitStructure);                      //初始化GPIO配置
32 }
33 
34 /*********************************************************************************************
35 * 名稱:get_key_status
36 * 功能:按鍵管腳初始化
37 * 參數:無
38 * 返回:key_status
39 * 修改:
40 *********************************************************************************************/
41 char get_key_status(void)                                                            //獲取按鍵狀態
42 {
43   char key_status = 0;
44   if(GPIO_ReadInputDataBit(K1_PORT,K1_PIN) == 0)                //判斷PB12引腳電平狀態
45     key_status |= K1_PREESED;                                   //低電平key_status bit0位置1
46   if(GPIO_ReadInputDataBit(K2_PORT,K2_PIN) == 0)                //判斷PB13引腳電平狀態
47     key_status |= K2_PREESED;                                   //低電平key_status bit1位置1
48   if(GPIO_ReadInputDataBit(K3_PORT,K3_PIN) == 0)                //判斷PB14引腳電平狀態
49     key_status |= K3_PREESED;                                   //低電平key_status bit2位置1
50   if(GPIO_ReadInputDataBit(K4_PORT,K4_PIN) == 0)                //判斷PB15引腳電平狀態
51     key_status |= K4_PREESED;                                   //低電平key_status bit3位置1
52     
53       if(GPIO_ReadInputDataBit(K5_PORT,K5_PIN) == 0)                //判斷PB12引腳電平狀態
54     key_status |= K5_PREESED;                                   //低電平key_status bit0位置1
55   if(GPIO_ReadInputDataBit(K6_PORT,K6_PIN) == 0)                //判斷PB13引腳電平狀態
56     key_status |= K6_PREESED;                                   //低電平key_status bit1位置1
57   if(GPIO_ReadInputDataBit(K7_PORT,K7_PIN) == 0)                //判斷PB14引腳電平狀態
58     key_status |= K7_PREESED;                                   //低電平key_status bit2位置1
59   if(GPIO_ReadInputDataBit(K8_PORT,K8_PIN) == 0)                //判斷PB15引腳電平狀態
60     key_status |= K8_PREESED;    
61   return key_status;
62 }

3.4 exit函數:

  1 #include "exti.h"
  2 #include "key.h"
  3 #include "delay.h"
  4 #include "led.h"
  5 extern char led_status;
  6 extern int led_count;
  7 extern unsigned char led_now;
  8 /*********************************************************************************************
  9 * 名稱:exti_init
 10 * 功能:外部中斷初始化
 11 * 參數:無
 12 * 返回:無
 13 * 修改:無
 14 *********************************************************************************************/
 15 void exti_init(void)                                                    //中斷初始化
 16 {
 17     NVIC_InitTypeDef   NVIC_InitStructure;
 18   EXTI_InitTypeDef   EXTI_InitStructure;
 19   key_init();                                                   //按鍵引腳初始化
 20 
 21   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);        //使能SYSCFG時鍾
 22      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource8); //PB12 連接到中斷線12
 23   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource9); //PB13 連接到中斷線13    
 24   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource10); //PB14 連接到中斷線14
 25   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource11); //PB15 連接到中斷線15
 26   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource12); //PB12 連接到中斷線12
 27   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource13); //PB13 連接到中斷線13    
 28   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource14); //PB14 連接到中斷線14
 29   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15); //PB15 連接到中斷線15
 30   
 31   EXTI_InitStructure.EXTI_Line = EXTI_Line8  | EXTI_Line9  | EXTI_Line10 | EXTI_Line11 |
 32                                                                  EXTI_Line12 | EXTI_Line13 | EXTI_Line14 | EXTI_Line15;     //LINE14、LINE15
 33   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;           //中斷事件
 34   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;       //下降沿觸發 
 35   EXTI_InitStructure.EXTI_LineCmd = ENABLE;                     //使能LINE14、LINE15
 36   EXTI_Init(&EXTI_InitStructure);                               //按上述參數配置
 37   
 38   NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;          //外部中斷15-10
 39   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     //搶占優先級0
 40   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;            //子優先級1
 41   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //使能外部中斷通道
 42   NVIC_Init(&NVIC_InitStructure);                               //按上述配置初始化
 43     
 44      NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;          //外部中斷15-10
 45    NVIC_Init(&NVIC_InitStructure);
 46   
 47 }
 48 /*********************************************************************************************
 49 * 名稱:EXTI15_10_IRQHandler
 50 * 功能:外部中斷15-10中斷處理函數
 51 * 參數:無
 52 * 返回:無
 53 * 修改:
 54 * 注釋:
 55 *********************************************************************************************/
 56 
 57 void EXTI9_5_IRQHandler(void)                                //中斷程序
 58 {
 59     if(get_key_status() == K1_PREESED){                           //檢測K1被按下
 60     delay_count(500);                                           //延時消抖
 61     if(get_key_status() == K1_PREESED){                         //確認K1被按下
 62       while(get_key_status() == K1_PREESED);                    //等待按鍵松開
 63       ++led_count;
 64             led_now = D1;
 65     }
 66   }
 67     if(get_key_status() == K2_PREESED){                           //檢測K2被按下
 68     delay_count(500);                                           //延時消抖
 69     if(get_key_status() == K2_PREESED){                         //確認K2被按下
 70       while(get_key_status() == K2_PREESED);                    //等待按鍵松開
 71       ++led_count;
 72             led_now = D2;
 73     }
 74     }
 75     
 76     if(EXTI_GetITStatus(EXTI_Line8)!=RESET)
 77     EXTI_ClearITPendingBit(EXTI_Line8);                        //清除LINE12上的中斷標志位
 78     if(EXTI_GetITStatus(EXTI_Line9)!=RESET)
 79     EXTI_ClearITPendingBit(EXTI_Line9);                        //清除LINE13上的中斷標志位
 80     
 81 }
 82 
 83 
 84 
 85 void EXTI15_10_IRQHandler(void)                                //中斷程序
 86 {
 87 
 88   if(get_key_status() == K3_PREESED){                           //檢測K3被按下
 89     delay_count(500);                                           //延時消抖
 90     if(get_key_status() == K3_PREESED){                         //確認K3被按下
 91       while(get_key_status() == K3_PREESED);                    //等待按鍵松開
 92       ++led_count;
 93             led_now = D3;
 94     }
 95   }
 96     if(get_key_status() == K4_PREESED){                           //檢測K4被按下
 97     delay_count(500);                                           //延時消抖
 98     if(get_key_status() == K4_PREESED){                         //確認K4被按下
 99       while(get_key_status() == K4_PREESED);                    //等待按鍵松開
100       ++led_count;
101             led_now = D4;
102     }
103   }
104         if(get_key_status() == K5_PREESED){                           //檢測K1被按下
105     delay_count(500);                                           //延時消抖
106     if(get_key_status() == K5_PREESED){                         //確認K1被按下
107       while(get_key_status() == K5_PREESED);                    //等待按鍵松開
108       ++led_count;
109             led_now = D5;
110     }
111   }
112     if(get_key_status() == K6_PREESED){                           //檢測K2被按下
113     delay_count(500);                                           //延時消抖
114     if(get_key_status() == K6_PREESED){                         //確認K2被按下
115       while(get_key_status() == K6_PREESED);                    //等待按鍵松開
116       ++led_count;
117             led_now = D6;
118     }
119   }
120         if(get_key_status() == K7_PREESED){                           //檢測K1被按下
121     delay_count(500);                                           //延時消抖
122     if(get_key_status() == K7_PREESED){                         //確認K1被按下
123       while(get_key_status() == K7_PREESED);                    //等待按鍵松開
124       ++led_count;
125             led_now = D7;
126     }
127   }
128     if(get_key_status() == K8_PREESED){                           //檢測K2被按下
129     delay_count(500);                                           //延時消抖
130     if(get_key_status() == K8_PREESED){                         //確認K2被按下
131       while(get_key_status() == K8_PREESED);                    //等待按鍵松開
132       ++led_count;
133             led_now = D8;
134     }
135   }
136  if(EXTI_GetITStatus(EXTI_Line10)!=RESET)
137     EXTI_ClearITPendingBit(EXTI_Line10);                        //清除LINE12上的中斷標志位
138     if(EXTI_GetITStatus(EXTI_Line11)!=RESET)
139     EXTI_ClearITPendingBit(EXTI_Line11);                        //清除LINE13上的中斷標志位
140     if(EXTI_GetITStatus(EXTI_Line12)!=RESET)
141     EXTI_ClearITPendingBit(EXTI_Line12);                        //清除LINE12上的中斷標志位
142     if(EXTI_GetITStatus(EXTI_Line13)!=RESET)
143     EXTI_ClearITPendingBit(EXTI_Line13);                        //清除LINE13上的中斷標志位
144   if(EXTI_GetITStatus(EXTI_Line14)!=RESET)
145     EXTI_ClearITPendingBit(EXTI_Line14);                        //清除LINE14上的中斷標志位
146   if(EXTI_GetITStatus(EXTI_Line15)!=RESET)
147     EXTI_ClearITPendingBit(EXTI_Line15);                        //清除LINE15上的中斷標志位
148 }

3.5 延時函數:

 1 #include "delay.h"
 2 
 3 /*********************************************************************************************
 4 * 名稱:delay_count
 5 * 功能:計數延時
 6 * 參數:times------計數數值
 7 * 返回:無
 8 * 修改:無
 9 *********************************************************************************************/
10 void delay_count(uint32_t times)
11 {
12   uint32_t temp = 0;                                            //定義臨時變量並初始化
13   
14   while(times --){                                              //times自減並判斷是否為空
15     temp = 1000;                                                //賦值1000
16     while(temp --);                                             //temp自減並判斷是否為空
17   }
18 }

總結:

  本實驗作為最基本的搶答器,只實現了最基本的搶答,沒有擴展復位按鍵,LCD液晶顯示,還有定時器計時等等;這只涉及最簡單的外部中斷。

 


免責聲明!

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



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