找回密码
 立即注册
查看: 109|回复: 9

第2篇_8H1K17的I2C无法对主机做出应答(附带主从机代码)

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-25 14:14:55 | 显示全部楼层 |阅读模式
我是用某单片机作为主机,读写8H1K17的I2C,结果是STC8H1K17无法应答主机发起的读设备地址:
1、8H1K17地址我设置为0x30

2、MA设置为0(为了调试,也曾设置为1,结果都是从机无法应答)

下图是我用逻辑分析仪抓取的主机读设备地址的信号
主机发送读设备地址.png

主机模拟I2C的代码:
  1. /**
  2.   ******************************************************************************
  3.   * @file    I2C_Soft_M.c
  4.   * @author  zhouq
  5.   * @Date    2024/11/11
  6.   * @brief   I2C通信驱动文件,实现软件模拟I2C主机功能
  7.   * @Description
  8.   ******************************************************************************
  9.   * @attention
  10.   ******************************************************************************
  11.   */
  12. /* Includes ------------------------------------------------------------------*/
  13. #include "HeaderInc.h"
  14. /* Private define-------------------------------------------------------------*/
  15. //引脚定义
  16. #define GPIO_I2C_SCL    GPIO_Pin_13  //PA13
  17. #define GPIO_I2C_SDA    GPIO_Pin_14  //PA14
  18. //置位与清零SCL管脚
  19. #define        SCL_SET    GPIOA_SetBits( GPIO_I2C_SCL )
  20. #define        SCL_CLR    GPIOA_ResetBits( GPIO_I2C_SCL )
  21. //置位与清零SDA管脚
  22. #define        SDA_SET    GPIOA_SetBits( GPIO_I2C_SDA )
  23. #define        SDA_CLR    GPIOA_ResetBits( GPIO_I2C_SDA )
  24. //读SDA管脚状态
  25. #define READ_SDA   GPIOA_ReadInPortPin( GPIO_I2C_SDA )
  26. /* Private variables----------------------------------------------------------*/
  27. static void               I2C_GPIO_Init(void);          //I2C GPIO模式初始化
  28. static void               I2C_Init(void);               //I2C初始化
  29. static void               I2C_Start(void);              //I2C起始信号
  30. static void               I2C_Stop(void);               //I2C停止信号
  31. static ACK_Value_t        I2C_Write_Byte(uint8_t);      //I2C写字节
  32. static uint8_t            I2C_Read_Byte (ACK_Value_t);  //I2C读字节
  33. static DeviceStatus_t I2C_Write_Frame(uint8_t dev_addr, uint8_t reg_addr, uint8_t *send_data, uint16_t length);
  34. static DeviceStatus_t I2C_Read_Frame(uint8_t dev_addr, uint8_t reg_addr, uint8_t *recv_data, uint16_t length);
  35. /* Public variables-----------------------------------------------------------*/
  36. I2C_Soft_M_t I2C_Soft_M =
  37. {
  38.         .Init = I2C_Init,
  39.         .Write_Frame = I2C_Write_Frame,
  40.         .Read_Frame = I2C_Read_Frame
  41. };
  42. /* Private function prototypes------------------------------------------------*/
  43. /*
  44.         * @name   I2C_GPIO_Init
  45.         * @brief  I2C GPIO初始化
  46.         * @param  None
  47.         * @retval None      
  48. */
  49. static void I2C_GPIO_Init(void)
  50. {
  51.         //将GPIO配置为开漏输出模式
  52.         GPIOA_ModeCfg( GPIO_I2C_SCL,GPIO_ModeOut_OP_8mA );
  53.         GPIOA_ModeCfg( GPIO_I2C_SDA,GPIO_ModeOut_OP_8mA );
  54.         
  55. }
  56. /*
  57.         * @name   I2C_Init
  58.         * @brief  I2C初始化
  59.         * @param  None
  60.         * @retval None      
  61. */
  62. static void I2C_Init(void)
  63. {
  64.         I2C_GPIO_Init();
  65.         SCL_SET;
  66.         SDA_SET;
  67. }
  68. /*
  69.         * @name   I2C_Start
  70.         * @brief  I2C起始信号
  71.         * @param  None
  72.         * @retval None      
  73. */
  74. static void I2C_Start(void)
  75. {
  76.         //SCL为高电平,SDA的下降沿为I2C起始信号
  77.         SDA_SET;
  78.         SCL_SET;
  79.         Public.Delay_us(1);
  80.         
  81.         SDA_CLR;
  82.         Public.Delay_us(5);
  83.         
  84.         //将SCL拉低,以免下一位是SDA出现上升沿,导致总线出现停止信号
  85.         //SCL为高电平,SDA出现上升沿视为停止信号
  86.         SCL_CLR;
  87.         Public.Delay_us(1);
  88. }
  89. /*
  90.         * @name   I2C_Stop
  91.         * @brief  I2C停止信号
  92.         * @param  None
  93.         * @retval None      
  94. */
  95. static void I2C_Stop(void)
  96. {
  97.         //SCL为高电平,SDA的上升沿为I2C停止信号
  98.         SDA_CLR;
  99.         SCL_SET;
  100.         
  101.         Public.Delay_us(5);
  102.         SDA_SET;
  103. }
  104. /*
  105.         * @name   I2C_Write_Byte
  106.         * @brief  I2C写字节
  107.         * @param  WR_Byte -> 待写入数据
  108.         * @retval ACK_Value_t -> 从机应答值      
  109. */
  110. static ACK_Value_t I2C_Write_Byte(uint8_t WR_Byte)
  111. {
  112.         uint8_t i;
  113.         ACK_Value_t  ack_respond;
  114.         
  115.         //SCL为低电平时,SDA准备数据,接着SCL为高电平,读取SDA数据
  116.         //数据按8位传输,高位在前,利用for循环逐个接收
  117.         for(i=0;i<8;i++)
  118.         {
  119.                 //SCL清零,主机SDA准备数据
  120.                 SCL_CLR;
  121.                 Public.Delay_us(1);
  122.                
  123.                 //MSB,先发送高位
  124.                 //待发送的数据循环左移,和BIT7比较
  125.                 if((WR_Byte&BIT7) == BIT7)
  126.                 {
  127.                         SDA_SET;
  128.                 }
  129.                 else
  130.                 {
  131.                         SDA_CLR;
  132.                 }
  133.                 Public.Delay_us(1);
  134.                 //SCL置高,传输数据
  135.                 SCL_SET;
  136.                 Public.Delay_us(5);
  137.                
  138.                 //准备发送下一比特位
  139.                 WR_Byte <<= 1;
  140.         }
  141.         
  142.         //主机在SCL的高电平读取应答位,所以要先拉低SCL
  143.         SCL_CLR;
  144.         
  145.         //释放SDA,等待从机拉高/拉低SDA
  146.         //如果主机不释放SDA,如果上一位数据是0,那么主机将占据SDA,从机没办法发送SDA=1的情况
  147.         SDA_SET;
  148.         Public.Delay_us(1);
  149.         
  150.         //主机在SCL的高电平读取应答位,拉低SCL后再将其拉高
  151.         SCL_SET;
  152.         //等待SDA被从机操作
  153.         Public.Delay_us(5);
  154.     // 读取从机应答时的超时处理
  155.     Timer1.Timeout = 0;
  156.     while (READ_SDA != 0) // 等待从机应答拉低
  157.     {
  158.         if (Timer1.Timeout >= TIMER1_1S)// 设置超时时间为1S
  159.         {
  160.             SCL_CLR; //从机应答超时,主机继续占用总线
  161.             return ERROR_TIMEOUT; // 返回超时错误
  162.         }
  163.     }        
  164.         
  165.         //从机应答后,主机继续占用总线
  166.         SCL_CLR;
  167.         Public.Delay_us(1);
  168.     // 返回从机的应答信号
  169.     return (READ_SDA == 0) ? I2C_ACK : I2C_NACK; // 返回ACK或NACK
  170. }
  171. /*
  172.         * @name   I2C_Read_Byte
  173.         * @brief  I2C读字节
  174.         * @param  ACK_Value -> 主机发送的ACK/NACK
  175.         * @retval 从机返回主机要读的数据
  176. */
  177. static uint8_t I2C_Read_Byte(ACK_Value_t ACK_Value)
  178. {
  179.         uint8_t read_byte = 0,i;
  180.                
  181.         //接收前,主机先确保释放SDA,避免干扰从机的数据发送
  182.         SDA_SET;
  183.         
  184.         //SCL为低电平时,SDA准备数据,接着SCL为高电平,读取SDA数据
  185.         //数据按8位传输,高位在前,利用for循环逐个接收
  186.         for(i=0;i<8;i++)
  187.         {
  188.                 //准备接收下一比特位
  189.                 read_byte <<= 1;//read_byte初始化时为0,第一次循环时,左移一位还是0
  190.                
  191.                 //SCL清零,从机SDA准备数据
  192.                 SCL_CLR;
  193.                 Public.Delay_us(5);
  194.                
  195.                 //SCL置高,获取数据
  196.                 SCL_SET;
  197.                 Public.Delay_us(5);
  198.                 //接收从机发送的数据,接收的数据放在最低位
  199.                 read_byte |= READ_SDA;
  200.         }
  201.         
  202.         //SCL清零,主机准备应答信号
  203.         SCL_CLR;
  204.         Public.Delay_us(1);
  205.         
  206.         //主机发送应答信号        
  207.         if(ACK_Value == I2C_ACK)//应答,让从机继续发数据
  208.         {
  209.                 SDA_CLR;
  210.         }
  211.         else//非应答,停止数据传输
  212.         {
  213.                 SDA_SET;
  214.     }
  215.         Public.Delay_us(1);
  216.         
  217.         //置起SCL,将SDA发送出去
  218.         SCL_SET;         
  219.         Public.Delay_us(5);
  220.         
  221.         //Note:
  222.     //释放SDA数据线
  223.         //SCL先清零,再释放SDA,防止连续传输数据时,从机错将SDA释放信号当成NACK信号
  224.         SCL_CLR;
  225.     SDA_SET;         
  226.         Public.Delay_us(1);
  227.         //返回数据
  228.         return read_byte;
  229. }
  230. /**
  231.   * @brief  I2C主机写一帧数据
  232.   * @param  dev_addr: 从机地址
  233.   * @param  reg_addr: 寄存器地址
  234.   * @param  send_data: 数据缓冲区指针
  235.   * @param  length: 数据长度
  236.   * @retval 0: 成功, 1: 失败
  237.   */
  238. static DeviceStatus_t I2C_Write_Frame(uint8_t dev_addr, uint8_t reg_addr, uint8_t *send_data, uint16_t length)
  239. {
  240.     uint16_t i;
  241.     ACK_Value_t ack;
  242.     I2C_Start(); // 发送起始信号
  243.     // 发送从机地址和写位
  244.     ack = I2C_Write_Byte(dev_addr & 0xFE);
  245.     if (ack != I2C_ACK) {
  246.         I2C_Stop();
  247.         return ERROR_Data; // 失败
  248.     }
  249.         // 发送寄存器地址
  250.     ack = I2C_Write_Byte(reg_addr);
  251.     if (ack != I2C_ACK) {
  252.         I2C_Stop();
  253.         return ERROR_Data; // 失败
  254.     }
  255.     // 发送数据
  256.     for (i = 0; i < length; i++) {
  257.         ack = I2C_Write_Byte(send_data[i]);
  258.         if (ack != I2C_ACK) {
  259.             I2C_Stop();
  260.             return ERROR_Data; // 失败
  261.         }
  262.     }
  263.     I2C_Stop(); // 发送停止信号
  264.     return HAL_OK; // 成功
  265. }
  266. /**
  267.   * @brief  I2C主机读一帧数据
  268.   * @param  dev_addr: 从机地址
  269.   * @param  reg_addr: 寄存器地址
  270.   * @param  recv_data: 数据缓冲区指针,用于存储读取的数据
  271.   * @param  length: 要读取的数据长度
  272.   * @retval 0: 成功, 1: 失败
  273.   */
  274. static DeviceStatus_t I2C_Read_Frame(uint8_t dev_addr, uint8_t reg_addr, uint8_t *recv_data, uint16_t length)
  275. {
  276.     uint16_t i;
  277.     ACK_Value_t ack;
  278.     I2C_Start(); // 发送起始信号
  279.     // 发送从机地址和读位
  280.     ack = I2C_Write_Byte(dev_addr | 0x01);
  281.     if (ack != I2C_ACK) {
  282.         I2C_Stop();
  283.         return ERROR_Data; // 失败
  284.     }
  285.         // 发送寄存器地址
  286.     ack = I2C_Write_Byte(reg_addr);
  287.     if (ack != I2C_ACK) {
  288.         I2C_Stop();
  289.         return ERROR_Data; // 失败
  290.     }
  291.         I2C_Start(); // 重新启动I2C总线
  292.     // 读取数据
  293.     for (i = 0; i < length; i++) {
  294.         if (i == length - 1) {
  295.             // 最后一个字节发送NACK
  296.             recv_data[i] = I2C_Read_Byte(I2C_NACK);
  297.         } else {
  298.             // 其他字节发送ACK
  299.             recv_data[i] = I2C_Read_Byte(I2C_ACK);
  300.         }
  301.     }
  302.     I2C_Stop(); // 发送停止信号
  303.     return HAL_OK; // 成功
  304. }
  305. /********************************************************
  306.   End Of File
  307. ********************************************************/
