STM32学习笔记---GPIO篇

目录

一、什么是GPIO口

1、GPIO口的作用

2、GPIO口的描述和数量

3、GPIO口控制器

二、如何配置GPIO口

1、GPIO口控制器框图

1.1 一个GPIO口可以配置几种模式

①输入

②通用输出

③复用功能

④模拟模式

1.2 通用输出和通用输入的细节说明

①通用输入部分

a.怎么读

 b.如何保持电平状态

c.读之前怎么配置

②通用输出部分

a.怎么输出

b.输出之前怎么配置

2、GPIO口寄存器描述

2.1 如何看寄存器

2.2 知道哪些模式具体使用那些寄存器配置

①通用输入

②通用输出

③复用模式

④模拟模式

2.3 总结配置思路

①输入:

②输出:

三、具体使用GPIO口

1、关于LED灯的使用

需求1:控制核心板的四个LED灯亮灭

需求2:流水灯函数(计数思想切换灯)

2、关于蜂鸣器的使用

需求:控制蜂鸣器的开关

3、关于按键的使用

需求:四个按键控制四个LED

4、关于传感器的使用

 4.1  传感器分类:

4.2 检测电平信号类传感器的使用

①火焰检测传感器

②红外避障传感器

总结:


一、什么是GPIO口

1、GPIO口的作用

GPIO是单片机与外界进行信息交换的唯一窗口;

2、GPIO口的描述和数量

STM32F407VG(E)T6有100引脚,其中包括5组IO口

5组:GPIOA,GPIOB,到E  每一组有0~15号(16个)   //16*5==80

GPIOA:0 1 2 3......15             16个    

GPIOB:0 1 2 3......15             16个

GPIOC:0 1 2 3......15             16个    

GPIOD:0 1 2 3......15             16个

GPIOE:0 1 2 3......15             16个    

PA5表示:GPIOA组的5号IO口  

3、GPIO口控制器

GPIO控制器: 每组都有一个GPIO控制器控制16个IO口   

 

二、如何配置GPIO口

GPIO框图:

1、GPIO口控制器框图

1.1 一个GPIO口可以配置几种模式

①输入

        直接读(检测)IO口的电平状态

②通用输出

        内核直接控制IO输出高低电平

③复用功能

a.复用输入:从IO进来的数据信号要经过片上外设(串口控制器),再到内核

b.复用输出:内核将数据信号发送到片上外设,片上外设再通过IO口传送出去

注:在M4中选用复用模式时没有严格的区分输入输出

④模拟模式

a.模拟输入:外界的模拟量(电压)通过IO口进入到ADC控制器,ADC控制器转换成数字量

b.模拟输出:  内核将数字信号发送到DAC上,DAC将数字信号转换成电压值,通过IO出去

1.2 通用输出和通用输入的细节说明

①通用输入部分

通用输入说明:

a.怎么读

①如何读取电平状态,通过读输入数据寄存器的对应位是0还是1,来确定IO高低电平

②上下拉电阻作用

           在通用输入的时候,也就是在读某个IO的电平的时候, 一定要让此IO口先保持一个电平状态,这样才能检测到不同电平状态。

 b.如何保持电平状态

①可以通过芯片内部的上下拉电阻,由于是弱上下拉一般不用

②硬件外界一个上拉电阻或者下拉电阻

c.读之前怎么配置

打开GPIOx的时钟

配置GPIOx的模式(输入模式 00  输出模式 01  复用模式 10  模拟模式 11)  --->端口模式寄存器

配置GPIOx的上下拉(无上下拉-0 上拉-01 下拉-10) --->端口上下拉寄存器

读取GPIOx的数据--->端口输入数据寄存器

②通用输出部分

通用输出说明:

a.怎么输出

①输出原则

   对输出数据寄存器的对应位写0 或 1,就可以控制对应编号的IO口输出低/高电平

②输出类型

推挽输出:IO口可以输出高电平,也可以输出低电平

开漏输出:IO口只能输出低电平

所以:在输出的时候,要选择推挽或者开漏

③关于场效应管(MOS管)的补充

④对于输出上下拉起到什么作用

  1. 放大电信号
  2. 降低功耗,但是电阻太大,电信号太弱,不用
b.输出之前怎么配置

打开GPIOx的时钟

