学习STM32(2)--STM32单片机GPIO应用

目录

1  引 言 

2  实验目的

3  实验内容

3.1掌握STM32F103的GPIO控制

3.1.1 GPIO的分组

3.1.2 GPIO的常用功能

3.1.3 STM32单片机GPIO位结构

3.1.4 STM32单片机GPIO工作模式

3.1.5 STM32的GPIO 输出-点亮LED编程要点

使用GPIO时,按下面步骤进行:

3.2掌握基于while循环的按键检测程序

3.2.1引脚定义

3.2.2KEY输入配置

3.3熟悉基于GPIO中断的按键检测程序

NVIC 的主要功能包括:

设置KEY1 按键中断所需的步骤:

4 深入解析

思考一(使用按键使得蜂鸣器发出声音)

项目主要代码

main.c

bsp_beep.c

bsp_beep.h

bsp_key.c

 bsp_key.h

 思考二

思考三(用蜂鸣器完成音乐播放)

main.c

bsp_beep.h

bsp_beep.c


引 言 

        在嵌入式系统中,GPIO(通用输入/输出)是一种重要的功能,它允许微控制器与外部设备进行通信和控制。STM32系列单片机作为一种广泛应用的嵌入式处理器,具有丰富的GPIO功能,可用于连接各种外部设备,如LED、按钮、传感器等。本次实验旨在探索STM32单片机的GPIO应用,通过学习如何配置GPIO引脚、读取和控制GPIO状态,以及使用GPIO实现简单的输入输出操作,从而深入理解STM32单片机的基本功能和应用。

实验目的

  1. 掌握STM32F103开发板GPIO的输出功能
  2. 掌握STM32F103的GPIO输入,轮询式按键程序使用
  3. 熟悉STM32F103的中断按键检测程序

实验内容

3.1掌握STM32F103的GPIO控制

        GPIO(General Purpose Input Output)通用输入输出端口,STM32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。掌握GPIO,就等于掌握了操作硬件的能力。

3.1.1 GPIO的分组

        GPIOA-GPIOG,共7组,每组16个引脚,引脚号从0~15如PA0-PA15等,共112/144个。

        通过读写相关寄存器,实现对GPIO引脚的控制。

3.1.2 GPIO的常用功能

        GPIO的常用功能普通输入和输出功能。

        输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等。

        输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等。

3.1.3 STM32单片机GPIO位结构

        如下图1中STM32单片机GPIO位结构所示,从宏观到微观,从整体到细节观察,右边为IO引脚,左边为STM32F103的逻辑单元。上面为输入驱动,下面为输出驱动。输入,输出一定是站在单片机本身STM32F103的内核上来说的。

                                                  图1    STM32单片机GPIO位结构

3.1.4 STM32单片机GPIO工作模式

GPIO端口的每个位可以由软件分别配置成以下的工作模式:

1)、输入 :浮空输入(Floating Input)(常用,在该模式下,引脚不连接到外部电路,处于高阻抗状态。可以通过读取引脚电平来检测外部信号。)

2)、输入 :上拉输入(Pull-up Input)

3)、输入 :下拉输入(Pull-down Input)

4)、输入 :模拟输入(Analog Input)

5)、输出: 推挽输出(Push-Pull Output)(常用,输出高低电平与电源电压基本没有压差,可以输出高电平或低电平,同时具有一定的驱动能力。引脚在输出低电平时形成低阻抗,输出高电平时形成高阻抗,可以驱动外部电路。)

6)、输出:开漏输出(Open-Drain Output)

7)、输出:复用推挽输出(AF Push-Pull Output)

8)、输出:复用开漏输出(AF Open-Drain Output)

3.1.5 STM32的GPIO 输出-点亮LED编程要点

使用GPIO时,按下面步骤进行:

1、配置系统时钟并打开GPIO口的时钟;

2、设置GPIO口位的工作模式;

3、使用GPIO口位进行输入或输出。

为了使工程更加有条理,把 LED 灯控制相关的代码独立分开存储(.c和.h),方便以后移植。

/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;

        使用 GPIO_InitTypeDef 定义 GPIO 初始化结构体变量,以便下面用于存储 GPIO 配置。