复制代码
主机发起的读操作
  1.      uint8_t CHA_Value[2];
  2.      CHA_Value[0]=0x3C;
  3.      CHA_Value[1]=0x3B;
  4.      I2C_Soft_M.Init();
  5.      I2C_Soft_M.Read_Frame(0x30,ChA_ID,CHA_Value,2);
复制代码


从机代码(STC8H1K17):
  1. /* Includes ------------------------------------------------------------------*/
  2. #include "HeaderInc.h"
  3. /* Private define-------------------------------------------------------------*/
  4. #define User_I2C_ADDR  0x30          //从机地址为0x30,高7位,MA=0,MA=0表示设备地址必须与I2CSLADR[7:1]相同
  5. #define WRMask         0x01          //读写操作掩码
  6. #define ADDR_IAP_STC   0x8A   //IAP升级芯片地址
  7. //I2C配置寄存器(I2CCFG)
  8. //使能I2C从机模式
  9. //B7-B6 10
  10. #define EnI2C_Slave    0x80
  11. //使能I2C主机模式
  12. //B7-B6 11
  13. //#define EnI2C_Master   0xC0
  14. //MSSPEED[5:0],I2C在主机模式下,MSSPEED设置才有效
  15. //I2C总线速度=FOSC / 2 / (MSSPEED * 2 + 4),设置总线速度为400K,那么MSSPEED=13
  16. //#define I2C_Speed      0x0D
  17. //I2C 从机状态寄存器(I2CSLST)
  18. #define I2C_S_BUSY       0x80          //从机状态位,0空闲,1忙,只读
  19. #define I2C_S_STAIF      0x40          //收到START信号的中断请求位
  20. #define I2C_S_RXIF       0x20          //从机收到1字节的数据的中断请求位
  21. #define I2C_S_TXIF       0x10          //从机发完1字节的数据的中断请求位
  22. #define I2C_S_STOIF      0x08          //从机收到STOP信号的中断请求位
  23. #define I2C_S_ACKI       0x02          //从机接收到的ACK数据
  24. #define I2C_S_ACKO       0x01          //从机准备要发送的ACK信号
  25. /* Private variables----------------------------------------------------------*/
  26. /* Private function prototypes------------------------------------------------*/      
  27. //声明使用的函数
  28. static void     I2C_S_Init(void);        //I2C初始化
  29. /* Public variables-----------------------------------------------------------*/
  30. //创建并初始化结构体
  31. I2C_S_t idata I2C_S =
  32. {
  33.         FALSE,      /* DevAddrFlag - 初始化时未接收到设备地址,即未收到任何数据 */
  34.         FALSE,      /* RegAddrFlag - 初始化时未接收到寄存器地址 */
  35.         FALSE,            /* 读写标志位,TRUE 表示读操作,FALSE 表示写操作 */
  36.         0,          /* DevAddr */
  37.         0,          /* RegAddr */
  38.         I2C_S_Init  /* Init */
  39. };
  40. /*
  41.         * @name   I2C_S_Init
  42.         * @brief  I2C初始化
  43.         * @param  None
  44.         * @retval None      
  45. */
  46. static void I2C_S_Init(void)
  47. {
  48.         //设置P14 P15为 I2C 功能
  49.     P_SW2 |= 0x80;
  50.         
  51.     //设置从机设备地址寄存器I2CSLADR=0011_0000B
  52.         //B0为MA,设置为0表示设备地址必须与I2CSLADR[7:1]相同
  53.         I2CSLADR = 0x30;                        
  54.         //配置从机状态为空闲,并清零所有中断标志
  55.         I2CSLST = 0x00;
  56.     //使能I2C从机模式,此寄存器涉及到端口
  57.         I2CCFG = EnI2C_Slave;
  58. }
  59. /*
  60.         * @name   I2C_INTR()
  61.         * @brief  I2C中断函数
  62.         * @param  参数说明
  63.         * @retval None      
  64. */
  65. void I2C_INTR() interrupt 24
  66. {               
  67.         P_SW2 |= 0x80;
  68.         
  69.         //收到START信号
  70.     if (I2CSLST & I2C_S_STAIF)
  71.     {
  72.         I2CSLST &= ~I2C_S_STAIF;//清零STAIF标志位
  73.                         
  74.     }//从机收到了1字节数据
  75.     else if (I2CSLST & I2C_S_RXIF)
  76.     {
  77.         I2CSLST &= ~I2C_S_RXIF;//清零RXIF标志位
  78.                         
  79.                 //接收设备地址
  80.         if (I2C_S.DevAddrFlag == FALSE)//如果设备标志位为FALSE,表示这是收到的第1字节                     
  81.         {        
  82.                         I2C_S.DevAddr = I2CRXD;//接收设备地址
  83.                         
  84.                         //下面代码多余了,MA=0时设备地址只有和I2CSLADR[7:1]相同才会处理数据,留着也无妨
  85.                         //第1字节数据是设备地址数据
  86.                         if((I2C_S.DevAddr & 0xFE) == User_I2C_ADDR)
  87.                         {
  88.                                 I2C_S.DevAddrFlag = TRUE;//处理RECV事件(RECV DEVICE ADDR)        
  89.                                 if (I2C_S.DevAddr & WRMask) {
  90.                                         I2C_S.ReadWriteFlag = TRUE;// 读操作
  91.                                 } else {
  92.                                         I2C_S.ReadWriteFlag = FALSE;// 写操作
  93.                                 }        
  94.                         }                        
  95.         }//接收寄存器地址,已经收到过设备地址,且I2C_S.RegAddrFlag为 FALSE,则表示此次数据是寄存器地址
  96.         else if ((I2C_S.DevAddrFlag == TRUE) && (I2C_S.RegAddrFlag == FALSE))                          
  97.         {
  98.             I2C_S.RegAddrFlag = TRUE;//处理RECV事件(RECV REG ADDR)        
  99.                         I2C_S.RegAddr = I2CRXD;//接收寄存器地址
  100.         }//读寄存器
  101.                 else if(I2C_S.ReadWriteFlag == TRUE)
  102.                 {
  103.                         //当前只读四个通道的值
  104.                         if (I2C_S.RegAddr == ChA_ID ||
  105.                                 I2C_S.RegAddr == ChB_ID ||
  106.                                 I2C_S.RegAddr == ChC_ID ||
  107.                                 I2C_S.RegAddr == ChD_ID)
  108.                         {
  109.                                 ChxDetec.BitValue = ChxDetec.GetBitValue(I2C_S.RegAddr);
  110.                                 I2CTXD = (uint8_t)(ChxDetec.BitValue >> 8);//上传低位的ADC值
  111.                         }
  112.                         else if(I2C_S.RegAddr == ADDR_IAP_STC)
  113.                         {
  114.                         }
  115.                 }//写寄存器
  116.                 else if(I2C_S.ReadWriteFlag == FALSE)
  117.                 {
  118.                         if(I2C_S.RegAddr == ADDR_IAP_STC)
  119.                         {
  120.                                 //buffer[i++] = I2CRXD;
  121.                         }
  122.                 }               
  123.                                 
  124.     }//从机发送完了1字节数据
  125.     else if (I2CSLST & I2C_S_TXIF)                                                                                
  126.     {
  127.         I2CSLST &= ~I2C_S_TXIF;//清零TXIF标志位
  128.                
  129.                 if(I2CSLST & I2C_S_ACKI)//如果ACKI=1,说明主机NACK了
  130.                 {
  131.                         //主机NACK停止发送数据
  132.                
  133.                 }//接收到ACK
  134.                 else
  135.                 {
  136.                         if (I2C_S.RegAddr == ChA_ID ||
  137.                                 I2C_S.RegAddr == ChB_ID ||
  138.                                 I2C_S.RegAddr == ChC_ID ||
  139.                                 I2C_S.RegAddr == ChD_ID)
  140.                         {
  141.                                 ChxDetec.BitValue = ChxDetec.GetBitValue(I2C_S.RegAddr);
  142.                                 I2CTXD = (uint8_t)(ChxDetec.BitValue & 0x00FF);//上传低位的ADC值
  143.                         }
  144.                         else if(I2C_S.RegAddr == ADDR_IAP_STC)
  145.                         {
  146.                                 //处理IAP升级的逻辑
  147.                         }
  148.                         
  149.                 }
  150.     }//从机收到STOP信号
  151.     else if (I2CSLST & I2C_S_STOIF)
  152.     {
  153.         I2CSLST &= ~I2C_S_STOIF;//清零STOIF标志位  
  154.                         
  155.         I2C_S.DevAddrFlag = FALSE;//将设备地址标志位恢复默认值
  156.         I2C_S.RegAddrFlag = FALSE;//将寄存器地址标志位恢复默认值
  157.                 I2C_S.ReadWriteFlag = FALSE;               
  158.                 I2C_S.DevAddr = 0;
  159.                 I2C_S.RegAddr = 0;
  160.     }
  161.         _pop_(P_SW2);
  162. }
  163. /********************************************************
  164.   End Of File
  165. ********************************************************/
