☰
GPIO输入——按键控制LED与光敏电阻控制蜂鸣器
2026/10/17 6:53:43 网站建设 项目流程
1、GPIO各输入函数
  1. GPIO_ReadInputDataBit:读某个引脚的输入电平,返回 0 或 1
  2. GPIO_ReadInputData:一次性读整个 GPIO 端口所有引脚的输入值,返回 16 位数字
  3. GPIO_ReadOutputDataBit:读某个引脚上输出寄存器的值(你程序输出的 0/1,不是引脚真实外部电平)
  4. GPIO_ReadOutputData:一次性读整个端口输出寄存器的 16 位值

简化来讲就是

  • Input 系列:看引脚外面真实电压(别人传给单片机)
  • Output 系列:看单片机内部打算输出的值(单片机计划发给别人)
  • Bit 结尾:只读单独 1 根引脚
  • 不带 Bit:一次性读整个端口 16 根
2、按键控制LED
//你好 #include "stm32f10x.h" //STM32标准库头文件 #include "Delay.h" //延时函数头文件 /** * @brief 按键扫描函数,检测PB1、PB11两个按键,松开后返回按键编号 * @retval 0:无按键按下;1:PB1按键;2:PB11按键 */ uint8_t Key_GetNumber(void) { uint8_t KeyNumber = 0; //定义按键编号变量,默认值0,代表没有按键按下 //检测PB1按键 if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0) //读取PB1引脚输入电平,等于0说明按键按下 { Delay_ms(20); //延时20ms,软件消抖,跳过按下瞬间机械抖动造成的电平乱跳 while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0); //原地循环等待,直到手指松开按键(引脚变为1才退出) Delay_ms(20); //松开按键再次消抖,防止松开瞬间抖动误触发 KeyNumber=1; //标记:本次按下的是PB1按键,编号1 } //检测PB11按键 if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0) //读取PB11引脚输入电平,等于0说明按键按下 { Delay_ms(20); //按下消抖 while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0); //原地等待,直到松开PB11按键 Delay_ms(20); //松开消抖 KeyNumber=2; //标记:本次按下的是PB11按键,编号2 } return KeyNumber; //返回按键编号,0无按键,1=PB1,2=PB11 } /** * @brief LED1状态翻转函数(PA4引脚) * @note 读取内部输出寄存器的值,当前亮就灭,当前灭就亮 */ void LED1_Turn(void) { //GPIO_ReadOutputDataBit:读取单片机内部输出寄存器设置的值,不是外部引脚真实电压 if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)==0) //如果PA4内部输出是0(LED亮) { GPIO_SetBits(GPIOA,GPIO_Pin_4); //PA4置高电平,熄灭LED1 } else { GPIO_ResetBits(GPIOA,GPIO_Pin_4); //PA4置低电平,点亮LED1 } } /** * @brief LED2状态翻转函数(PA5引脚) * @note 读取内部输出寄存器的值,当前亮就灭,当前灭就亮 */ void LED2_Turn(void) { if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)==0) //读取PA5内部输出值,如果是0(LED亮) { GPIO_SetBits(GPIOA,GPIO_Pin_5); //PA5置高电平,熄灭LED2 } else { GPIO_ResetBits(GPIOA,GPIO_Pin_5); //PA5置低电平,点亮LED2 } } int main() { //开启GPIOA外设时钟,GPIO使用前必须打开时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //定义GPIO初始化结构体,用来配置PA4、PA5 GPIO_InitTypeDef GPIO_InitStructure_0; GPIO_InitStructure_0.GPIO_Mode=GPIO_Mode_Out_PP; //模式:推挽输出,用来驱动LED GPIO_InitStructure_0.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5; //选中PA4、PA5两个引脚 GPIO_InitStructure_0.GPIO_Speed=GPIO_Speed_50MHz; //IO口翻转速度,输出模式才生效 GPIO_Init(GPIOA,&GPIO_InitStructure_0); //把上面配置写入GPIOA寄存器,生效 //开启GPIOB外设时钟,按键在PB引脚,需要开启GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //定义GPIOB初始化结构体,配置PB1 PB11按键引脚 GPIO_InitTypeDef GPIO_InitStructure_1; GPIO_InitStructure_1.GPIO_Mode=GPIO_Mode_IPU; //模式:内部上拉输入,适合按键(松开为高电平1,按下为低电平0) GPIO_InitStructure_1.GPIO_Pin=GPIO_Pin_1 | GPIO_Pin_11; //选中PB1、PB11两个按键引脚 GPIO_InitStructure_1.GPIO_Speed=GPIO_Speed_50MHz; //输入模式下,这个参数无效,可以随便写 GPIO_Init(GPIOB,&GPIO_InitStructure_1); //配置写入GPIOB寄存器,生效 while(1) //死循环,程序一直在这里循环跑 { uint8_t Key = Key_GetNumber(); //调用按键函数,获取按键编号,0无按键,1/2对应两个按键 if (Key==1) //如果拿到的编号等于1,代表PB1按键按下并松开 { LED1_Turn(); //翻转LED1状态,亮变灭、灭变亮 } if (Key==2) //如果拿到的编号等于2,代表PB11按键按下并松开 { LED2_Turn(); //翻转LED2状态 } } }
3、光敏电阻控制蜂鸣器
//你好 #include "stm32f10x.h" // STM32标准外设库头文件,提供GPIO、时钟等底层函数 #include "Delay.h" // 延时函数头文件,提供Delay_ms毫秒延时 /** * @brief 读取光敏传感器DO引脚电平 * @retval 返回PA9引脚读到的电平,1=高电平,0=低电平 */ uint8_t Photosen_Get(void) { // GPIO_ReadInputDataBit:读取引脚外部实际输入电平(数字输入) return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9); } /** * @brief 打开蜂鸣器(江科大有源低电平触发蜂鸣器) */ void Buzzer_On(void) { // GPIO_ResetBits:将PA8引脚置低电平(0V),蜂鸣器响 GPIO_ResetBits(GPIOA,GPIO_Pin_8); } /** * @brief 关闭蜂鸣器 */ void Buzzer_Off(void) { // GPIO_SetBits:将PA8引脚置高电平(3.3V),蜂鸣器关闭 GPIO_SetBits(GPIOA,GPIO_Pin_8); } int main() { // 开启GPIOA外设时钟,所有PA口引脚使用前,必须开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 定义GPIO初始化结构体,用来配置蜂鸣器PA8引脚 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // 推挽输出模式,用来驱动蜂鸣器 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8 ; // 选择PA8引脚 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // IO翻转速度,仅输出模式生效 GPIO_Init(GPIOA,&GPIO_InitStructure); // 将配置写入寄存器,使PA8配置生效 // 配置光敏传感器PA9引脚 // 再次开启GPIOA时钟(GPIOA时钟只需开启一次,重复写也没问题,不会报错) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 定义光敏引脚初始化结构体 GPIO_InitTypeDef GPIO_PhotosenStructure; GPIO_PhotosenStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; // 浮空输入,光敏模块DO自带上下拉,单片机用浮空输入读取 GPIO_PhotosenStructure.GPIO_Pin=GPIO_Pin_9 ; // 选择PA9引脚,接光敏DO数字输出 GPIO_PhotosenStructure.GPIO_Speed=GPIO_Speed_50MHz; // 输入模式下该参数无效,可保留 GPIO_Init(GPIOA,&GPIO_PhotosenStructure); // 光敏引脚配置生效 // 主循环,程序会一直循环执行这里 while(1) { // 判断光敏传感器读到的电平是否等于0 if (Photosen_Get() == 0) { Buzzer_On(); // 读到0(遮光),打开蜂鸣器 } else { Buzzer_Off(); // 读到1(有光),关闭蜂鸣器 } Delay_ms(100); // 延时100ms,降低扫描频率,减少频繁读取IO的压力 } }
4、C语言

