如何将uint8_t放置在uint16_t的中间而不影响其他位?

3

我正在为使用16位SPI消息的DAC芯片编写SPI驱动程序...表示输出的值从第11位到第4位(一个8位DAC)。我已经编写了以下掩码,但我不知道如何在不影响其他位的情况下更新数据:

#define MCP4901_SPI_MASK_DATA               0x0FF0
//So data mask in binary is 0000 1111 1111 0000

extern uint16_t mcpA;

static inline void mcpSetData(uint16_t* mcp, uint8_t value) {
    //????
   *mcp =| value & MCP4901_SPI_MASK_DATA; //NOT WORKING
}

为什么你会只写入SPI数据寄存器的一部分而不是全部呢?这没有任何意义。难道有某种复杂的“串联”硬件吗? - Lundin
@Lundin 还有其他的配置位(位15-12),我可以将它们设置为单个位,我的问题只是将8位DAC值移位到11到4位置。 - DEKKER
1个回答

3
您对使用 |& 操作符的用法是正确的,但是您没有按正确的顺序使用它们,并且没有正确地定位其中一个操作数。
下面是正确的做法:
*mcp &= ~MCP4901_SPI_MASK_DATA; // Clear out the middle bits
*mcp |= ((uint16_t)value) << 4; // Put in the value in the middle

由于您正在写入硬件寄存器,应使用单个写操作来避免可能的副作用:

*mcp = (*mcp & ~MCP4901_SPI_MASK_DATA) | (((uint16_t)value) << 4);

MCP4901_SPI_MASK_DATA被反转以清除0x0FF0之外的位。或者,您可以将掩码定义为0xF00F,并省略~运算符。

这个8位值向左移动4位,使其位于16位的中间,然后通过“OR”操作符与数字合并。

演示。


2
我会非常小心连续多次写入SPI数据寄存器。读写操作可能会产生副作用,例如标志位被清除或数据被发送。这取决于具体的硬件。 - Lundin
@Lundin 您是正确的,我完全忽略了 OP 正在写入硬件寄存器的事实。谢谢! - Sergey Kalinichenko
@Lundin 感谢您提出这个讨论。我只是使用 mcpSetData() 函数来更新 U16 变量的内容...其他位和设置都是用其他函数完成的。当所需数据准备好后,我使用单个命令 (STM32 中的 HAL_SpiTransmit) 将其推送到 SPI。现在它运行得很好 :) - DEKKER

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接