ST意法半导体
直播中

吴湛

11年用户 968经验值
擅长:电源/新能源
私信 关注
[问答]

使用stm8作为从机与esp32进行i2c通讯,主机扫描的i2c地址与stm8从机设置的i2c地址不一样,如何解决?

这个是stm8从机代码
===
#include // #include  // 假设你使用了STM8标准库// #include "i2c_slave.h"#include "Wire.h"#define I2C_SLAVE_ADDR 0x30#define I2C_DATA_SIZE 8#if ((I2C_DATA_SIZE > 0) && ((I2C_DATA_SIZE & (I2C_DATA_SIZE - 1)) != 0))#error I2C_DATA_SIZE isnt a power of 2.#endif#define uint8_bits_def(x)           union                             {                                   unsigned char x;                  struct                            {                                   unsigned char x##_Bit0 : 1,           x##_Bit1 : 1,                     x##_Bit2 : 1,                     x##_Bit3 : 1,                     x##_Bit4 : 1,                     x##_Bit5 : 1,                     x##_Bit6 : 1,                     x##_Bit7 : 1;               };                              }uint8_bits_def(tagI2C);uint8_t i2c_addr = 0;uint8_t i2c_data[I2C_DATA_SIZE] = {0x00};int tagI2C_Bit0 = 0;// // I2C中断服务处理函数声明// void I2C_ISR(void) __interrupt(19); // I2C中断向量号void Serial_print(const char *str){  while (*str)  {    Serial_write(*str++); // 逐个字符发送  }}void I2C_Slave_IRQHandler(void){  volatile I2C_Event_TypeDef Event = I2C_GetLastEvent();  Serial_print("STM8 I2C_Slave_IRQHandler.");  /* Slave address matched with the address sent by master */  /* EV1: ADDR = 1, 顺序读SR1,SR3寄存器清除此标志位 */  if (Event == (I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED))  {    tagI2C_Bit0 = 1;  }  /* Slave received the data byte from master */  /* EV2: RxNE = 1, 读DR寄存器清除此位 */  else if (Event == (I2C_EVENT_SLAVE_BYTE_RECEIVED))  {    uint8_t ch = I2C_ReceiveData();    if (tagI2C_Bit0)    {      tagI2C_Bit0 = 0;      i2c_addr = ch;    }    else    {      i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)] = ch;    }  }  /* Slave received STOP byte from master */  /* EV4: STOPF = 1,读SR1寄存器后再写CR2清除 */  else if (Event == (I2C_EVENT_SLAVE_STOP_DETECTED))  {    I2C_GetFlagStatus(I2C_FLAG_STOPDETECTION);    I2C_GenerateSTOP(DISABLE);  }  /* SLAVE TRANSMITTER */  /* Data transmited from slave to master */  /* EV3: TxE = 1, 写DR寄存器清除DR */  else if ((Event == (I2C_EVENT_SLAVE_BYTE_TRANSMITTED)) ||           (Event == (I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED)))  {    uint8_t ch = i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)];    I2C_SendData(ch);  }  /* Acknowledge failure */  /* EV3-2: AF = 1, AF is cleared by writing '0' in AF bit of SR2 register */  else if (Event == (I2C_EVENT_SLAVE_ACK_FAILURE))  {    I2C_ClearFlag(I2C_FLAG_ACKNOWLEDGEFAILURE);  }}// INTERRUPT_HANDLER(I2C_IRQHandler, 19)// {//   I2C_Slave_IRQHandler();// }void I2C_Slave_Init(void){  // open I2C clk  CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);  I2C_DeInit();  I2C_Init(50000, I2C_SLAVE_ADDR, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, (CLK_GetClockFreq() / 1000000));  /* Enable Error Interrupt*/  I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);  /* enable IIC*/  I2C_Cmd(ENABLE);  // enableInterrupts();}void setup(){  // 初始化串口通信,波特率为9600  Serial_begin(9600);  // 给串口输出一条消息,表示系统已经启动  Serial_print("STM8 initialized and ready.");  I2C_Slave_Init();  // pid_i2c_init();}void loop(){}这个是esp32主机代码
===
#include #include "Wire.h"uint32_t I2C2_SPEED = 50000;void setup(){  Serial.begin(115200);  Wire.begin(21, 22, I2C2_SPEED);}void loop(){  byte error, address;  int nDevices = 0;  delay(3000);  Serial.println("Scanning for I2C devices ...");  for (address = 0x01; address < 0x7f; address++)  {    Wire.beginTransmission(address);    // Wire.write(0x11);    error = Wire.endTransmission();    if (error == 0)    {      Serial.printf("I2C device found at address 0x%02Xn", address);      nDevices++;    }    else if (error != 2)    {      Serial.printf("Error %d at address 0x%02Xn", error, address);    }  }  if (nDevices == 0)  {    Serial.println("No I2C devices found");  }}esp32 debug:Scanning for I2C devices ...I2C device found at address 0x18Scanning for I2C devices ...I2C device found at address 0x18Scanning for I2C devices ...I2C device found at address 0x18当esp32扫描到这个i2c地址后stm8会重启,当前不知道是什么原因导致的