复制代码
IO初始化和中断配置
  1. static void GPIO_Init(void)
  2. {
  3.         //M1  M0
  4.         //0   0             准双向口
  5.         //0   1             推挽输出
  6.         //1   0             高阻输入
  7.         //1   1             开漏
  8.         
  9.         //使用 P10 作为 PWM-1K 的输出引脚
  10.         //设置P10为准双向口
  11.         //P14 P15为I2C接口,配置开漏输出
  12.         P1M1 = 0x30;
  13.         P1M0 = 0x30;
  14.         
  15.         
  16.         //P30 P31作为UART 设置为准双向口
  17.         //P32 P33 P34 P35为ADC采样端口,设置为高阻输入
  18.         P3M1 = 0x3C; //0011 1100
  19.         P3M0 = 0x00; //0000 0000
  20. }
  21. /*
  22.         * @name   INTR_Init
  23.         * @brief  中断初始化
  24.         * @param  None
  25.         * @retval None      
  26. */
  27. static void INTR_Init(void)
  28. {        
  29.         /* 定时器1用作串口波特率发生器
  30.            定时器1中断设置 */
  31.         ET1 = 0;                    //禁止定时器1中断
  32.         TR1 = 1;                    //启动定时器1
  33.         ES = 1;             //串行口开中断
  34.         
  35.         //定时器0中断设置
  36.         ET0 = 1;                    //开启定时器0中断
  37.         //I2C从机模式的各种中断使能
  38.         I2CSLCR = 0x78;
  39.         
  40.         //开中断
  41.         EA = 1;             //打开总中断
  42. }
