【问题标题】:How to read/write into specific bits of a unsigned char如何读/写无符号字符的特定位
【发布时间】:2016-09-27 21:06:27
【问题描述】:

我想根据下表读取/写入无符号字符:

例如我有以下变量:

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

我想将hsi_div 写入位 4,3,将 cpu_div 写入位 2,1,0(假设整个字符名为 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 */ }

我的按位运算有问题吗!?我没有得到正确的行为。

【问题讨论】:

  • 你想使用uint8_t,它是8位的。 unsigned char至少 8 位,但可能更多。
  • 使用固定宽度类型(参见stdiont.h),而不是标准整数类型。并选择您使用的语言。 C 和 C++ 是不同的语言!
  • @ThomasMatthews 我使用的编译器和平台无关紧要
  • 你得到什么行为?
  • 使用两个 RMW 访问 volatile 硬件寄存器是不好的设计。一次写入值。

标签: c bit-manipulation bitwise-operators


【解决方案1】:

我假设CLK_DIVR 是一个硬件外围寄存器,应该是volatile。此类寄存器应设置为尽可能少的写入。您更改所有可写位,所以只需

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

注意使用固定宽度类型。这使得提及它是一个 8 位寄存器是不必要的。根据摘录,高位是只读的,因此在写入时不会更改。强制转换使编译器不会发出截断警告,这是建议始终启用的警告之一(包含在 gcc 的 -Wconversion 中)。

移位计数实际上是字段开始的位(LSbit)。 0 的移位计数表示“不移位”,因此不需要移位运算符。我仍然用它来澄清我的意思是该字段从位 0 开始。只要让编译器优化,专注于编写可维护的代码。


注意:您的代码位或寄存器中已经存在的任何内容。 Bit-or 只能设置位,但不能清除它们。此外,班次计数错误。


不确定,但如果摘录是针对 ARM Cortex-M CPU(STM32Fxxxx?),减少外部总线周期变得更加相关,因为 ARM 可能需要相当多的周期才能访问。

【讨论】:

  • 谢谢,它是STM8,我不认为它是基于ARM的......而是ST自己的核心
  • @SaeidYazdani:它不是 ARM。但名称与 STM32 时钟模块中的名称相似(只是布局不同)。只是在黑暗中开枪。这些陈述仍然适用。如果回答了您的问题,请记得点赞和/或接受答案。
【解决方案2】:

对于您想要的 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;

【讨论】:

  • register(作为关键字)是变量的坏名称;)
  • @JesperJuhl:感谢您的提醒。在硬件方面,被访问的东西也称为寄存器。 :-(
【解决方案3】:

只是

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

由于 hsi_div 是 2 位二进制,您必须将其移动三个位置才能跳过 CPUDIV 字段。而cpu_div 已经在该字段的末尾。

【讨论】:

  • 查看我的回答为什么这是错误的方法(多种原因)。
猜你喜欢
  • 2013-11-06
  • 1970-01-01
  • 2015-07-28
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-21
相关资源
最近更新 更多