1、STM32有5组GPIO引脚,分别是GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,每组GPIO有16个引脚。
2、每个引脚都有4个位来配置其端口,可以配置出不同的输入\输出模式
表1配置IO口输出方式
配置模式 CNF1 CNF2 M1 M0
推挽式输出 0 0 1 1 50MHz速度
开漏输出 0 1 0 1 10MHz速度
复用推挽式输出
0 0 1 0 2MHz速度
复用开漏输出
1
1
1 1 50MHz速度
模拟输入
0
0
0
0
浮空输入
0
1
0
0
下拉输入
1
0
0
0
上拉输入
1
1
0
0
M0
M1
输出速度 0
1
10MHz ; 1
0
2MHz; 1
1
50MHz
3、GPIOA->CRL(32位) 是用来配置低8个引脚的,GPIOA->CRH(32位) 是用来配置高8个引脚的。配置方式见参考手册
4、GPIOA->IDR(32位,只用到低16位配置对应16个引脚)是用来配置端口输入数据寄存器的(外设->MCU)。
5、GPIOA->ODR(32位,只用到低16位配置对应16个引脚)是用来配置端口输出数据寄存器的(MCU->外设)。
6、用软件仿真的时候,如果在一个引脚给如一个高电平,只能在Pins相应的位打上√(看程序里的第3次课代码调试)
7、位运算主要有& | ~(取反) << >> ^(异或) 等操作,因为都是针对寄存器编程,寄存器的引脚状态就0和1,所以一般用位运算。STM32不同于51和其他单片机,它内部有集成了2个对位运算的寄存器(BSRR对某一位置1,BRR对某一位清0)。这样运算的速度快,代码量少,效率高出很多倍。(具体见GPIO程序第4节课的例子)。(位运算与或的作用,清0,置1,隐藏)。
8、位绑定 把某一位映射到内存地址上,对地址的最低位进行操作来把引脚这一位给置1和清0.
位n
映射
内存地址a
n = 0/1
a = 0 2 4 8(最低位为0)/1 3 5 7(最低位为1)
传统置1和清0需要3步完成,读 修改 写
只有STM32以下2个区的位才可以进行位绑定(可以看参考手册2.3节内存分布图)
SRAM区
0x2000 0000~
0x200f
ffff
1M(20位,2~20=1M)(n = 0~7,A=0x2000 0000~0x200f
ffff)
公式:AliasAddr = 0x22000000 + ((A-0x2000 0000)*8 +n)*4
= 0x22000000 + (A-0x2000 0000)*32 +n*4
片上外设 0x4000
0000~
0x400f
ffff
1M
(n = 0~31,A=0x4000 0000~0x400f ffff)
公式:AliasAddr = 0x42000000 + ((A-0x4000 0000)*8 +n)*4
= 0x42000000 + (A-0x4000 0000)*32 +n*4
例子:把GPIOA的6位作为输出,GPIOA的14位作为输入,用位绑定的方式对其进行位操作
//A = GPIOA_BASE + ODR偏移地址 = GPIOA_BASE + 0x0c n = 6
//A = GPIOA_BASE + IDR偏移地址 = GPIOA_BASE + 0x08 n = 14
//AliasAddr = 0x42000000 + (A-0x4000 0000)*32 +n*4
u32 *PAO6 = (u32 *) (0x42000000 + (0x4001080c - 0x40000000)*32 + 6*4);0c为输出的偏移地址(手册),第6位n=6
u32 *PAI14 = (u32 *) (0x42000000 + (0x40010808 - 0x40000000)*32 + 14*4);08为输入的偏移地址(手册),第14位n=14
if (*PAI14 == 1)
*PAO6 = 1;//1也可以换成其他的奇数,只要满足最低位为1
else
*PAO6 = 0;//0也可以换成其他的偶数,只要满足最低位为0
/***通用位绑定GPIO端口****/
#define GPIOA_ODR_A (GPIOA_BASE+0x0c)
#define
GPIOA_IDR_A (GPIOA_BASE+0x08)
#define GPIOA_ODR_B (GPIOB_BASE+0x0c)
#define
GPIOA_IDR_B (GPIOB_BASE+0x08)
#define GPIOA_ODR_C (GPIOC_BASE+0x0c)
#define
GPIOA_IDR_C (GPIOC_BASE+0x08)
#define GPIOA_ODR_D (GPIOD_BASE+0x0c)
#define
GPIOA_IDR_D (GPIOD_BASE+0x08)
#define GPIOA_ODR_E (GPIOE_BASE+0x0c)
#define
GPIOA_IDR_E (GPIOE_BASE+0x08)
位绑定的指定位的地址中的值
绑定的地址的类型
取地址最高位(2或4)
次高位
取低5位并*32
相应的位n*4
#define BitBand(Addr,BitNum)
*(volatile unsigned long *)((Addr & 0xf0000000) + 0x2000000+ ((Addr & 0xfffff)<<5) + (BitNum<<2))
//在MCU运算处理器中,位运算比乘法运算要快(左移n等价于乘以2~n;右移n位等价于除以2~n),volatile关键字的作用是告诉编译器,这处的代码不需要
//去优化它,直接从源头处去读取就行了。
#define PAout(n) BitBand(GPIOA_ODR_A,n)
#define PAin(n) BitBand(GPIOA_IDR_A,n)
#define PBout(n) BitBand(GPIOB_ODR_B,n)
#define PBin(n) BitBand(GPIOB_IDR_B,n)
#define PCout(n) BitBand(GPIOC_ODR_C,n)
#define PCin(n) BitBand(GPIOC_IDR_C,n)
#define PDout(n) BitBand(GPIOD_ODR_D,n)
#define PDin(n) BitBand(GPIOD_IDR_D,n)
#define PEout(n) BitBand(GPIOE_ODR_E,n)
#define PEin(n) BitBand(GPIOE_IDR_E,n)
/****操作测试****/
if(PAin(14) == 1)
PAout(6) = 1;
else
PAout(6) = 0