配置GPIOx的模式(输入模式 00  输出模式 01  复用模式 10  模拟模式 11) --->端口模式寄存器

配置GPIOx的输出类型(推挽-0 开漏-1) --->端口输出类型寄存器

配置GPIOx的输出速度(2Mhz-00 25Mhz-01 50Mhz-10 ) --->端口输出速度寄存器

配置GPIOx的上下拉(无上下拉-0 上拉-01 下拉-10) --->端口上下拉寄存器

配置GPIOx的输出数据(具体看什么电平触发) --->端口输出数据寄存器

2、GPIO口寄存器描述

2.1 如何看寄存器

看中文参考手册---GPIO寄存器内容

2.2 知道哪些模式具体使用那些寄存器配置

①通用输入

端口模式寄存器

端口上下拉寄存器

端口输入数据寄存器

②通用输出

端口模式寄存器

端口输出类型寄存器

端口输出速度寄存器

端口上下拉寄存器

端口输出数据寄存器

③复用模式

输入:

端口模式寄存器

端口上下拉寄存器

复用功能寄存器

输出:

端口模式寄存器

端口输出类型寄存器

端口输出速度寄存器

端口上下拉寄存器

复用功能寄存器

④模拟模式

输入:

端口模式寄存器

输出:

端口模式寄存器

2.3 总结配置思路

在本篇着重输入输出,复用模拟在后面再继续细说.....

①输入:

打开GPIOx的时钟

配置GPIOx的模式

配置GPIOx的上下拉

②输出:

打开GPIOx的时钟

配置GPIOx的模式

配置GPIOx的输出类型

配置GPIOx的输出速度

配置GPIOx的上下拉

配置GPIOx的输出数据

三、具体使用GPIO口

1、关于LED灯的使用

需求1:控制核心板的四个LED灯亮灭

分析:

原理图:①具体管脚   ② 用到IO的模式灯 ③ 如何亮灭

LED1--------PC4

LED2--------PC5

LED3--------PC6

LED4--------PC7

管脚要配置通用输出模式---推挽输出

管脚输出低电平亮   输出高电平灭

思路:

所用IO的初始化配置

{

//端口模式配置------通用输出

//输出类型配置-------推挽

//输出速度配置-------2M

//上下拉配置-----------无

//输出数据寄存器配置-----关

}

LED灯初始化配置函数(四个灯):

/*
函数名: LED_init
函数功能:LED灯IO初始化
返回值:void
形参:void
函数说明:
LED1--------PC4
LED2--------PC5
LED3--------PC6
LED4--------PC7
管脚要配置通用输出模式---推挽输出
高电平熄灭,低电平点亮
*/


void LED_init(void)
{
//	打开GPIOC的时钟
	RCC->AHB1ENR |= 1 << 2;
//	配置GPIOC的模式(输出模式 01)
	GPIOC->MODER |= 0x55 << 8;
//	配置GPIOC的输出类型(推挽-0 开漏-1)
	GPIOC->OTYPER &= ~(0xf << 4);//PC4-P7配置为推挽输出
//	配置GPIOC的输出速度(2Mhz-00 25Mhz-01 50Mhz-10)
    GPIOC->OSPEEDR |= 0x55 << 8;
//	配置GPIOC的上下拉(无上下拉-00 上拉-01 下拉-10)
    GPIOC->PUPDR &= ~(0xff << 8);
//	配置GPIOC的输出数据(具体看什么电平触发)
	GPIOC->ODR |= 0xf << 4;
}

所有灯开函数   

/*
函数名: ALL_LED_ON
函数功能:4个LED灯亮
返回值:void
形参:void
函数说明:

*/
void ALL_LED_ON(void)
{
	
	LED_ON;//宏定义 #define LED_ON  (GPIOC->ODR &= ~(0xf << 4))
}

所有灯关函数:

/*
函数名: ALL_LED_OFF
函数功能:4个LED灯灭
返回值:void
形参:void
函数说明:

*/
void ALL_LED_OFF(void)
{
	
	LED_OFF;//宏定义 #define LED_OFF (GPIOC->ODR |= 0xf << 4)
}

某一个灯开函数:

/*
函数名: LEDx_ON
函数功能:某一个灯亮
返回值:void
形参:u8 x
函数说明:

*/
void LEDx_ON(u8 x)
{
	
	switch(x)
	{
		case 1:LED1_ON;break;
		case 2:LED2_ON;break;
		case 3:LED3_ON;break;
		case 4:LED4_ON;break;
		
	}
}

某一个灯关函数:

/*
函数名: LEDx_OFF
函数功能:某一个灯灭
返回值:void
形参:u8 x
函数说明:

*/
void LEDx_OFF(u8 x)
{
	
	switch(x)
	{
		case 1:LED1_OFF;break;
		case 2:LED2_OFF;break;
		case 3:LED3_OFF;break;
		case 4:LED4_OFF;break;
		
	}
}

需求2:流水灯函数(计数思想切换灯)

分析:

延时函数会影响其他功能的运行,故需要删掉延时函数,具体方法如下:

	    /**方案一**/
	    LED1_ON;
		Delay_ms(500);
		LED1_OFF;
		
		LED2_ON;
		Delay_ms(500);
		LED2_OFF;
		
		LED3_ON;
		Delay_ms(500);
		LED3_OFF;
		
		LED4_ON;
		Delay_ms(500);
		LED4_OFF;
		//缺点:1、灯多 2、延时影响其它功能的运行
		//说明:while一圈,切换4个LED
		
		/**方案二**/
		LEDx_ON(n);
		Delay_ms(100);
		LEDx_OFF(n);
		
		n++;
		if(n > 4)
		n = 1;
		//缺点:2、延时影响其它功能的运行
		//说明:while一圈,切换1个LED
		
		/**方案三**/
		LEDx_ON(n);
		count++;
		if(count == 200000)
		{
			LEDx_OFF(n);
			n++;
			if(n > 4)
			{
				n = 1;
			}
			count = 0;
		}
		//说明:while 200000圈,切换1个LED

封装流水灯函数:

/*
函数名: LED_flash
函数功能:控制流水灯速度
返回值:void
形参:u8 speed
函数说明:
    计数思想切换灯
*/

void LED_flash(u8 speed)
{
	static u8 n = 1;
	static u32 count = 0;
	LEDx_ON(n);
	count++;
	if(count >= 100000 * speed)
	{
		LEDx_OFF(n);
		n++;
		if(n > 4)
		{
			n = 1;
		}
		count = 0;
	}
	
}

2、关于蜂鸣器的使用

需求:控制蜂鸣器的开关

分析:

原理图:①具体IO     ②用到IO的模式  ③蜂鸣器如何启动

BEEP---------PE0

管脚要配置通用输出模式---推挽输出

高电平开  低电平关

思路:

蜂鸣器所用的IO口初始配置

{

//端口时钟使能

//端口模式配置

//端口输出类型

//端口输出速度

//上下拉

//输出数据寄存器---关---低

}

蜂鸣器IO初始化函数:

/*
函数名: Beep_init
函数功能:蜂鸣器IO初始化
返回值:void
形参:void
函数说明:
BEEP---------PE0
高电平开(NPN)  低电平关 
管脚要配置通用输出模式---推挽输出
*/
void Beep_init(void)
{
	//打开GPIOE的时钟
	RCC->AHB1ENR |= 1 << 4;
	
	//配置GPIOE的模式---输出01
	GPIOE->MODER |= 1 << 0;
	
	//配置GPIOE的输出类型---推挽0  
	GPIOE->OTYPER &= ~(1 << 0);
	
	//配置GPIOE的速度---50hz			
	GPIOE->OSPEEDR |= 2 << 0;
	
	//配置GPIOE的上下拉---无     
	GPIOE->PUPDR &= ~(3 << 0);
	
	//配置GPIOE的输出数据				
	GPIOE->ODR &= ~(1 << 0);
}

3、关于按键的使用

需求1:四个按键控制四个LED

分析:原理图:①具体IO     ②用到IO的模式  ③内核如何识别按键是否按下

通过原理图确定按键是配置为通用输入模式

KEY1-----------PA0    检测到高电平表示按键按下

KEY2-----------PE2    检测到低电平表示按键按下

KEY3-----------PE3    检测到低电平表示按键按下

KEY4-----------PE4    检测到低电平表示按键按下

思路:

按键所用IO初始化函数

{

 //时钟使能    A   E

 //端口模式配置--------通用输入

//上下拉-----------------浮空

}