/*开启LED相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE);

        调用库函数 RCC_APB2PeriphClockCmd 来使能 LED 灯的 GPIO 端口时钟,该函数有两个输入参数,第一个参数用于指示要配置的时钟,如本例中的“RCC_ APB2Periph_GPIOB”,应用时使用“|”操作同时配置 3 个 LED 灯的时钟;函数的第二个参数用于设置状态,可输入“Disable”关闭或“Enable”使能时钟。

/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;/*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  

        向 GPIO 初始化结构体赋值,把引脚初始化成推挽输出模式,其中的 GPIO_Pin 使用宏“LEDx_GPIO_PIN”来赋值,使函数的实现方便移植。

/*设置引脚速率为50MHz */  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*调用库函数,初始化GPIO*/GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure); 

使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化,这里的 GPIO 端口使用“LEDx_GPIO_PORT”宏来赋值,也是为了程序移植方便。

/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;/*调用库函数,初始化GPIO*/GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);

使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它 LED 灯使用的GPIO 引脚。

3.2掌握基于while循环的按键检测程序

                                                          图2 Key_Scan函数

        定义了一个 Key_Scan 函数用于扫描按键状态。GPIO 引脚的输入电平可通过读取IDR寄存器对应的数据位来感知,而 STM32标准库提供了库函数GPIO_ReadInputDataBit 来获取位状态,该函数输入 GPIO 端口及引脚号,函数返回该引脚的电平状态,高电平返回 1,低电平返回 0。Key_Scan 函数中以 GPIO_ReadInputDataBit 的返回值与自定义的宏“KEY_ON”对比,若检测到按键按下,则使用 while 循环持续检测按键状态,直到按键释放,按键释放后 Key_Scan 函数返回一个“KEY_ON”值;若没有检测到按键按下,则函数直接返回“KEY_OFF”。若按键的硬件没有做消抖处理,需要在这个 Key_Scan 函数中做软件滤波,防止波纹抖动引起误触发。

        消抖是为了处理开关或按钮在按下或释放时产生的短暂不稳定信号。这种不稳定信号可能会导致系统错误地识别用户的操作。消抖的基本思路是在检测到按钮状态改变时,延时一小段时间,然后再次确认按钮状态,以确保信号稳定。

3.2.1引脚定义

                                                        图3按键引脚定义

                                                        图4 LED引脚定义

3.2.2KEY输入配置

                                                        图5 KEY输入配置 

总结:对比输入和输出的配置步骤。基本上都包含了开启时钟、选择引脚、选择工作模式、选择速度。但是在输入模式下,无需配置引脚速度。

3.3熟悉基于GPIO中断的按键检测程序

EXTI_Key_Config();

初始化EXTI中断,按下按键会触发中断,

触发中断会进入stm32f4xx_it.c文件中的函数

KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。

                                                        图6 初始化EXTI函数 

中断可以分为两种类型:可屏蔽中断(IRQ)和非可屏蔽中断(NMI)

NVIC 的主要功能包括:

中断优先级管理:每个中断都有一个相应的优先级,NVIC 允许程序员配置每个中断的优先级,以确保高优先级中断能够及时响应。

中断使能与禁止:NVIC 可以控制每个中断的使能状态。当某个中断被禁用时,它将不会触发处理器的中断服务例程。

中断状态查询:NVIC 允许程序查询每个中断的触发状态,以确定哪些中断正在等待处理。

中断处理:当一个中断被触发时,NVIC 会根据中断优先级,中断向量表等信息来决定调用哪个中断服务例程(ISR,Interrupt Service Routine)来处理该中断。

设置KEY1 按键中断所需的步骤:

开启按键GPIO口的时钟:通过 RCC_APB2PeriphClockCmd开启按键GPIO口的时钟。

配置NVIC中断:调用 NVIC_Configuration(); 配置 NVIC 中断。

配置GPIO引脚:

选择用于 KEY1 的 GPIO 引脚。

将引脚配置为浮空输入,即不连接任何外部电路。这通常用于输入引脚,使其状态由外部设备决定。

使用 GPIO_Init() 函数对 GPIO 进行配置。

