在KE系列MCU中提供了多种寄存器用于实现GPIO的控制:
-PDOR寄存器,用于写入或读取IO的输出状态
-PSOR寄存器,用于置位IO口
-PCOR寄存器,用于清零IO口
-PTOR寄存器,用于翻转IO口
-PDIR寄存器,用于读取IO口的输入状态
当我们想要将PTA0置1时,有多种方法可以选择:
1. 直接操作寄存器,PDOR或PSOR都可以实现:
GPIOA->PDOR |= 0x0001;
GPIOA->PSOR |= 0x0001;
直接操作寄存器的效率更高,但可读性较差。
2. 使用官方的库函数操作
GPIO_PinSet(GPIOA, GPIO_PTA0);
库函数的可读性很好,但显得有些啰嗦,字符较多。
通过KE的BME来实现GPIO的操作能够很好的解决上面的问题,只用将附件中的头文件gpio_bitdef.h包含到工程里,再调用里边的宏定义就可以了。
对PTA0置位和清零可以使用下面的语句:
POUTA0 = -1;
POUTA0 = 0;
读取PTA0的输入状态则可以使用:
tmp = PINA0;
上面的语句是不是看上去简洁了很多呢。
实际上上面GPIO的读写指令,是通过BME的BFI(位域插入)和BFX(位域提取)指令来实现的。
-其中ADDR是存储空间内的地址,我们最终操作的还是GPIO的寄存器,因此在两个指令中分别取GPIOA的PDOR寄存器地址和PDIR寄存器地址。
-bit则表示需要插入或提取位域的起始位置,由于这里是PTA0,PTA0位于寄存器的最低位,因此这里填入了0。
-width则表示需要插入或提取位域的宽度,我们只对单个管脚进行操作,也就是单个位进行操作,宽度自然就是1了。
需要注意的是,BFI(位域插入)指令在插入时,是将对应位插入到目的地址。因此,如果直接为POUTxx赋值为1的话,有可能出现错误。
POUTA0 = 0x01;//正确
POUTA1 = 0x02;//正确
POUTA2 = 0x04;//正确
POUTA1 = 0x01;//错误
为了避免这种情况,我们可以在IO口需要置位时,直接将POUTxx赋值为-1,即0xFFFF FFFF,这样保证了每一位的值都为1。
#define BME_BFI(ADDR,bit,width) (*(volatile uint32_t *)((((uint32_t)ADDR&0xFFFF)) \
| (5 <<28) \
| ((bit)<<23) | ((width-1))<<19))
#define BME_BFX(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t)ADDR&0xFFFF) \
| (5 <<28) \
| ((bit)<<23) | ((width-1))<<19))
#define POUTA0 BME_BFI(&GPIOA->PDOR,0,1)
#define PINA0 BME_BFX(&GPIOA->PDIR,0,1)