按键扫描函数

{

  //检测按键是否按下

  //延时消抖

  //再次检测按键是否按下

  //赋值键值

  //等待按键松开

  //返回键值

}

由于等待按键会影响其它功能的运行(卡住CPU),故需要优化程序

那直接删了等待按键松开这个步骤会怎样?

结果是每次按下按键,会不断返回所按下按键的按键值,这就造成了LED灯一直在闪。这不是我们想要的效果,那需要怎么优化呢?

优化要求:

1、不能卡死程序(不能等待按键松开)

2、按下一次按键只能返回一个键值(标志位思想)

解决方案:

按下按键锁住标志位,松开按键解锁标志位

当按下按键没有松开后,锁住标志位,不允许再识别按键;

当松开按键后,解锁标志位,下次按下按键又允许识别按键。

优化程序后的具体思路:

返回值类型  按键扫描函数(void)

{

         //键值默认值

        //定义静态标志位变量

        if(按键按下)

        {

                //延时消抖

                if(按键真的按下 && 标志位)

                {

                        //赋值键值

                        //锁住标志位

                }

                if(松开按键)

                {

                      //解锁标志位

                }

        }

        //返回键值

}

按键IO初始化函数:

/*
函数名: Key_init
函数功能:按键IO初始化
返回值:void
形参:void
函数说明:
KEY1-----------PA0    检测到高电平表示按键按下
KEY2-----------PE2    检测到低电平表示按键按下
KEY3-----------PE3	  检测到低电平表示按键按下
KEY4-----------PE4    检测到低电平表示按键按下
管脚要配置通用输入模式---浮空
*/


void Key_init(void)
{
//	打开GPIOA、GPIOE的时钟
	RCC->AHB1ENR |= 1 << 0;
	RCC->AHB1ENR |= 1 << 4;
	
//	配置GPIOA、GPIOE的模式(输入模式 00)
	GPIOC->MODER &= ~(3 << 0);
	GPIOE->MODER &= ~(0x3f << 4);

//	配置GPIOA、GPIOE的上下拉(无上下拉-00 上拉-01 下拉-10)
	GPIOC->PUPDR &= ~(3 << 0);
	GPIOE->PUPDR &= ~(0x3f << 4);
	
}

按键扫描函数: 

/*
函数名: Key_scan
函数功能:按键扫描返回键值
返回值:u8
形参:void
函数说明:
按键扫描过程
1、检测按键按下
2、延时消抖
3、再次检测按键按下
4、赋值键值
5、等待按键松开
6、返回键值
*/
u8 Key_scan(void)
{
	u8 key_val = 0xff;
	static u8 key_flag = 1;
	
	//检测按键按下
	if((KEY1 || KEY2 || KEY3 || KEY4)  && key_flag)
	{
		//延时消抖
		Delay_ms(20);
		//再次检测按键按下
		if(KEY1)
		{
			//赋值键值
			key_val = 1;
		}
		if(KEY2)
		{
			//赋值键值
			key_val = 2;
		}
		if(KEY3)
		{
			//赋值键值
			key_val = 3;
		}
		if(KEY4)
		{
			//赋值键值
			key_val = 4;
		}
		//锁定标志位
		key_flag = 0;
	}
	
	
	//判断按键抬起
	if((!KEY1) && (!KEY2) && (!KEY3) && (!KEY4))
	{
		key_flag = 1;
	}
	
	
	//返回键值
	return key_val;
}

需求2: 四个按键控制流水灯

分析:

        按键1控制开

        按键2控制关

        按键3控制加速

        按键4控制减速

	    u8 keynum;
	    u8 flag = 0;
	    u8 speed = 5;
        while(1)
		{
			keynum = Key_scan();
			switch(keynum)
			{
				case 1:flag = 1;break;//按键1打开流水灯
				case 2:flag = 0;LED_OFF;break;//按键2关闭流水灯
				case 3:speed -= 1;if(speed < 1){speed = 5;}break;//按键3加速
				case 4:speed += 1;if(speed > 10){speed = 5;}break;//按键4减速
			}
			if(flag == 1)
			{
				LED_flash(speed);
			}
			
		}

优化需求:

关闭流水灯时候,调速是无作用的

        u8 keynum;
	    u8 flag = 0;
	    u8 speed = 5;
        while(1)
		{
			keynum = Key_scan();
			switch(keynum)
			{
				case 1:flag = 1;break;//按键1打开流水灯
				case 2:flag = 0;LED_OFF;break;//按键2关闭流水灯
				case 3:if(flag){speed -= 1;if(speed < 1)speed = 5;}break;//按键3加速
				case 4:if(flag){speed += 1;if(speed > 10)speed = 5;}break;//按键4减速
			}
			if(flag == 1)
			{
				LED_flash(speed);
			}
			
		}

4、关于传感器的使用

 4.1  传感器分类:

        通过检测电平信号类

        通过ADC转换获取数据类

        通过通信获取数据类

4.2 检测电平信号类传感器的使用

①火焰检测传感器

功能:

检测火焰  有无

引脚:

VCC----3.3V

GND----GND

DO  -----PC9

如何获取信号或者数据:

检测到火焰,DO引脚就会出低电平,没有火焰,就会出高电平

DO脚接到主控芯片的PC9  IO口上

IO口配置为通用输入模式,

程序设计:

火焰传感器所用IO口初始化程序(火焰传感器初始化函数)

/*
函数名:flame_init
函数功能:火焰传感器IO初始化
返回值:void
形参:void
函数说明:
VCC --- 3.3V
GND --- GND
DO  --- PC9
检测到低电平,表示有火焰;否则,反之
管脚要配置通用输入模式---浮空
*/
void flame_init(void)
{
	//打开GPIOC的时钟
	  RCC->AHB1ENR |= 1 << 2;
	//配置GPIOC的模式--输入模式---浮空
	  GPIOC->MODER &= ~(3 << 18);
	//配置GPIOC的上下拉--无
	  GPIOC->PUPDR &= ~(3 << 18);
}

获取火焰传感器数据函数

/*
函数名:flame_data
函数功能:获取火焰传感器数据
返回值:u8
形参:void
函数说明:
返回0:检测到有火焰
返回1:检测到无火焰
*/
u8 flame_data(void)
{
	if(GPIOC->IDR & (1 << 9))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

②红外避障传感器

功能:

检测障碍物2cm~30cm

引脚:

VCC-------3.3V

GND-------GND

OUT-------PC8

如何获取信号或者数据:

检测到障碍物,OUT引脚就会出低电平,没有障碍物,就会出高电平

OUT脚接到主控芯片的PC8IO口上

IO口配置为通用输入模式,

检测到IO高低电平就知道是否有障碍物

程序设计:

传感器所有用IO口初始化配置(传感器初始配置)

/*
函数名:infra_init
函数功能:红外避障传感器IO初始化
返回值:void
形参:void
函数说明:
VCC --- 3.3V
GND --- GND
OUT --- PC8
检测到低电平,表示有火焰;否则,反之
管脚要配置通用输入模式---浮空
*/
void infra_init(void)
{
	//打开GPIOC的时钟
	  RCC->AHB1ENR |= 1 << 2;
	//配置GPIOC的模式--输入模式---浮空
	  GPIOC->MODER &= ~(3 << 16);
	//配置GPIOC的上下拉--无
		GPIOC->PUPDR &= ~(3 << 16);
	  
}

传感器信号获取函数

/*
函数名:infra_data
函数功能:获取红外避障传感器数据
返回值:void
形参:u8
函数说明:
返回0:检测到有障碍物
返回1:检测到无火焰
*/
u8 infra_data(void)
{
	
	if(GPIOC->IDR & (1 << 8))
	{
		return 1;
	}
	else
	{
		return 0;
	}
	
	
}

总结:

GPIO口

  1. 什么是GPIO口

        GPIO口的作用

        GPIO口的描述和数量

        GPIO口控制器

    2.如何配置GPIO口

       2.1 GPIO口控制器框图

        一个GPIO口可以配置几种模式(能知道每种模式的使用场景)

        通用输出和通用输入的细节说明

        通用输入和通用输出 都需要配置什么

       2.2 GPIO口寄存器描述

        如何看寄存器

        知道哪些模式具体使用那些寄存器配置

        总结配置思路

        1.3 设计程序

  3.具体使用GPIO口

        关于LED灯的使用

        关于蜂鸣器的使用

        关于按键的使用

        关于传感器的使用

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值