回帖(2)

李之涵

2025-3-12 16:07:22
通常可以调试看看地址寄存器的内容是否是设置的地址,同时看看响应时的寄存器标志位 ADDR 是否置位。


另外STM8速度通常只有16Mhz,响应中断要尽可能快,所以最好优化中断执行时间,可参考一下例程。
举报

h1654155275.5697

2025-3-13 18:14:35

在使用STM8作为从机与ESP32进行I2C通信时,如果主机扫描的I2C地址与STM8从机设置的I2C地址不一致,可能是由于以下几个原因导致的。以下是可能的解决方案和代码修正建议:


1. 检查I2C地址设置



  • 确保STM8从机设置的I2C地址与ESP32主机扫描的地址一致。I2C地址通常是7位或8位格式,7位地址的范围是0x08到0x77。

  • 如果使用7位地址,确保在STM8代码中正确设置。例如,如果STM8从机地址设置为0x30,ESP32主机应该扫描0x30。


2. I2C地址格式



  • I2C地址可以是7位或8位格式。通常,7位地址是最常见的。如果你使用的是7位地址,确保在代码中正确设置。

  • 在STM8代码中,I2C_SLAVE_ADDR应该是7位地址。例如,#define I2C_SLAVE_ADDR 0x30


3. 硬件连接



  • 确保STM8和ESP32之间的I2C线路连接正确,包括SDA和SCL线。

  • 检查I2C总线上是否有上拉电阻。通常,SDA和SCL线需要上拉电阻(4.7kΩ)以确保信号稳定。


4. STM8 I2C从机初始化



  • 确保STM8的I2C从机初始化代码正确。以下是一个简单的STM8 I2C从机初始化代码示例:


#include 

#define I2C_SLAVE_ADDR 0x30

void I2C_Slave_Init(void) {
    // Enable I2C peripheral clock
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);

    // Configure I2C pins
    GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_SLOW); // SDA
    GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_SLOW); // SCL

    // Initialize I2C
    I2C_DeInit();
    I2C_Init(100000, I2C_SLAVE_ADDR, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);
    I2C_Cmd(ENABLE);

    // Enable I2C interrupts
    I2C_ITConfig(I2C_IT_EVT | I2C_IT_BUF, ENABLE);
}

5. ESP32主机扫描I2C地址



  • 在ESP32主机端,使用以下代码扫描I2C总线,确保能够正确识别STM8从机地址:


#include 

void setup() {
    Wire.begin();
    Serial.begin(115200);
    Serial.println("nI2C Scanner");
}

void loop() {
    byte error, address;
    int nDevices;

    Serial.println("Scanning...");

    nDevices = 0;
    for(address = 1; address < 127; address++ ) {
        Wire.beginTransmission(address);
        error = Wire.endTransmission();

        if (error == 0) {
            Serial.print("I2C device found at address 0x");
            if (address < 16)
                Serial.print("0");
            Serial.print(address, HEX);
            Serial.println("  !");

            nDevices++;
        }
        else if (error == 4) {
            Serial.print("Unknown error at address 0x");
            if (address < 16)
                Serial.print("0");
            Serial.println(address, HEX);
        }   
    }
    if (nDevices == 0)
        Serial.println("No I2C devices foundn");
    else
        Serial.println("donen");

    delay(5000); // Wait 5 seconds for next scan
}

6. 调试



  • 如果仍然无法识别I2C地址,可以使用逻辑分析仪或示波器检查I2C总线上的信号,确保数据传输正常。

  • 检查STM8的I2C中断处理程序,确保从机能够正确响应主机的请求。


7. STM8 I2C中断处理



  • 确保STM8的I2C中断处理程序正确实现。以下是一个简单的I2C中断处理示例:


INTERRUPT_HANDLER(I2C_IRQHandler, 8) {
    if (I2C_GetITStatus(I2C_IT_EVT)) {
        // Handle I2C event
    }

    if (I2C_GetITStatus(I2C_IT_BUF)) {
        // Handle I2C buffer
    }

    I2C_ClearITPendingBit(I2C_IT_EVT | I2C_IT_BUF);
}

总结


通过检查I2C地址设置、硬件连接、初始化代码和中断处理程序,应该能够解决STM8从机与ESP32主机I2C通信中地址不一致的问题。如果问题仍然存在,建议使用调试工具进一步分析I2C总线上的信号。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分