簡體   English   中英

如何讀取/寫入unsigned char的特定位

[英]How to read/write into specific bits of a unsigned char

我想根據下表從/向無符號字符讀取和寫入: 在此輸入圖像描述

例如,我有以下變量:

unsigned char hsi_div = 0x01; /* HSI/2 */
unsigned char cpu_div = 0x05; /* Fmaster/32 */

我想將hsi_div寫入位4,3,將cpu_div寫入位2,1,0(想象整個char被命名為CLK_DIVR):

CLK_DIVR |= hsi_div << 4; //not correct!
CLK_DIVR |= cpu_div << 2; //not correct!

並且讓我說我想讀回寄存器以確保我做到了正確:

if( ((CLK_DIVR << 4) - 1) & hsi_div) ) { /* SET OK */ }
if( ((CLK_DIVR << 2) - 1) & cpu_div) ) { /* SET OK */ }

我的按位操作有什么問題!? 我沒有得到正確的行為。

我假設CLK_DIVR是硬件外設寄存器,應該是合格的volatile 這些寄存器應盡可能少地寫入。 你改變了所有可寫位,所以只是

 CLK_DIVR = (uint8_t)((hsi_div << 3) | (cpu_div << 0));

注意使用固定寬度類型。 這使得它不需要8位寄存器。 根據摘錄,高位是只讀的,因此在寫入時不會改變它們。 -Wconversion使編譯器不會發出截斷警告,這是始終啟用的建議警告之一(包含在gcc的-Wconversion中)。

移位計數實際上是字段開始的位(LSbit)。 移位計數為0表示“無移位”,因此不需要移位運算符。 我仍然用它來澄清我的意思是該字段從第0位開始。 只需讓編譯器優化,專注於編寫可維護的代碼。


注意:您的代碼位或已經在寄存器中的任何內容。 位或只能設置位,但不能清除它們。 另外,班次計數錯了。


不確定,但如果摘錄是針對ARM Cortex-M CPU(STM32Fxxxx?),則減少外部總線周期變得更加相關,因為ARM可能需要相當多的周期才能進行訪問。

對於您想要的HSIDIV位字段:

hw_register = (hw_register & 0x18) | (hsi_value & 0x03) << 0x03;

這會將值屏蔽為2位寬,然后移位到位3和4。

CPUDIV字段是:

hw_register = (hw_register & 0x7) | (cpu_value & 7);

閱讀登記冊:

hsi_value = (hw_register & 0x18) >> 3;
cpu_value = hw_register & 0x07;

只是

CLK_DIVR |= hsi_div << 3;
CLK_DIVR |= cpu_div << 0;

由於hsi_div是一個2位二進制文​​件,因此您必須將其移動三個位置才能跳過CPUDIV字段。 並且cpu_div已經在該字段的末尾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM