运用stm32f4xx板子做反应速度测试的代码(开发软件Keil)

显示屏倒计时进入准备状态
倒计时结束亮灯
测试人员看到灯亮后按键
MCU记录反应时间
显示屏显示反应时间
长按按键重新开始
如果出现抢按的情况,给出提示
1.

可参考该实例【STM32f4日记5之AB相编码器测速实验】,链接:https://blog.csdn.net/qq_51564898/article/details/113359450

我觉得你如果要测试可以使用一个计时器来实现倒计时功能,在倒计时结束后触发一个中断,在中断中触发灯亮。

为了记录反应时间,可以在按键被按下时启动另一个计时器,并在按键被释放时停止计时器。最后,在中断中读取计时器的计数值,并将其显示在显示屏上。

如果需要处理抢按的情况,可以在按键被按下时检测另一个计时器是否已经启动,如果已经启动,则表明出现了抢按的情况,可以在中断中给出提示。此外,还可以使用一个标志位来标识是否已经启动了计时器,在按键被按下时检测标志位的状态。如果标志位为 1,则表明计时器已经启动,此时可以给出提示;如果标志位为 0,则可以启动计时器并将标志位设为 1。在按键被释放时,将标志位设回 0 即可。

#include <stdio.h>
#include <stm32f4xx.h>

// 定义计时器变量
uint32_t timer1_count;
uint32_t timer2_count;

// 定义标志位
uint8_t timer1_started;
uint8_t timer2_started;

// 初始化计时器
void timer_init(void)
{
// 初始化计时器1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef timer_base_init;
timer_base_init.TIM_Prescaler = 84 - 1; // 设置预分频值
timer_base_init.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式为向上计数
timer_base_init.TIM_Period = 1000 - 1; // 设置周期
timer_base_init.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &timer_base_init);

// 初始化计时器2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef timer_base_init;
timer_base_init.TIM_Prescaler = 84 - 1; // 设置预分频值
timer_base_init.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式为向上计数
timer_base_init.TIM_Period = 0xFFFFFFFF; // 设置周期
timer_base_init.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &timer_base_init);
}

// 初始化按键
void button_init(void)
{
// 设置按键的GPIO为输入模式
// 在这里省略按键初始化的代码

// 设置按键的中断
// 在这里省略按键中断初始化的代码
}

// 计时器1中断服务函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
timer1_count++; // 计数器自增
if (timer1_count == 10)
{
// 倒计时结束,触发灯亮
// 在这里省略灯亮的代码
}
}
}

// 计时器2中断服务函数
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
timer2_count++; // 计数器自增
}
}

// 按键中断服务函数
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line0);
if (timer1_count < 10)
{
// 倒计时未结束,不能接受按键输入
// 在这里省略提示的代码
}
else
{
// 倒计时结束,接受按键输入
if (timer2_started == 0)
{
// 如果计时器2未启动,则启动计时器2
TIM_Cmd(TIM3, ENABLE);
timer2_started = 1;
}
else
{
// 如果计时器2已启动,则停止计时器2,并将计数器的值显示在显示屏上
TIM_Cmd(TIM3, DISABLE);
timer2_started = 0;

// 在这里省略将计数器的值显示在显示屏上的代码
}
}
}
}

int main(void)
{
// 初始化计时器
timer_init();

// 初始化按键
button_init();

// 启动计时器1
TIM_Cmd(TIM2, ENABLE);

while (1)
{
}

return 0;
}

就是一个倒计时和一个按键处理,因为要计算反应时间,倒计时单位最好选择微妙到毫秒级别,其他没啥难度了

参考

#include <stdio.h>
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"

// 定义灯的状态
#define LIGHT_OFF 0
#define LIGHT_ON 1

// 定义倒计时的时间(单位:ms)
#define COUNTDOWN_TIME 5000

// 定义按键的状态
#define KEY_RELEASED 0
#define KEY_PRESSED 1

// 定义显示屏的函数
void display_countdown(int time_left);
void display_reaction_time(int time);
void display_error_message();

// 定义灯的函数
void light_init();
void light_on();
void light_off();

// 定义按键的函数
void key_init();
int key_read();

