C语言 将枚举作为函数参数传递,接受错误值

vqlkdk9b  于 2022-12-29  发布在  其他
关注(0)|答案(1)|浏览(155)

我刚刚完成了一个简单的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);   
}
e4eetjau

e4eetjau1#

  1. case不需要任何括号
    1.错误在其他地方
  2. register_address没有在代码中的任何地方使用,所以它没有什么区别。
  3. switch(...) case将完全按照您编写的方式工作,即如果address为0、1或2,它将分配或获取值(three情况下只有break)(
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);   
}

如果上述代码设置了寄存器,则意味着这两个字节中仅设置了两个LS位。

相关问题