色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          "); //-->

          博客專欄

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

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

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

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

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

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

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

          首先中斷影響,因?yàn)橹袛嗵幚頃r(shí)間幾乎在微妙級(jí)別,如果你的中斷處理在毫秒級(jí)別,那么你的系統(tǒng)實(shí)時(shí)性一定不怎么高。

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

          為什么明明分開操作了,影響還是比較小呢,這是因?yàn)槿绻氵@個(gè)代碼用于并口總線驅(qū)動(dòng),那么總線驅(qū)動(dòng)一般會(huì)用另外的 IO 變化來確定并口數(shù)據(jù)的穩(wěn)定性。

          比如說 SPI 總線(非并口),會(huì)定義 CLK 上升沿或下降沿才開始采集數(shù)據(jù),并口一般也有這樣的規(guī)定,這樣就保證了即使并口數(shù)據(jù)沒有一次性輸出,因?yàn)榱硗獾男盘?hào)線沒有產(chǎn)生下降沿或下降沿,從機(jī)也不會(huì)對(duì)并口上的數(shù)據(jù)采樣的。

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

          但還有一種情況是系統(tǒng)使用了 RTOS 。

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

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

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

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

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

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

          1.png

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

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

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

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

          // 僅用于 8 位數(shù)據(jù) 假設(shè)使用 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); // 錯(cuò)誤寫法
          }
          // 使用宏,更高效,任意位數(shù)
          #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)

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

          希望本期筆記對(duì)各位道友開發(fā)項(xiàng)目有所幫助,如有幫助,歡迎轉(zhuǎn)發(fā)支持魚鷹。

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

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


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


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


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

          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