选择EXTI的信号源:通过 GPIO_EXTILineConfig选择 EXTI 的信号源,即选择外部中断线连接到哪个 GPIO 引脚上。

配置EXTI中断:

设置 EXTI_Line 为 KEY1 的外部中断线。

将 EXTI 模式设置为中断模式。

将触发模式设置为上升沿触发,即在按键按下时触发中断。

使能中断线。

4 深入解析

思考一(使用按键使得蜂鸣器发出声音)

         1.日常电话在拨号过程中,按键的同时会有不同的按键声音。也就出现网络上流传的大学生通过按键声音破译了360董事长的手机号码。实验要求:基于STMF103单片机实现按键声音和按键检测功能,包含2个按键模拟数字,2个按键要采用不同的声音。

①初始化:

        配置单片机的GPIO引脚,将按键连接到输入引脚,将扬声器连接到输出引脚。

        初始化定时器,用于生成按键声音的方波。

②按键检测功能:

循环执行以下步骤:

        读取按键的状态(按下或释放)。

如果检测到按键按下:

        播放相应的按键声音。

可以通过控制扬声器引脚的高低电平来实现声音的播放。

③按键声音的生成:

        当检测到按键按下时,根据不同的按键选择不同的频率和持续时间生成方波。

        可以使用定时器来定期改变输出引脚的状态,以产生方波。

        确保不同的按键对应不同的方波参数,以产生不同的声音效果。

思考题一实现代码:

                                                      图7 主要的实现代码

项目主要代码

main.c
#include "stm32f10x.h"
#include "bsp_beep.h"
#include "bsp_key.h" void SysTick_Delay_us( __IO uint32_t us) ; /*** @brief  主函数* @param  无  * @retval 无*/void Sound(u16 frq)
{u32 time;if(frq != 1000)//if(frq != 1000):条件判断语句,判断音调的频率是否不等于 1000 Hz。{
//		time = 500000/((u32)frq);time = 100000/((u32)frq);//根据音调的频率计算延时时间。通常情况下,频率越高,延时时间越短,声音越高。
//		PBeep = 1;BEEP( ON );//打开蜂鸣器--根据自己的硬件情况调整,通常就是控制蜂鸣器的gpio引脚置1SysTick_Delay_us(time);
//		PBeep = 0;BEEP( OFF );//关闭蜂鸣器--根据自己的硬件情况调整,通常就是控制蜂鸣器的gpio引脚置0SysTick_Delay_us(time);}elseSysTick_Delay_us(1000);//time = 100000/((u32)frq);:根据音调的频率计算延时时间。通常情况下,频率越高,延时时间越短,声音越高。
}int main(void)
{	/* BEEP GPIO 初始化 */BEEP_GPIO_Config();	Key_GPIO_Config();while(1)                            {	   u32 yanshi;u16 e;yanshi = 4;//10;  4;  2if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  ){for(e=0;e<(u16)(2*262/yanshi);e++){//在内部循环中,计算发声的次数,通过 (u16)time[i] * tone[music[i]] / yanshi 来确定。//这里将音符持续时间乘以音符对应的频率,再除以延时因子 yanshi,得到需要发声的次数。Sound(262);}	} if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON  ){for(e=0;e<(u16)(2*262/yanshi);e++){//在内部循环中,计算发声的次数,通过 (u16)time[i] * tone[music[i]] / yanshi 来确定。//这里将音符持续时间乘以音符对应的频率,再除以延时因子 yanshi,得到需要发声的次数。Sound(262);}}		}
}void SysTick_Delay_us( __IO uint32_t us) 
{uint32_t i;SysTick_Config(SystemCoreClock/1000000); for (i=0; i<us; i++){	// 当计数器的值减小到 0 的时候,CRTL 寄存器的位 16 会置 1 // 当置 1 时,读取该位会清 0 while ( !((SysTick->CTRL)&(1<<16)) ); }SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
/*********************************************END OF FILE**********************/
bsp_beep.c
#include "./beep/bsp_beep.h"   /*** @brief  初始化控制蜂鸣器的IO* @param  无* @retval 无*/
void BEEP_GPIO_Config(void)
{		/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启控制蜂鸣器的GPIO的端口时钟*/RCC_APB2PeriphClockCmd( BEEP_GPIO_CLK, ENABLE); /*选择要控制蜂鸣器的GPIO*/															   GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;	/*设置GPIO模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置GPIO速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化控制蜂鸣器的GPIO*/GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);			 /* 关闭蜂鸣器*/GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);	 
}
/*********************************************END OF FILE**********************/
bsp_beep.h
#ifndef __BEEP_H
#define	__BEEP_H#include "stm32f10x.h"/* 定义蜂鸣器连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的蜂鸣器引脚 */
#define BEEP_GPIO_PORT    	GPIOC			              /* GPIO端口 */
#define BEEP_GPIO_CLK 	    RCC_APB2Periph_GPIOC		/* GPIO端口时钟 */
#define BEEP_GPIO_PIN		  GPIO_Pin_0			        /* 连接到蜂鸣器的GPIO *//* 高电平时,蜂鸣器响 */
#define ON  1
#define OFF 0/* 带参宏,可以像内联函数一样使用 */
#define BEEP(a)	if (a)	\GPIO_SetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);\else		\GPIO_ResetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN)void BEEP_GPIO_Config(void);#endif /* __BEEP_H */
bsp_key.c
#include "./key/bsp_key.h"  /*** @brief  配置按键用到的I/O口* @param  无* @retval 无*/
void Key_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*开启按键端口的时钟*/RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);//选择按键的引脚GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN; // 设置按键的引脚为浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //使用结构体初始化按键GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);//选择按键的引脚GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN; //设置按键的引脚为浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //使用结构体初始化按键GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);	
}/** 函数名:Key_Scan* 描述  :检测是否有按键按下* 输入  :GPIOx:x 可以是 A,B,C,D或者 E*		     GPIO_Pin:待读取的端口位 	* 输出  :KEY_OFF(没按下按键)、KEY_ON(按下按键)*/
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{			/*检测是否有按键按下 */if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )  {	 /*等待按键释放 */while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);   return 	KEY_ON;	 }elsereturn KEY_OFF;
}
/*********************************************END OF FILE**********************/
 bsp_key.h
