首页 > 其他分享 >嵌入式开发学习之--抢答器

嵌入式开发学习之--抢答器

时间:2023-02-20 22:31:41浏览次数:33  
标签:-- void 嵌入式 NVIC INT InitStructure GPIO 抢答器 EXTI

前言

  前一篇大致了解了什么是中断,中断需要配置的参数,再结合之前的按键输入,这一篇实战一下。

一、项目概况

1.1、项目需求

  两个按键,按下后蜂鸣器都会响;

  1号按键按下,led红灯长亮;2号按键按下,led蓝灯长亮;

  任意一个按键按下后,另一个按键按下将没有任何反应;也就是说led只会有一种颜色。

1.2、项目来源

  作者脑洞;

1.3、开发环境

  软件: keil5;

  硬件: 野火挑战者开发板。

1.4、项目意义

  可以用在很多娱乐活动中,也可以增加家庭娱乐气氛,也可以用来维持讨论时的纪律,工作的人应该都知道讨论问题尤其是要负责任的问题时,有多么吵。

二、开发步骤

2.1、涉及硬件电路

  电路图请参考之前按键检测试验,这里不放了。

2.2、项目代码

2.2.1、中断配置

  代码如下(示例):

  exti.h

#ifndef __EXTI_H
#define	__EXTI_H

#include "stm32f4xx.h"

#define KEY1_INT_GPIO_PORT                GPIOA
#define KEY1_INT_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define KEY1_INT_GPIO_PIN                 GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE          EXTI_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE           EXTI_PinSource0
#define KEY1_INT_EXTI_LINE                EXTI_Line0
#define KEY1_INT_EXTI_IRQ                 EXTI0_IRQn

#define KEY1_IRQHandler                   EXTI0_IRQHandler

#define KEY2_INT_GPIO_PORT                GPIOC
#define KEY2_INT_GPIO_CLK                 RCC_AHB1Periph_GPIOC
#define KEY2_INT_GPIO_PIN                 GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE          EXTI_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE           EXTI_PinSource13
#define KEY2_INT_EXTI_LINE                EXTI_Line13
#define KEY2_INT_EXTI_IRQ                 EXTI15_10_IRQn

#define KEY2_IRQHandler                   EXTI15_10_IRQHandler
/*******************************************************/

void EXTI_Key_Config(void);

#endif /* __EXTI_H */

  exti.c

#include "exti.h"

static void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  

    NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
    NVIC_Init(&NVIC_InitStructure);
}

void EXTI_Key_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; 
    EXTI_InitTypeDef EXTI_InitStructure;

    RCC_AHB1PeriphClockCmd(KEY1_INT_GPIO_CLK|KEY2_INT_GPIO_CLK ,ENABLE);  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    NVIC_Configuration();

    GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;	    		

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure); 

    SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);

    EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  

    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;  

    GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);      

    SYSCFG_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE,KEY2_INT_EXTI_PINSOURCE);

    EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
}

简单说一下,NVIC_Configuration(void)函数中定义了中断优先级以及初始化; EXTI_Key_Config(void)函数则是在按键输入的基础上又加了中断的一些配置,比如上升沿还是下降沿触发,触发的引脚是什么,宏定义中,注意外部中断用的是哪个,则后面的中断函数也需要用哪一个。

  app.c

#include "app.h"

enum Respond respond;

void app_init(void)
{
    respond = NOBODY;
}

uint8_t user_rank(void)
{
    if (respond==NOBODY) {
        respond=FIRST;
        return FIRST;
    } else {
        return NOBODY;
    }
}

  app.h

#ifndef __APP_H
#define __APP_H

#include "stm32f4xx.h"
#define NONE 0
#define GAIN 1

enum Respond{
    NOBODY = 0,
    FIRST = 1
};

extern enum Respond respond;

void app_init(void);
uint8_t user_rank(void);

#endif

  app.c中做了一个user_rank函数,利用类似互斥锁的理论,来锁定哪一个先触发。

  stm32f4xx.c


void KEY1_IRQHandler(void)
{
    if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) 
    {
        if (user_rank() == FIRST) {
            LED_RED;
        }
        EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
    }  
}

void KEY2_IRQHandler(void)
{
    if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) 
    {
        if (user_rank() == FIRST) {
            LED_BLUE;
        }
        EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     
    }
}

  将中断函数放在stm32f4xx.c中,无论哪一个触发一次后,另一个按键将不会生效了。

#include "stm32f4xx.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "app.h"

void bsp_init(void)
{
    BEEP_GPIO_Config();
//  Key_GPIO_Config();
    LED_GPIO_Config();
    EXTI_Key_Config();
}

uint8_t key1_inspect()
{
    if (KEY1_READ==KEY_ON) {
        return KEY_ON;
    } else if (KEY1_READ==KEY_OFF) {
        return KEY_OFF;
    }
}

uint8_t key2_inspect()
{
    if (KEY2_READ == KEY_ON) {
        return KEY_ON;
    } else if(KEY2_READ == KEY_OFF) {
        return KEY_OFF;
    }
}

int main(void)
{
    uint8_t led_status;

    led_status=OFF;
    bsp_init();
    app_init();

    while (1) {
        if (key1_inspect() == KEY_ON) {
            BEEP_ON;			
            while (key1_inspect() == KEY_ON) {

            }
            BEEP_OFF;	
        }	
        
        if (key2_inspect() == KEY_ON) {
            BEEP_ON;			
            while (key1_inspect() == KEY_ON) {

            }
            BEEP_OFF;	
        }
    }		
}

  main.c主要是按键按下后蜂鸣器的处理。

总结

  1、利用中断能节省资源,提高效率;

  2、能实现任务并行。

  3、在写上层逻辑中,要注意的是当多中断同时调用某一变量或者某一函数,最好加互斥锁,否则可能数据会出错。

标签:--,void,嵌入式,NVIC,INT,InitStructure,GPIO,抢答器,EXTI
From: https://blog.51cto.com/u_15941409/6074491

相关文章

  • 每日总结-23.2.20
    今日软件工程课上明确了每日写总结的目标,之后每周一到周五的软件学习进度都要写总结。今日留下了关于android开发app的作业——每日打卡app。课下我在b站找......
  • 2023.3.20总结
    今日软件工程课上,建明老师给我们讲解了很多关于软件工程相关知识,以及什么是“做中学”,以及如何做中学,还有如何学好软件工程布置了完成关于Android下app的制作......
  • 【ZJOI2019】线段树
    【ZJOI2019】线段树Description九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜欢的就是线段树。线段树的核心是懒标记,下面是一个带懒标记的线段树的伪......
  • 流运算
    流运算现有的加密算法可以划分为:对称加密块加密流加密非对称加密协议2.1介绍2.1.1流运算与块运算对比对称加密可以分为块加密与流加密。流加密对比特位......
  • MyBatis-RedisCache源码分析
    回顾在前面,我们通过redis​集成了MyBatis​的二级缓存,440.MyBatis的二级缓存整合redis,接下来,我们来分析一下RedisCache​的源码。源码分析RedisCache主要是通过......
  • Map接口
    一、Map的实现类的结构:*|----Map:双列数据,存储key-value对的数据---类似于高中的函数:y=f(x)*|----HashMap:作为Map的主要实现类;线程不安全的,效率高;存储nul......
  • 如何清除Microsoft Teams的缓存
    前言最近,碰到一个很恼火的问题,为什么说恼火呢?就是事情不大,但是处理起来很麻烦,怎么都搞不定。就是,用户更新了Teams的一些信息,但是,在其他人的Teams里面,却一直......
  • Windows提权的几个方向(持续更新中)
    1、利用Windows系统漏洞匹配可提权漏洞编号,系统是否缺失该补丁。1、人工查用systeminfo命令或wmicqfegetHotFixID命令获取已经打了的补丁编号。2、利用Metasploit......
  • 第十九章 特殊工具和技术
    第十九章特殊工具与技术控制内存分配重载new和deletenew表达式的工作机理:string*sp=newstring("avalue");//分配并初始化一个string对象string*arr=news......
  • 服务器业务逻辑处理框架
    1. 多线程    (1)在主线程中利用epoll进程数据的接收,将收到的数据包(包头+包体)给加上消息头(包含连接池的地址)后 扔到消息队列中去;    (2)多个线程从消息队......