嵌入式-Stm32-江科大基于标准库的GPIO4个小实验

这篇具有很好参考价值的文章主要介绍了嵌入式-Stm32-江科大基于标准库的GPIO4个小实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


核心:本文共4个小实验:

第一个:LED灯闪烁
第二个:LED流水灯
第三个:按键控制LED
第四个:光敏传感器控制蜂鸣器

一 、硬件介绍

1.1 LED、蜂鸣器、面包板

  • LED:发光二极管,正向通电点亮,反向通电不亮。
  • 有源蜂鸣器(本实验):内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定。如下图所示的蜂鸣器模块使用三极管作为开关。
  • 无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音(UP的51单片机课程中用晶振提供振荡源)。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大注:LED长脚为正极,灯里面内部小头为正极。本实验的蜂鸣器低电平驱动。
最右边的半圆符号是蜂鸣器

1.2 硬件电路嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大

  • 上图给出了led和蜂鸣器的驱动电路图。注意,三极管的发射极一定要直接接正电源/地,这是因为三极管的开启需要发射极和基极之间有一定的电压(电压差),如果接在负载侧则有可能会导致三极管无法正常开启。

  • 三极管开关是最简单的驱动电路

  • 这里的保护电阻(限流电阻)在UP视频中为了方便没有加,自己设计电路需要加上去。

  • 很多单片机中或者芯片片,都使用了高电平弱驱动,低电平强驱动的规则。
    上右一的图是PNP三极管驱动电路类型:当基极R1给低电平,蜂鸣器能被驱动工作,当R1给高电平,三极管截止电流,蜂鸣器不工作,PNP的三极管最好接在上边,NPN的三极管最好接在下边。
    下右二的图是NPN类型:当基极(R1)给高电平导通,低电平断开

1.3 三极管的简单介绍

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大

三极管(Transistor):
三极管是一种由三个半导体区域组成的电子元件,通常是NPN或PNP型。它具有三个引脚:发射极(Emitter)、基极(Base)和集电极(Collector)。三极管是一种可控电流放大器,可以根据输入信号的变化来控制输出电流。它可以作为开关或放大器使用。在放大器应用中,输入信号作用在基极上,通过控制基极电流,可以放大电流并将其输出到集电极。在开关应用中,基极电流的变化可以控制集电极与发射极之间的电流流动,实现开关功能。
PNP三极管驱动电路类型:当基极R1给低电平,蜂鸣器能被驱动工作,当R1给高电平,三极管截止电流,蜂鸣器不工作,PNP的三极管最好接在上边,NPN的三极管最好接在下边。
NPN类型:当基极给高电平导通,低电平断开。

1.4 面包板
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大上图是面包板。可以看出,面包板中间的金属爪是竖着排列的,用于插各种元器件;最上和最下的两条金属爪是横着排列的,一般用于供电。注意,在使用面包板之前,一定要观察孔位的连接情况,比如接电源那里可能会有断开的情况,而且用杜邦线插拔可能会接触不到位的情况。

二 、实验:LED闪烁、LED流水灯、蜂鸣器提示

2.1 需求1:面包板上的LED以1s为周期进行闪烁。亮0.5s,灭0.5s…

  • LED低电平驱动

低电平驱动(Low-Level Driving)是指在数字电路中,输出信号的电平为低电平(通常为低电压)时,能够正确地驱动连接的设备或元件。在数字电路中,通常将高电平定义为逻辑1,低电平定义为逻辑0。相当于低电平触发。

  • 需要用到延时函数Delay.h、Delay.c ,在UP提供的“程序源码”中,为了方便管理,应在工程内建System文件夹,专门存放这些可以复用的代码。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大上图为LED闪烁接线图,实际上,应该在led和驱动电源之间接上保护电阻,但由于本电路过于简单,于是直接省略保护电阻。后面的"LED流水灯“、”蜂鸣器提示”实验同样省略保护电阻(我试过如果Vcc接5V甚至更大,如图的小发光二极管(容忍电压上限3v左右)会冒烟烧坏)

2.1 代码展示
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大

选中函数名,按F12进入查看函数参数原型(部分注释没有改过来别搞乱了,关注点是红色框框)
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大

