2023-12-21 22:09:14 [显示全部楼层]
1377浏览
查看: 1377|回复: 2

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

[复制链接]
本帖最后由 hanppiness 于 2023-12-21 22:31 编辑
  1. void oledShow(char pStr[])
  2. {//输出str
  3.   int len = strlen(pStr);
  4.   int start = 0;
  5.   int end = 0;
  6.   int8_t row = 2;
  7.   String str(pStr, len);
  8.   while (start < len)
  9.   {
  10.     end = str.indexOf((char)0x0A, start);
  11.     if (end < 0) {end = len - 1;}
  12.     OLED.ShowString(0, row, str.substring(start, end));//输出到OLED12864屏显示,注释掉这句就不重启了
  13.     start = end + 1;//跳过0x0A换行符
  14.     row ++;
  15.   }
  16. }
复制代码
  1. void OLED12864_I2C::ShowString(int8_t x, int8_t y, String str)
  2. {
  3.   SetCursor(x, y);
  4.   int n = str.length();
  5.   for (int i = 0; i < n; i ++)
  6.   {
  7.     int8_t c = (int8_t)str.charAt(i) - 0x20;
  8.     if (c >= 0 && c < 0x60)
  9.     {
  10.       ShowChar((char)c);
  11.     }
  12.   }
  13. }
复制代码


pStr的长度大概为70,是手机蓝牙发送过来的,运行一会就重启,用调试口监视报:
Guru Meditation Error: Core  0 panic'ed (Interrupt wdt timeout on CPU0). Core  0 register dump:PC      : 0x40084e54  PS      : 0x00050b35  A0      : 0x400816f2  A1      : 0x3ffbefbc  A2      : 0x00000000  A3      : 0x3ffd0c20  A4      : 0x00001000  A5      : 0x3ffbef7c  A6      : 0x3ffba464  A7      : 0x00000000  A8      : 0x3ffbe070  A9      : 0x00000000  A10     : 0x3ffbe070  A11     : 0x00000000  A12     : 0x00000001  A13     : 0x3ffbef5c  A14     : 0x3ffbe070  A15     : 0x3ffbef84  SAR     : 0x0000001d  EXCCAUSE: 0x00000005  EXCVADDR: 0x00000000  LBEG    : 0x40090c68  LEND    : 0x40090c7e  LCOUNT  : 0xffffffff  Core  0 was running in ISR context:EPC1    : 0x400e5787  EPC2    : 0x00000000  EPC3    : 0x40081678  EPC4    : 0x40081678Backtrace: 0x40084e51:0x3ffbefbc |<-CORRUPTEDCore  1 register dump:PC      : 0x4019897a  PS      : 0x00060a35  A0      : 0x800e427c  A1      : 0x3ffbd8e0  A2      : 0x00000000  A3      : 0x80000001  A4      : 0x80096870  A5      : 0x3ffbd800  A6      : 0x00000003  A7      : 0x00060023  A8      : 0x00000014  A9      : 0x00000004  A10     : 0x3ffbd9b8  A11     : 0x80000001  A12     : 0x80096870  A13     : 0x3ffca2a0  A14     : 0x00000003  A15     : 0x00060023  SAR     : 0x00000000  EXCCAUSE: 0x00000005  EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  Backtrace: 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个字符,就没问题,如:
  1. void showIRIG_B()
  2. {//显示IRIG_B码
  3.   st.BCD_SetTime();//用IRIG_B的BCD码设置时间
  4.   st.addASecond();//秒数增加1秒,相应的分、时、日、月、年需变化的变化
  5.   if (bAuto)
  6.   {
  7.     digitalWrite(MCU, LOW);
  8.     st.B_StopOut();
  9.   }
  10.   else
  11.   {
  12.     st.B_StartOut();
  13.   }
  14.   //08 yyyy-mm-dd hh:mm:ss cf sbs 09
  15.   String str = "";
  16.   if (SerialBT.hasClient())
  17.   {
  18.     SerialBT.write(BEGIN);//写入开始符
  19.   }
  20.   str += st.getYear(); str += '-';//写入年
  21.   TowDigits(str, st.getMonth()); str += '-';//写入月
  22.   TowDigits(str, st.getDay()); str += ' ';//写入日
  23.   TowDigits(str, st.getHour()); str += ':';//写入时
  24.   TowDigits(str, st.getMinute()); str += ':';//写入分
  25.   TowDigits(str, st.getSecond());//写入秒
  26.   if (nMode == MODE_B1)
  27.   {
  28.     if (irig_b_status == IRIG_B_PE)
  29.       str += '+';//显示电B码正极性标志
  30.     else
  31.       str += '-';//显示电B码反极性标志   
  32.   }
  33.   else
  34.     str += 'B';//显示光B码标志
  35.   OLED.ShowString(0, 2, str);
  36.   if (SerialBT.hasClient())
  37.   {
  38.     SerialBT.print(str);
  39.     SerialBT.write(0x0A);
  40.   }  
  41.   //LSP=1,LS=1,SP=1,ST=1
  42.   str = "";
  43.   CTRLFNWORD cfw = st.getCtrlFnWord();//得到控制功能字
  44.   str += "LSP="; str += cfw.LSP;//写入闰秒预告
  45.   str += ",LS="; str += cfw.LS;//写入闰秒符号位
  46.   str += ",DP="; str += cfw.DSP;//写入夏令时
  47.   str += ",DT="; str += cfw.DST;//写入夏令时标志
  48.   OLED.ShowString(0, 3, str);
  49.   if (SerialBT.hasClient())
  50.   {
  51.     SerialBT.print(str);
  52.     SerialBT.write(0x0A);
  53.   }
  54.   //TCH=0,TOFF=0,TOFF5=0
  55.   str = "";
  56.   str += "TCH="; str += cfw.TCH;//写入时间偏移符号位
  57.   str += ",TOFF="; str += String(cfw.TOFF, HEX);//写入时间偏移h
  58.   str += ",TOFF5="; str += cfw.TOFF5;//写入时间偏移0.5h
  59.   OLED.ShowString(0, 4, str);  
  60.   if (SerialBT.hasClient())
  61.   {
  62.     SerialBT.print(str);
  63.     SerialBT.write(0x0A);
  64.   }
  65.   //TQ=0,ODD=0,SBS=86400
  66.   
  67.   str = "";
  68.   str += "TQ="; str += String(cfw.TQUA, HEX);//写入时间质量
  69.   str += ",ODD=";
  70.   str += cfw.ODD;//写入奇校验位
  71.   str += ",SBS=";//写入一天的秒数
  72.   uint32_t SBS = st.getSBS();//得到一天中的秒数(straight binary second)
  73.   uint8_t a = (SBS / 10000) % 10; str += a;//写入万位
  74.   uint8_t b = (SBS / 1000) % 10; str += b;//写入千位
  75.         uint8_t c = (SBS / 100) % 10; str += c;//写入百位
  76.         uint8_t d = (SBS / 10) % 10; str += d;//写入十位
  77.         uint8_t e = SBS % 10; str += e;//写入个位
  78.   OLED.ShowString(0, 5, str);
  79.   if (SerialBT.hasClient())
  80.   {
  81.     SerialBT.print(str);
  82.     SerialBT.write(0x0A);
  83.     bool b = false;   
  84.     if (!st.oddCheck())
  85.     {
  86.       SerialBT.print("奇校验错误");
  87.       b = true;
  88.     }
  89.     if (!st.sbsCheck())
  90.     {
  91.       if (b) SerialBT.print(",");
  92.       SerialBT.print("一天的总秒数错误");
  93.       SerialBT.write(0x0A);
  94.     }
  95.     SerialBT.write(END);
  96.   }  
  97. }