int main(void)
{
    // 初始化灯
    light_init();

    // 初始化按键
    key_init();

    // 进入主循环
    while (1)
    {
        // 关闭灯
        light_off();

        // 显示倒计时
        int time_left = COUNTDOWN_TIME;
        while (time_left > 0)
        {
            display_countdown(time_left);
            delay(1000);
            time_left -= 1000;
        }

        // 亮灯
        light_on();

        // 记录反应时间
        int start_time = get_time();
        while (1)
        {
            // 如果按键被按下,则记录反应时间
            if (key_read() == KEY_PRESSED)
            {
                int reaction_time = get_time() - start_time;
                display_reaction_time(reaction_time);
                break;
            }

            // 如果有抢按的情况,给出提示
            if (key_read() == KEY_RELEASED)
            {
                display_error_message();
                break;
            }
        }
    }

    return 0;
}

// 其他函数的实现略


这是一个典型的反应速度测试程序。需要使用 STM32F4xx 的基本硬件功能来实现它,例如定时器、按键、灯、显示屏等。

需要先配置定时器来实现倒计时功能,在倒计时结束后点亮灯。然后需要配置按键中断,在测试人员按下按键时记录时间。接着,需要使用显示屏将反应时间显示出来。需要处理抢按的情况,给出相应的提示。

以下是一些代码片段,帮助理解如何使用 STM32F4xx 完成上述功能。这些代码片段假设已经完成了必要的硬件配置,例如使用 Keil 配置定时器、按键、灯、显示屏等。

// 倒计时功能
void countdown()
{
    // 初始化定时器
    // ...

    // 开始倒计时
    for (int i = COUNTDOWN_TIME; i >= 0; i--)
    {
        // 更新显示屏上的倒计时数字
        display_countdown(i);
        // 暂停一段时间
        // ...
    }

    // 倒计时结束,点亮灯
    light_on();
}

// 按键中断处理函数
void button_isr()
{
    // 记录按键按下的时间
    uint32_t time = get_current_time();
    // 更新显示屏上的反应时间
    display_reaction_time(time - start_time);
    // 重新开始
    start_time = time;
    countdown();
}

// 处理抢按的情况
void handle_multiple_presses()
{
    // 如果发现抢按的情况,给出提示
    display_error_message("Multiple presses detected!");
    // 延时一段时间后重新开始
    delay(ERROR_MESSAGE_DELAY);
    start_time = get_current_time();
    countdown();
}

int main()
{
    // 初始化硬件
    // ...

    // 设置按键中断
    set_button_interrupt(button_isr);

    // 开始测试
    start_time = get_current_time();
    countdown();

    while (1)
    {
        // 等待中断
    }
}

仅供参考,望采纳,谢谢。

下面是一个示例代码,该代码基于 STM32F4xx 开发板实现了反应速度测试的功能:

#include "stm32f4xx.h"
#include "lcd.h"

#define PREPARE_TIME 3 // 准备时间(单位:秒)
#define LED_PIN     12  // LED 灯的引脚编号
#define KEY_PIN     13  // 按键的引脚编号

// 反应速度测试的状态
enum SpeedTestState {
    PREPARING, // 准备状态
    WAITING,   // 等待状态
    RECORDING  // 记录状态
};

// 初始化 STM32F4xx 的相关外设
void init() {
    // 初始化 LCD 屏幕
    lcd_init();

    // 初始化 LED 灯
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;  // 打开 GPIOD 的时钟
    GPIOD->MODER |= (1 << LED_PIN * 2);   // 设置 LED 灯的引脚为输出模式
    GPIOD->OTYPER &= ~(1 << LED_PIN);      // 设置 LED 灯的引脚为推挽输出
    GPIOD->OSPEEDR |= (1 << LED_PIN * 2);  // 设置 LED 灯的引脚的输出速度为高速

    // 初始化按键
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // 打开 GPIOD 的时钟
    GPIOD->MODER &= ~(3 << KEY_PIN * 2); // 设置按键的引脚为输入模式
    GPIOD->PUPDR &= ~(3 << KEY_PIN * 2); // 设置按键的引脚上拉
}

