<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > 這個(gè)寄存器多余了嗎?

這個(gè)寄存器多余了嗎?

發(fā)布人:魚(yú)鷹談單片機 時(shí)間:2021-06-17 來(lái)源:工程師 發(fā)布文章

上次寫(xiě)過(guò)一篇筆記《介紹一個(gè)高效無(wú)隱患輸出 IO 的方法》,介紹了如何避免直接操作 ODR 導致的隱患問(wèn)題,然后有道友留言對以下代碼提出了疑問(wèn):

void out_data(uint8_t byte)
{
  GPIOA->BSRR = ((uint16_t)byte << 8);  // set
  byte = ~byte;  // 打斷后續運行
  GPIOA->BRR = ((uint16_t)byte << 8);  // reset
}

那就是兩條操作寄存器的代碼間如果產(chǎn)生中斷或者任務(wù)切換了,會(huì )不會(huì )產(chǎn)生影響,它的電平是否處于不穩定狀態(tài)。

這里魚(yú)鷹來(lái)解釋一下,并給出具體的解決方案。

首先中斷影響,因為中斷處理時(shí)間幾乎在微妙級別,如果你的中斷處理在毫秒級別,那么你的系統實(shí)時(shí)性一定不怎么高。

所以中斷在這里造成的影響比較小。

為什么明明分開(kāi)操作了,影響還是比較小呢,這是因為如果你這個(gè)代碼用于并口總線(xiàn)驅動(dòng),那么總線(xiàn)驅動(dòng)一般會(huì )用另外的 IO 變化來(lái)確定并口數據的穩定性。

比如說(shuō) SPI 總線(xiàn)(非并口),會(huì )定義 CLK 上升沿或下降沿才開(kāi)始采集數據,并口一般也有這樣的規定,這樣就保證了即使并口數據沒(méi)有一次性輸出,因為另外的信號線(xiàn)沒(méi)有產(chǎn)生下降沿或下降沿,從機也不會(huì )對并口上的數據采樣的。

但是不能保證有些并口總線(xiàn)規范會(huì )定義最長(cháng)的時(shí)間,但即使有,微秒級別也差不多沒(méi)什么問(wèn)題。

但還有一種情況是系統使用了 RTOS 。

這樣會(huì )導致切換到另一個(gè)線(xiàn)程,而這個(gè)線(xiàn)程的執行時(shí)間根本不確定,執行毫秒級別是正常的事情,所以,這種情況該如何處理呢?

兩種方法,關(guān)中斷或關(guān)調度器。(關(guān)于這些內容可以看歷史文章,比如《信號量保護之禁止中斷》,《嵌入式系統優(yōu)先級詳解》等)

但是對于幾行代碼就要使用這些代碼,還是太奢侈了一些,雖然對系統的效率影響不大,但畢竟還是不爽,那么是否有更好的辦法可以解決這個(gè)問(wèn)題。

有個(gè)道友的留言提醒了魚(yú)鷹,就是有一個(gè)寄存器是可以同時(shí)操作 set 和 reset 的。

以前初學(xué) STM32 的時(shí)候,看到這個(gè)寄存器可以同時(shí)操作 set 和 reset,而另一個(gè)寄存器也可以操作 reset,以為功能重復了,誰(shuí)知道在這里等著(zhù)魚(yú)鷹呢。

這個(gè)寄存器就是 BSRR。

1.png

通過(guò)它,就能用一條語(yǔ)句完成多個(gè) IO 的同步操作。

(這里有個(gè)錯誤,應該是操作 32 bit,畢竟它在庫函數中可是 32 bit 數據。另外特別注意框出來(lái)的地方,不過(guò)除非你的代碼有問(wèn)題,不然沒(méi)人會(huì )沒(méi)事同時(shí)操作一個(gè) IO 的 BSy、BRy)。

在這里特別感謝這幾位道友的留言提醒。

上面的代碼可以改成這樣:

// 僅用于 8 位數據 假設使用 PA8~15
void out_data(uint8_t byte)
{
  GPIOA->BSRR = ((uint32_t)((uint8_t)~byte) << (0 + 16)) | ((uint32_t)byte << 0);
  // GPIOA->BSRR = ((uint32_t)(~byte) << (8 + 16)) | ((uint32_t)byte << 8); // 錯誤寫(xiě)法
}
// 使用宏,更高效,任意位數
#define GPIOA_RESET_SET(data, offset, msk)  GPIOA->BSRR = ((uint32_t)(~(data) & (msk)) << ((offset) + 16)) | ((uint32_t)((data) & (msk)) << (offset)) 
// 等效代碼  PA8~PA15 輸出
#define GPIOA_RESET_SET_BYTE(byte)          GPIOA_RESET_SET(byte, 8, 0xff)

如果你的代碼對性能要求比較高,建議使用宏,但同時(shí)你需要知道里面還有一個(gè) & 的計算,這個(gè)會(huì )在運行時(shí)計算,而對于固定的 8 bit 數據,這個(gè)計算可以通過(guò)強制轉化去掉(就像前面的代碼一樣,并沒(méi)有 & 計算),這樣效率會(huì )更高,另一種方法是使用內聯(lián)函數,在使用上應該會(huì )比宏更加安全(優(yōu)化級別提高的情況下)。

希望本期筆記對各位道友開(kāi)發(fā)項目有所幫助,如有幫助,歡迎轉發(fā)支持魚(yú)鷹。

*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。

逆變器相關(guān)文章:逆變器原理


逆變器相關(guān)文章:逆變器工作原理


光伏發(fā)電相關(guān)文章:光伏發(fā)電原理


關(guān)鍵詞: 單片機

相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>