nodemcu ESP32s遇到了一个奇怪的问题。-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 647|回复: 6

[已解决] nodemcu ESP32s遇到了一个奇怪的问题。

[复制链接]
发表于 2022-5-21 16:39 | 显示全部楼层 |阅读模式
本帖最后由 llk_007 于 2022-5-23 17:06 编辑

想用nodemcu32s做个指纹锁,遇到一个奇怪的问题,卡了好几天了。

有一条长度一共18字节的报文需要处理,前11个字节是报文头,后面的7个字节是报文内容。
第一个for,向串口打印了一遍报文。
第二个for,要打印报文内容的时候,好像是崩溃了。




  1. void wifi_message_analyse(uint8_t *data, int lenght, WiFiClient *client)
  2. {

  3. wdtFeed();//喂狗
  4. int i;
  5. for(i=0;i<lenght;i++)
  6. {
  7. Serial.write(data[i]);
  8. }//这里打印出来需要处理的报文 0xF1 1F E2 2E B6 6B A8 8A 00 07 86 00 00 00 00 FF FF 02
  9. Serial.write(i); //i打印出来0x12

  10. int msg_len = check_message_head(data);
  11. if ( msg_len == 0 ) return;

  12. Serial.write(msg_len);
  13. uint8_t msg_data[msg_len];
  14. //因为0xF1 1F E2 2E B6 6B A8 8A 00 07 86这一段是报文头,后面的才是报文具体消息,所以打算读取一下后面的几位,报文头里有报文长度,解析后就是msg_len  打印0x07 长度7是正确的

  15. //后面因为单独处理报文内容出问题了,就在这里输出想看下问题出在哪,然后到这个for循环这里就出问题了,只执行了1次,然后貌似是芯片直接重启了。
  16. for(int j=0;j<msg_len;j++){
  17. Serial.write( data[DEF_MSG_HEAD_LEN+j]);
  18. Serial.write(j);
  19. }

  20. ............

  21. }
复制代码
微信图片_20220521163326.png




发表于 2022-5-21 17:32 | 显示全部楼层

简化一下,报文处理是能够工作的。接下来加入数据源后再看吧

屏幕截图 2022-05-21 172932.png
 楼主| 发表于 2022-5-21 17:40 | 显示全部楼层