上图为除库函数之外的LED闪烁-代码调用
main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
															//使用各个外设前必须开启时钟,否则对外设的操作无效
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;					//先定义结构体变量,再给结构体赋值
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//GPIO模式,赋值为推挽输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				//GPIO引脚,赋值为第0号引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//GPIO速度,赋值为50MHz
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将赋值后的构体变量传递给GPIO_Init函数
															//函数内部会自动根据结构体的参数配置相应寄存器
															//实现GPIOA的初始化
	
	/*主循环,循环体内的代码会一直循环执行*/
	while (1)
	{
		/*设置PA0引脚的高低电平,实现LED闪烁,下面展示3种方法*/
		
		/*方法1:GPIO_ResetBits设置低电平,GPIO_SetBits设置高电平*/
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为低电平
		Delay_ms(500);										//延时500ms
		GPIO_SetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
		
		/*方法2:GPIO_WriteBit设置低/高电平,由Bit_RESET/Bit_SET指定*/
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);		//将PA0引脚设置为低电平,第三个参数是指定写入的值
		Delay_ms(500);										//延时500ms
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);			//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
		
		/*方法3:GPIO_WriteBit设置低/高电平,由数据0/1指定,数据需要强转为BitAction类型*/
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);		//将PA0引脚设置为低电平
		Delay_ms(500);										//延时500ms
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);		//将PA0引脚设置为高电平
		Delay_ms(500);										//延时500ms
	}
}

Delay.c //延时模块,不用管代码怎么实现,直接拿来用就行

#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 

Delay.h

#ifndef __DELAY_H   //这是预处理指令,用来判断某个宏是否已经定义,如果该宏(没有)定义,则执行下面的代码
#define __DELAY_H  //宏定义

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

当一个头文件(例如delay.h)被多个源文件引用时,可以使用预处理指令 #ifndef、#define 和 #endif 来确保头文件只被编译一次。

#ifndef 预处理指令:
#ifndef 是 “if not defined” 的简写。
#ifndef 用于检查某个宏是否未定义。如果该宏未定义,则执行下面的代码。
如果宏已经定义过了,#ifndef 中的代码将被忽略。

举例子说明:
#endif 是C/C++中的预处理指令,用于结束条件编译块。

当在代码中使用 #ifdef#ifndef#if 这些条件编译指令时,需要使用 #endif
来标记条件编译块的结束位置。

例如,以下是一个简单的条件编译示例:

#ifdef DEBUG_MODE
    // 调试模式下执行的代码
    printf("Debug mode is enabled.\n");
#else
    // 正常模式下执行的代码
    printf("Debug mode is disabled.\n");
#endif 

在这个示例中, #ifdef DEBUG_MODE  判断是否定义了  DEBUG_MODE
宏。如果定义了该宏,则执行调试模式下的代码;否则,执行正常模式下的代码。

最后的 #endif 指令用于标记条件编译块的结束位置。它表示上面的条件编译块已经结束,之后的代码将会被正常编译。

总结来说, #endif  用于结束条件编译块,它与  #ifdef 、 #ifndef  或  #if 
一起使用,确保条件编译的范围正确闭合。

注意:此后Delay.h、Delay.c 将作为常用处理函数长期存放于System文件夹中,后续如果使用到将直接调用,故后续不会再在笔记中展示源代码。
编程感想:

  1. Keil编译过后,整个工程会比较大,不利于分享给别人。可以使用UP主提供的批处理程序(KeilKill.bat),删掉工程中的中间文件后再分享给别人(编译前2M,编译后20M,所以要使用批处理程序),其他人使用的时候只需要重新编译一下就行。
  2. 本教程用到了RCC和GPIO两个外设,这些外设的库函数在Library中,一般存放在相应的.h文件的最后。
  3. 将LED的短脚接负极,长脚接PA0口,就是高电平驱动方式,但是现象和低电平相同。
  4. 将GPIO设置成开漏输出模式,可以发现高电平(高阻态)无驱动能力,低电平有驱动能力,所以一般常使用推挽输出模式 ,以便同时具备高电平和低电平的驱动能力。

5.记得添加文件夹的路径

2.2 需求2: 8个LED实现流水灯

面包板上的8个LED以0.5s切换一个的速度,实现流水灯。低电平驱动。
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大上图为LED流水灯-接线图
代码调用关系与“2-1的LED闪烁实验”相同,下面是代码展示:
main.c