复制代码
我的STC8H1K17程序结构,在进入while(1)之前,会先调用GPIO_Init()和INTR_Init()配置IO和中断

我尝试过多种调试,但没能找到问题,可能是只缘身在此山中吧。
花有重开日,人无再少年
回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 2025-3-25 14:18:00 | 显示全部楼层
针对您描述的STC8H1K17的I2C无法对主机做出应答的问题,以下是一些可能的原因及解决方案,供您参考:

1. 设备地址设置问题
您提到将STC8H1K17的地址设置为0x30,但请注意,I2C设备地址通常为7位,且需要在数据传输时左移一位,并在最低位添加读写位(0表示写,1表示读)。因此,如果您设置的是7位地址0x30,实际发送的地址应为0x60(写操作)或0x61(读操作)。
请确认您在主机发送地址时是否正确处理了地址位。

2. I2C时序问题
I2C通信对时序要求非常严格。如果时序不符合规范,可能导致从机无法正确响应。建议您检查以下时序参数:
起始条件:SCL为高电平时,SDA由高电平跳变到低电平。
停止条件:SCL为高电平时,SDA由低电平跳变到高电平。
ACK/NACK:在每个字节传输后,接收方应在第9个时钟周期内拉低SDA以表示ACK。
您可以使用逻辑分析仪或示波器检查这些时序是否符合I2C协议的要求。