#ifndef __KEY_H
#define	__KEY_H#include "stm32f10x.h"//  引脚定义
#define    KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA
#define    KEY1_GPIO_PORT    GPIOA			   
#define    KEY1_GPIO_PIN		 GPIO_Pin_0#define    KEY2_GPIO_CLK     RCC_APB2Periph_GPIOC
#define    KEY2_GPIO_PORT    GPIOC		   
#define    KEY2_GPIO_PIN		  GPIO_Pin_13/** 按键按下标置宏*  按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0*  若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可*/
#define KEY_ON	1
#define KEY_OFF	0void Key_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);#endif /* __KEY_H */

 思考二

2.在上述的电话按键系统设计过程中,如何设计可以避免通过按键声音破译手机号码(要求声音保留)。

        1.随机化声音生成:每次按下按键时,不要产生固定频率和持续时间的声音。而是在一定的范围内随机选择频率和持续时间,以使得声音不易被识别和破解。

        2.将所有按键的声音都改为同一声音

                                                   图8 思考题2实现代码 

思考三(用蜂鸣器完成音乐播放)

详细内容看博客:http://t.csdnimg.cn/V0uRD

main.c

#include "stm32f10x.h"
#include "./beep/bsp_beep.h"  void Buzzer_On(void)
{GPIO_SetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}void Buzzer_Off(void)
{GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);
}void delay_us (const uint32_t usec)
{RCC_ClocksTypeDef  RCC_Clocks;/* Configure HCLK clock as SysTick clock source */SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);RCC_GetClocksFreq(&RCC_Clocks);// Set SysTick Reload(1us) register and Enable// usec * (RCC_Clocks.HCLK_Frequency / 1000000) < 0xFFFFFFUL  -- because of 24bit timerSysTick_Config(usec * (RCC_Clocks.HCLK_Frequency / 1000000));//HCLK_Frequency=48M// 72/72000000 --> 1usec// 0.001msec = 1usec// 1Hz = 1sec, 10Hz = 100msec, 100Hz = 10msec, 1KHz = 1msec,// 10KHz = 0.1msec, 100Khz = 0.01msec, 1MHz = 1usec(0.001msec)// 1usec = 1MHz// SysTick Interrupt DisableSysTick->CTRL  &= ~SysTick_CTRL_TICKINT_Msk ;// Until Tick count is 0while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
}void BEEP_Init(void)
{   /*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启控制蜂鸣器的GPIO的端口时钟*/RCC_APB2PeriphClockCmd( BEEP_GPIO_CLK, ENABLE); /*选择要控制蜂鸣器的GPIO*/															   GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;	/*设置GPIO模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置GPIO速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化控制蜂鸣器的GPIO*/GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);			 /* 关闭蜂鸣器*/GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);	 
}void Sound(u16 frq)
{u32 time;if(frq != 1000)//if(frq != 1000):条件判断语句,判断音调的频率是否不等于 1000 Hz。{
//		time = 500000/((u32)frq);time = 100000/((u32)frq);//根据音调的频率计算延时时间。通常情况下,频率越高,延时时间越短,声音越高。
//		PBeep = 1;Buzzer_On();//打开蜂鸣器--根据自己的硬件情况调整,通常就是控制蜂鸣器的gpio引脚置1delay_us(time*2);
//		PBeep = 0;Buzzer_Off();//关闭蜂鸣器--根据自己的硬件情况调整,通常就是控制蜂鸣器的gpio引脚置0delay_us(time*2);}elsedelay_us(1000);//time = 100000/((u32)frq);:根据音调的频率计算延时时间。通常情况下,频率越高,延时时间越短,声音越高。
}
void play_music(void)
{//             低7  1   2   3   4   5   6   7  高1 高2  高3 高4 高5 不发音uc16 tone[] = {247,262,294,330,349,392,440,494,523,587,659,698,784,1000};//音频数据表//小燕子u8 music[]={3,5,8,6,5,13,//音调3,5,6,8,5,13,8,10,9,8,9,8,6,8,5,13,3,5,6,5,6,8,9,5,6,13,3,2,1,2,13,2,2,3,5,5,8,2,3,5,13};u8 time[] ={2,2,2,2,6,4,//时间  2,2,2,2,6,4,6,2,4,4,2,2,2,2,6,4,6,2,4,2,2,4,2,2,6,4,2,2,4,6,4,4,2,2,4,4,4,2,2,6,4};//	u8 music[]={13,1,2,3,4,5,6,7,8};//测试基础音
//	u8 time[] ={4, 4,4,4,4,4,4,4,4};u32 yanshi;u16 i,e;yanshi = 4;//10;  4;  2//实际播放的音调和持续时间会受到延时因子yanshi的影响,通过调节yanshi的值可以控制播放速度。for(i=0;i<sizeof(music)/sizeof(music[0]);i++){for(e=0;e<((u16)time[i])*tone[music[i]]/yanshi;e++){//在内部循环中,计算发声的次数,通过 (u16)time[i] * tone[music[i]] / yanshi 来确定。//这里将音符持续时间乘以音符对应的频率,再除以延时因子 yanshi,得到需要发声的次数。Sound((u32)tone[music[i]]);}	}
}int main(void)
{	BEEP_Init();while(1){play_music();}return 0;
}

