1.1GPIO概述
1.1.1 GPIO的概念
GPIO:标准输入输出端口,每个GPIO端口上至多含有16个GPIO引脚。端口的命名方式为GPIOA、GPIOB、GPIOC......,每个端口上引脚的命名方式为 PA0、PA1、PA2........
1.1.2 GPIO的特性
参考中文数据手册
根据数据手册中列出的每个I/O端口的特定硬件特征,GPIO端口的每个位可以由软件分别配置为多种模式
输入模式——浮空输入 | 上拉输入 | 下拉输入 | 模拟输入
输出模式——开漏输出 | 推挽输出
复用模式——推挽复用 | 开漏复用
每个GPIO引脚都可以通过软件配置成各种模式
·输入/输出:以主控芯片的角度考虑数据信息的流通方向,若芯片需要从外部通过GPIO引脚获取某些数据,此时该引脚应当是输入。若芯片需要通过某个引脚向外部电路输出一个信号(输出信号、控制模块),此时该引脚应当是输出。
若一个引脚的连接对象是LED灯,那么此时该引脚功能是为了控制LED灯,信号的流通方向就应当是芯片到LED灯,则应配置为输出。
若一个引脚的连接对象是按键,该引脚功能是为了判断按键是否按下,此时信号是由按键流向芯片。则应当配置为输入。
·浮空/上拉/下拉:这三者的区别主要是在引脚的外部电路没有提供具体信号时,此时的默认电平。若为上拉输入,则默认高电平,下拉输入,默认低电平,浮空输入,以外部电路为准。
·模拟输入:模拟输入下,芯片得到的是一个模拟量数据(引脚检测到的电压值)。一般和ADC有关。
·推挽/开漏:GPIO引脚内部有两个连接起来的MOS管,在推挽模式下,我们可以主动的输出高电平或低电平,即两个MOS管都可以正常导通。在开漏模式下,只能主动的输出低电平而无法输出高电平(MOS管无法导通)。
相对于推挽模式,开漏模式有自己特有的应用场景。如,推挽模式下高电平的上限由芯片决定,而开漏模式下,可以选择在外部接上拉电阻提供高电平,此时可以增强GPIO引脚的驱动能力。开漏模式下可以实现线与功能。
·通用输出/复用输出:通用输出模式下,芯片直接操作数据寄存器,使GPIO引脚输出指定电平。复用输出是指,若通信对象与芯片进行信息交流时,传输的信息较为复杂,要求符合某种时序,那么此时可以将GPIO引脚复用给芯片的某种外设,帮助实现这种时序。
1.2 GPIO寄存器
寄存器是一个真实存在在芯片内部的存储器,用于存储一些控制信号或信息。每个寄存器都有自己的地址,我们可以通过他们的地址来找到这些寄存器,并通过对指定寄存器写入数据来实现指定的功能。在这个过程中要求我们必须找到对应的寄存器,并确定应该对寄存器如何操作。
1.2.1端口配置低寄存器
输出模式下的速度,指的是引脚电平的翻转速度
1.2.2端口配置高寄存器
与端口配置低寄存器的区别在于所操作的引脚不同
1.2.3端口输入数据寄存器
若此时需要判断 PC4的电平是高还是低,若为高打印 h 若为低打印l
if(GPIOC->IDR & (1<<4))
printf(“h”);
else
printf(“l”);
1.2.4端口输出数据寄存器
使PB2输出低电平
GPIOB->ODR &= ~(1<<2);
1.2.5 端口位设置/清除寄存器
1.3 代码实战(以STM32F103ZET6为例)
1.3.1点亮LED(寄存器版本)
初始化部分
将PB5设置为通用推挽输出
默认输出高电平(熄灭状态)
使用部分
想点亮等时输出低电平
int main(void)
{
//初始化部分
//使能GPIOB
RCC->APB2ENR |= (1<<3);//时钟激活
//将PB5设置为通用推挽输出
GPIOB->CRL &= ~(1<<23);
GPIOB->CRL &= ~(1<<22);
GPIOB->CRL |= (1<<21);
GPIOB->CRL &= ~(1<<20);
//默认输出高电平(熄灭状态)
GPIOB->ODR |= (1<<5);
while(1)//while(1)中是程序运行时实际执行的代码
{
//使用部分
//想点亮等时输出低电平
GPIOB->ODR &= ~(1<<5);
}
return 0;
}
1.3.2 时钟开启
在使用相应的外设资源前要先让时钟总线为其提供时钟频率
查看芯片数据手册
寄存器需要在RCC章节寻
想要使能GPIOB端口 只需要
RCC->APB2ENR |= (1<<3);
1.3.4源代码(寄存器编写)
LED.c
#include "main.h"
//初始化led
void led_init(void)
{
RCC->APB2ENR |=(1<<3);//RCC寄存器开启,使能GPIOB
RCC->APB2ENR |=(1<<2);//RCC寄存器开启,使能GPIOA(A:1<<2;B:1<<3;C:1<<4;D:1<<5;E:1<<6)
RCC->APB2ENR |=(1<<6);//RCC寄存器开启,使能GPIOE
//将PB5设置为通用推挽输出;
GPIOB->CRL &=~(1<<20);
GPIOB->CRL |=(1<<21);
GPIOB->CRL &=~(1<<22);
GPIOB->CRL &=~(1<<23);
//将PA5设置为通用推挽输出;
GPIOA->CRL &=~(1<<20);
GPIOA->CRL |=(1<<21);
GPIOA->CRL &=~(1<<22);
GPIOA->CRL &=~(1<<23);
//将PA6设置为通用推挽输出;
GPIOA->CRL &=~(1<<24);
GPIOA->CRL |=(1<<25);
GPIOA->CRL &=~(1<<26);
GPIOA->CRL &=~(1<<27);
//将PE5设置为通用推挽输出;
GPIOE->CRL &=~(1<<20);
GPIOE->CRL |=(1<<21);
GPIOE->CRL &=~(1<<22);
GPIOE->CRL &=~(1<<23);
//默认输出高电平(熄灭状态)
GPIOB->ODR |=(1<<5);
GPIOA->ODR |=(1<<5);
GPIOA->ODR |=(1<<6);
GPIOE->ODR |=(1<<5);
}
LED.h
#ifndef LED_H_
#define LED_H_
#include "stm32f10x.h"
#define led1_on GPIOB->ODR &=~(1<<5)
#define led1_off GPIOB->ODR |=(1<<5)
#define led2_on GPIOA->ODR &=~(1<<5)
#define led2_off GPIOA->ODR |=(1<<5)
#define led3_on GPIOE->ODR &=~(1<<5)
#define led3_off GPIOE->ODR |=(1<<5)
#define led4_on GPIOA->ODR &=~(1<<6)
#define led4_off GPIOA->ODR |=(1<<6);
void led_init(void);
#endif
main.h
#ifndef __MAIN_H
#define __MAIN_H
#include "stm32f10x.h"
#include "led.h"
#include "BEEP.h"
#endif
main.c
#include "main.h"
//#include "led.h"
void delay(unsigned int i)
{
while(i--);
}
int main(void)
{
led_init();//LED初始化
//beep_init();
while(1)
{
led1_on;
led2_on;
led3_on;
led4_on;
delay(0xFFFFF);
led1_off;
led3_off;
delay(0xFFFFF);
GPIOB->ODR &=~(1<<8);
delay(0xFFFFF);
GPIOB->ODR |=(1<<8);
delay(0xFFFFF);
}
}