3. I2C引脚配置
确保STC8H1K17的I2C引脚(SDA和SCL)已正确配置为开漏输出模式,并已启用内部上拉电阻或外部上拉电阻(通常为4.7kΩ)。
检查主机和从机的I2C引脚是否连接正确,且没有短路或断路的情况。

4. MA(多主机)模式设置
您提到将MA设置为0和1进行调试,但无论设置为哪种模式都无法应答。建议您检查以下几点:
如果MA设置为0,表示STC8H1K17作为从机工作,应确保主机发送的地址与从机地址匹配。
如果MA设置为1,表示STC8H1K17作为主机工作,此时它不会对主机的地址请求做出应答。
建议在调试阶段将MA设置为0,并确保主机发送的地址与从机地址一致。

5. 电源和地连接
确保主机和从机的电源和地连接良好,且电压稳定。电源噪声或地线问题可能导致I2C通信失败。

6. 代码检查
请检查主机模拟I2C的代码,确保起始条件、停止条件、ACK/NACK处理等逻辑正确实现。以下是示例代码片段:
   
  1. c
  2.      void I2CStart(void) {
  3.          SDAHIGH;
  4.          SCLHIGH;
  5.          delayus(5);
  6.          SDALOW;
  7.          delayus(5);
  8.          SCLLOW;
  9.      }
  10.      void I2CStop(void) {
  11.          SDALOW;
  12.          SCLHIGH;
  13.          delayus(5);
  14.          SDAHIGH;
  15.          delayus(5);
  16.      }
  17.      uint8t I2CReadACK(void) {
  18.          SCLHIGH;
  19.          delayus(5);
  20.          uint8t ack = SDAREAD;
  21.          SCLLOW;
  22.          return ack;
  23.      }
