资讯详情

STM32【H7】理论——GPIO

文章目录

  • 1. GPIO
    • 1.1 GPIIO 功能模式分析
    • 1.2 四种输出模式
      • 1.2.1 推挽输出
      • 1.2.2 开漏输出
      • 1.2.3 复用推挽和开漏
    • 1.3 四种输入模式
    • 1.4 GPIO 拉电流负载和灌电流负载能力
    • 1.5 IO 补偿单位(高速IO)
    • 1.6 GPIIO 兼容 CMOS 和 TTL 电平
    • 1.* 【实验】无源蜂鸣器控制
      • 1.*.1 蜂鸣器简介
      • 1.*.2 电路设计
      • 1.*.3 程序设计
        • 1.*.3.1 `bsp_beep.h`
        • 1.*.3.2 `bsp_beep.c`
  • 2. GPIO FIFO
    • 2.1 程序设计
      • 2.1.1 `bsp_key.h`
      • 2.1.2 `bsp_key.c`
      • 2.1.3 `main.c`
    • 2.2 按键检测中断或查询

使用芯片:STM32H743XIH6 . 开发板:安富莱V7

1. GPIO


注意事项:

  1. 对于未使用的引脚,建议设置为,悬空即可。
  2. GPIO 当速度等级高时,最好使能量 IO 补偿单元。
  3. GPIO 还涉及注入电流的问题,详见:http://www.armbbs.cn/forum.php?mod=viewthread&tid=87675 .
  4. STM32H7的GPIO控制三极管驱动各种负载的安全措施和注意事项

1.1 GPIIO 功能模式分析

