找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7943|回復: 8
打印 上一主題 下一主題
收起左側

怎么給STM32 GPIO多個操作不影響其他的?

[復制鏈接]
跳轉到指定樓層
樓主
ID:313060 發(fā)表于 2019-3-8 12:20 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
40黑幣
怎么給GPIO多個操作位不影響其他的;像GPIOE->ODR = dat<<5;
這樣會影響低五位。
請問有什么好的方法?

最佳答案

查看完整內容

是不是應該還有屏的頭文件*.h之類的,在里面定義了顯示方向
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發(fā)
ID:10947 發(fā)表于 2019-3-8 12:20 | 只看該作者
是不是應該還有屏的頭文件*.h之類的,在里面定義了顯示方向
回復

使用道具 舉報

板凳
ID:330198 發(fā)表于 2019-3-9 11:30 | 只看該作者
一位一位賦值
回復

使用道具 舉報

地板
ID:248705 發(fā)表于 2019-3-10 17:38 | 只看該作者
GPIOE->ODR| = (uint32_t)1<<5;應該是這樣的吧
回復

使用道具 舉報

5#
ID:138119 發(fā)表于 2019-3-11 15:52 | 只看該作者
STM32的16位端口輸出8位數(shù)據(jù)方法

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 發(fā)表于 2019-3-11 15:53 | 只看該作者
用GPIOx_BSRR寄存器

BRy位寫0無影響寫1復位相應bit位
BSy位寫0無影響寫1置位相應bit位

例如要對PORTA口低8位送出D0-D7數(shù)據(jù),而不觸及高8位的數(shù)據(jù):

假定要送出D0-D7的數(shù)據(jù)變量為ldata,
  unsigned char ldata;
  GPIOA_BSRR = ((unsigned int)~ldata << 16) | ldata;

如果ldata=0x34,這相當于設置:
  GPIOA_BSRR=0x00CB0034;
回復

使用道具 舉報

7#
ID:138119 發(fā)表于 2019-3-11 15:54 | 只看該作者
據(jù)官方數(shù)據(jù)手冊上面說, 這兩個寄存器用于專門對ODR進行原子操作的位操作, 都是在置1的時候對某位有影響.

舉例說下怎么對IO端口賦值:

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

很明顯, 這個只需要操作BRR寄存器即可:

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

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

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

當然了, 使用下面2,3的兩個宏也可以完全該清零操作~ stm32固件庫是不是應該加上這兩個宏/函數(shù)?

2.對低8位置數(shù)

涉及到置數(shù), 這個就是操作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位

總結, 以下的宏實現(xiàn)對某端口的低8位置數(shù), 不影響高8位:

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

這個和單獨對低8位置數(shù)其實是一樣的, 只是設置的位不一樣罷了

同樣, 要使高8位為0x55, 那么:

低16位應該置為 0101 0101 0000 0000

高16位應該置為 1010 1010 0000 0000, 同樣是取反的結果; 不影響低8位的數(shù)據(jù)

這樣, BSRR寄存器的值就是 1010 1010 0000 0000 0101 0101 0000 0000, 可以看出, 其實它就是上面那個結果左移8位

總結, 以下的宏實現(xiàn)對某端口的高8位置數(shù), 不影響低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 發(fā)表于 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端口        發(fā)布時間: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位具有相同功能。





舉個例子說明如何使用這兩個寄存器和所體現(xiàn)的優(yōu)勢。例如GPIOE的16個IO都被設置成輸出,而每次操作僅需要改變低8位的數(shù)據(jù)而保持高8位不變,假設新的8位數(shù)據(jù)在變量Newdata中,

這個要求可以通過操作這兩個寄存器實現(xiàn),STM32的固件庫中有兩個函數(shù)GPIO_SetBits()和GPIO_ResetBits()使用了這兩個寄存器操作端口。

上述要求可以這樣實現(xiàn):

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寄存器,可以實現(xiàn)8個端口位的同時修改操作。




//==============================================================================================
如果不是用BRR和BSRR寄存器,則上述要求就需要這樣實現(xiàn):

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

平時用的比較多.
//===================================================================================================



使用BRR和BSRR寄存器可以方便地快速地實現(xiàn)對端口某些特定位的操作,而不影響其它位的狀態(tài)。

比如希望快速地對GPIOE的位7進行翻轉,則可以:

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

如果使用常規(guī)'讀-改-寫'的方法:

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數(shù)據(jù),而不觸及高8位的數(shù)據(jù):

假定要送出D0-D7的數(shù)據(jù)變量為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寄存器可以方便地快速地實現(xiàn)對端口某些特定位的操作,而不影響其它位的狀態(tài)。

比如希望快速地對GPIOE的位7進行翻轉,則可以:

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

如果使用常規(guī)'讀-改-寫'的方法:

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;

規(guī)則:

一、置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;// 使用規(guī)則一



2)要設置D1、D3、D14、D15為低,而保持其它I/O口不變,只需一行語句:

  GPIOD->BRR = 0xC00A;// 使用規(guī)則三



3)要同時設置D0、D5、D10、D11為高,設置D1、D3、D14、D15為低,而保持其它I/O口不變

,也只需一行語句:

  GPIOD->BSRR = 0xC00A0C21;// 使用規(guī)則一和規(guī)則二

如果中斷中要對IO口設置,最好使用BSRR和BRR操作,而不要用ODR .

回復

使用道具 舉報

9#
ID:142059 發(fā)表于 2019-3-11 20:41 來自手機 | 只看該作者
位或|了解一下
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表