找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7943|回复: 8
打印 上一主题 下一主题
收起左侧

怎么给STM32 GPIO多个操作不影响其他的?

[复制链接]
跳转到指定楼层
楼主
ID:313060 发表于 2019-3-8 12:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
40黑币
怎么给GPIO多个操作位不影响其他的;像GPIOE->ODR = dat<<5;
这样会影响低五位。
请问有什么好的方法?

最佳答案

查看完整内容

是不是应该还有屏的头文件*.h之类的,在里面定义了显示方向
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:10947 发表于 2019-3-8 12:20 | 只看该作者
是不是应该还有屏的头文件*.h之类的,在里面定义了显示方向
回复

使用道具 举报

板凳
ID:330198 发表于 2019-3-9 11:30 | 只看该作者
一位一位赋值
回复

使用道具 举报

地板
ID:248705 发表于 2019-3-10 17:38 | 只看该作者
GPIOE->ODR| = (uint32_t)1<<5;应该是这样的吧
回复

使用道具 举报

5#
ID:138119 发表于 2019-3-11 15:52 | 只看该作者
STM32的16位端口输出8位数据方法

u16 temp;
u8 yourdata;

temp=GPIOA->ODR&0xff00;
temp+=yourdata;
GPIOA->ODR=temp;

或者:GPIOA->ODR=GPIOA->ODR&0xff00+(u16)yourdata;


=======================================================





先定义宏:
#define  GPIO_SETLOWBITS(GPIOA,UINT8)       GPIOA->ODR = ((GPIOA->ODR)&0xFF00) + UINT8
调用:

GPIO_SETLOWBITS(GPIOA,0xaa);
GPIO_SETLOWBITS(GPIOA,0x55);


=====================================================


最通用的方法是读-修改-写


因为对于STM32,IO操作比寄存器操作慢得多,所以我常用这样的写法:
GPIOA->BSRR=data|((data^0xff)<<16);
回复

使用道具 举报

6#
ID:138119 发表于 2019-3-11 15:53 | 只看该作者
用GPIOx_BSRR寄存器

BRy位写0无影响写1复位相应bit位
BSy位写0无影响写1置位相应bit位

例如要对PORTA口低8位送出D0-D7数据,而不触及高8位的数据:

假定要送出D0-D7的数据变量为ldata,
  unsigned char ldata;
  GPIOA_BSRR = ((unsigned int)~ldata << 16) | ldata;

如果ldata=0x34,这相当于设置:
  GPIOA_BSRR=0x00CB0034;
回复

使用道具 举报

7#
ID:138119 发表于 2019-3-11 15:54 | 只看该作者
据官方数据手册上面说, 这两个寄存器用于专门对ODR进行原子操作的位操作, 都是在置1的时候对某位有影响.

举例说下怎么对IO端口赋值:

1.对高8位/低8位/全部清零

很明显, 这个只需要操作BRR寄存器即可:

对高8位清零:GPIOA->BRR = 0xFF00

对低8位清零:GPIOA->BRR = 0x00FF

全部清零: GPIOA->BRR = 0xFFFF 或 GPIOA->ODR = 0x0000

当然了, 使用下面2,3的两个宏也可以完全该清零操作~ stm32固件库是不是应该加上这两个宏/函数?

2.对低8位置数

涉及到置数, 这个就是操作BSRR寄存器了

比如要使端口A的低8位为 0x55 (01010101B), 那么对于BSRR这个32位寄存器来说:

低16位应该置为 0000 0000 0101 0101, 这个就等于 0x55, 置1使某位为1, 置0的位不影响原来的值

高16位应该置为 0000 0000 1010 1010, 这个就等于 ~0x55(即取反)的结果, 置1使某位为0, 置0不影响原来的值

这样, BSRR寄存器的值就是 0000 0000 1010 1010 0000 0000 0101 0101, 两部分的高8位均为0, 所以不会影响到IO口的高8位

总结, 以下的宏实现对某端口的低8位置数, 不影响高8位:

#define GPIO_WriteLow(GPIOx,a)    GPIOx->BSRR=(((uint32_t)(uint8_t)~(a))<<16)|((uint32_t)(uint8_t)(a))
3.对高8位置数

这个和单独对低8位置数其实是一样的, 只是设置的位不一样罢了

同样, 要使高8位为0x55, 那么:

低16位应该置为 0101 0101 0000 0000

高16位应该置为 1010 1010 0000 0000, 同样是取反的结果; 不影响低8位的数据

这样, BSRR寄存器的值就是 1010 1010 0000 0000 0101 0101 0000 0000, 可以看出, 其实它就是上面那个结果左移8位

总结, 以下的宏实现对某端口的高8位置数, 不影响低8位:

#define GPIO_WriteHigh(GPIOx,a)    GPIOx->BSRR=(((uint8_t)(uint8_t)~(a))<<24)|(((uint32_t)(uint8_t)(a))<<8)
大家不用担心效率问题, 上面那两个宏最终的结果就是 GPIOx->BSRR=value 的形式, 所以担心是多余的
回复

使用道具 举报

8#
ID:138119 发表于 2019-3-11 15:55 | 只看该作者
怎么对高八位或低八位写值而不影响其它位,还有怎样单独读取高八位或低八位的值?


((u8*)(&GPIOB->ODR))[0] = 0xaa;写低八位

g_io_tempvalue = ((u8*)(&GPIOB->ODR))[1];读高八位

=============================================




写高八位  
GPIOB->CRH &= 0X00000000;  
GPIOB->CRH |= 0X33333333;  
GPIOB->ODR |= 0XFF00;  

低八位也一样,做与或者或运算的时候就可以避免影响不想改变的位。  