#include "stm32f10x.h"                  // Device header 
#include "Delay.h"

int main(void){
//  //配置RCC寄存器,使能GPIOC的时钟。GPIO都属于APB2外设
//  RCC->APB2ENR = 0x00000010;
//  //配置寄存器PC13:通用推挽输出模式、输出模式50MHz
//  GPIOC->CRH = 0x00300000;
//  //输出数据寄存器PC13:
//  //GPIOC->ODR = 0x00002000;//LED灭
//	GPIOC->ODR = 0x00000000;//LED亮
	
	//1.开启GPIO的外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//2.配置寄存器PC13的端口模式
	//2.1 首先配置GPIO结构体
	GPIO_InitTypeDef GPIO_InitStructure ;//给结构体起名字
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//寄存器模式为通用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//寄存器引脚为13
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度为50MHz
	//2.2 然后才能调用函数配置寄存器
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//3.配置数据寄存器PC13的输出
	//GPIO_SetBits(GPIOC,GPIO_Pin_13);//设置高电平,灯灭
//	GPIO_ResetBits(GPIOC,GPIO_Pin_13);//设置低电平,灯亮
	  
  while(1)
{
	
	//使用GPIO_SetBits、GPIO_ResetBits进行赋值,这里仅用于演示“或操作”同时赋值
	
	GPIO_SetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
	GPIO_ResetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
	//使用GPIO_Write,同时设置GPIOA所有引脚的高低电平,实现LED流水灯
	//对指定的端口同时赋值
	GPIO_Write(GPIOA,~0x01);  //0x0001  二进制:0000 0000 0000 0001
	Delay_ms(500);
	GPIO_Write(GPIOA,~0x02);  //二进制:0000 0000 0000 0010
	Delay_ms(500);
	GPIO_Write(GPIOA,~0x04);//二进制:0000 0000 0000 1000
	Delay_ms(500);
	GPIO_Write(GPIOA,~0x08);
	Delay_ms(500);
	GPIO_Write(GPIOA,~0x010);
	Delay_ms(500);
	 GPIO_Write(GPIOA, ~0x20);
	Delay_ms(500);
	GPIO_Write(GPIOA, ~0x40);
	Delay_ms(500);
	GPIO_Write(GPIOA, ~0x80);//对应的二进制数 1000 0000,表示最高位的引脚
}
}


思路:使用或操作 | 就可以实现只初始化定义某几个GPIO,或者某几个外设的时钟

2.3 需求3:蜂鸣器不断地发出滴滴、滴滴…的提示音。蜂鸣器低电平触发。

注:蜂鸣器执行四个动作为1个周期,分别是响0.1s,静音0.1s,响0.1s,静音0.1s。
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大
上图是蜂鸣器提示-接线图(GPIOB,Pin_12)
代码调用关系与“LED闪烁”实验相同,下面是代码展示:
mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void){
    // 开启APB2-GPIOB的外设时钟RCC
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    // 初始化PB12端口:定义结构体及参数
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    while(1){
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        Delay_ms(600);
    };
}


编程感想:
1.控制蜂鸣器的IO端口可以随便选,但是不要选择三个JTAG调试端口:PA15、PB3、PB4。本实验选择PB12端口进行输出。
2.关于调用库函数,有以下几种方法:

  • 直接查看每一个外设的.h函数,拖到最后就可以看到本外设的所有库函数,然后在对应的.c文件中查看函数定义和调用方式即可。
  • 查看库函数的用户手册-“stm32f103xx固件函数库用户手册.pdf”,这个中文版比较老;新版本的用户手册可以在st公司的帮助文档中查看,但只有英文版。
  • CSDN百度别人的代码。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大