bsp_beep.h

#ifndef __BEEP_H
#define	__BEEP_H#include "stm32f10x.h"/* 定义蜂鸣器连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的蜂鸣器引脚 */
#define BEEP_GPIO_PORT    	GPIOC			              /* GPIO端口 */
#define BEEP_GPIO_CLK 	    RCC_APB2Periph_GPIOC		/* GPIO端口时钟 */
#define BEEP_GPIO_PIN		  GPIO_Pin_0			        /* 连接到蜂鸣器的GPIO *//* 高电平时,蜂鸣器响 */
#define ON  1
#define OFF 0/* 带参宏,可以像内联函数一样使用 */
#define BEEP(a)	if (a)	\GPIO_SetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);\else		\GPIO_ResetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN)void BEEP_GPIO_Config(void);#endif /* __BEEP_H */

bsp_beep.c

#include "./beep/bsp_beep.h"   /*** @brief  初始化控制蜂鸣器的IO* @param  无* @retval 无*/
void BEEP_GPIO_Config(void)
{		/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启控制蜂鸣器的GPIO的端口时钟*/RCC_APB2PeriphClockCmd( BEEP_GPIO_CLK, ENABLE); /*选择要控制蜂鸣器的GPIO*/															   GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;	/*设置GPIO模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置GPIO速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化控制蜂鸣器的GPIO*/GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);			 /* 关闭蜂鸣器*/GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);	 
}
/*********************************************END OF FILE**********************/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392527.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署服务器项目及发布