复制代码

7. 逻辑分析仪数据
您提到使用逻辑分析仪抓取了信号,但未提供具体波形。建议您分析波形,确认以下几点:
起始条件是否正确。
主机发送的地址是否正确(包括读写位)。
从机是否在ACK周期内拉低了SDA。

通过以上步骤逐一排查,您应该能够找到STC8H1K17无法应答的原因并解决问题。如果问题仍然存在,建议进一步检查硬件连接或咨询STC的技术支持团队。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-25 14:50:12 | 显示全部楼层
从机面对主机的读写,我需要自己手动设置ACK和NACK吗?
花有重开日,人无再少年
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:15
  • 最近打卡:2025-04-30 08:42:14

10

主题

126

回帖

1463

积分

版主

积分
1463
发表于 2025-3-25 16:11:42 | 显示全部楼层
【新提醒】部分较难问题需要帮忙分析的,可跟贴放上原帖链接通知我 | 新问题另外开贴 - 第12页 - C语言,汇编语言,Proteus MCU软件仿真 国芯技术交流网站 - AI32位8051交流社区  https://www.stcaimcu.com/forum.p ... ;extra=&page=12  关注下这个贴114楼
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-25 16:25:52 | 显示全部楼层
补充:
我另外还测试了官方例程,和我写的代码一样的情况
主机和从机的SDA SCL均配置为开漏输出,SDA SCL通过5.1K电阻上拉到3.3V
花有重开日,人无再少年
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-25 16:39:48 | 显示全部楼层
补充,已排除焊接不良、芯片损坏的情况
花有重开日,人无再少年
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-01 07:10:25
已绑定手机

