一、GPIO内部结构
输出数据:从芯片内部到芯片I/O端口
方式一:通过写操作直接控制位设置/清除寄存器而后到输出数据寄存器
方式二:通过读写操作直接到达输出数据寄存器
两种方式到达输出数据寄存器后到达输出控制(即一个锁存器),通过输出控制,可改变输出信号值。
eg:输出数据寄存器向输出控制(锁存器)输出信号1,则P-MOS处信号为1,N-MOS处信号为0,则输出Vdd高电平(3.3V),反之,输出数据寄存器向输出控制(锁存器)输出信号0,则P-MOS处信号为0,N-MOS处信号为1,则输出Vss低电平。
输入数据:从芯片I/O端口到芯片内部(保护二极管可防止输入电平过高或过低对芯片内部电路造成损坏)
通用功能I/O(GPIO)和复用功能I/O(APIO)
GPIO功能描述:每个GPIO端口有两个32位配置寄存器(GPIOx_CRL,GPIOx
_CRH,即上文所说的控制寄存器),两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。
根据数据手册中列出的每个I/O端口的特定硬件特征,GPIO端口的每个位可以由软件分别配置完成多种模式。
输入浮空、输入上拉、输入下拉、模拟输入、
开漏输出、推挽输出(P-MOS、N-MOS均正常工作)、推挽式复用功能、开漏式复用功能
每个I/O端口位可以自由编程,然而I/O端口寄存器必需按32位字被访问(不允许半字或者字节访问),GPIOx_BSRR和GPIOx_BRR允许对任何GPIO寄存器的读/更改的独立访问,这样,在读和更改访问之间产生IRQ时不会发生危险。
(CNF0最后一行应为1、0)
通用I/O(GPIO)
复位期间和刚复位后,复用功能未开启,I/O端口被配制成浮空输入模式(CNFx[1:0] = 01b,MODE[1:0] = 00b)
复位后,JTAG引脚被置于输入上拉或下拉模式
PA15:JTD1置于上拉模式
PA14:JTCK置于下拉模式
PA13:JTMS置于上拉模式
PB4:JNTRST置于上拉模式
当作为配置输出时,写到输出数据寄存器上的值(GPIOx_ODR)输出到相应的I/O引脚。可以以推挽模式或者开漏模式(当输出0时,只有N-MOS被打开)使用输出驱动器。
输入数据寄存器(GPIOx_IDR)在每个APB2时钟周期捕捉I/O引脚上的数据)
所有GPIO引脚有一个内部弱上拉和弱下拉,当配置为输入时,它们可以被激活也可以不被激活.
单独的未设置或者位清除
当对GPIOx_ODR的个别位编程时,软件不需要禁止中断,在单次APB2写操作里,可以只更改一个或者多个位。
这是通过对“置位/复位寄存器”(GPIOx_BSRR)中想要该写位写1来实现的,没被选择的位则不被更改。
所有的端口都有外部中断能力,为了使用外部中断线,端口必须配置成输入模式。
输入配置:
当I/O端口配置为输入时:
输出缓冲器被禁止,施密特触发输入被激活,根据输入配置(上拉、下拉、浮空)的不同,弱上拉和下拉电阻被连接
出现在I/O引脚上的数据在每个APB2时钟被采样到输入数据寄存器,对输入数据寄存器的读访问可得到I/O口的状态
输出配置:
当I/O端口被配置为输出时:
输出缓冲寄存器被激活
—开漏模式:输出寄存器上的0激活N-MOS,而输出寄存器上的1将端口置于高阻状态(P-MOS从不被激活)
—推挽模式:输出寄存器上的0激活N-MOS,而输出寄存器上的1将激活P-MOS
施密特触发输入被激活,弱上拉和下拉电阻被禁止,出现在I/O引脚上的数据在在每个APB2时钟被采样到输入数据寄存器,在开漏模式时,对输入数据寄存器的读即可得到I/O状态,在推挽模式时,对输入数据寄存器的读访问的得到最后一次写的值。
eg:x = A;则CRL控制GPIOA的0 —15引脚的工作模式
eg:x = A;则CRL控制GPIOA的8—15引脚的工作模式
编程:一、
1、设置GPIOA引脚的工作模式,GPIOA.0,GPIO.1,推挽输出,速度50MHz
GPIOA->CRL = 0x33;
2、在相应的引脚输出一个电平
GPIOA->ODR = 0x0; //00
GPIOA->DDR = 0x3; //11
二、
int main(void)
{
// 1、GPIOA.0口输出 PA.8口输入
GPIOA->CRL = 0x03; //50MHz推挽式输出
GPIOA->CRH = 0x04; //浮空输入
//2、PA.0 == PA.8
while(1)
{
if((GPIOA->IDR & 0x0100) == 0x0100)
GPIOA->ODR = 0x01;
else
GPIOA->ODR = 0x00;
}
return (1);
}
三、
&:与运算,隐藏,清零
GPIOA->CRL & 0x01(起到隐藏作用,只与部分位进行运算)
GPIOA->CRL & ~(0x01) (起到对最低一位清零的作用)
| :或运算,置一
GPIOA->CRL = GPIOA->CRL | 0x01(起到对最低一位置一的作用)
GPIOA->CRH高八位输入控制低八位CRL输出
//1、PA.0-PA.7 50MHz推挽输出 PA.8-PA.15浮空输入
GPIOA->CRL = 0x33333333;
GPIOA->CRH = 0x44444444;
//2、输入状态反应到对应引脚的输出
while(1)
{
if((GPIOA->IDR) & 0x0100) == 0x0100) GPIOA->ODR = GPIOA->ODR | 0x01;
else GPIOA->ODR = GPIOA->ODR & (~0x01);
if((GPIOA->IDR) & 0x0100) == 0x0200) GPIOA->ODR = GPIOA->ODR | 0x02;
else GPIOA->ODR = GPIOA->ODR & (~0x02);
if((GPIOA->IDR) & 0x0100) == 0x0400) GPIOA->ODR = GPIOA->ODR | 0x04;
else GPIOA->ODR = GPIOA->ODR & (~0x04);
if((GPIOA->IDR) & 0x0100) == 0x0800) GPIOA->ODR = GPIOA->ODR | 0x08;
else GPIOA->ODR = GPIOA->ODR & (~0x08);
if((GPIOA->IDR) & 0x0100) == 0x1000) GPIOA->ODR = GPIOA->ODR | 0x01;
else GPIOA->ODR = GPIOA->ODR & (~0x10);
if((GPIOA->IDR) & 0x0100) == 0x2000) GPIOA->ODR = GPIOA->ODR | 0x01;
else GPIOA->ODR = GPIOA->ODR & (~0x20);
if((GPIOA->IDR) & 0x0100) == 0x4000) GPIOA->ODR = GPIOA->ODR | 0x01;
else GPIOA->ODR = GPIOA->ODR & (~0x40);
if((GPIOA->IDR) & 0x0100) == 0x8000) GPIOA->ODR = GPIOA->ODR | 0x01;
else GPIOA->ODR = GPIOA->ODR & (~0x80);
}
方法二:
端口位设置/复位寄存器(GPIOx_BSRR)(x=A……E)
端口复位寄存器(GPIOx_BRR)(x = A……E)
GPIOA->BSRR = 0x01;
GPIOA->BRR = 0x01;
方法三:
#define PA1 GPIOA->BSRR
#define PA0 GPIOA->BRR
PA1 = 0x01;
PA0 = 0x01;
根据硬件所提供的BSRR及BRR寄存器即可实现功能。