关键字

位数

表示范围

stdint关键字

ST关键字

char

8

-128 ~ 127

int8_t

s8

unsigned char

8

0 ~ 255

uint8_t

u8

short

16

-32768 ~ 32767

int16_t

s16

unsigned short

16

0 ~ 65535

uint16_t

u16

int

32

-2147483648 ~ 2147483647

int32_t

s32

unsigned int

32

0 ~ 4294967295

uint32_t

u32

long

32

-2147483648 ~ 2147483647

unsigned long

32

0 ~ 4294967295

long long

64

-(2^64)/2 ~ (2^64)/2-1

int64_t

unsigned long long

64

0 ~ (2^64)-1

uint64_t

float

32

-3.4e38 ~ 3.4e38

double

64

-1.7e308 ~ 1.7e308

以后要用stdint的关键字,含义没变就是变了个名字而已。

宏定义:#define

用途:用一个字符串代替一个数字,便于理解,防止出错;提取程序中经常出现的参数,便于快速修改

定义宏定义: #define ABC 12345

引用宏定义: int a = ABC; //等效于int a = 12345

typedef

用途:将一个比较长的变量类型名换个名字,便于使用

定义typedef: typedef unsigned char uint8_t;(uint8_t是新名字)

引用typedef: uint8_t a; //等效于unsigned char a;

(typedef与宏定义的区别:两个都是用来改名的,宏定义是全局无脑改名,typedef是专门改变量的名字并且能检查错误)

结构体struct

用途:数据打包,不同类型变量的集合(数组eg.char[10] /int[10]只能集合一种类型,需要集合不同类型就用struct)

定义结构体变量: struct{char x; int y; float z;} StructName; 因为结构体变量类型较长,所以通常用typedef更改变量类型名

怎么使用?StructName . x=1 就是结构体名字 . 里面子变量名字然后赋值

怎么用typedef重命名struct?

typedef struct{ int x; char y;} struct_a; int main() { struct_a.x=1; struct_a.y=2; }

(在库函数里也可以看见GPIO初始化的结构体就是这样重命名的)

枚举:enum

用途:定义一个取值受限制的整型变量,用于限制变量取值范围;宏定义的集合(就比如说我定义一个枚举是week,只能有七天,如果我后面将week赋值为星期八,就会显示错误)

定义枚举变量: enum{FALSE = 0, TRUE = 1} EnumName; 因为枚举变量类型较长,所以通常用typedef更改变量类型名(跟结构体类似定义方法)

引用枚举成员: EnumName = FALSE; EnumName = TRUE;

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询