0

我一直在尝试使用 SPI 写入外部EEPROM,但我取得了好坏参半。数据确实以相反的方式移出。EEPROM 需要一个起始位,然后是一个操作码,该操作码本质上是用于读取、写入和擦除的 2 位代码。本质上,起始位和操作码组合成一个字节。我正在创建一个 32 位无符号整数,然后将值移位到其中。当我传输这些时,我看到首先看到的是实际数据,然后是 SB+操作码,然后是内存地址。我如何反转这个以首先查看操作码,然后是内存地址,然后是实际数据。如下图所示,数据为BCDE,SB+opcode为07,内存地址为3F。正确的顺序应该是 07、3F 和 BCDE(我认为!)。

在此处输入图像描述

这是代码:

uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint32_t write_package = (ERASE << 24 | mem_addr << 16 | data);

while (1)
{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
  HAL_SPI_Transmit(&hspi1, &write_package, 2, HAL_MAX_DELAY);
  HAL_Delay(10);

}
/* USER CODE END 3 */
4

3 回答 3

2

您将信息打包成一个 32 位整数,在代码的第 3 行,您可以决定将哪些数据位放置在单词中的哪个位置。要更改顺序,您可以将该行替换为:

uint32_t write_package = ((data << 16) | (mem_addr << 8) | (ERASE));

也就是将data16 位左移到字的最高有效 16 位,mem_addr向上移动 8 位并进行或运算,然后添加ERASE最低有效位。

于 2018-07-10T08:13:47.827 回答
2

看起来您的 SPI 接口设置为一次处理 16 位半字。因此,将要发送的数据分解为 16 位半字也是有意义的。那将负责订购。

uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint16_t write_package[2] = {
    (ERASE << 8) | mem_addr,
    data
};

HAL_SPI_Transmit(&hspi1, (uint8_t *)write_package, 2, HAL_MAX_DELAY);

编辑

添加了明确的演员表。如评论中所述,如果没有显式转换,它不会编译为 C++ 代码,并会导致一些警告为 C 代码。

于 2018-07-10T11:15:59.497 回答
0

你的问题是Endianness

默认情况下,STM32 使用 little edian,因此 uint32_t 的最低字节存储在第一个地址。

如果我是对的,这是您使用的传输功能的声明:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

它需要一个指向 uint8_t 的指针作为数据(而不是 uint32_t),所以如果你编译你的代码,你至少应该得到一个警告。

如果您想编写独立于使用的字节序的代码,您应该将数据存储到一个数组而不是一个“大”变量中。

uint8_t write_package[4];

write_package[0] = ERASE;
write_package[1] = mem_addr;
write_package[2] = (data >> 8) & 0xFF;
write_package[3] = (data & 0xFF);
于 2018-07-10T09:23:58.230 回答