用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-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: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]