You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32通过SPI与93C46 EEPROM通信:非8倍数时钟周期发送难题

解决STM32 SPI与93C46 EEPROM的20位命令通信问题

由于STM32 HAL库的SPI发送函数仅支持8位倍数的字节传输,而93C46的写命令需要精准的20位时钟周期,可通过以下三种实用方法实现通信:

方法一:直接操作GPIO手动生成20位时序

绕开HAL库的字节限制,直接控制SPI的NSS、SCK、MOSI引脚电平,精准生成每个时钟周期的数据位,是最可靠的方案。

步骤与代码示例

  1. 提前将NSS、SCK、MOSI对应的GPIO配置为推挽输出模式;
  2. 按93C46的高位先传规则,逐位输出数据并翻转时钟:
// 引脚宏定义(根据实际硬件连接修改)
#define SPI_NSS_LOW()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define SPI_NSS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define SPI_SCK_LOW()  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
#define SPI_SCK_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET)
#define SPI_MOSI_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET)
#define SPI_MOSI_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET)

void SPI_Send_20Bits(uint32_t cmd_data) {
    SPI_NSS_LOW(); // 拉低片选,启动命令传输
    
    // 从最高位(第19位)到最低位(第0位)逐位发送
    for(int i = 19; i >= 0; i--) {
        // 设置MOSI电平
        (cmd_data & (1 << i)) ? SPI_MOSI_HIGH() : SPI_MOSI_LOW();
        
        // 生成SCK时钟上升沿(匹配93C46 CPOL=0、CPHA=0的时序)
        SPI_SCK_HIGH();
        // 延时确保时钟宽度满足93C46要求(可根据SPI频率调整,比如用空循环替代HAL_Delay)
        for(uint16_t d=0; d<100; d++);
        SPI_SCK_LOW();
        for(uint16_t d=0; d<100; d++);
    }
    
    SPI_NSS_HIGH(); // 拉高片选,结束命令传输
}

// 使用示例:发送写命令(命令码01 + 地址0x00 + 数据0x123)
uint32_t write_cmd = (0x1 << 18) | (0x00 << 12) | 0x123;
SPI_Send_20Bits(write_cmd);

方法二:HAL SPI函数+手动补充剩余位

如果希望保留HAL库的部分封装,可先发送前16位(2字节),再手动补充剩余4位:

void SPI_Send_20Bits_HAL(uint32_t cmd_data) {
    uint8_t buf[2];
    // 拆分20位数据的高16位为两个字节(高位先传)
    buf[0] = (cmd_data >> 12) & 0xFF;
    buf[1] = (cmd_data >> 4) & 0xFF;
    
    SPI_NSS_LOW();
    // HAL发送前16位
    HAL_SPI_Transmit(&hspi1, buf, 2, HAL_MAX_DELAY);
    
    // 手动发送剩余4位
    uint8_t low4 = cmd_data & 0x0F;
    for(int i=3; i>=0; i--) {
        (low4 & (1 << i)) ? SPI_MOSI_HIGH() : SPI_MOSI_LOW();
        SPI_SCK_HIGH();
        for(uint16_t d=0; d<100; d++);
        SPI_SCK_LOW();
        for(uint16_t d=0; d<100; d++);
    }
    
    SPI_NSS_HIGH();
}

方法三:16位SPI模式+手动补位

部分STM32的SPI支持16位数据宽度,可先配置为16位模式发送高16位,再手动补充低4位:

// 初始化时需设置SPI数据宽度为16位:hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
void SPI_Send_20Bits_16Mode(uint32_t cmd_data) {
    uint16_t high16 = (cmd_data >> 4) & 0xFFFF;
    
    SPI_NSS_LOW();
    // HAL发送16位数据
    HAL_SPI_Transmit(&hspi1, (uint8_t*)&high16, 1, HAL_MAX_DELAY);
    
    // 手动发送低4位
    uint8_t low4 = cmd_data & 0x0F;
    for(int i=3; i>=0; i--) {
        (low4 & (1 << i)) ? SPI_MOSI_HIGH() : SPI_MOSI_LOW();
        SPI_SCK_HIGH();
        for(uint16_t d=0; d<100; d++);
        SPI_SCK_LOW();
        for(uint16_t d=0; d<100; d++);
    }
    
    SPI_NSS_HIGH();
}

额外注意事项

  • 93C46写操作前需先发送WREN写使能命令(通常为3位),同样可使用上述方法处理非8位倍数的时序;
  • 时钟延时需根据93C46的最大时钟频率调整,避免因时钟过快导致数据采样错误;
  • 严格控制NSS引脚的拉低/拉高时机,确保每个命令的独立性。

内容的提问来源于stack exchange,提问作者MHBagh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:52:17