基于STM32设计一个抢答器系统。基本功能要求: (1)实现8路功能抢答; (2)具备回答时间倒计时功能; (3)设置专用的主持人按钮,包括抢答按钮和停止答题按钮等; (4)可以有加分和减分功能。 提供设备:STM32开发板、LCD显示模块、4*4矩阵按键 进行代码的编写并详细注释以及文字描述如何接线
时间: 2023-06-19 16:03:19 浏览: 888
接线方式如下:
- LCD显示模块与STM32开发板的接线
| LCD显示模块 | STM32开发板 |
| :---------: | :----------: |
| VSS | GND |
| VDD | 5V |
| VO | 电位器中点 |
| RS | PA0 |
| RW | GND |
| EN | PA1 |
| D0 | |
| D1 | |
| D2 | |
| D3 | |
| D4 | PA2 |
| D5 | PA3 |
| D6 | PA4 |
| D7 | PA5 |
| A | 5V |
| K | GND |
- 4*4矩阵按键与STM32开发板的接线
| 4*4矩阵按键 | STM32开发板 |
| :---------: | :----------: |
| 1 | PB0 |
| 2 | PB1 |
| 3 | PB2 |
| 4 | PB3 |
| 5 | PB4 |
| 6 | PB5 |
| 7 | PB6 |
| 8 | PB7 |
| 9 | PB8 |
| 10 | PB9 |
| 11 | PB10 |
| 12 | PB11 |
| 13 | PB12 |
| 14 | PB13 |
| 15 | PB14 |
| 16 | PB15 |
代码如下:(注释中有详细的功能描述)
```c
#include "stm32f10x.h"
#include "lcd.h" // LCD显示模块库
#include "delay.h" // 延时库
// 定义8个抢答器的状态
#define FREE 0 // 空闲状态
#define OCCUPIED 1 // 被占用状态
// 定义抢答器按键的GPIO端口和引脚号
#define KEY_PORT GPIOB
#define KEY_PIN1 GPIO_Pin_0
#define KEY_PIN2 GPIO_Pin_1
#define KEY_PIN3 GPIO_Pin_2
#define KEY_PIN4 GPIO_Pin_3
#define KEY_PIN5 GPIO_Pin_4
#define KEY_PIN6 GPIO_Pin_5
#define KEY_PIN7 GPIO_Pin_6
#define KEY_PIN8 GPIO_Pin_7
// 定义主持人按键的GPIO端口和引脚号
#define HOST_PORT GPIOA
#define HOST_BTN_PIN GPIO_Pin_0
#define STOP_BTN_PIN GPIO_Pin_1
// 定义抢答计时器的定时时间(单位为1ms)
#define ANSWER_TIME 10000 // 10秒
// 定义加分和减分的值
#define ADD_SCORE 10
#define SUB_SCORE 5
// 定义每个抢答器的得分和状态
struct Responder {
int score; // 得分
int status; // 状态(空闲或被占用)
} responders[8];
// 定义主持人按钮的状态
int host_btn_status = 0; // 0为未按下,1为已按下
int stop_btn_status = 0; // 0为未按下,1为已按下
// 定义抢答计时器的计时时间和状态
int answer_timer = 0; // 计时时间
int answer_status = 0; // 0为未开始计时,1为正在计时
// 函数声明
void init_gpio();
void init_responders();
int scan_key();
void update_lcd();
void host_btn_handler();
void stop_btn_handler();
void answer_timer_handler();
int main(void)
{
// 初始化GPIO
init_gpio();
// 初始化LCD显示模块
LCD_Init();
// 初始化抢答器状态
init_responders();
while (1) {
// 扫描抢答器按键
int key_num = scan_key();
// 如果有抢答器按键按下
if (key_num > 0) {
// 如果抢答计时器未开始计时
if (answer_status == 0) {
// 将抢答器状态设置为被占用状态
responders[key_num - 1].status = OCCUPIED;
// 开始抢答计时器
answer_timer = ANSWER_TIME;
answer_status = 1;
}
}
// 更新LCD显示
update_lcd();
// 处理主持人按键
host_btn_handler();
// 处理停止答题按键
stop_btn_handler();
// 处理抢答计时器
answer_timer_handler();
}
}
// 初始化GPIO
void init_gpio()
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIOA和GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// 配置LCD显示模块的GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置4*4矩阵按键的GPIO
GPIO_InitStructure.GPIO_Pin = KEY_PIN1 | KEY_PIN2 | KEY_PIN3 | KEY_PIN4 | KEY_PIN5 | KEY_PIN6 | KEY_PIN7 | KEY_PIN8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_PORT, &GPIO_InitStructure);
// 配置主持人按键的GPIO
GPIO_InitStructure.GPIO_Pin = HOST_BTN_PIN | STOP_BTN_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(HOST_PORT, &GPIO_InitStructure);
}
// 初始化抢答器状态
void init_responders()
{
int i;
for (i = 0; i < 8; i++) {
responders[i].score = 0;
responders[i].status = FREE;
}
}
// 扫描抢答器按键
int scan_key()
{
int i, j;
int key_num = 0;
// 设置行为高电平输出
KEY_PORT->ODR |= 0x0F;
// 扫描列
for (i = 0; i < 4; i++) {
// 将当前列设置为低电平输出
KEY_PORT->ODR &= ~(1 << (i + 4));
// 扫描行
for (j = 0; j < 4; j++) {
// 如果当前按键按下
if (!(KEY_PORT->IDR & (1 << j))) {
// 计算抢答器编号
key_num = i * 4 + j + 1;
}
}
// 将当前列恢复为高电平输出
KEY_PORT->ODR |= (1 << (i + 4));
}
return key_num;
}
// 更新LCD显示
void update_lcd()
{
int i;
// 清空LCD显示
LCD_Clear();
// 显示抢答器状态和得分
for (i = 0; i < 8; i++) {
if (responders[i].status == FREE) {
LCD_WriteString("R");
LCD_WriteInt(i + 1);
LCD_WriteString(": Free");
} else {
LCD_WriteString("R");
LCD_WriteInt(i + 1);
LCD_WriteString(": Occupied");
}
LCD_SetCursor(0, i + 1);
LCD_WriteString("Score:");
LCD_WriteInt(responders[i].score);
}
// 显示主持人按键状态
if (host_btn_status == 1) {
LCD_SetCursor(0, 9);
LCD_WriteString("Host Btn: Pressed");
} else {
LCD_SetCursor(0, 9);
LCD_WriteString("Host Btn: Released");
}
if (stop_btn_status == 1) {
LCD_SetCursor(0, 10);
LCD_WriteString("Stop Btn: Pressed");
} else {
LCD_SetCursor(0, 10);
LCD_WriteString("Stop Btn: Released");
}
// 显示抢答计时器状态
if (answer_status == 1) {
LCD_SetCursor(0, 11);
LCD_WriteString("Answer Timer: ");
LCD_WriteInt(answer_timer / 1000);
LCD_WriteString("s");
} else {
LCD_SetCursor(0, 11);
LCD_WriteString("Answer Timer: Stopped");
}
}
// 处理主持人按键
void host_btn_handler()
{
// 如果主持人按键按下
if (!(HOST_PORT->IDR & HOST_BTN_PIN)) {
host_btn_status = 1;
// 给所有被占用的抢答器加分
int i;
for (i = 0; i < 8; i++) {
if (responders[i].status == OCCUPIED) {
responders[i].score += ADD_SCORE;
}
}
} else {
host_btn_status = 0;
}
}
// 处理停止答题按键
void stop_btn_handler()
{
// 如果停止答题按键按下
if (!(HOST_PORT->IDR & STOP_BTN_PIN)) {
stop_btn_status = 1;
// 停止抢答计时器
answer_status = 0;
// 给所有被占用的抢答器减分
int i;
for (i = 0; i < 8; i++) {
if (responders[i].status == OCCUPIED) {
responders[i].score -= SUB_SCORE;
if (responders[i].score < 0) {
responders[i].score = 0;
}
responders[i].status = FREE;
}
}
} else {
stop_btn_status = 0;
}
}
// 处理抢答计时器
void answer_timer_handler()
{
// 如果抢答计时器正在计时
if (answer_status == 1) {
// 延时1ms
delay_ms(1);
// 减少计时时间
answer_timer--;
// 如果计时时间为0
if (answer_timer == 0) {
// 给抢答器加分
int i;
for (i = 0; i < 8; i++) {
if (responders[i].status == OCCUPIED) {
responders[i].score += ADD_SCORE;
responders[i].status = FREE;
}
}
// 停止抢答计时器
answer_status = 0;
}
}
}
```
阅读全文