三、硬件介绍-按键开关、光敏电阻

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大上图是按键开关实物图,虽然前面说过,GPIO端口有专门的肖特基触发器对输入信号进行整型,但按键开关的抖动幅度大、时间长,所以还需要“软件消抖”。基本思路就是延迟5-10ms,跳过抖动时间范围即可。
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大
上图是按键开关硬件电路,上图给出了按键开关的硬件电路设计图(下接按键(常用)和上接按键)。对于按键开关来说,常见以上四种设计方法,而行业规范中,单片机端口一般都有上拉输入模式(弱上拉),所以基本上就选择内部上拉/外部上拉的设计电路。

  • 下接按键(常用):第一个图,按下按键,引脚为低电平,松手,引脚为高电平
  • 如果电路同时存在内部上拉和外部上拉,那么其高电平的驱动能力更强,但是低电平会更加耗电。两个下拉电路则可以使低电平驱动能力更强,而不会明显增加损耗。
  • 浮空输入模式下,每部没有上下拉,此时必须在外部有上下拉电路。
  • 注意内部和外部的上下拉必须一致,内部有上下拉时,就可以不用配置外部上下拉。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大
上图是传感器模块实物图,从左到右依次是:光敏电阻传感器、热敏电阻传感器、对射式红外传感器、反射式红外传感器。传感器(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出。
嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大上图是传感器模块原理图:
上述所给出的是一个比较通用的传感器模块格式

  • 左起第三个模块:下面的可变电阻就是各种传感器模块所对应的阻值,与上面的分压电压R1进行,进而输出模拟电压值A0。电容C2是滤波电容。
  • 左边起第一个模块:使用LM393模块,通过运算放大器实现“电压比较器”的功能。IN-是一个可以调节的值,IN+则直接连接传感器的模拟分压AO,当AO>IN-时,数字输出DO拉高;当AO<IN-时,数字输出DO拉低。
  • 左边起第二个模块:通过一个滑变电阻器实现比较电压IN-的调整。
  • 左边起第四个模块:电源指示灯。
  • 左边起第五个模块:传感器模块的端口。LED2用于指示数字输出DO的值。注意R5上拉电阻保证DO的默认值为高。
    补充情况:
    1.对于对射式红外传感器来说,N1就是红外接收管,并且额外还有一个点亮红外发射管的电路,模拟电压表示时接收红外信号的强度。并且该模块常用于检测通断,所以用两个电阻将阈值固定为1/2的参考电压,而不是采用滑动变阻器。
    2.对于反射式红外式传感器,向下发射和接收红外光,可以做循迹小车。

而对于传感器模块的电路设计来说,由于采用模块的方案,所以直接给传感器接上VCC和GND,将模拟信号AO和数字信号DO接在stm32的对应端口上即可。
本次实验采用数字信号DO接入,关于模拟信号接入的使用方法在后面AD/DA的实验中继续讲解。

四、 实验 按键控制LED、光敏传感器控制蜂鸣器

4.1 需求1:一个按键开关控制一个LED,每次按下按键,LED就改变自己的亮灭状态;两套系统互不影响

  • LED低电平驱动。
  • 按键B11控制LEDA2,按键B1控制LEDA1.
  • LED的状态改变是“松开触发”。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大
上图分别依次是按键控制LED-接线图和代码调用(不包括库函数)
以下是代码展示
main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

uint8_t KeyNum;		//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	LED_Init();		//LED初始化
	Key_Init();		//按键初始化
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			LED1_Turn();			//LED1翻转
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			LED2_Turn();			//LED2翻转
		}
	}
}

LED.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);

#endif

Key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

LED.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:LED初始化,初始化PA2、PA1作为两个LED的输出端口
  * 参    数:无
  * 返 回 值:无
  */
void LED_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//开启GPIOA的时钟
	
	/*GPIO初始化*/
	//初始化PA的输出端口:定义结构体及参数
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA1和PA2引脚初始化为推挽输出
	
	/*设置GPIO初始化后的默认电平,默认输出为低电平LED初始不亮*/
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);				//设置PA1和PA2引脚为高电平
}

/**
  * 函    数:LED1开启
  * 参    数:无
  * 返 回 值:无
  */
void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);		//设置PA1引脚为低电平
}

/**
  * 函    数:LED1关闭
  * 参    数:无
  * 返 回 值:无
  */
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);		//设置PA1引脚为高电平
}

/**
  * 函    数:LED1状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);					//则设置PA1引脚为高电平
	}
	else													//否则,即当前引脚输出高电平
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);					//则设置PA1引脚为低电平
	}
}

/**
  * 函    数:LED2开启
  * 参    数:无
  * 返 回 值:无
  */
void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);		//设置PA2引脚为低电平
}

/**
  * 函    数:LED2关闭
  * 参    数:无
  * 返 回 值:无
  */