STM32H7 的 GPIO 特性如下:

  1. 输出状态:泄漏/推拉 上拉/下拉电阻。
  2. 输出数据寄存器(GPIOx_ODR)或者外设(GPIO 将数据输出到复用模式中。
  3. GPIO 设置速度等级。
  4. 输入状态:浮空、上拉/下拉、模拟。
  5. 输入数据寄存器(GPIOx_IDR)或者外设(GPIO 将数据设置为复用模式)输入。
  6. 通过寄存器 GPIOx_BSRR 实现寄存器 GPIOx_ODR 的位操作。
  7. 配置寄存器 GPIOx_LCKR 实现冻结的机制 IO 口配置。
  8. 每两个时钟周期可以翻一次 IO。
  9. 引脚复用功能高度灵活,允许 IO 可以做引脚 GPIO 功能复用也可以做。

STM32H7 的 GPIO 端口可配置如下 8 种模式: 11. 输入浮空 12. 输入上拉 13. 输入下拉 14. 模拟功能 15. 具有上拉或下拉功能的泄漏输出 16. 具有上拉或下拉功能的推拉输出 17. 具有上拉或下拉功能的复用功能推拉 18. 具有上拉或下拉功能的复用功能泄漏

另外,由于上拉和下拉是可选配置,对应 HAL 使用下面的库配置 6 种可以表示: 19. GPIO_MODE_INPUT 输入模式 20. GPIO_MODE_OUTPUT_PP 推挽输出 21. GPIO_MODE_OUTPUT_OD 开漏输出 22. GPIO_MODE_AF_PP 复用推挽 23. GPIO_MODE_AF_OD 复用开漏 24. GPIO_MODE_ANALOG 模拟模式

1.2 四种输出模式

1.2.1 推挽输出

推挽电路是两个参数相同的三极管或 MOSFET,在电路中以推挽的方式存在。 当电路工作时,两个对称的开关管每次只有一个导管,导管损耗小,效率高。输出不仅可以向负载灌注电流,还可以从负载中提取电流。提高电路的负载能力。 与泄漏输出模式相比,推拉输出的最大优点是平时输出高电,上升时间快,电压驱动能力强。 在这里插入图片描述

1.2.2 开漏输出

开漏端相当于 MOS 管道泄漏极(三极管的集电极)必须在高电平状态下连接上拉电阻,因此高电平输出的驱动能力完全由外拉电阻决定,但低电平输出的驱动能力很强。 泄漏电路具有以下特点:

  1. 输出高电通常利用外部电路的驱动能力来降低 IC 内部驱动。
  2. 泄漏是用来连接不同电平和匹配电平的装置,因为当泄漏引脚不连接外部上拉电阻时,只能输出低电平。如果需要同时具有输出高电平的功能,则需要连接拉电阻。一个很好的优点是,传输电平可以通过改变上拉电源的电压来改变。上拉电阻的电阻值决定了逻辑电平转换的速度。电阻值越大,速度越低,功耗越小。
  3. 泄漏输出提供了一种灵活的输出方式,但也有其弱点,即上升边缘的延迟。由于上升边缘通过外部上拉无源电阻充电负载,当电阻选择小时延迟较小,但功耗较大;相反,延迟功耗较小。因此,如果有延迟要求,建议使用下降边缘输出。
  4. 多个泄漏输出可以连接到一条线上。在不增加任何装置的情况下,通过上拉电阻形成与逻辑关系,即线与。可以简单单地理解为:当所有的引脚连接在一起时,如果有一个引脚输出作为逻辑 0、相当于接地,并联电路相当于被导线短路 0.只有高电平时,结果才是逻辑 1 .

1.2.3 复用推挽和开漏

复用指的是 GPIO 切换到 CPU 内部设备(如 SPI,I2C,UART 等待电路),即 GPIO 不是普通的IO 使用由内部设备直接驱动。推拉和开漏的特点相同。

1.3 四种输入模式

  1. 浮空输入:CPU 内部上拉电阻和下拉电阻电阻和下拉电阻。
  2. 下拉输入:CPU 输入模式为内部下拉电阻和上拉电阻断开。
  3. 上拉输入:CPU 内部上拉电阻使能和下拉电阻断开的输入模式。
  4. 模拟输入模式: GPIO 引脚直接连接内部 ADC。

:主要考虑功耗和防干扰。

  1. 所有用于带拉电阻输入的用途 I/O 当引脚外部保持较低时,就会产生电流消耗。该电流消耗的值可以通过使用静态特性提供的上拉 / 下拉电阻值简单算出。
  2. 对于输出引脚,还必须考虑任何外部下拉电阻或外部负载来估计电流消耗。
  3. 如果外部施加中间电平,则额外 I/O 电流消耗是由于配置输入 I/O。这种电流消耗是由用于区分输入值的输入施密特触发器电路引起的。除非应用程序需要这种特定的配置,否则这些可以通过 I/O 配置为模拟模式,避免此电流消耗。 ADC 这入引脚应配置为模拟输入。
  4. 由于外部电磁噪声,任何浮动输入引脚都可能成为中间电平或意外切换。为防止与浮动引脚相关的电流消耗,必须配置为模拟模式或内部强制数字值。这可以通过使用上拉来实现 / 下拉电阻或将引脚配置为输出模式。

1.4 GPIO 拉电流负载和灌电流负载能力

  • :负载电流从驱动门流向外电路,称为拉电流负载。例如,使用 STM32H7 的 GPIO 直接驱动 LED (MCU输出高电平)是拉电流的形式。
  • :负载电流从外电路流入驱动门,称为灌电流负载。如下图所示 LED 驱动电路。

  • STM32H7 的 IO 驱动能力(截图来自 STM32H7 数据手册:通过截图STM32H7 总拉电流和灌电流不得超过 140mA,单引脚灌最大电流不得超过 20mA .

1.5 IO 补偿单位(高速IO)

IO 补偿单元用于控制 I/O 通信压摆率(tfall / trise)以此来降低 I/O 噪声。当前 STM32H7 的速度等级可以配置为以下四种:

/** @defgroup GPIO_speed_define GPIO speed define * @brief GPIO Output Maximum frequency * @{ */ 
#define GPIO_SPEED_FREQ_LOW ((uint32_t)0x00000000U) /*!< Low speed */
#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)0x00000001U) /*!< Medium speed */
#define GPIO_SPEED_FREQ_HIGH ((uint32_t)0x00000002U) /*!< Fast speed */
#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)0x00000003U) /*!< High speed */

使用后两种速度等级的话,最好使能 IO 补偿单元。另外不同速度等级下,IO 补偿使能与否对 IO 最大速度的影响可以看此贴:http://www.armbbs.cn/forum.php?mod=viewthread&tid=87677

1.6 GPIIO 兼容 CMOS 和 TTL 电平

详见http://www.armbbs.cn/forum.php?mod=viewthread&tid=87676

下面是CMOS、TTL电平图:

1.* 【实验】无源蜂鸣器控制

资料来源:安富莱STM32H7 开发板

1.*.1 蜂鸣器简介

蜂鸣器主要有两种,而且都有蜂鸣器和蜂鸣器两类。这里使用的是电磁式无源蜂鸣器。

蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器,而且都含有源和无源

1.*.2 电路设计

1.*.3 程序设计

1.*.3.1 bsp_beep.h

typedef struct _BEEP_T
{ 
        
uint8_t ucEnalbe; // 用于使能或者禁止蜂鸣器
uint8_t ucState; // 状态变量,用于蜂鸣器鸣叫和停止的区分
uint16_t usBeepTime; // 鸣叫时间,单位 10ms
uint16_t usStopTime; // 停止鸣叫时间,单位 10ms
uint16_t usCycle; // 鸣叫和停止的循环次数
uint16_t usCount; // 用于鸣叫和停止时的计数
uint16_t usCycleCount; // 用于循环次数计数
uint8_t ucMute; // 用于静音
}BEEP_T;

1.*.3.2 bsp_beep.c

include "bsp.h"

//#define BEEP_HAVE_POWER /* 定义此行表示有源蜂鸣器,直接通过GPIO驱动, 无需PWM , 不定义即使用无源蜂鸣器*/ 

#ifdef BEEP_HAVE_POWER /* 有源蜂鸣器 */

	/* PA8 */
	#define GPIO_RCC_BEEP RCC_AHB1Periph_GPIOA
	#define GPIO_PORT_BEEP GPIOA
	#define GPIO_PIN_BEEP GPIO_PIN_8

	#define BEEP_ENABLE() GPIO_PORT_BEEP->BSRRL = GPIO_PIN_BEEP /* 使能蜂鸣器鸣叫 */
	#define BEEP_DISABLE() GPIO_PORT_BEEP->BSRRH = GPIO_PIN_BEEP /* 禁止蜂鸣器鸣叫 */
#else /* 无源蜂鸣器 */
	/* PA0 ---> TIM5_CH1 */

	/* 1500表示频率1.5KHz,5000表示50.00%的占空比 */
	#define BEEP_ENABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 5000);

	/* 禁止蜂鸣器鸣叫 */
	#define BEEP_DISABLE() bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 1500, 0);
#endif

BEEP_T g_tBeep;		/* 定义蜂鸣器全局结构体变量 */
/* ********************************************************************************************************* * 函 数 名: BEEP_InitHard * 功能说明: 初始化蜂鸣器硬件 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_InitHard(void)
{ 
        
#ifdef BEEP_HAVE_POWER /* 有源蜂鸣器 */
	GPIO_InitTypeDef GPIO_InitStructure; 

	/* 打开GPIOF的时钟 */
	RCC_AHB1PeriphClockCmd(GPIO_RCC_BEEP, ENABLE);

	BEEP_DISABLE();

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		/* 设为输出口 */
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;		/* 设为推挽模式 */
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	/* 上下拉电阻不使能 */
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	/* IO口最大速度 */

	GPIO_InitStructure.GPIO_Pin = GPIO_PIN_BEEP;
	GPIO_Init(GPIO_PORT_BEEP, &GPIO_InitStructure); // 初始化GPIO
#endif
	
	g_tBeep.ucMute = 0;	/* 关闭静音 */
}
/* ********************************************************************************************************* * 函 数 名: BEEP_Start * 功能说明: 启动蜂鸣音。 * 形 参: _usBeepTime : 蜂鸣时间,单位10ms; 0 表示不鸣叫 * _usStopTime : 停止时间,单位10ms; 0 表示持续鸣叫 * _usCycle : 鸣叫次数, 0 表示持续鸣叫 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_Start(uint16_t _usBeepTime, uint16_t _usStopTime, uint16_t _usCycle)
{ 
        
	if (_usBeepTime == 0 || g_tBeep.ucMute == 1)
	{ 
        
		return;
	}

	g_tBeep.usBeepTime = _usBeepTime; // 设置蜂鸣时间,单位 10ms,配置为 0 表示不鸣叫
	g_tBeep.usStopTime = _usStopTime; // 设置蜂鸣时间,单位 10ms,配置为 0 表示不鸣叫
	g_tBeep.usCycle = _usCycle; // 设置鸣叫次数,配置为 0 表示持续鸣叫
	g_tBeep.usCount = 0;
	g_tBeep.usCycleCount = 0;
	g_tBeep.ucState = 0;
	g_tBeep.ucEnalbe = 1;	/* 设置完全局参数后再使能发声标志 */

	BEEP_ENABLE();			/* 开始发声 */
}



