我刚刚完成了一个简单的SPI实现,用于2个MCU在PCB上通信。该通信应该将16位值从主机传递到从机上的虚拟寄存器。帧长度为64位。
通信帧构建如下:
位0:读或写寄存器。(0 ==读; 1 ==写入)
bit1-bit15:寄存器地址
位16 - 31:0xFFFF用于适应从机提供数据的计算时间
位32 - 47:寄存器值
位48 - 63:循环冗余校验
通信工作完美。
然而,这是我不明白的,我通过获取前2个传输字节并将其转换为uint16_t来检索地址,如下所示:
寄存器地址=(uint16_t)(((字节0)和0xFF)〈〈8|((字节1)和0xFF));
然后,在从全局寄存器结构检索值的函数中使用此地址。作为参数,它应仅接受枚举类型"virtual_register_address_t"中的值
typedef enum virtual_register_address_t
{
//READ/WRITE
REGISTER_ONE_ADD = 0,
REGISTER_TWO_ADD,
REGISTER_THREE_ADD,
//READ ONLY
ERROR_REGISTER_ADD
}virtual_register_address_t;
uint16_t get_virtual_register(virtual_register_address_t address)
{
uint16_t value = 0;
switch(address)
{
case(REGISTER_ONE_ADD):
value = virtual_register.registerOne;
break;
case(REGISTER_TWO_ADD):
value = virtual_register.registerTwo;
break;
case(REGISTER_THREE_ADD):
value = virtual_register.registerThree;
break;
case(ERROR_REGISTER_ADD):
value = virtual_register.errorRegister;
break;
default:
value = 0xFF;
break;
}
return value;
}
void set_virtual_register(virtual_register_address_t address, uint16_t data)
{
switch(address)
{
case(REGISTER_ONE_ADD):
virtual_register.registerOne = data;
break;
case(REGISTER_TWO_ADD):
virtual_register.registerTwo = data;
break;
case(REGISTER_THREE_ADD):
virtual_register.registerThree = data;
break;
case(ERROR_REGISTER_ADD):
break;
default:
break;
}
}
但是,正如你们中的一些人可能已经认识到的那样,我犯了一个错误,从spi帧中复制了位0 - 15,而不是位1 - 15。因此,在写入情况下复制的地址(第一位1)应始终〉= 32768。枚举"virtual_register_address_t"最多只能定义为8。但是,该代码工作完美。2它将参数作为"virtual_register_address_t"类型,即使该值在枚举定义中不被考虑。3即使该值在开关中不被考虑,它也不会进入默认状态。如果我在写地址后读了它,它会可靠地改变值,并将它们发送回来。
我将register_address的获取更改为
register_address = (uint16_t)(((byte0) & 0x7F) << 8 | ((byte1) & 0xFF));
现在还能用。
据我所知,函数"set_virtual_register"如果不是用开关的方式给出值,它应该什么也不做,但是它依赖于设置值。
我的问题是,如果枚举作为函数参数,这种情况是否总是发生?当它不应该工作时,它是如何工作的?
编辑:
用户要求添加使用寄存器地址的函数调用:
void spi_serialize(spi_handle_t* handle, virtual_register_address_t address, SPI_State read_or_write)
{
uint16_t crc = 0;
uint16_t data = 0;
switch(read_or_write)
{
case(READ):
data = get_virtual_register(address);
handle->dataTx[4] = (uint8_t)((data >> 8) & 0xff);
handle->dataTx[5] = (uint8_t)(data & 0xff);
break;
case(WRITE):
handle->dataTx[4] = (0xFF);
handle->dataTx[5] = (0xFF);
break;
default:
handle->dataTx[4] = (0xAA);
handle->dataTx[5] = (0xBB);
break;
}
//crc
crc = calculateCRC(handle->dataTxBase, SPI_FRAMESIZE-2);
handle->dataTx[SPI_FRAMESIZE-2] = ((crc >> 8) & 0XFF);
handle->dataTx[SPI_FRAMESIZE-1] = (crc & 0xFF);
}
void spi_deserialize(spi_handle_t* handle)
{
uint16_t register_address = 0;
uint16_t data = 0;
register_address = (uint16_t)(((handle->dataRx[0]) & 0xFF) << 8 | ((handle->dataRx[1]) & 0xFF));
data = (uint16_t)(((handle->dataRx[4]) & 0xFF) << 8 | ((handle->dataRx[5]) & 0xFF));
set_virtual_register(register_address, data);
}
1条答案
按热度按时间e4eetjau1#
case
不需要任何括号1.错误在其他地方
register_address
没有在代码中的任何地方使用,所以它没有什么区别。switch(...) case
将完全按照您编写的方式工作,即如果address
为0、1或2,它将分配或获取值(three
情况下只有break
)(如果上述代码设置了寄存器,则意味着这两个字节中仅设置了两个LS位。