博客專欄

        EEPW首頁 > 博客 > 這個寄存器多余了嗎?

        這個寄存器多余了嗎?

        發布人:魚鷹談單片機 時間:2021-06-17 來源:工程師 發布文章

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

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

        那就是兩條操作寄存器的代碼間如果產生中斷或者任務切換了,會不會產生影響,它的電平是否處于不穩定狀態。

        這里魚鷹來解釋一下,并給出具體的解決方案。

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

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

        為什么明明分開操作了,影響還是比較小呢,這是因為如果你這個代碼用于并口總線驅動,那么總線驅動一般會用另外的 IO 變化來確定并口數據的穩定性。

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

        但是不能保證有些并口總線規范會定義最長的時間,但即使有,微秒級別也差不多沒什么問題。

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

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

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

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

        有個道友的留言提醒了魚鷹,就是有一個寄存器是可以同時操作 set 和 reset 的。

        以前初學 STM32 的時候,看到這個寄存器可以同時操作 set 和 reset,而另一個寄存器也可以操作 reset,以為功能重復了,誰知道在這里等著魚鷹呢。

        這個寄存器就是 BSRR。

        1.png

        通過它,就能用一條語句完成多個 IO 的同步操作。

        (這里有個錯誤,應該是操作 32 bit,畢竟它在庫函數中可是 32 bit 數據。另外特別注意框出來的地方,不過除非你的代碼有問題,不然沒人會沒事同時操作一個 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); // 錯誤寫法
        }
        // 使用宏,更高效,任意位數
        #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)

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

        希望本期筆記對各位道友開發項目有所幫助,如有幫助,歡迎轉發支持魚鷹。

        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。

        逆變器相關文章:逆變器原理


        逆變器相關文章:逆變器工作原理


        光伏發電相關文章:光伏發電原理


        關鍵詞: 單片機

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 神农架林区| 焉耆| 九寨沟县| 定南县| 蒲城县| 广西| 达拉特旗| 荆州市| 五寨县| 保康县| 琼海市| 鄂温| 北海市| 安顺市| 彭山县| 昂仁县| 贵德县| 贡嘎县| 汉中市| 罗山县| 抚顺县| 望江县| 浙江省| 武平县| 武清区| 白朗县| 南安市| 曲阳县| 潼关县| 衡东县| 阳原县| 北海市| 新竹市| 慈利县| 怀仁县| 韶关市| 双桥区| 玉门市| 西盟| 鲜城| 延庆县|