/* ********************************************************************************************************* * 函 数 名: BEEP_KeyTone * 功能说明: 发送按键音 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_KeyTone(void)
{ 
        
	BEEP_Start(5, 1, 1);	/* 鸣叫50ms,停10ms, 1次 */
}




/* ********************************************************************************************************* * 函 数 名: BEEP_Pro * 功能说明: 此函数需每隔10ms调用1次该函数,用于控制蜂鸣器发声。该函数在 bsp_timer.c 中被调用。 * 该函数是蜂鸣器的主处理函数,用于实现鸣叫时间、停止鸣叫时间和循环次数的处理。 * 形 参: 无 * 返 回 值: 无 * 特别说明: * 1. 如果是裸机使用,将此函数放在 bsp.c 文件的 bsp_RunPer10ms 函数里面即可,这个函数是由滴答定时器调用的,前提是定时器的初始化函数 bsp_InitTimer 一定要调用。 2. 如果是 RTOS 使用,需要开启一个 10ms 为周期的任务调用函数 BEEP_Pro . ********************************************************************************************************* */
void BEEP_Pro(void)
{ 
        
	if ((g_tBeep.ucEnalbe == 0) || (g_tBeep.usStopTime == 0) || (g_tBeep.ucMute == 1))
	{ 
        
		return;
	}

	if (g_tBeep.ucState == 0)
	{ 
        
		if (g_tBeep.usStopTime > 0)	/* 间断发声 */
		{ 
        
			if (++g_tBeep.usCount >= g_tBeep.usBeepTime)
			{ 
        
				BEEP_DISABLE();		/* 停止发声 */
				g_tBeep.usCount = 0;
				g_tBeep.ucState = 1;
			}
		}
		else
		{ 
        
			;	/* 不做任何处理,连续发声 */
		}
	}
	else if (g_tBeep.ucState == 1)
	{ 
        
		if (++g_tBeep.usCount >= g_tBeep.usStopTime)
		{ 
        
			/* 连续发声时,直到调用stop停止为止 */
			if (g_tBeep.usCycle > 0)
			{ 
        
				if (++g_tBeep.usCycleCount >= g_tBeep.usCycle)
				{ 
        
					/* 循环次数到,停止发声 */
					g_tBeep.ucEnalbe = 0;
				}

				if (g_tBeep.ucEnalbe == 0)
				{ 
        
					g_tBeep.usStopTime = 0;
					return;
				}
			}

			g_tBeep.usCount = 0;
			g_tBeep.ucState = 0;

			BEEP_ENABLE();			/* 开始发声 */
		}
	}
}
/* ********************************************************************************************************* * 函 数 名: BEEP_Stop * 功能说明: 停止蜂鸣音。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_Stop(void)
{ 
        
	g_tBeep.ucEnalbe = 0;

	if ((g_tBeep.usStopTime == 0) || (g_tBeep.usCycle == 0))
	{ 
        
		BEEP_DISABLE();	/* 必须在清控制标志后再停止发声,避免停止后在中断中又开启 */
	}
}
/* ********************************************************************************************************* * 函 数 名: BEEP_Pause * 功能说明: 由于TIM冲突等原因,临时屏蔽蜂鸣音。通过 BEEP_Resume 恢复 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_Pause(void)
{ 
        
	BEEP_Stop();
	
	g_tBeep.ucMute = 1;		/* 静音 */
}

