我有一个带有USART HAL的嵌入式项目。该USART一次只能发送或接收8或16位(取决于我选择的usart寄存器,即单/双输入/输出)。由于它是32位MCU,因此我认为我最好绕过32位字段,因为(据我所知)这是对MPU的一种更有效的使用。同样适用于64位MPU,即传递64位整数。也许那是误导的建议,或者是脱离上下文的建议。
考虑到这一点,我已经通过移位将8位压缩为32位字段。我在usart上为TX和RX都这样做。
仅8位寄存器的代码如下(16位寄存器只有一半的移位位数):
int zg_usartTxdataWrite(USART_data* MPI_buffer,
USART_frameconf* MPI_config,
USART_error* MPI_error)
{
MPI_error = NULL;
if(MPI_config != NULL){
zg_usartFrameConfWrite(MPI_config);
}
HPI_usart_data.txdata = MPI_buffer->txdata;
for (int i = 0; i < USART_TXDATA_LOOP; i++){
if((USART_STATUS_TXC & usart->STATUS) > 0){
usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
}
usart->IFC |= USART_STATUS_TXC;
}
return 0;
}
编辑:重新输入上述代码的逻辑,并在注释部分中讨论了三元算子隐式提升问题的清晰度,并添加了定义
(HPI_usart和USART_data结构是相同的,只是级别不同,此后,我删除了HPI_usart层,但是为了这个示例,我将其保留在其中)
#define USART_TXDATA_LOOP 4
#define SINGLE_BYTE_SHIFT 8
typedef struct HPI_USART_DATA{
...
uint32_t txdata;
...
}HPI_usart
HPI_usart HPI_usart_data = {'\0'};
const uint8_t USART_TXDATA_DATABITS = 0xFF;
int zg_usartTxdataWrite(USART_data* MPI_buffer,
USART_frameconf* MPI_config,
USART_error* MPI_error)
{
MPI_error = NULL;
if(MPI_config != NULL){
zg_usartFrameConfWrite(MPI_config);
}
HPI_usart_data.txdata = MPI_buffer->txdata;
for (int i = 0; i < USART_TXDATA_LOOP; i++){
if((USART_STATUS_TXC & usart->STATUS) > 0){
usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
}
usart->IFC |= USART_STATUS_TXC;
}
return 0;
}
但是,我现在意识到这可能导致比解决方案更多的问题,因为我本质上是对这些位进行内部编码,然后当它们传入/传出不同的数据层时几乎必须立即对其进行解码。我觉得这是一个聪明而性感的解决方案,但是我现在正试图解决一个我本不应该创建的问题。就像如何在存在偏移量时提取变量位字段,即在gps nmea句子中,前8位可能是一个相关字段,然后其余是32位字段。所以最终变成这样:
32位数组成员0:
bits 24-31 bits 15-23 bits 8-15 bits 0-7
| 8位值| 32位值A,位24-31 | 32位值A,位16-23 | 32位值A,第8-15位|
32位数组成员1:
bits 24-31 bits 15-23 bits 8-15 bits 0-7
| 32位值A,位0-7 | 32位值B,位24-31 | 32位值B,位16-23 | 32位值B,位8-15 |
32位数组成员2:
bits 24-31 15-23 8-15 ...
| 32位值B,位0-7 |等... | .... | .... |
上面的示例需要手动解码,我想这很好,但是每个nmea语句都不同,并且感觉比编程更具手动性。
我的问题是:位移位与数组索引比较合适?
是否应该将每个传入/传出的值分配给32位数组成员,然后以这种方式进行索引?我觉得这是解决方案,因为它不仅使遍历其他层上的数据更加容易,而且我将能够消除所有这些移位逻辑,然后rx或tx函数之间的唯一区别就是数据走向的方向。
这确实意味着对接口和所得到的gps模块层进行了少量重写,但这听起来像是工作量少了,而且在我的项目初期也很便宜。
关于此的任何想法和一般经验也将很棒。
答案 0 :(得分:2)
由于它是32位MCU,所以我认为我也应该绕过32位字段
这并不是程序员真正的使命。将8位或16位变量放入结构中。如果需要,让编译器添加填充。另外,您可以使用uint_fast8_t
和uint_fast16_t
。
我的问题是:位移位与数组索引比较合适?
数组索引用于访问数组。如果有数组,请使用它。如果没有,那就不要。
虽然可以逐字节检查较大的数据块,但是必须更加仔细地编写此类代码,以免遇到各种细微的类型转换和指针别名错误。
通常,在访问最大为CPU字大小的数据(在这种情况下为32位)时,最好使用位移。它既快速又可移植,因此您不必考虑端倪。这是首选的整数序列化/反序列化方法。