kpj001 发表于 2022-5-21 17:32
简化一下,报文处理是能够工作的。接下来加入数据源后再看吧
  1. #include <WiFi.h>
  2. #include "esp_system.h"
  3. #include <EEPROM.h> //导入Flash库文件

  4. const int conn_button = 0;
  5. String ssid;
  6. String psw;


  7. uint8_t def_server_name[16] = {0x01, 'f', 'i', 'n', 'g', 'e', 'r', '-', '8', '2', '6', '6', '-', '0', '0', '1'}; //定义设备ID 第一个为server type

  8. uint8_t def_massage_psw[4] = {0x00, 0x00, 0x00, 0x00}; //报文密码

  9. #define MAX_SRV_CLIENTS 10 //定义TCP服务器最大允许4个连接数
  10. #define MAX_MASSAGE_LENGH 200 //定义socket消息最大长度

  11. #define DEF_MSG_HEAD_LEN 11 //报文头消息长度
  12. #define DEF_MASSAGE_HEAD {0xF1,0x1F,0xE2,0x2E,0xB6,0x6B,0xA8,0x8A} //报文头
  13. #define DEF_MASSAGE_COMMAND_GET_SERVER_NAME {0XFF,0XFF} //获取设备ID
  14. #define DEF_MASSAGE_REG_FINGER {0x01,0x11}




  15. #define DEF_WIFI_MSG_TYPE_GET_SERVER_NAME 1   //获取设备ID参数
  16. #define DEF_WIFI_MSG_BEGIN_REG_FINGER 2   //开始录入指纹


  17. uint8_t wifimessage[MAX_MASSAGE_LENGH];



  18. //自制看门狗
  19. hw_timer_t *timer = NULL;

  20. void IRAM_ATTR resetModule() {
  21. esp_restart();
  22. }

  23. //开启看门狗
  24. void wdtEnable(int wdtTimeout)
  25. {
  26.   timer = timerBegin(0, 80, true);                  //初始化定时器 定时器编号0,分频数 80,是否是累加模式:true
  27.   timerAttachInterrupt(timer, &resetModule, true);  //附加回调
  28.   timerAlarmWrite(timer, wdtTimeout * 1000, false); //设置定时器
  29.   timerAlarmEnable(timer);                          //开启中断
  30. }

  31. //喂狗
  32. void wdtFeed() {
  33.   timerWrite(timer, 0);
  34. }


  35. //创建server 端口号是58266
  36. WiFiServer server(58266);

  37. WiFiClient serverClients[MAX_SRV_CLIENTS];

  38. struct config_type
  39. {
  40.   char stassid[32];//定义配网得到的WIFI名长度(最大32字节)
  41.   char stapsw[64];//定义配网得到的WIFI密码长度(最大64字节)
  42. };

  43. config_type config;//声明定义内容





  44. void saveConfig()//保存函数
  45. {
  46.   EEPROM.begin(1024);//向系统申请ROM
  47.   //开始写入
  48.   uint8_t *p = (uint8_t*)(&config);
  49.   for (int i = 0; i < sizeof(config); i++)
  50.   {
  51.     EEPROM.write(i, *(p + i)); //在闪存内模拟写入
  52.   }
  53.   EEPROM.commit();//执行写入ROM
  54. }

  55. void loadConfig()//读取函数
  56. {

  57.   EEPROM.begin(1024);
  58.   uint8_t *p = (uint8_t*)(&config);
  59.   for (int i = 0; i < sizeof(config); i++)
  60.   {
  61.     *(p + i) = EEPROM.read(i);
  62.   }
  63.   EEPROM.commit();
  64.   ssid = config.stassid;
  65.   psw = config.stapsw;
  66. }

  67. void smartConfig()//配网函数
  68. {
  69.   // 等待配网
  70.   WiFi.beginSmartConfig();
  71.   while (1)
  72.   {
  73.   //  wdtFeed();//喂狗
  74.     digitalWrite(2, HIGH);
  75.     delay(200);
  76.     digitalWrite(2, LOW);  //加个LED快闪,确认配网是否成功!成功就不闪了。
  77.     delay(200);
  78.     if (WiFi.smartConfigDone())
  79.     {
  80.       strcpy(config.stassid, WiFi.SSID().c_str()); //名称复制
  81.       strcpy(config.stapsw, WiFi.psk().c_str()); //密码复制
  82.       saveConfig();//调用保存函数
  83.       WiFi.setAutoConnect(true);  // 设置自动连接
  84.       break;
  85.     }
  86.     //启动server
  87.     server.begin();
  88.     //关闭小包合并包功能,不会延时发送数据
  89.     server.setNoDelay(true);
  90.   }
  91. }




  92. //数据和校验方法
  93. uint8_t FP_protocol_get_checksum(uint8_t *data, int len)
  94. {
  95.   uint8_t sum = 0;
  96.   for (int i = 0; i < len; i++) {
  97.     sum = sum + data[i];
  98.   }
  99.   return (~sum) + 1;
  100. }


  101. int check_message_head(uint8_t *data)
  102. {
  103.   uint8_t msg_head[8] = DEF_MASSAGE_HEAD;
  104.   int i;
  105.   for (i = 0; i < 8; i++)
  106.   {
  107.     if (msg_head[i] != data[i])
  108.       return 0;
  109.   }

  110.   if (data[DEF_MSG_HEAD_LEN - 1] != FP_protocol_get_checksum(data, DEF_MSG_HEAD_LEN - 1)) return 0;
  111.   uint8_t uint_len[] = {data[9], data[10]};
  112.   uint8_t *l_p = uint_len;
  113.   unsigned short *plen = (unsigned short *)l_p;
  114.   int ilen = (int) * plen;
  115.   return ilen;
  116. }


  117. bool check_message_content(uint8_t *data, int len)
  118. {  
  119.   int i;
  120.   for(i=0;i<4;i++)
  121.   {
  122.     if (def_massage_psw[i] != data[i])
  123.       return false;
  124.   }
  125.   int lenc = len - 1;

  126.   uint8_t sum_i = FP_protocol_get_checksum(data, lenc);
  127.   return data[lenc] == sum_i;
  128. }




  129. int get_msg_command(uint8_t *command_data)
  130. {

  131.   uint8_t comd_type[2] = DEF_MASSAGE_COMMAND_GET_SERVER_NAME;
  132.   if (command_data[DEF_MSG_HEAD_LEN + 4] == comd_type[0] && command_data[DEF_MSG_HEAD_LEN + 5] == comd_type[1])
  133.     return DEF_WIFI_MSG_TYPE_GET_SERVER_NAME;
  134.   /*
  135.     uint8_t temp1[2] = DEF_MASSAGE_REG_FINGER;
  136.     memcpy (comd_type, temp1, 2);
  137.     if (command_data[DEF_MSG_HEAD_LEN + 4] == comd_type[0] && command_data[DEF_MSG_HEAD_LEN + 5] == comd_type[1])
  138.       return DEF_WIFI_MSG_BEGIN_REG_FINGER;

  139.   */
  140.   return 0;
  141. }


  142. void wifi_message_get_server_name( WiFiClient *client)
  143. {
  144.   uint8_t msg_head[8] = DEF_MASSAGE_HEAD;
  145.   uint8_t msg_cmd[2] = DEF_MASSAGE_COMMAND_GET_SERVER_NAME;

  146.   uint16_t content_len_short = sizeof(def_server_name) / sizeof(uint8_t);
  147.   content_len_short = 4 + 2 + content_len_short + 1;
  148.   uint8_t content_len[2];
  149.   content_len[0] = (uint8_t)(content_len_short >> 8);
  150.   content_len[1] = (uint8_t)(content_len_short);
  151.   for (int i = 0; i < 8; i++)
  152.     wifimessage[i] = msg_head[i];
  153.   for (int i = 0; i < 2; i++)
  154.     wifimessage[i + 8] = content_len[i];
  155.   wifimessage[10] = FP_protocol_get_checksum(wifimessage, 10);

  156.   for (int i = 0; i < 4; i++)
  157.     wifimessage[DEF_MSG_HEAD_LEN + i] = def_massage_psw[i];
  158.   for (int i = 0; i < 2; i++)
  159.     wifimessage[i + 15] = msg_cmd[i];
  160.   for (int i = 0; i < content_len_short; i++)
  161.     wifimessage[i + 17] = def_server_name[i];

  162.   wifimessage[DEF_MSG_HEAD_LEN + content_len_short - 1] = FP_protocol_get_checksum(&wifimessage[DEF_MSG_HEAD_LEN], content_len_short - 1);

  163.   if (*client && client->connected())
  164.     client->write(wifimessage, DEF_MSG_HEAD_LEN + content_len_short);

  165. }




  166. void wifi_message_analyse(uint8_t *data, int lenght, WiFiClient *client)
  167. {

  168. // wdtFeed();//喂狗
  169.   int i;
  170.   for(i=0;i<lenght;i++)
  171.   {
  172.      Serial.write(data[i]);
  173.   }
  174.   
  175.   int msg_len1 = check_message_head(data);
  176.   if ( msg_len1 == 0 ) return;

  177.   Serial.write(msg_len1);
  178.   uint8_t msg_data[msg_len1];
  179.   
  180.   for(int j=0;j<msg_len1;j++){
  181.     Serial.write( data[11+j]);
  182.     Serial.write(j);
  183.   }
  184.   
  185.   if (!check_message_content(msg_data, msg_len1)) return;
  186.   Serial.write(0x99);
  187.   int wifi_msg_type = get_msg_command(data);
  188.   if (wifi_msg_type == DEF_WIFI_MSG_TYPE_GET_SERVER_NAME)
  189.   {

  190.     wifi_message_get_server_name(client);
  191.     return;
  192.   }

  193.   /*
  194.     if (wifi_msg_type == DEF_WIFI_MSG_BEGIN_REG_FINGER)
  195.     {
  196.       wifi_message_reg_finger(data, lenght, client);
  197.       return;
  198.     }
  199.   */

  200. }

  201. void setup() {

  202.    digitalWrite(2, HIGH);
  203.    delay(1000);
  204.    digitalWrite(2, LOW);  //重启或者开机亮蓝灯1秒

  205.   Serial.begin(57600);
  206.   WiFi.mode(WIFI_STA);
  207.   delay(500);
  208. // wdtEnable(10000);//设定看门狗
  209.   loadConfig();//读取ROM是否包含密码
  210.   //判断ROM是否有密码
  211.   if (ssid != 0 && psw != 0) {
  212.     WiFi.begin(ssid.c_str(), psw.c_str()); //如果有密码则自动连接
  213.     while (WiFi.status() != WL_CONNECTED) {
  214.       if (digitalRead(0) == LOW) {
  215.         smartConfig();//如果配网按钮被按下则停止当前连接开始配网
  216.         break;//跳出所有循环进入主程序
  217.       }
  218.       digitalWrite(2, HIGH);
  219.       delay(1000);
  220.       digitalWrite(2, LOW);  //加个LED慢闪,确认联网是否成功!成功就不闪了。
  221.       delay(1000);
  222.     }
  223.     //启动server
  224.     server.begin();
  225.     //关闭小包合并包功能,不会延时发送数据
  226.     server.setNoDelay(true);
  227.   } else {
  228.     smartConfig();//如果ROM没有密码则自动进入配网模式
  229.   }

  230. }




  231. void loop() {
  232.   // put your main code here, to run repeatedly:


  233. //  wdtFeed();//先喂狗释放资源
  234.   if (digitalRead(conn_button) == 0) delay(2000);
  235.   if (digitalRead(conn_button) == 0) Serial.println("smartconfig will begin.");
  236.   if (digitalRead(conn_button) == 0) smartConfig(); //如果配网按钮被按下则停止所有任务开始重新配网
  237.   //检测是否有新的client请求进来
  238. //  wdtFeed();//再喂狗释放资源
  239.   uint8_t i;
  240.   if (server.hasClient()) {
  241.     for (i = 0; i < MAX_SRV_CLIENTS; i++) {
  242.       //释放旧无效或者断开的client
  243.       if (!serverClients[i] || !serverClients[i].connected()) {
  244.         if (serverClients[i]) {
  245.           serverClients[i].stop();
  246.         }
  247.         //分配最新的client
  248.         serverClients[i] = server.available();
  249.         break;
  250.       }
  251.     }
  252.     //当达到最大连接数 无法释放无效的client,需要拒绝连接
  253.     if (i == MAX_SRV_CLIENTS) {
  254.       WiFiClient serverClient = server.available();
  255.       serverClient.stop();
  256.     }
  257.   }



  258.   //WIFI通信
  259.   for (i = 0; i < MAX_SRV_CLIENTS; i++) {
  260.     if (serverClients[i] && serverClients[i].connected()) {
  261.       if (serverClients[i].available()) {
  262.         int j = 0;
  263.         uint8_t client_msg[MAX_MASSAGE_LENGH];
  264.         while (serverClients[i].available()) {
  265.           //发送到串口调试器
  266.           client_msg[j] = serverClients[i].read();
  267.           j++;
  268.         }
  269.         wifi_message_analyse(client_msg, j, &serverClients[i]);
  270.       }
  271.     }
  272.   }




  273.   //串口通信
  274.   if (Serial.available()) {
  275.     //把串口调试器发过来的数据 发送给client
  276.     size_t len = Serial.available();
  277.     uint8_t sbuf[len];
  278.     Serial.readBytes(sbuf, len);
  279.     for (i = 0; i < MAX_SRV_CLIENTS; i++) {
  280.       if (serverClients[i] && serverClients[i].connected()) {
  281.         serverClients[i].write(sbuf, len);
  282.         delay(1);
  283.       }
  284.     }
  285.   }

  286. }
