PIC 18F46K22与Waveshare 1.54寸SPI电子墨水屏通信异常问题
我来帮你梳理下这个SPI通信的问题,从你的描述和代码来看,有几个关键错误直接导致了输出位异常和SCL时钟偏差,咱们一步步来解决:
1. 最核心的错误:SPI被配置成了Slave模式!
你看你的SPI_Init_Master函数里:
SSP1CON1=0x20; /* Slave mode,Serial enable, idle state high for clk */
0x20对应的二进制是00100000,其中SSPM3:SSPM0位是0010,这是SPI Slave模式的配置!但你需要的是Master模式,这就导致PIC不会主动输出SCL时钟,完全依赖外部设备提供时钟,自然会出现时钟偏差和数据输出错误。
修正方案:
把SPI配置为Master模式,同时匹配Waveshare 1.54寸墨水屏的SPI时序(一般是模式0:CPOL=0,CPHA=0,即空闲时SCL低,上升沿采样数据)。修改后的SPI_Init_Master函数如下:
void SPI_Init_Master() { /* PORT definition for SPI pins*/ TRISCbits.TRISC4 = 1; /* SDI (RC4) as input */ TRISCbits.TRISC3 = 0; /* SCK (RC3) as output */ TRISCbits.TRISC5 = 0; /* SDO (RC5) as output */ TRISBbits.TRISB2 = 0; /* CS (RB2) as output */ EPD_CS_PIN = 1; // CS引脚空闲时拉高,符合EPD的要求 // 配置SPI为模式0(CPOL=0, CPHA=0),适配Waveshare EPD SSP1STAT = 0x40; // CKE=1(数据在SCK上升沿变化),SMP=0(主模式下在时钟边沿采样数据) SSP1CON1 = 0x30; // SSPEN=1(启用SPI),SSPM3:SSPM0=0000(Master模式,时钟=FOSC/4),CKP=0(空闲时SCL为低) PIR1bits.SSP1IF = 0; // 清除SPI中断标志 ADCON1 = 0x0F; // 将所有引脚设置为数字IO,避免模拟功能干扰 }
这个配置会让PIC以8MHz/4=2MHz的频率输出SCL时钟,完全符合你的设计要求。
2. 优化SPI数据交换的等待逻辑
你的SPI1_Exchange8bit函数里的等待逻辑可以更直观,把:
while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS) { }
改成:
while(!SSP1STATbits.BF); // 等待接收缓冲满,即数据传输完成
这样代码可读性更强,功能完全一致。
3. 确认CS引脚的正确控制
确保在每次SPI传输前拉低EPD_CS_PIN,传输完成后拉高。比如在调用SPI1_Exchange8bitBuffer或者SPI1_Exchange8bit前后添加:
EPD_CS_PIN = 0; // 拉低CS,开始通信 // 执行SPI传输操作 SPI1_Exchange8bit(my_data); EPD_CS_PIN = 1; // 拉高CS,结束通信
这是SPI通信的标准流程,避免其他设备干扰。
4. 后续验证步骤
修改完成后,用逻辑分析仪重新测试:
- 检查SCL时钟频率是否为2MHz(8MHz/4),现在应该由PIC主动输出稳定的时钟信号。
- 发送一个固定字节(比如你代码里的
0x58),验证SDO线上的位是否和预期一致(MSB优先)。 - 查看UART输出,确认
EPD_Init是否成功,如果还是失败,检查RST、DC、BUSY引脚的硬件连接和时序是否符合墨水屏的数据手册要求。
内容的提问来源于stack exchange,提问作者Naman Shandilya
相关产品推荐
相关产品推荐