/* ********************************************************************************************************* * 函 数 名: BEEP_Resume * 功能说明: 恢复蜂鸣器正常功能 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
void BEEP_Resume(void)
{ 
        
	BEEP_Stop();
	
	g_tBeep.ucMute = 0;		/* 静音 */
}

2. GPIO FIFO


FIFO 是 First Input First Output 的缩写,。下面以按键FIFO 实验进行讲解。

这里以已被定义的 5 个字节的 FIFO 空间进行说明。Write 变量表示写位置,Read 变量表示读位置。初始状态时,Read = Write = 0,每向队列写入一个数据,则Write 加1 ,同理,每从队列中读出一个数据,Read 加1 ,直到Write= Read ,表示没有新的读写时间发生。 如果 Write!= Read,则认为有新的按键事件。现在通过函数 bsp_GetKey 读取一个按键值进行处理后,Read 变量变为 1,而Write 变量不变。 继续通过函数 bsp_GetKey 读取 3 个按键值进行处理后,Read 变量变为 4 . 此时 Read = Write = 4 ,表示已经没有新的按键事件需要处理。

另外值得注意的是,如果 FIFO 空间写满了,Write 会自动被重新赋值为 0,即重新从第一个字节空间填数据进去,如果这个地址空间的数据未被及时读取,那么则会被后来的数据覆盖掉。


  1. 可靠地记录每一个按键事件,避免遗漏按键事件。特别是需要实现按键的按下、长按、自动连发、弹起等事件时。
  2. 读取按键的函数可以设计为非阻塞的,不需要等待按键抖动滤波处理完毕。
  3. 按键 FIFO 程序在嘀嗒定时器中定期的执行检测,不需要在主程序中一直做检测,这样可以有效地降低系统资源消耗。