76

主题

4833

回帖

8343

积分

超级版主

DebugLab

积分
8343
发表于 2025-3-25 17:32:29 | 显示全部楼层
使用官方I2C从机例程仍然不正常
建议先排查一下主机的问题
可以使用我写的这个程序下载到一箭双雕上扫描一下所有从机,看能不能扫描到:
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=9938

DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-25 17:57:41 | 显示全部楼层
Debu*** 发表于 2025-3-25 17:32
使用官方I2C从机例程仍然不正常
建议先排查一下主机的问题
可以使用我写的这个程序下载到一箭双雕上扫描一 ...

我没有您提到的“一箭双雕”,我主机的代码和逻辑分析仪抓取的信号都在帖子里
花有重开日,人无再少年
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-01 07:10:25
已绑定手机

76

主题

4833

回帖

8343

积分

超级版主

DebugLab

积分
8343
发表于 2025-3-27 10:17:22 | 显示全部楼层
该从机拉低的时候无法拉低,怀疑主机是推挽输出了
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:43
  • 最近打卡:2025-05-01 07:14:14
已绑定手机

12

主题

29

回帖

316

积分

中级会员

积分
316
发表于 2025-3-27 11:44:27 | 显示全部楼层
Debu*** 发表于 2025-3-27 10:17
该从机拉低的时候无法拉低,怀疑主机是推挽输出了

可以看我的配置,主机配置为开漏输出
花有重开日,人无再少年
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 06:32 , Processed in 0.219255 second(s), 104 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表