32G12k128和8G1K08使用SPI互为主从通讯失败
两个单片机SPI都使用的P32,P33,P34,P35四个IO口,串口都用的uart1(P30,P31),主频都是22.1184MHz:8G1K08配置如下:
void SPI_PS_init(void)
{
SPI_InitTypeDef SPI_InitStructure;
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate= 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable= ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
SPI_InitStructure.SPI_Enable = ENABLE; //SPI启动 ENABLE, DISABLE
SPI_InitStructure.SPI_SSIG = DISABLE; //片选位 ENABLE, DISABLE
SPI_InitStructure.SPI_FirstBit= SPI_MSB; //移位方向 SPI_MSB, SPI_LSB
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //主从选择 SPI_Mode_Master, SPI_Mode_Slave
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟相位 SPI_CPOL_High, SPI_CPOL_Low
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据边沿 SPI_CPHA_1Edge,SPI_CPHA_2Edge
SPI_InitStructure.SPI_Speed = SPI_Speed_4; //SPI速度 SPI_Speed_4, SPI_Speed_8, SPI_Speed_16, SPI_Speed_2/SPI_Speed_32
SPI_Init(&SPI_InitStructure);
NVIC_SPI_Init(ENABLE,Priority_3); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
P3_MODE_IO_PU(GPIO_Pin_All);
SPI_SW(SPI_P35_P34_P33_P32);
SPI_SS_4 = 1;
}
void Sample_SPI_PS(void)
{
u8 i;
if(COM1.RX_TimeOut > 0)
{
if(--COM1.RX_TimeOut == 0)
{
if(COM1.RX_Cnt > 0)
{
UartReceived = 1; //设置串口接收标志
}
}
}
if((UartReceived) && (SPI_SS_4))
{
SPI_SetMode(SPI_Mode_Master);
SPI_SS_4 = 0; //拉低从机 SS 管脚
delay_ms(1);
for(i=0;i<COM1.RX_Cnt;i++)
{
SPI_WriteByte(RX1_Buffer); //发送串口数据
}
SPI_SS_4 = 1; //拉高从机的 SS 管脚
SPI_SetMode(SPI_Mode_Slave);
COM1.RX_Cnt = 0;
UartReceived = 0;
}
if(SPI_RxTimerOut > 0)
{
if(--SPI_RxTimerOut == 0)
{
printf("spi[%d]:",SPI_RxCnt);
if(SPI_RxCnt > 0)
{
for(i=0; i<SPI_RxCnt; i++) TX1_write2buff(SPI_RxBuffer);
}
SPI_RxCnt = 0;
}
}
}
STC32G12K128配置如下:
/****************SPI初始化函数 *****************/
void SPI_config(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Enable = ENABLE; //SPI启动 ENABLE, DISABLE
SPI_InitStructure.SPI_SSIG = DISABLE; //片选位 ENABLE, DISABLE
SPI_InitStructure.SPI_FirstBit= SPI_MSB; //移位方向 SPI_MSB, SPI_LSB
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //主从选择 SPI_Mode_Master, SPI_Mode_Slave
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟相位 SPI_CPOL_High, SPI_CPOL_Low
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据边沿 SPI_CPHA_1Edge,SPI_CPHA_2Edge
SPI_InitStructure.SPI_Speed = SPI_Speed_4; //SPI速度 SPI_Speed_4, SPI_Speed_16, SPI_Speed_64, SPI_Speed_128
SPI_Init(&SPI_InitStructure);
NVIC_SPI_Init(ENABLE,Priority_3); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
P3_MODE_IO_PU(GPIO_Pin_All);
SPI_SW(SPI_P35_P34_P33_P32); //SPI_P54_P13_P14_P15,SPI_P22_P23_P24_P25,SPI_P54_P40_P41_P43,SPI_P35_P34_P33_P32
SPI_SS_4 = 1;
}
/**********************************************/
void main(void)
{
u8 i;
u16 cnt=0;
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXSFR(); //扩展SFR(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
GPIO_config();
UART_config();
SPI_config();
EA = 1;
printf("STC32G_SPI_TEST\r\n"); //UART发送一个字符串
while (1)
{
delay_ms(1);
if(cnt++%250==0) P46 = !P46;
if(COM1.RX_TimeOut > 0)
{
if(--COM1.RX_TimeOut == 0)
{
if(COM1.RX_Cnt > 0)
{
UartReceived = 1; ////设置串口接收标志
}
}
}
if((UartReceived) && (SPI_SS_4))
{
SPI_SetMode(SPI_Mode_Master); //SPI设置主机模式,开始发送数据
SPI_SS_4 = 0; //拉低从机 SS 管脚
delay_ms(1);
for(i=0;i<COM1.RX_Cnt;i++)
{
SPI_WriteByte(RX1_Buffer); //发送串口数据
}
SPI_SS_4 = 1; //拉高从机的 SS 管脚
SPI_SetMode(SPI_Mode_Slave); //SPI设置从机模式,进入接收状态
COM1.RX_Cnt = 0;
UartReceived = 0;
}
if(SPI_RxTimerOut > 0)
{
if(--SPI_RxTimerOut == 0) //SPI超时计数器每1ms减1,并判断是否为0
{
printf("SPI[%d]",SPI_RxCnt);
if(SPI_RxCnt > 0) //SPI接收超时后判断SPI接收数据长度是否非零
{
for(i=0; i<SPI_RxCnt; i++) TX1_write2buff(SPI_RxBuffer); //通过串口输出数据
}
SPI_RxCnt = 0; //清除SPI已接收数据长度
}
}
}
}
有没有大佬帮忙分析一下无法通讯的原因呀?
STC8G1K08的main函数 两个程序都是参考例程改的,但是通讯没反应
请直接下载例程测试,试验成功后再修改
请上传原理图及逻辑分析仪或示波器测量结果
以下为AI生成内容:
根据提供的代码和问题描述,STC32G12K128 与 STC8G1K08 的 SPI 互为主从通讯失败可能由以下原因导致,需逐一排查:
一、SPI 引脚配置与复用问题
[*]引脚功能映射错误
[*]两者均使用 SPI_P35_P34_P33_P32 映射引脚,对应关系为:
[*]P3.2(SCLK)、P3.3(MOSI)、P3.4(MISO)、P3.5(SS)。
[*]关键检查:
[*]确认两单片机的 SPI 引脚是否支持该复用功能(参考数据手册外设映射表)。
[*]STC8G1K08 的 SPI 默认引脚是否需通过 P_SW1 或 P_SW2 寄存器切换(如文档中提到的功能脚切换寄存器)。
[*]确保引脚方向正确(主机:SCLK/MOSI/SS 输出,MISO 输入;从机:SCLK/MOSI 输入,MISO/SS 输入)。
[*]片选信号(SS)控制错误
[*]问题:从机的 SS 引脚应由主机控制,而不是从机自身。
[*]当前代码中,从机模式下 SPI_SS_4 = 1 可能错误地将 SS 置为输入或内部拉高,导致从机未被选中。
[*]修正:主机负责拉低从机的 SS 引脚,从机的 SS 引脚应设为输入模式,不主动控制。
二、主从模式与时序配置不匹配
[*]主从模式切换逻辑
[*]代码行为:两单片机在检测到串口数据时切换为 SPI_Mode_Master 发送数据,理论上允许互为主从(分时主从),但需确保:
[*]同一时刻仅一方为主机,另一方为从机。
[*]切换模式后需等待时钟稳定,避免时序混乱。
[*]时钟相位与极性(CPOL/CPHA)
[*]两者均配置为 SPI_CPOL_Low 和 SPI_CPHA_2Edge(模式 3),理论一致。但需确认:
[*]主机和从机的时钟极性和相位是否完全匹配(示波器抓波形验证)。
[*]是否存在时钟频率过高导致时序不兼容(22.1184MHz 下 SPI 速度 SPI_Speed_4 对应分频因子是否合理)。
三、SPI 速度与时钟配置
[*]分频系数不一致
[*]STC8G1K08:SPI_Speed_4 通常对应 Fosc/4(如文档中提到 SPI 速度可选 Fosc/2、Fosc/4 等)。
[*]STC32G12K128:SPI_Speed_4 可能定义不同(如 Fosc/64),需查阅两者数据手册确认分频因子。
[*]建议:统一设置为较低速度(如 Fosc/16),排除时钟过快导致的时序问题。
[*]主频确认
[*]确保两单片机均正确配置为 22.1184MHz(检查时钟寄存器 CLKSEL 或外部晶振配置)。
四、软件逻辑问题
[*]片选信号时序
[*]主机发送数据时,需在数据传输前拉低 SS,传输完成后拉高。当前代码中 delay_ms(1) 可能过长,导致 SPI 超时。
[*]优化:使用更精确的延时(如 10μs),或直接操作寄存器避免不必要的延时。
[*]中断与缓冲区处理
[*]SPI 接收中断是否正确启用(两机均调用 NVIC_SPI_Init(ENABLE, Priority_3),但需确认中断服务函数是否正确处理接收数据)。
[*]串口接收标志 UartReceived 是否在处理后正确清零,避免重复触发发送。
[*]主从角色混淆
[*]确保通讯时明确主从角色(如固定某一为主机,另一为从机),避免同时切换模式导致总线竞争。
五、硬件连接与电气特性
[*]接线错误
[*]检查接线:SCLK-MOSI-MISO-SS 需一一对应,共地是否可靠。
[*]从机的 SS 引脚是否浮空(需由主机驱动,不可悬空)。
[*]上拉电阻配置
[*]SPI 引脚在高阻状态时需外部上拉(尤其 MISO),除非内部上拉已启用(代码中 P3_MODE_IO_PU(GPIO_Pin_All) 已使能上拉,可确认)。
六、调试建议
[*]分步测试
[*]固定一方为主机,另一方为从机,单向通讯测试(如主机发从机收,反之亦然)。
[*]使用示波器抓取 SCLK、MOSI、MISO 波形,确认时序是否匹配。
[*]简化代码
[*]暂时移除串口相关逻辑,直接通过 SPI 发送固定数据(如主机发送 0x55,从机接收后返回 0xAA),定位问题是否在串口触发逻辑。
[*]寄存器检查
[*]打印两机的 SPI 控制寄存器(如 SPCTL、SPSTAT),确认配置一致。
总结可能原因
[*]片选信号由从机自身控制,而非主机驱动,导致从机未正确选中。
[*]SPI 速度分频系数在两型号中定义不同,导致时钟不匹配。
[*]引脚复用或方向配置错误,如从机的 MOSI/MISO 未设为输入。
[*]主从模式切换时的时序延迟过长,或未正确等待时钟稳定。
通过逐行对比寄存器配置、抓波形分析时序、简化测试流程,可快速定位问题。
页:
[1]