[开发资料] GPIO位输出操作的几种方法

[复制链接]
763|47
 楼主| mikewalpole 发表于 2025-7-24 22:52 | 显示全部楼层 |阅读模式
1、端口位设置/清除

   可对BSRR、BRR寄存器相应的位置1,以实现置位和清零操作,如:

  1.   GPIOA->BSRR = (1<<3);          // 设置端口A的位3为1

  2.   GPIOA->BRR  = (1<<3);          // 清除端口A的位3为0




2、端口直接输出

   可对ODR寄存器相应的位置1或0,以实现置位和清零操作,如:  

  1.   GPIOA->ODR |=  (1<<3);        // 端口A的位3输出1

  2.   GPIOA->ODR &= ~(1<<3);        // 端口A的位3输出0




3、端口位带输出

  参考《Cortex-M3 权威指南》第五章,第5小节 位带操作(87页~92页)。

  为简化位带操作,可以定义一些宏。比如,我们可以建立一个把“位带地址+位序号”转换成别名地址的宏, 再建立一个把别名地址转换成指针类型的宏。  


  1.   //1):把“位带地址+位序号”转换成别名地址的宏

  2.   #define     BITBAND(addr, bitnum)    ((addr & 0xF0000000)+0x2000000+((addr & 0xFFFFF)<<5)+(bitnum<<2))

  3.   //2):把该地址转换成一个指针

  4.   #define     MEM_ADDR(addr)        *((volatile unsigned long *) (addr))

  5.   //3):使用位带别名地址访问

  6.   #define     BIT_ADDR(addr, bitnum)    MEM_ADDR(BITBAND(addr, bitnum))


  应用如下:



  1.   #define  PAout(n)  BIT_ADDR((uint32_t)&GPIOA->ODR, n)

  2.     

  3.   PAout(3) = 1;    //端口A的位3输出1

  4.   PAout(3) = 0;    //端口A的位3输出0




4、端口位域输出

  定义一个端口位域  


  1.   #pragma  anon_unions    //以便结构体或共用体无需另起名字

  2.   

  3.   typedef union{

  4.     uint32_t WORDS;

  5.     struct{

  6.       int    bit00    :1;

  7.       int    bit01    :1;

  8.       int    bit02    :1;

  9.       int    bit03    :1;

  10.       int    bit04    :1;

  11.       int    bit05    :1;

  12.       int    bit06    :1;

  13.       int    bit07    :1;

  14.       int    bit08    :1;

  15.       int    bit09    :1;

  16.       int    bit10    :1;

  17.       int    bit11    :1;

  18.       int    bit12    :1;

  19.       int    bit13    :1;

  20.       int    bit14    :1;

  21.       int    bit15    :1;

  22.       int    bit16    :1;

  23.       int    bit17    :1;

  24.       int    bit18    :1;

  25.       int    bit19    :1;

  26.       int    bit20    :1;

  27.       int    bit21    :1;

  28.       int    bit22    :1;

  29.       int    bit23    :1;

  30.       int    bit24    :1;

  31.       int    bit25    :1;

  32.       int    bit26    :1;

  33.       int    bit27    :1;

  34.       int    bit28    :1;

  35.       int    bit29    :1;

  36.       int    bit30    :1;

  37.       int    bit31    :1;

  38.       };

  39.   }PORT;



  应用如下:



  #define  PAout03  (((PORT *)(&GPIOA->ODR))->bit03)

  PAout03 = 1;    //端口A的位3输出1
  PAout03 = 0;    //端口A的位3输出0



5、综述

  以上4种方法,1、2两种较为多见;方法3为位带操作,速度最快,但只对具备位带的U有效;方法4是一种新颖的通用方法,只要找到输入或输出寄存器即可,对任意U有效!

迷雾隐者 发表于 2025-7-28 19:00 | 显示全部楼层
确实,端口位设置/清除和端口直接输出是最常用的方法,简单直接。
迷雾隐者 发表于 2025-7-28 20:22 | 显示全部楼层
确实,端口位设置/清除是最常用的方法之一,简单直接。
我是一颗胖蘑菇 发表于 2025-7-29 12:41 | 显示全部楼层
确实,端口位设置/清除是最常用的方法之一,简单直接。
forgot 发表于 2025-7-30 09:00 | 显示全部楼层
为简化位带操作,可以定义一些宏。端口位设置/清除和端口直接输出是最常用的方法,简单直接。
wwppd 发表于 2025-8-4 10:39 | 显示全部楼层
直接寄存器操作              
dspmana 发表于 2025-8-4 12:11 | 显示全部楼层
直接操作寄存器                      
linfelix 发表于 2025-8-4 13:10 | 显示全部楼层
直接寄存器操作 + 结构体封装。
 楼主| mikewalpole 发表于 2025-8-4 15:05 | 显示全部楼层
直接操作GPIO寄存器              
juliestephen 发表于 2025-8-4 17:55 | 显示全部楼层
端口直接输出              
pl202 发表于 2025-8-5 09:18 | 显示全部楼层
通过联合体将整字寄存器与各比特域关联,直接访问特定位
primojones 发表于 2025-8-5 11:56 | 显示全部楼层
大多数微控制器厂商提供了标准的库函数,用于简化GPIO的操作。这些函数通常封装了底层的寄存器操作。
alvpeg 发表于 2025-8-5 13:41 | 显示全部楼层
原子操作              
loutin 发表于 2025-8-5 15:25 | 显示全部楼层
直接操作寄存器              
破晓战神 发表于 2025-8-6 09:37 | 显示全部楼层
确实,端口位设置/清除和端口直接输出是最常用的方法,代码简洁,易于理解。
maudlu 发表于 2025-8-7 09:58 | 显示全部楼层
直接操作寄存器和使用gpiolib库适合底层开发
uytyu 发表于 2025-8-7 13:05 | 显示全部楼层
为避免重复编写位操作代码,可通过​​宏定义​​封装置1、置0、翻转等操作,提高代码简洁性和可维护性。
burgessmaggie 发表于 2025-8-7 15:22 | 显示全部楼层
直接通过操作硬件寄存器来控制GPIO的状态。
hilahope 发表于 2025-8-7 17:35 | 显示全部楼层
端口位设置/清除(BSRR/BRR寄存器)
beacherblack 发表于 2025-8-8 11:22 | 显示全部楼层
底层方法              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

1761

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部