复制代码
     能否帮我看下整体的代码,我也挺奇怪的,我是通过tcp发送过来的报文。感觉这个问题出现的挺突然的,之前运行的好好的,突然就这样了。
 楼主| 发表于 2022-5-23 15:37 | 显示全部楼层
kpj001 发表于 2022-5-21 17:32
简化一下,报文处理是能够工作的。接下来加入数据源后再看吧

解决了,原来问题不在数组上,而是在那个msg_len上,我在check_message_head()里要把2个8位的usigned char 搞成一个int,但是方法好像有点问题,虽然最后串口输出出来的是07,但是它其实内部应该是一个比较大的数,我直接返回的usigned short就不会出错了。具体转换的写法在这里,我还没弄清楚具体错在哪,希望能指点一下。
  1. uint8_t uint_len[] = {data[9], data[10]};
  2.   uint8_t *l_p = uint_len;
  3.   unsigned short *plen = (unsigned short *)l_p;  //如果直接return *plen就没问题了。
  4.   int ilen = (int) * plen;
  5.   return ilen;
复制代码
发表于 2022-5-23 16:07 | 显示全部楼层
llk_007 发表于 2022-5-23 15:37
解决了,原来问题不在数组上,而是在那个msg_len上,我在check_message_head()里要把2个8位的usigned cha ...

