lewen 发表于 2025-4-23 14:53:59

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已接收数据长度
                        }
                }
      }
}

有没有大佬帮忙分析一下无法通讯的原因呀?

lewen 发表于 2025-4-23 14:57:29

STC8G1K08的main函数

lewen 发表于 2025-4-23 14:59:02

两个程序都是参考例程改的,但是通讯没反应

DebugLab 发表于 2025-4-23 16:25:00

请直接下载例程测试,试验成功后再修改
请上传原理图及逻辑分析仪或示波器测量结果
以下为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]
查看完整版本: 32G12k128和8G1K08使用SPI互为主从通讯失败