void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);		//设置PA2引脚为高电平
}

/**
  * 函    数:LED2状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void LED2_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{                                                  
		GPIO_SetBits(GPIOA, GPIO_Pin_2);               		//则设置PA2引脚为高电平
	}                                                  
	else                                               		//否则,即当前引脚输出高电平
	{                                                  
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);             		//则设置PA2引脚为低电平
	}
}

Key.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/**
  * 函    数:按键初始化,初始化B11、B1作为按键2、按键1
  * 参    数:无
  * 返 回 值:无
  */
void Key_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB1和PB11引脚初始化为上拉输入
}

/**
  * 函    数:按键获取键码
  * 参    数:无
  * 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
  * 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
  */
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;		//定义变量,默认键码值为0
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)			//读PB1输入寄存器的状态,如果为0,则代表按键1按下
	{
		Delay_ms(20);											//延时消抖
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);	//等待按键松手
		Delay_ms(20);											//延时消抖
		KeyNum = 1;												//置键码为1
	}
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下
	{
		Delay_ms(20);											//延时消抖
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);	//等待按键松手
		Delay_ms(20);											//延时消抖
		KeyNum = 2;												//置键码为2
	}
	
	return KeyNum;			//返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}

编程感想:

1 .代码提示框如果不弹出,可以使用CTRL+space 弹出代码提示框。如果没用的话,大概率是和中英切换快捷键冲突,输入法右键设置取消即可。
2.GPIO配置好之后默认就是低电平,所以配置好后LED会默认是亮的状态。
3.本工程创建了全新的驱动函数文件夹Hardware,专门用于存放程序中使用到的外设(如LED、按键、光敏传感器等)的驱动函数。做好驱动代码的提取是非常重要的,可以极大地方便梳理框架。
4.其实写完之后发现,这个按键开关非常不灵敏,经常出现按键松手后LED没有反应的情况,大概这就是设置“光敏传感器控制蜂鸣器”实验的原因吧

4.2 需求2:光敏电阻被遮挡,蜂鸣器长鸣,光敏电阻不被遮挡,蜂鸣器不响。

  • 蜂鸣器低电平驱动。
  • 光敏传感器,光强越强阻值越小,分压越小;DO的LED指示灯低电平驱动。

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大
上图是光敏传感器控制蜂鸣器的接线图,下图是代码调用(不包括库函数)

嵌入式-Stm32-江科大基于标准库的GPIO4个小实验,江科大-Stm32-学习笔记,嵌入式-STM32单片机,stm32,嵌入式硬件,单片机,mcu,江科大stm32,江科大main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"

int main(void)
{
	/*模块初始化*/
	Buzzer_Init();			//蜂鸣器初始化
	LightSensor_Init();		//光敏传感器初始化
	
	while (1)
	{
		if (LightSensor_Get() == 1)		//如果当前光敏输出1
		{
			Buzzer_ON();				//蜂鸣器开启
		}
		else							//否则
		{
			Buzzer_OFF();				//蜂鸣器关闭
		}
	}
}

Buzzer.h

#ifndef __BUZZER_H
#define __BUZZER_H

void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);
void Buzzer_Turn(void);

#endif

Buzzer.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:蜂鸣器初始化
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB12引脚初始化为推挽输出
	
	/*设置GPIO初始化后的默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_12);							//设置PB12引脚为高电平
}

/**
  * 函    数:蜂鸣器开启
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_ON(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为低电平
}

/**
  * 函    数:蜂鸣器关闭
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_OFF(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为高电平
}

/**
  * 函    数:蜂鸣器状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为高电平
	}
	else														//否则,即当前引脚输出高电平
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为低电平
	}
}

LightSensor.h

#ifndef __LIGHT_SENSOR_H
#define __LIGHT_SENSOR_H

void LightSensor_Init(void);
uint8_t LightSensor_Get(void);

#endif

LightSensor.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:光敏传感器初始化
  * 参    数:无
  * 返 回 值:无
  */
void LightSensor_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB13引脚初始化为上拉输入
}

/**
  * 函    数:获取当前光敏传感器输出的高低电平
  * 参    数:无
  * 返 回 值:光敏传感器输出的高低电平,范围:0/1
  */
uint8_t LightSensor_Get(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);			//返回PB13输入寄存器的状态
}