当技术总监直接丢给我一个服务器账号密码时&#xff0c;我该怎么完成映射本机&#xff1b;配置网关&#xff1b;配置代理和发布项目呢&#xff1f; 我使用的是putty远程登录到服务器 输入ip后&#xff0c;点open 输入账号密码 登录的账号如果不是root&#xff1b;使用sudo su…

sqllab靶场练习第1~15关

1、第一关 代码解析 if(isset($_GET[id]))//判断获取的id字段是否为空 { $id$_GET[id]; //logging the connection parameters to a file for analysis. $fpfopen(result.txt,a);//打开这个文件&#xff0c;记录操作的日志 fwrite($fp,ID:.$id."\n"); fclose($fp);…

【C++高阶】深入理解C++异常处理机制:从try到catch的全面解析

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;Lambda表达式 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀C异常 &#x1f4d2;1. C异常概念…

WPF学习(3)- WrapPanel控件(瀑布流布局)+DockPanel控件(停靠布局)

WrapPanel控件&#xff08;瀑布流布局&#xff09; WrapPanel控件表示将其子控件从左到右的顺序排列&#xff0c;如果第一行显示不了&#xff0c;则自动换至第二行&#xff0c;继续显示剩余的子控件。我们来看看它的结构定义&#xff1a; public class WrapPanel : Panel {pub…

【前端】(仅思路)如何在前端实现一个fc手柄,将手机作为游戏手柄设备。

文章目录 背景界面demo原型图&#xff08;没错&#xff0c;就是它&#xff0c;童年回忆&#xff09; 遇到的问题最终后端demo(甚至比前端逻辑更简单) 背景 突发奇想&#xff0c;想要在前端实现一个fc游戏手柄&#xff0c;然后控制电脑的nes模拟器玩玩魂斗罗。 思路很简单&…

【编程笔记】解决移动硬盘无法访问文件或目录损坏且无法读取

解决移动硬盘无法访问文件或目录损坏且无法读取 只解决&#xff1a;移动硬盘无法访问文件或目录损坏且无法读取 问题 由于频繁下载数据&#xff0c;多次安装虚拟机导致磁盘无法被系统识别。磁盘本身是好的&#xff0c;只是不能被识别&#xff0c;如果将磁盘格式化&#xff0c…

Chainlit快速实现AI对话应用1 分钟内实现聊天数据的持久化保存

概述 默认情况下&#xff0c;Chainlit 应用不会保留其生成的聊天和元素。即网页一刷新&#xff0c;所有的聊天记录&#xff0c;页面上的所有聊天记录都会消失。但是&#xff0c;存储和利用这些数据的能力可能是您的项目或组织的重要组成部分。 一旦启用&#xff0c;数据持久性…

Unlikely argument type for equals(): int seems to be unrelated to Long

代码审查不规范&#xff1a; Unlikely argument type for equals(): int seems to be unrelated to Long check package code_check;public class Obj {public Obj(){}private Long mail;public Long getMail(){return mail;}public void setMail(Long mail){this.mail mail;…

【零基础实战】基于物联网的人工淡水湖养殖系统设计

文章目录 一、前言1.1 项目介绍1.1.1 开发背景1.1.2 项目实现的功能1.1.3 项目硬件模块组成1.1.4 ESP8266工作模式配置 1.2 系统设计方案1.2.1 关键技术与创新点1.2.2 功能需求分析1.2.3 现有技术与市场分析1.2.4 硬件架构设计1.2.5 软件架构设计1.2.6 上位机开发思路 1.3 系统…

