为何此SPI代码中数据无法写入SPDR寄存器?
问题分析与解决方案
核心问题:SPDR读取值为0的本质原因
SPI主机模式下,发送数据的同时会同步接收从机返回的数据,SPDR寄存器在传输完成后存储的是从机发来的字节,而非你发送的字节。由于你未连接任何从机,MISO引脚处于浮空状态,此时读取到的SPDR值是不确定的(可能固定为0、随机值,取决于引脚浮空时的电平)。你期望SPDR等于发送的0xAA是错误逻辑——主机的SPDR是发送缓冲区与接收缓冲区共用的物理寄存器,但发送和接收是独立流程:
- 写SPDR是加载要发送的数据
- 读SPDR是获取从机返回的数据
配置排查与修正点
- 引脚定义缺失验证:你的代码使用了
MOSI_pin、SCK_pin等宏,但未给出具体定义,请确认对应ATmega328的正确引脚:- Arduino Uno标准SPI引脚:MOSI=PB3(数字11)、SCK=PB5(数字13)、MISO=PB4(数字12)、SS=PB2(数字10)
- 确保MISO引脚(PB4)处于输入模式(默认即为输入,无需修改DDRB,不要误设为输出)
- CS引脚控制逻辑:SPI主机模式下,CS是手动控制的从机选通信号,当前代码中
PORTB |= (1 << CS_pin)拉高CS的操作没问题,后续连接从机时只需在发送前拉低、发送后拉高即可。 - SPI传输等待逻辑:
spi_send函数中等待SPIF标志位的写法是正确的,该标志位会在传输完成后置1,确保数据发送完成。
验证主机功能的可行方案
如果要确认SPI主机发送功能正常,无需依赖SPDR返回值,可通过以下方式测试:
- 硬件观测:用示波器或逻辑分析仪查看MOSI和SCK引脚,调用
spi_send(0xAA)后,MOSI应输出二进制10101010的波形,SCK会产生对应时钟脉冲。 - 回环测试:将MOSI与MISO引脚短接,此时发送的数据会被自身接收,SPDR读取值将等于发送值,可直接验证收发链路是否正常。
- 简化测试逻辑:去掉对SPDR的无效判断,改为验证
spi_send是否能正常执行完成:void led(){ spi_send(0xAA); // 传输完成后点亮LED,说明spi_send执行成功 PORTD |= (1 << LED_pin); _delay_ms(2500); PORTD &= ~(1 << LED_pin); _delay_ms(2500); }
补充代码:引脚宏定义示例
确保引脚宏与硬件对应,比如:
// Arduino Uno引脚对应定义 #define MOSI_pin 3 // PB3(数字11) #define SCK_pin 5 // PB5(数字13) #define CS_pin 2 // PB2(数字10) #define RST_pin 0 // 根据你的硬件需求修改 #define LED_pin 7 // PD7(数字7)
内容的提问来源于stack exchange,提问作者Chandler Thornton
相关产品推荐
相关产品推荐

