hanppiness 发表于 2023-12-21 22:09:14

用ESP32驱动I2C的OLED12864,ESP32的I2C,一次发送的数据不能过多

本帖最后由 hanppiness 于 2023-12-21 22:31 编辑

void oledShow(char pStr[])
{//输出str
int len = strlen(pStr);
int start = 0;
int end = 0;
int8_t row = 2;
String str(pStr, len);
while (start < len)
{
    end = str.indexOf((char)0x0A, start);
    if (end < 0) {end = len - 1;}
    OLED.ShowString(0, row, str.substring(start, end));//输出到OLED12864屏显示,注释掉这句就不重启了
    start = end + 1;//跳过0x0A换行符
    row ++;
}
}void OLED12864_I2C::ShowString(int8_t x, int8_t y, String str)
{
SetCursor(x, y);
int n = str.length();
for (int i = 0; i < n; i ++)
{
    int8_t c = (int8_t)str.charAt(i) - 0x20;
    if (c >= 0 && c < 0x60)
    {
      ShowChar((char)c);
    }
}
}

pStr的长度大概为70,是手机蓝牙发送过来的,运行一会就重启,用调试口监视报:
Guru Meditation Error: Core0 panic'ed (Interrupt wdt timeout on CPU0). Core0 register dump:PC      : 0x40084e54PS      : 0x00050b35A0      : 0x400816f2A1      : 0x3ffbefbcA2      : 0x00000000A3      : 0x3ffd0c20A4      : 0x00001000A5      : 0x3ffbef7cA6      : 0x3ffba464A7      : 0x00000000A8      : 0x3ffbe070A9      : 0x00000000A10   : 0x3ffbe070A11   : 0x00000000A12   : 0x00000001A13   : 0x3ffbef5cA14   : 0x3ffbe070A15   : 0x3ffbef84SAR   : 0x0000001dEXCCAUSE: 0x00000005EXCVADDR: 0x00000000LBEG    : 0x40090c68LEND    : 0x40090c7eLCOUNT: 0xffffffffCore0 was running in ISR context:EPC1    : 0x400e5787EPC2    : 0x00000000EPC3    : 0x40081678EPC4    : 0x40081678Backtrace: 0x40084e51:0x3ffbefbc |<-CORRUPTEDCore1 register dump:PC      : 0x4019897aPS      : 0x00060a35A0      : 0x800e427cA1      : 0x3ffbd8e0A2      : 0x00000000A3      : 0x80000001A4      : 0x80096870A5      : 0x3ffbd800A6      : 0x00000003A7      : 0x00060023A8      : 0x00000014A9      : 0x00000004A10   : 0x3ffbd9b8A11   : 0x80000001A12   : 0x80096870A13   : 0x3ffca2a0A14   : 0x00000003A15   : 0x00060023SAR   : 0x00000000EXCCAUSE: 0x00000005EXCVADDR: 0x00000000LBEG    : 0x00000000LEND    : 0x00000000LCOUNT: 0x00000000Backtrace: 0x40198977:0x3ffbd8e0 0x400e4279:0x3ffbd900 0x40094a60:0x3ffbd920ELF file SHA256: 94c4def03c3c0bbdFEX 1 8Rebooting...ets Jul 29 2019 12:21:46rst:0xc (SW_CPU_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)configsip: 0, SPIWP:0xeeclk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00mode:DIO, clock div:1load:0x3fff0030,len:1184load:0x40078000,len:13260load:0x40080400,len:3028entry 0x400805e4