编程感想:
1.模块化编程香,每个模块都写一个专门的驱动函数存放在Hardware文件夹中,使得main.c函数极其简单,几乎就可以直接按照人类正常的功能逻辑书写代码
2.蜂鸣器是低电平驱动 光敏传感器,光强越强那阻值越小,分压越小;光敏电阻被阻挡,蜂鸣器长鸣。
3.获取光敏电阻返回的GPIO值初始值是1,当有光源时,变为0。

参考:B站STM32江协自动化&【哈工大虎慕】文章来源地址https://www.toymoban.com/news/detail-812951.html

道友:蹉跎者光阴如梭,有志者岁月如歌

到了这里,关于嵌入式-Stm32-江科大基于标准库的GPIO4个小实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式-stm32-江科大-EXTI外部中断

    1.1 STM32 中断系统 中断 是指在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续执行, 当中断发生时是由硬件自动调用中断函数执行的,期间编译器会保护现场最后还原现场

    2024年01月25日
    浏览(52)
  • 嵌入式——新建STM32工程(标准库)

    目录 一、初识标准库 1.CMSIS标准及库层级关系 2.库文件介绍 (1)Libraries文件夹 ①CMSIS文件夹 ②STM32F10x_Std_Periph_Driver文件夹 ③ 在用库建立一个完整的工程时,还需要添加stm32f10x_it.c、 stm32f10x_conf.h 和 system_stm32f10x.c文件 (2)Project文件夹 (3)Utilities文件夹 3.库各文件之间的关

    2024年01月23日
    浏览(59)
  • 嵌入式毕设分享 基于单片机的风速测量系统 - 物联网 嵌入式 stm32 arduino

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(69)
  • 嵌入式毕设分享 基于单片机的智能音响设计与实现 -物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月22日
    浏览(60)
  • 【项目设计】基于STM32人脸识别系统 - 单片机 物联网 嵌入式

    项目设计主要是对于所学知识的整体回顾,需要结合各个学科,才能做出达到符合标准的设计。 文章的目的在分享优质的项目以及项目经验,提供设计思路,欢迎交流与指正不足之处。 由于人脸识别技术具有无需接触、安全性高、可靠性高等优点,在身份认证领域具有广阔

    2024年01月21日
    浏览(69)
  • stm32毕设分享 基于stm32的便携用电功率统计系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月22日
    浏览(62)
  • 毕设开源 基于stm32的智能平衡小车 - 单片机 物联网嵌入式

    文章目录 0 前言 1 项目背景 2 设计思路 3 硬件设计 4 软件设计 4.2 直立控制程序设计 4.3 速度控制程序设计 4.4 方向控制程序设计 4.5 关键代码 5 最后 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这

    2024年02月22日
    浏览(65)
  • STM32G431RB--基于HAL库(蓝桥杯嵌入式赛前梳理)

    明天就进行蓝桥杯的比赛了,最后一天再重新梳理一下各个模块的使用和代码的编写。 如果各个模块的MX配置是根据我之前发的来的,那么这篇文章中的代码完全适用;如不是,原理部分也是相同的,代码部分适用,可以自行判断,作为一个参考。 引脚: 1.控制LED灯亮灭时需

    2023年04月08日
    浏览(96)
  • 毕业设计 - 基于STM32的智能路灯设计与实现 - 物联网 嵌入式 单片机

    Hi,大家好,今天向大家介绍一个 单片机项目 基于STM32的智能路灯设计与实现 大家可用于 课程设计 或 毕业设计 🔥 项目分享与指导: https://gitee.com/sinonfin/sharing 每当夜幕降临,城市中各种各样、色彩缤纷的路灯亮起,为城市披上了一层绚丽的外衣。但在这绚丽的外表下则隐

    2024年02月05日
    浏览(59)
  • 【毕业设计】基于RFID的门禁系统 - 单片机 物联网 嵌入式 stm32

    Hi,大家好,这里是丹成学长,今天向大家介绍一个 如何使用RFID技术构建一个单片机门禁系统 基于RFID的门禁系统 大家可用于 课程设计 或 毕业设计 单片机-嵌入式毕设选题大全及项目分享: https://blog.csdn.net/m0_71572576/article/details/125409052 本篇博客,学长先向大家介绍射频识别

    2024年02月03日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包