读高八位:  
u8 temp;  
temp = ((GPIOB->IDR>>8)&0xff)  
读低八位  
temp = ((GPIOB->IDR&0xff)

====
使用BSRR和BRR寄存器直接操作STM32的I/O端口        发布时间:2009-11-12 12:39:27
技术类别:单片机         

STM32的每个GPIO端口都有两个特别的寄存器,GPIOx_BSRR和GPIOx_BRR寄存器,通过这两个寄存器可以直接对对应的GPIOx端口置'1'或置'0'。

GPIOx_BSRR的高16位中每一位对应端口x的每个位,对高16位中的某位置'1'则端口x的对应位被清'0';寄存器中的位置'0',则对它对应的位不起作用。

GPIOx_BSRR的低16位中每一位也对应端口x的每个位,对低16位中的某位置'1'则它对应的端口位被置'1';寄存器中的位置'0',则对它对应的端口不起作用。

简单地说GPIOx_BSRR的高16位称作清除寄存器,而GPIOx_BSRR的低16位称作设置寄存器。另一个寄存器GPIOx_BRR只有低16位有效,与GPIOx_BSRR的高16位具有相同功能。





举个例子说明如何使用这两个寄存器和所体现的优势。例如GPIOE的16个IO都被设置成输出,而每次操作仅需要改变低8位的数据而保持高8位不变,假设新的8位数据在变量Newdata中,

这个要求可以通过操作这两个寄存器实现,STM32的固件库中有两个函数GPIO_SetBits()和GPIO_ResetBits()使用了这两个寄存器操作端口。

上述要求可以这样实现:

GPIO_SetBits(GPIOE, Newdata & 0xff);
GPIO_ResetBits(GPIOE, (~Newdata & 0xff));

也可以直接操作这两个寄存器:

GPIOE->BSRR = Newdata & 0xff;
GPIOE->BRR = ~Newdata & 0xff;

当然还可以一次完成对8位的操作:

GPIOE->BSRR = (Newdata & 0xff) | (~Newdata & 0xff)<<16;

从最后这个操作可以看出使用BSRR寄存器,可以实现8个端口位的同时修改操作。




//==============================================================================================
如果不是用BRR和BSRR寄存器,则上述要求就需要这样实现:

GPIOE->ODR = GPIOE->ODR & 0xff00 | Newdata;  低8位 ; //更新低8位,高8位不变
GPIOE->ODR = ((GPIOE->ODR & 0xff00) | (uint16_t)(Newdata<<8)); 高8位//更新高8位,低8位不变

平时用的比较多.
//===================================================================================================



使用BRR和BSRR寄存器可以方便地快速地实现对端口某些特定位的操作,而不影响其它位的状态。

比如希望快速地对GPIOE的位7进行翻转,则可以:

GPIOE->BSRR = 0x80; // 置'1'
GPIOE->BRR = 0x80; // 置'0'

如果使用常规'读-改-写'的方法:

GPIOE->ODR = GPIOE->ODR | 0x80; // 置'1'
GPIOE->ODR = GPIOE->ODR & 0xFF7F; // 置'0'





有人问是否BSRR的高16位是多余的,请看下面这个例子:

假如你想在一个操作中对GPIOE的位7置'1',位6置'0',则使用BSRR非常方便:
  GPIOE->BSRR = 0x400080;

如果没有BSRR的高16位,则要分2次操作,结果造成位7和位6的变化不同步!
  GPIOE->BSRR = 0x80;
  GPIOE->BRR = 0x40;

=========================================
例如要对PORTA口低8位送出D0-D7数据,而不触及高8位的数据:

假定要送出D0-D7的数据变量为ldata,
  unsigned char ldata;
  GPIOA_BSRR = ((unsigned int)~ldata << 16) | ldata;

如果ldata=0x34,这相当于设置:
  GPIOA_BSRR=0x00CB0034;

===================================
先定义宏:
#define  GPIO_SETLOWBITS(GPIOA,UINT8)       GPIOA->ODR = ((GPIOA->ODR)&0xFF00) + UINT8
调用:

GPIO_SETLOWBITS(GPIOA,0xaa);
GPIO_SETLOWBITS(GPIOA,0x55);


=================================================
STM32 GPIO寄存器ODR BSRR BRR  


使用BRR和BSRR寄存器可以方便地快速地实现对端口某些特定位的操作,而不影响其它位的状态。

比如希望快速地对GPIOE的位7进行翻转,则可以:

GPIOE->BSRR = 0x80; // 置'1'
GPIOE->BRR = 0x80; // 置'0'

如果使用常规'读-改-写'的方法:

GPIOE->ODR = GPIOE->ODR | 0x80; // 置'1'
GPIOE->ODR = GPIOE->ODR & 0xFF7F; // 置'0'

有人问是否BSRR的高16位是多余的,请看下面这个例子:

假如你想在一个操作中对GPIOE的位7置'1',位6置'0',则使用BSRR非常方便:
  GPIOE->BSRR = 0x00400080;

如果没有BSRR的高16位,则要分2次操作,结果造成位7和位6的变化不同步!
  GPIOE->BSRR = 0x80;
  GPIOE->BRR = 0x40;

规则:

一、置GPIOD->BSRR低16位的某位为'1',则对应的I/O端口置'1';而置GPIOD->BSRR低16位

的某位为'0',则对应的I/O端口不变。

二、置GPIOD->BSRR高16位的某位为'1',则对应的I/O端口置'0';而置GPIOD->BSRR高16位

的某位为'0',则对应的I/O端口不变。

三、置GPIOD->BRR低16位的某位为'1',则对应的I/O端口置'0';而置GPIOD->BRR低16位的

某位为'0',则对应的I/O端口不变。



例如:

1)要设置D0、D5、D10、D11为高,而保持其它I/O口不变,只需一行语句:

  GPIOD->BSRR = 0x0C21;// 使用规则一



2)要设置D1、D3、D14、D15为低,而保持其它I/O口不变,只需一行语句:

  GPIOD->BRR = 0xC00A;// 使用规则三



3)要同时设置D0、D5、D10、D11为高,设置D1、D3、D14、D15为低,而保持其它I/O口不变

,也只需一行语句:

  GPIOD->BSRR = 0xC00A0C21;// 使用规则一和规则二

如果中断中要对IO口设置,最好使用BSRR和BRR操作,而不要用ODR .

回复

使用道具 举报

9#
ID:142059 发表于 2019-3-11 20:41 来自手机 | 只看该作者
位或|了解一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表