2.1 程序设计

2.1.1 bsp_key.h

  1. 便于新增键值,方便调整顺序。
  2. 使用{ } 将一组相关的定义封装起来便于理解。
  3. 编译器可帮我们避免键值重复。

对于简单的程序,可以借用按键 FIFO 来进行少量的信息传递。对于复杂的应用,推荐使用bsp_msg 专门来做这种任务间的通信。因为bsp_msg 除了传递消息代码外,还可以传递参数结构。

#define KEY_FIFO_SIZE 10 // 定义FIFO 队列大小为10 
typedef struct // 定义FIFO 结构体
{ 
        
	uint8_t Buf[KEY_FIFO_SIZE]; /* 键值缓冲区 */
	uint8_t Read; /* 缓冲区读指针 1 */
	uint8_t Write; /* 缓冲区写指针 */
	uint8_t Read2; /* 缓冲区读指针 2 */
}KEY_FIFO_T;

#define KEY_COUNT 10 /* 按键个数, 8 个独立建 + 2 个组合键 */
// 每个按键对象都分配一个结构体变量,这些结构体变量以数组的形式存在将便于简化程序代码行数。
// 使用函数指针 IsKeyDownFunc 可以将每个按键的检测以及组合键的检测代码进行统一管理。
typedef struct
{ 
        
	/* 下面是一个函数指针,指向判断按键手否按下的函数 */
	uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1 表示按下 */
	uint8_t Count; /* 滤波器计数器 */
	uint16_t LongCount; /* 长按计数器 */
	uint16_t LongTime; /* 按键按下持续时间, 0 表示不检测长按 */
	uint8_t State; /* 按键当前状态(按下还是弹起) */
	uint8_t RepeatSpeed; /* 连续按键周期 */
	uint8_t RepeatCount; /* 连续按键计数器 */
}KEY_T;