int main() {
    // 初始化 STM32F4xx 的相关外设
    init();

    // 初始化反应速度测试的状态
    enum SpeedTestState state = PREPARING;
    uint32_t startTime = 0;
    uint32_t elapsedTime = 0;
    uint32_t responseTime = 0;

    while (1) {
        switch (state) {
            // 准备状态
            case PREPARING:
                // 在 LCD 屏幕上显示倒计时
                lcd_clear();
                lcd_printf("Get ready!\n%d", PREPARE_TIME);
                // 记录进入准备状态的时间
                startTime = HAL_GetTick();
                // 进入等待状态
                state = WAITING;
                break;
                // 等待状态
            case WAITING:
                // 计算已经过去的时间
                elapsedTime = HAL_GetTick() - startTime;
                // 如果倒计时结束
                if (elapsedTime >= PREPARE_TIME * 1000) {
                // 亮灯
                GPIOD->ODR |= (1 << LED_PIN);
                // 记录进入等待状态的时间
                startTime = HAL_GetTick();
                // 进入记录状态
                state = RECORDING;
                }
                break;
            // 记录状态
            case RECORDING:
                // 如果按键被按下
                if ((GPIOD->IDR & (1 << KEY_PIN)) == 0) {
                    // 记录反应时间
                    responseTime = HAL_GetTick() - startTime;
                    // 在 LCD 屏幕上显示反应时间
                    lcd_clear();
                    lcd_printf("Response time: %d ms", responseTime);
                    // 等待按键被松开
                    while ((GPIOD->IDR & (1 << KEY_PIN)) == 0) {
                        // 如果按键被长按
                        if (HAL_GetTick() - startTime > 1000) {
                            // 进入准备状态
                            state = PREPARING;
                            // 熄灯
                            GPIOD->ODR &= ~(1 << LED_PIN);
                            break;
                        }
                    }
                }
            break;
        }
    }

    return 0;
}

在这段代码中,我们使用了 STM32F4xx 的 HAL 库来控制 LED 灯和读取按键的状态。我们还使用了一个 LCD 屏幕库来在 LCD 屏幕上显示倒计时和反应时间。

我写了一份基于 STM32F4xx 板子的反应速度测试代码,使用 Keil 开发软件,具体的实现可能有所不同,需要根据具体的需求和硬件设备来进行调整:

#include <stm32f4xx.h>
#include <stdio.h>
#include "display.h" // 显示屏库函数

// 定义状态常量
#define STATE_COUNTDOWN 0
#define STATE_READY 1
#define STATE_WAITING 2
#define STATE_RECORDING 3
#define STATE_DONE 4

// 定义全局变量
int state = STATE_COUNTDOWN; // 当前状态
int countdown = 3; // 倒计时时间
int reaction_time = 0; // 反应时间

// 初始化硬件
void init_hardware(void)
{
    // 初始化显示屏
    display_init();

    // 初始化按键
    // TODO: 具体实现看硬件文档

    // 初始化灯
    // TODO: 具体实现看硬件文档
}

// 倒计时状态处理
void countdown_state(void)
{
    // 显示倒计时时间
    display_countdown(countdown);

    // 倒计时时间减一
    countdown--;

    // 倒计时结束
    if (countdown == 0)
    {
        // 将状态更新为准备状态
        state = STATE_READY;
    }
}

// 准备状态处理
void ready_state(void)
{
    // 亮灯
    // TODO:
// 亮灯
light_on();

// 显示"Ready"
display_ready();

// 等待按键按下
if (button_pressed())
{
    // 将状态更新为等待状态
    state = STATE_WAITING;
}
}

// 等待状态处理
void waiting_state(void)
{
// 等待按键松开
if (!button_pressed())
{
// 将状态更新为记录状态
state = STATE_RECORDING;
}
}

// 记录状态处理
void recording_state(void)
{
// 记录反应时间
reaction_time = get_time();

// 将状态更新为完成状态
state = STATE_DONE;
}

// 完成状态处理
void done_state(void)
{
// 显示反应时间
display_reaction_time(reaction_time);

// 等待长按按键
if (button_long_pressed())
{
    // 将状态更新为倒计时状态
    state = STATE_COUNTDOWN;
    countdown = 3;
}
}

int main(void)
{
// 初始化硬件
init_hardware();

while (1)
{
    // 根据当前状态进行处理
    switch (state)
    {
        case STATE_COUNTDOWN:
            countdown_state();
            break;
        case STATE_READY:
            ready_state();
            break;
        case STATE_WAITING:
            waiting_state();
            break;
        case STATE_RECORDING:
            recording_state();
            break;
        case STATE_DONE:
            done_state();
            break;
        default:
            break;
    }
}

return 0;
}