为什么字符组合转换,既然是 python 和 arduino 的通讯,收发都是16进制不就好了?
 楼主| 发表于 2022-5-23 16:20 | 显示全部楼层
kpj001 发表于 2022-5-23 16:07
为什么字符组合转换,既然是 python 和 arduino 的通讯,收发都是16进制不就好了? ...

因为是用两个8位16进制 0x00 0x06这样组合成的一个报文长度的标记。  要处理的时候 就要把这个长度标记转成一个int,不然不好操作呀。 比如  说报文长度是301,那么就得些 0x01 0x2D  这样组合起一个0x12d 才能转换成10进制的301  或者16进制的0x12d。

我刚发现,改成返回ushort还是不行
如果我加一行 msg_len=6;就不会报错。
如果 我用msg_len = check_message_head(data); 下面的循环就会出错。
for(int j=0;j<msg_len;j++){
Serial.write( data[DEF_MSG_HEAD_LEN+j]);
Serial.write(j);
}
 楼主| 发表于 2022-5-23 17:06 | 显示全部楼层
kpj001 发表于 2022-5-23 16:07
为什么字符组合转换,既然是 python 和 arduino 的通讯,收发都是16进制不就好了? ...

  终于弄明白了,一个尴尬的大乌龙。
  1. uint8_t uint_len[] = {data[9], data[10]};
  2.   uint8_t *l_p = uint_len;
  3.   unsigned short *plen = (unsigned short *)l_p;  //如果直接return *plen就没问题了。
  4.   int ilen = (int) * plen;
  5.   return ilen;
复制代码

气死了,一开始的数据就取错了。应该取data[8]和data[9],取成9和10了。
data[9] = 0x06 data[10]=0x86
组成的ushort 用串口输出居然给我输出个0x06。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2025-1-1 21:18 , Processed in 0.082709 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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