// 按键事件
typedef enum
{ 
        
	KEY_NONE = 0, /* 0 表示按键事件 */
	KEY_1_DOWN, /* 1 键按下 */
	KEY_1_UP, /* 1 键弹起 */
	KEY_1_LONG, /* 1 键长按 */
	KEY_2_DOWN, /* 2 键按下 */
	KEY_2_UP, /* 2 键弹起 */
	KEY_2_LONG, /* 2 键长按 */
	KEY_3_DOWN, /* 3 键按下 */
	KEY_3_UP, /* 3 键弹起 */
	KEY_3_LONG, /* 3 键长按 */
	KEY_4_DOWN, /* 4 键按下 */
	KEY_4_UP, /* 4 键弹起 */
	KEY_4_LONG, /* 4 键长按 */
	KEY_5_DOWN, /* 5 键按下 */
	KEY_5_UP, /* 5 键弹起 */
	KEY_5_LONG, /* 5 键长按 */
	KEY_6_DOWN, /* 6 键按下 */
	KEY_6_UP, /* 6 键弹起 */
	KEY_6_LONG, /* 6 键长按 */
	KEY_7_DOWN, /* 7 键按下 */
	KEY_7_UP, /* 7 键弹起 */
	KEY_7_LONG, /* 7 键长按 */
	KEY_8_DOWN, /* 8 键按下 */
	KEY_8_UP, /* 8 键弹起 */
	KEY_8_LONG, /* 8 键长按 */
	/* 组合键 */
	KEY_9_DOWN, /* 9 键按下 */
	KEY_9_UP, /* 9 键弹起 */
	KEY_9_LONG, /* 9 键长按 */
	KEY_10_DOWN, /* 10 键按下 */
	KEY_10_UP, /* 10 键弹起 */
	KEY_10_LONG, /* 10 键长按 */
}KEY_ENUM;

/* 按键滤波时间 50ms, 单位 10ms。 只有连续检测到 50ms 状态不变才认为有效,包括弹起和按下两种事件 即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件 */
#define KEY_FILTER_TIME 5
#define KEY_LONG_TIME 100 /* 单位 10ms, 持续 1 秒,认为长按事件 */

2.1.2 bsp_key.c

static KEY_FIFO_T s_tKey; /* 定义 FIFO 结构体变量 */
static KEY_T s_tBtn[KEY_COUNT];
static KEY_FIFO_T s_tKey; /* 按键 FIFO 变量,结构体 */


/* ********************************************************************************************************* * 函 数 名: bsp_PutKey * 功能说明: 将 1 个键值压入按键 FIFO 缓冲区。可用于模拟一个按键。 * 形 参: _KeyCode : 按键代码 * 返 回 值: 无 * 说明: 当按键事件触发后,即可调用该函数,将键值写入到FIFO 队列 ********************************************************************************************************* */
void bsp_PutKey(uint8_t _KeyCode)
{ 
        
	s_tKey.Buf[s_tKey.Write] = _KeyCode;
	if (++s_tKey.Write >= KEY_FIFO_SIZE)
	{ 
        
		s_tKey.Write = 0;
	} 
}