Java | Leetcode Java题解之第324题摆动排序II

题目&#xff1a; 题解&#xff1a; class Solution {Random random new Random();public void wiggleSort(int[] nums) {int n nums.length;int x (n 1) / 2;int mid x - 1;int target findKthLargest(nums, n - mid);for (int k 0, i 0, j n - 1; k < j; k) {if…

DAMA学习笔记(十)-数据仓库与商务智能

1.引言 数据仓库&#xff08;Data Warehouse&#xff0c;DW&#xff09;的概念始于20世纪80年代。该技术赋能组织将不同来源的数据整合到公共的数据模型中去&#xff0c;整合后的数据能为业务运营提供洞察&#xff0c;为企业决策支持和创造组织价值开辟新的可能性。与商务智能&…

使用Go语言绘制柱状图教程

使用Go语言绘制柱状图教程 本文将介绍如何使用Go语言及gg包绘制柱状图&#xff0c;并将图表保存为PNG格式的图片。gg包是一个功能强大的2D图形库&#xff0c;适合用于绘制各种图表。 安装gg包 首先&#xff0c;确保你已经安装了gg包。如果还没有安装&#xff0c;可以使用以下…

【安当产品应用案例100集】005-安当ASP实现Exchange双因素登录认证

Exchange双因素登录通过增加额外的安全验证层&#xff0c;可以有效提高企业邮箱系统的安全性&#xff0c;减少了数据泄露和账号被盗的风险&#xff0c;同时也符合了日益严格的安全合规要求。 其必要性主要体现在以下几个方面&#xff1a; 提高安全性&#xff1a;传统的用户名…

1.MySQL面试题之innodb如何解决幻读

1. 写在前面 在数据库系统中&#xff0c;幻读&#xff08;Phantom Read&#xff09;是指在一个事务中&#xff0c;两次读取同一范围的数据集时&#xff0c;由于其他事务的插入操作&#xff0c;导致第二次读取结果集发生变化的问题。InnoDB 作为 MySQL 的一个存储引擎&#xff…

【期货】收盘点评。昨天说的,p2409棕榈油在今天或者周一会走出行情

收盘点评 昨天说的&#xff0c;p2409棕榈油在今天或者周一会走出行情。事实就是如此。震荡了几天了&#xff0c;波幅不大的来回震荡&#xff0c;其实主力是不想震荡的&#xff0c;但是不震荡自己的货和行情走不出来。所以我昨天就说&#xff0c;应该就是这一两天会走出一波小行…

Linux中的无人值守安装脚本Kickstart

目录 一.kickstart自动安装脚本的作用 在企业中安装多台操作系统时面临的问题 如何解决以上问题&#xff1f; 二.实验环境 三.kickstart自动安装脚本的制作 通过模板生成kickstart文件 1.安装图形化生成kickstart自动安装脚本的工具 2.图形化工具配置流程 3.配置文件详…

力扣热题100_二叉树_94_二叉树的中序遍历

文章目录 题目链接解题思路解题代码 题目链接 94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root [] 输…

C#中重写tospring方法

在C#中&#xff0c;重写ToString方法允许你自定义对象的字符串表示形式。当你想要打印对象或者在调试时查看对象的状态时&#xff0c;重写ToString方法非常有用。 默认情况下&#xff0c;ToString方法返回对象的类型名称。通过重写这个方法&#xff0c;你可以返回一个更有意义…

sqli 1- 10

sql靶场 第一关 首先我们需要判断是否存在sql注入点&#xff0c;前端界面提示我使用ID作为参数,在url地址栏输入?id1 通过输入不同的id值查询数据库相对应的内容&#xff0c;之后判断为数字型还是字符型 根据查询内容判断为字符型且有注入点&#xff0c;再通过联合查询&…

#71结构体案例2(三国游戏,冒泡排序)

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <string> using namespace std;//英雄结构体 struct Hero {string name;int age;string gender; };//冒泡排序 void bubbleSort(struct Hero hArray[],int len) {for(int i0;i<len-1;i){for(i…