我其它地方也用到OLED12864_I2C::ShowString()函数呀,就没报错,不过是执行一会,才输出20个字符,就没问题,如:void showIRIG_B()
{//显示IRIG_B码
st.BCD_SetTime();//用IRIG_B的BCD码设置时间
st.addASecond();//秒数增加1秒,相应的分、时、日、月、年需变化的变化
if (bAuto)
{
    digitalWrite(MCU, LOW);
    st.B_StopOut();
}
else
{
    st.B_StartOut();
}
//08 yyyy-mm-dd hh:mm:ss cf sbs 09
String str = "";
if (SerialBT.hasClient())
{
    SerialBT.write(BEGIN);//写入开始符
}
str += st.getYear(); str += '-';//写入年
TowDigits(str, st.getMonth()); str += '-';//写入月
TowDigits(str, st.getDay()); str += ' ';//写入日
TowDigits(str, st.getHour()); str += ':';//写入时
TowDigits(str, st.getMinute()); str += ':';//写入分
TowDigits(str, st.getSecond());//写入秒
if (nMode == MODE_B1)
{
    if (irig_b_status == IRIG_B_PE)
      str += '+';//显示电B码正极性标志
    else
      str += '-';//显示电B码反极性标志   
}
else
    str += 'B';//显示光B码标志
OLED.ShowString(0, 2, str);
if (SerialBT.hasClient())
{
    SerialBT.print(str);
    SerialBT.write(0x0A);
}
//LSP=1,LS=1,SP=1,ST=1
str = "";
CTRLFNWORD cfw = st.getCtrlFnWord();//得到控制功能字
str += "LSP="; str += cfw.LSP;//写入闰秒预告
str += ",LS="; str += cfw.LS;//写入闰秒符号位
str += ",DP="; str += cfw.DSP;//写入夏令时
str += ",DT="; str += cfw.DST;//写入夏令时标志

OLED.ShowString(0, 3, str);
if (SerialBT.hasClient())
{
    SerialBT.print(str);
    SerialBT.write(0x0A);
}
//TCH=0,TOFF=0,TOFF5=0
str = "";
str += "TCH="; str += cfw.TCH;//写入时间偏移符号位
str += ",TOFF="; str += String(cfw.TOFF, HEX);//写入时间偏移h
str += ",TOFF5="; str += cfw.TOFF5;//写入时间偏移0.5h
OLED.ShowString(0, 4, str);
if (SerialBT.hasClient())
{
    SerialBT.print(str);
    SerialBT.write(0x0A);
}
//TQ=0,ODD=0,SBS=86400

str = "";
str += "TQ="; str += String(cfw.TQUA, HEX);//写入时间质量
str += ",ODD=";
str += cfw.ODD;//写入奇校验位
str += ",SBS=";//写入一天的秒数
uint32_t SBS = st.getSBS();//得到一天中的秒数(straight binary second)
uint8_t a = (SBS / 10000) % 10; str += a;//写入万位
uint8_t b = (SBS / 1000) % 10; str += b;//写入千位
      uint8_t c = (SBS / 100) % 10; str += c;//写入百位
      uint8_t d = (SBS / 10) % 10; str += d;//写入十位
      uint8_t e = SBS % 10; str += e;//写入个位
OLED.ShowString(0, 5, str);
if (SerialBT.hasClient())
{
    SerialBT.print(str);
    SerialBT.write(0x0A);
    bool b = false;   
    if (!st.oddCheck())
    {
      SerialBT.print("奇校验错误");
      b = true;
    }
    if (!st.sbsCheck())
    {
      if (b) SerialBT.print(",");
      SerialBT.print("一天的总秒数错误");
      SerialBT.write(0x0A);
    }
    SerialBT.write(END);
}
}
将I2C的频率改成100K、400K、1M,都不行,SCL、SDK上拉电阻22K,难道是ESP32的I2C,一次发送的数据不能过多?


hanppiness 发表于 2023-12-23 23:23:44

本帖最后由 hanppiness 于 2023-12-29 13:48 编辑

现在好了,还是OLED显示字符多耗时太大,最大时有100多ms,最后优化了代码,一行一行处理,发现有不同的字符再去显示,这样就好了:
void OLED12864_I2C::ShowString(int8_t row, String str)
{//只更新变化的字符,strPrev存有上一次的字符
if (strPrev == "" && str != "")
{
    ShowStr(row, str);
    strPrev = str;
}
else if (strPrev != str)
{
    byte nLenPrev = strPrev.length();
    byte nLen = str.length();
    byte n = min(nLenPrev, nLen);
    for (byte col = 0; col < n; col ++)
    {
      if (strPrev != str)
      {
      ShowChar(col * 6, row, str);
      strPrev = str;
      }
    }
    if (nLenPrev < nLen)
    {
      for (byte col = nLenPrev; col < nLen; col ++)
      {
      ShowChar(col * 6, row, str);
      strPrev = str;         
      }
    }
    else if (nLen < nLenPrev)
    {
      for (byte col = nLen; col < nLenPrev; col ++)
      {
      ShowChar(col * 6, row, 0x20);
      strPrev = 0;
      }
    }
}
}

hanppiness 发表于 2023-12-25 11:44:18

本帖最后由 hanppiness 于 2023-12-25 11:50 编辑

不但对只显示变化数据的代码进行了优化,还对I2C发多个命令和数据的代码做了优化,数据变化量大时,20ms左右,平时也就是5ms以下。void OLED12864_I2C::WriteCmds(byte *cmds, byte size)
{
i2c->beginTransmission(_adr);
i2c->write(0x00);
i2c->write(cmds, size);
i2c->endTransmission();
}

void OLED12864_I2C::WriteDatas(byte *dats, size_t size)
{
i2c->beginTransmission(_adr);
i2c->write(0x40);
i2c->write(dats, size);
i2c->endTransmission();
}

页: [1]
查看完整版本: 用ESP32驱动I2C的OLED12864,ESP32的I2C,一次发送的数据不能过多