[英]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.