/* ********************************************************************************************************* * 函 数 名: bsp_GetKey * 功能说明: 从按键 FIFO 缓冲区读取一个键值。 * 形 参: 无 * 返 回 值: 按键代码 * 说明: 读取FIFO 队列中的值 ********************************************************************************************************* */
uint8_t bsp_GetKey(void)
{ 
        
	uint8_t ret;
	if (s_tKey.Read == s_tKey.Write) // 若Read = Write,则认为没有新事件需要处理
	{ 
        
		return KEY_NONE;
	}
	else
	{ 
        
		ret = s_tKey.Buf[s_tKey.Read];
		if (++s_tKey.Read >= KEY_FIFO_SIZE)
		{ 
        
			s_tKey.Read = 0;
		}
			return ret;
	} 
}


/* ********************************************************************************************************* * 函 数 名: bsp_GetKey2 * 功能说明: 从按键 FIFO 缓冲区读取一个键值。独立的读指针。 * 形 参: 无 * 返 回 值: 按键代码 ********************************************************************************************************* */
uint8_t bsp_GetKey2(void)
{ 
        
	uint8_t ret;
	if (s_tKey.Read2 == s_tKey.Write)
	{ 
        
		return KEY_NONE;
	}
	else
	{ 
        
		ret = s_tKey.Buf[s_tKey.Read2];
		if (++s_tKey.Read2 >= KEY_FIFO_SIZE)
		{ 
        
			s_tKey.Read2 = 0; // 按键缓冲区为空,即所有的按键时间已经处理完毕
		}
			return ret;
	} 
}

/* ********************************************************************************************************* * 函 数 名: bsp_InitKey * 功能说明: 初始化按键. 该函数被 bsp_Init() 调用。 * 形 参: 无 * 返 回 值: 无 * 说 明:因为函数指针必须先赋值,才能被作为函数执行。因此在定时扫描按键之前,必须先执行下面初始化函数(即bsp_InitKey)来设置每个按键的函数指针和参数。 ********************************************************************************************************* */
void bsp_InitKey(void)
{ 
        
	bsp_InitKeyVar(); /* 初始化按键变量 */
	bsp_InitKeyHard(); /* 初始化按键硬件 */
}

/* ********************************************************************************************************* * 函 数 名: bsp_InitKeyVar * 功能说明: 初始化按键变量 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */
static void bsp_InitKeyVar(void)
{ 
        
	uint8_t i;
	/* 对按键 FIFO 读写指针清零 */
	s_tKey.Read = 0;
	s_tKey.Write = 0;
	s_tKey.Read2 = 0;
	/* 给每个按键结构体成员变量赋一组缺省值 */
	for (i = 0; i < KEY_COUNT; i++)
	{ 
        
		s_tBtn[i].LongTime = KEY_LONG_TIME; /* 长按时间 0 表示不检测长按键事件 */
		s_tBtn[i].Count = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 ,没有设置为 0,是为了避免主板上电的瞬间,检测到一个无效按键按下或弹起事件。*/
		s_tBtn[i].State = 0; /* 按键缺省状态,0 为未按下 */
		s_tBtn[i].RepeatSpeed = 0; /* 按键连发的速度,0 表示不支持连发 */
		s_tBtn[i].RepeatCount = 0; /* 连发计数器 */
	}
	/* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */
	/* 摇杆上下左右,支持长按 1 秒后,自动连发 */
	bsp_SetKeyParam(KID_JOY_U, 100, 6);
	bsp_SetKeyParam(KID_JOY_D, 100, 6);
	bsp_SetKeyParam(KID_JOY_L, 100, 6);
	bsp_SetKeyParam(KID_JOY_R, 100, 6);
}
/* ********************************************************************************************************* * 函 数 名: KeyPinActive * 功能说明: 判断按键是否按下 * 形 参: 无 * 返 回 值: 返回值 1 表示按下(导通),0 表示未按下(释放) *************************************************************************************

标签: bsp62三极管外接5k电阻到5v

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台