复制代码

将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,最后优化了代码,一行一行处理,发现有不同的字符再去显示,这样就好了:
  1. void OLED12864_I2C::ShowString(int8_t row, String str)
  2. {//只更新变化的字符,strPrev[8]存有上一次的字符
  3.   if (strPrev[row] == "" && str != "")
  4.   {
  5.     ShowStr(row, str);
  6.     strPrev[row] = str;
  7.   }
  8.   else if (strPrev[row] != str)
  9.   {
  10.     byte nLenPrev = strPrev[row].length();
  11.     byte nLen = str.length();
  12.     byte n = min(nLenPrev, nLen);
  13.     for (byte col = 0; col < n; col ++)
  14.     {
  15.       if (strPrev[row][col] != str[col])
  16.       {
  17.         ShowChar(col * 6, row, str[col]);
  18.         strPrev[row][col] = str[col];
  19.       }
  20.     }
  21.     if (nLenPrev < nLen)
  22.     {
  23.       for (byte col = nLenPrev; col < nLen; col ++)
  24.       {
  25.         ShowChar(col * 6, row, str[col]);
  26.         strPrev[row][col] = str[col];         
  27.       }
  28.     }
  29.     else if (nLen < nLenPrev)
  30.     {
  31.       for (byte col = nLen; col < nLenPrev; col ++)
  32.       {
  33.         ShowChar(col * 6, row, 0x20);
  34.         strPrev[row][col] = 0;
  35.       }
  36.     }
  37.   }
  38. }
复制代码
回复

使用道具 举报

hanppiness  学徒
 楼主|

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

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

不但对只显示变化数据的代码进行了优化,还对I2C发多个命令和数据的代码做了优化,数据变化量大时,20ms左右,平时也就是5ms以下。
  1. void OLED12864_I2C::WriteCmds(byte *cmds, byte size)
  2. {
  3. i2c->beginTransmission(_adr);
  4.   i2c->write(0x00);
  5.   i2c->write(cmds, size);
  6.   i2c->endTransmission();
  7. }
  8. void OLED12864_I2C::WriteDatas(byte *dats, size_t size)
  9. {
  10.   i2c->beginTransmission(_adr);
  11.   i2c->write(0x40);
  12. i2c->write(dats, size);
  13.   i2c->endTransmission();
  14. }
复制代码


回复

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail