一、GPIO是什么?
GPIO的全称是General-Purpose Input /Output Ports,中文意思是通用IO端口。GPIO是单片机的最基本功能之一,也是我们学习单片机最基础的部分。顾名思义,GPIO具有输入和输出功能,无论是输入还是输出,都有高电平和低电平两种形式。下面我们就来介绍一下GPIO的配置。
STM32F103ZET6有112个GPIO端口,他们分别是GPIOA——GPIOG,每组各有16个GPIO端口(0:15)。
1.GPIO的输入模式
GPIO的输入模式主要有四种,浮空输入,上拉输入,下拉输入和模拟输入,都可以通过软件配置成要用的模式。
2.GPIO的输出模式
输出模式有四种,开漏输出,推挽式输出,推挽式复用功能,开漏复用功能。通俗来说,推挽式输出高电平就是高电平,输出低电平就是低电平,而开漏输出输出低电平就是低电平,输出高电平还要看输出1时要看上拉还是下拉电阻,这个上下拉可以配置。平时用的最多的就是推挽输出。而复用推挽输出和复用开漏输出指的是GPIO口被用作第二功能时的配置情况(并非作为通用IO口使用),比如在配置串口的TXD端口时,就需要把模式配置为复用推挽输出。
二、GPIO的配置
1.使能时钟
在使用GPIO之前,我们先要使能对应GPIO的时钟,STM32F103ZET6的GPIO都是挂在APB2总线上的,所以我们要调用APB2时钟使能函数使能相应的IO端口。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
2.初始化IO口(配置IO端口)
下面给出一段代码,配置IO端口为推挽输出模式,输出速率为50MHZ
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
STM32中文参考手册给出了各个外设配置时应该选择的GPIO模式,如果不清楚该怎么配置,可以直接查阅该表。
3.输出高低电平
GPIO_SetBits(GPIOE,GPIO_Pin_5); //输出低电平为GPIO_ReSetBits
4.跑马灯实验
接下来就是著名的点灯大师的操作,下面以跑马灯为例,使用通用IO的输入和输出功能
void LED_Init()//配置I/O端口
{
// 库函数操作
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
// 寄存器操作
// *RCC->APB2ENR|=1<<3;//时钟使能
// RCC->APB2ENR|=1<<6;
// GPIOB->CRL&=0XFF0FFFFF;
// GPIOB->CRL|=0X00300000;
// GPIOB->ODR|=1<<5;
// GPIOE->CRL&=0XFF0FFFFF;
// GPIOE->CRL|=0X00300000;
// GPIOE->ODR|=1<<5;//设置I/O口模式
}
主函数为
while(1)
{
LED1=1;
LED2=0;
delay_ms(300);
LED1=0;
LED2=1;
delay_ms(300);
}
这样就实现跑马灯的功能了,其实就是交替控制连接跑马灯的IO口输出高低电平。
三、IO中断
具有112个IO端口的大容量芯片,最多可以在配置16个外部中断。
外部中断的意思就是在IO口的输入电平是我们想要的变化时(上升沿或者下降沿)就触发中断,这个可以用来检测按键的按下和测量脉冲数量。下面给出一段使用外部来检测按键按下的程序。
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); // 按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
EXTI_InitStructure.EXTI_Line=EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOE.4 中断线以及中断初始化配置 下降沿触发 //KEY0
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOA.0 中断线以及中断初始化配置 上升沿触发 PA0 WK_UP
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能按键KEY0所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
值得注意的是,在配置外部中断时需要使能AFIO时钟,这里顺便提一下,什么时候要使能AFIO时钟,我们从《STM32中文参考手册_V10》中找到:对寄存器 AFIO_EVCR、AFIO_MAPR 和 AFIO_EXTICRX 进行读写操作前,应当首先打开 AFIO 的时钟,这些寄存器是用于“事件控制”、“重映射”、“调试IO配置”、“外部中断”的。例如 AFIO_EXTICRX 用于选择 EXTIx 外部中断的输入源。
关于外部中断的部分就讲到这里,后续还会更新中断篇,会在那里更详细地记录自己的理解。
总结
GPIO的使用在单片机开发中很常见,使用起来也很简单,就是使能时钟然后根据需要配置模式即可,在使用任意一个IO之前都要记得事先配置IO才能使用,这一点经常忘记。这次的学习总结就记录到这里,请各位大佬批评指正。