迪文科技论坛

 找回密码
 立即注册
搜索
查看: 138|回复: 0

【开源】无线调试器

[复制链接]

17

主题

114

回帖

1287

积分

金牌会员

Rank: 6Rank: 6

积分
1287
QQ
发表于 2024-7-30 21:30:46 | 显示全部楼层 |阅读模式
1、介绍

目前很多单片机调试都是采用串口,而有些设备的调试接口不会暴露在外边,为此我设计了一款无线调试器,可以通过无线的方式监测设备信息数据。同时搭配了锂电池,实现真无线调试,锂电池没电的时候可以通过TypeC进行充电。

2、硬件准备
这次选用了4.3英寸迪文科技COF串口屏DMG80480F043_01W

设计了一块电路板,电路板上有ESP32-C3 WIFI芯片还有PCF8563时钟芯片,其中ESP32-C3和迪文屏采用串口通信,PCF8563和迪文屏采用IIC通信,电路原理图如下:

屏幕选择了一个白色的,所以电路板也设计了一个白色的。


3、界面设计
界面采用了科技风,让其更富有科技感,界面设计的AI工作如下:

接下来就是界面的设计,首先就是首页,有一个进入按钮。

接下来是调试界面,左上角是显示当前时间,右上角有一个进入WIFI设置的按钮,右边显示页数,还有显示时间戳,最下面是清除当前界面,左边部分就是显示调试信息,可以显示连接的设备情况。

WIFI信息部分,主要显示WIFI信息,有修改名字和密码的按钮。

点击修改WIFI名字,就可以进入WIFI名字修改界面,设计的是全字母+数字以及一些字符

修改WIFI密码类似,最多可以设计32位。

为了按钮显示效果好,还修改了设计了按下的界面,按键边缘发黑。


4、程序设计
程序分为Dwin和ESP32,Dwin主要是接收串口数据,然后显示出来,同时获取PCF8563时钟芯片的数据,主要代码如下:
  1. /*协议
  2. AA 03 31 32 33
  3. AA为协议,添加显示内容
  4. 03为后续内容长度
  5. 31 32 33为内容
  6. */
  7. //u8 rec_data_g[40];
  8. void esp32_analysis(u8 rec_data[])
  9. {
  10.     int i = 0;
  11.     int pass = 0;
  12.     u8 date_temp[256] = {0};

  13.     if(rec_data[0] == 0xAA) //显示内容
  14.     {
  15.         if(display_time == 0)
  16.         {
  17.             memcpy(date_temp, &rec_data[2], rec_data[1]);
  18.         }
  19.         else
  20.         {
  21.             getTimeStr(date_temp);
  22.             memcpy(&date_temp[10], &rec_data[2], rec_data[1]);
  23.         }

  24.         display_current_line += line_check(date_temp);
  25.         if(display_current_line > 10)
  26.         {
  27.             display_current_line = 1;
  28.             if(display_page_total < 10)
  29.             {
  30.                 if(display_page_current == display_page_total)
  31.                 {
  32.                     display_page_current++;
  33.                 }
  34.                 display_page_total++;
  35.             }
  36.             else
  37.             {
  38.                 for(i = 0;i < 9;i++)
  39.                 {
  40.                     memcpy(display_data[i], display_data[i+1], 512);
  41.                 }
  42.                 memset(display_data[9], 0, 512);
  43.                 if(display_page_current != display_page_total)
  44.                 {
  45.                     if(display_page_current > 1)
  46.                     {
  47.                         display_page_current--;
  48.                     }
  49.                 }
  50.             }
  51.             display_page_str[0] = display_page_current / 10 + 0x30;
  52.             display_page_str[1] = display_page_current % 10 + 0x30;
  53.             display_page_str[3] = display_page_total / 10 + 0x30;
  54.             display_page_str[4] = display_page_total % 10 + 0x30;
  55.             write_dgus_vp(0x2120, display_page_str, 8);
  56.         }
  57.         memcpy(&display_data[display_page_total - 1][strlen(display_data[display_page_total - 1])], date_temp, strlen(date_temp));
  58.         write_dgus_vp(0x3000, display_data[display_page_current - 1], strlen(display_data[display_page_current - 1]));
  59.     }
  60.     else if(rec_data[0] == 0xAB) //wifi名字和密码
  61.     {
  62.         memset(wifi_ssid, 0, 32);
  63.         memset(wifi_pass, 0, 32);
  64.         for(i = 0;i < rec_data[1];i++)
  65.         {
  66.             if(rec_data[i + 2] != ',')
  67.             {
  68.                 if(pass == 0)
  69.                 {
  70.                     wifi_ssid[strlen(wifi_ssid)] = rec_data[i + 2];
  71.                 }
  72.                 else
  73.                 {
  74.                     wifi_pass[strlen(wifi_pass)] = rec_data[i + 2];
  75.                 }
  76.             }
  77.             else
  78.             {
  79.                 pass = 1;
  80.             }
  81.         }
  82.         refresh_wifi_ssid();
  83.         refresh_wifi_pass();
  84.     }
  85.     else if(rec_data[0] == 0xAC)
  86.     {
  87.         myTime.year = RTC_BinToBcd2((rec_data[4] - 0x30) * 10 + (rec_data[5] - 0x30));
  88.         myTime.mon = RTC_BinToBcd2((rec_data[7] - 0x30) * 10 + (rec_data[8] - 0x30));
  89.         myTime.day = RTC_BinToBcd2((rec_data[10] - 0x30) * 10 + (rec_data[11] - 0x30));
  90.         myTime.hour = RTC_BinToBcd2((rec_data[13] - 0x30) * 10 + (rec_data[14] - 0x30));
  91.         myTime.min = RTC_BinToBcd2((rec_data[16] - 0x30) * 10 + (rec_data[17] - 0x30));
  92.         myTime.sec = RTC_BinToBcd2((rec_data[19] - 0x30) * 10 + (rec_data[20] - 0x30));
  93.         SetRealTime(&myTime);
  94.     }
  95. }

  96. //发送wifi名字
  97. void send_wifi_ssid(u8 wifi_temp[])
  98. {
  99.     u8 wifi_send[40] = {0xAA};

  100.     wifi_send[1] = strlen(wifi_temp) + 1;
  101.     wifi_send[2] = 0x01;
  102.     memcpy(&wifi_send[3], wifi_temp, strlen(wifi_temp));

  103.     Uatr_Send_Data(4, wifi_send, wifi_send[1] + 2);
  104. }

  105. //发送wifi密码
  106. void send_wifi_pass(u8 wifi_temp[])
  107. {
  108.     u8 wifi_send[40] = {0xAA};

  109.     wifi_send[1] = strlen(wifi_temp) + 1;
  110.     wifi_send[2] = 0x02;
  111.     memcpy(&wifi_send[3], wifi_temp, strlen(wifi_temp));

  112.     Uatr_Send_Data(4, wifi_send, wifi_send[1] + 2);
  113. }



  114. void refresh_time()
  115. {
  116.     GetRealTime(&myTime);

  117.     Write_Dgus(0x2100, 2);
  118.     Write_Dgus(0x2102, 0);
  119.     Write_Dgus(0x2104, myTime.year/16%10);
  120.     Write_Dgus(0x2106, myTime.year%16);

  121.     Write_Dgus(0x210A, RTC_Bcd2ToBin(myTime.mon)/10%10);
  122.     Write_Dgus(0x210C, RTC_Bcd2ToBin(myTime.mon)%10);

  123.     Write_Dgus(0x2110, RTC_Bcd2ToBin(myTime.day)/10%10);
  124.     Write_Dgus(0x2112, RTC_Bcd2ToBin(myTime.day)%10);

  125.     Write_Dgus(0x2114, RTC_Bcd2ToBin(myTime.hour)/10%10);
  126.     Write_Dgus(0x2116, RTC_Bcd2ToBin(myTime.hour)%10);

  127.     Write_Dgus(0x211A, RTC_Bcd2ToBin(myTime.min)/10%10);
  128.     Write_Dgus(0x211C, RTC_Bcd2ToBin(myTime.min)%10);

  129. }
复制代码
ESP32则是保存WIFI名称和密码,同时将WIFI的情况通过串口发送给Dwin屏,主要代码如下:

  1. static void udp_server_task(void *pvParameters)
  2. {
  3.     char rx_buffer[120];
  4.     char addr_str[120];
  5.     int addr_family = (int)pvParameters;
  6.     int ip_protocol = 0;
  7.     struct sockaddr_in6 dest_addr;

  8.     while (1) {

  9.         if (addr_family == AF_INET) {
  10.             struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
  11.             dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
  12.             dest_addr_ip4->sin_family = AF_INET;
  13.             dest_addr_ip4->sin_port = htons(BROADCAST_PORT);
  14.             ip_protocol = IPPROTO_IP;
  15.         } else if (addr_family == AF_INET6) {
  16.             bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
  17.             dest_addr.sin6_family = AF_INET6;
  18.             dest_addr.sin6_port = htons(BROADCAST_PORT);
  19.             ip_protocol = IPPROTO_IPV6;
  20.         }

  21.         int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
  22.         if (sock < 0) {
  23.             ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
  24.             break;
  25.         }
  26.         ESP_LOGI(TAG, "Socket created");

  27. #if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)
  28.         int enable = 1;
  29.         lwip_setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
  30. #endif

  31. #if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)
  32.         if (addr_family == AF_INET6) {
  33.             // Note that by default IPV6 binds to both protocols, it is must be disabled
  34.             // if both protocols used at the same time (used in CI)
  35.             int opt = 1;
  36.             setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  37.             setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
  38.         }
  39. #endif
  40.         // Set timeout
  41.         struct timeval timeout;
  42.         timeout.tv_sec = 10;
  43.         timeout.tv_usec = 0;
  44.         setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);

  45.         int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
  46.         if (err < 0) {
  47.             ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
  48.         }
  49.         ESP_LOGI(TAG, "Socket bound, port %d", BROADCAST_PORT);

  50.         struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
  51.         socklen_t socklen = sizeof(source_addr);

  52. #if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)
  53.         struct iovec iov;
  54.         struct msghdr msg;
  55.         struct cmsghdr *cmsgtmp;
  56.         u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];

  57.         iov.iov_base = rx_buffer;
  58.         iov.iov_len = sizeof(rx_buffer);
  59.         msg.msg_control = cmsg_buf;
  60.         msg.msg_controllen = sizeof(cmsg_buf);
  61.         msg.msg_flags = 0;
  62.         msg.msg_iov = &iov;
  63.         msg.msg_iovlen = 1;
  64.         msg.msg_name = (struct sockaddr *)&source_addr;
  65.         msg.msg_namelen = socklen;
  66. #endif

  67.         while (1) {
  68.             ESP_LOGI(TAG, "Waiting for data");
  69. #if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)
  70.             int len = recvmsg(sock, &msg, 0);
  71. #else
  72.             int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
  73. #endif
  74.             // Error occurred during receiving
  75.             if (len < 0) {
  76.                 ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
  77.                 break;
  78.             }
  79.             // Data received
  80.             else {
  81.                 // Get the sender's ip address as string
  82.                 if (source_addr.ss_family == PF_INET) {
  83.                     inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
  84. #if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)
  85.                     for ( cmsgtmp = CMSG_FIRSTHDR(&msg); cmsgtmp != NULL; cmsgtmp = CMSG_NXTHDR(&msg, cmsgtmp) ) {
  86.                         if ( cmsgtmp->cmsg_level == IPPROTO_IP && cmsgtmp->cmsg_type == IP_PKTINFO ) {
  87.                             struct in_pktinfo *pktinfo;
  88.                             pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgtmp);
  89.                             ESP_LOGI(TAG, "dest ip: %s", inet_ntoa(pktinfo->ipi_addr));
  90.                         }
  91.                     }
  92. #endif
  93.                 } else if (source_addr.ss_family == PF_INET6) {
  94.                     inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
  95.                 }

  96.                 rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string...
  97.                 ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);
  98.                 ESP_LOGI(TAG, "%s", rx_buffer);
  99.                 char send_data[256] = {0};
  100.                 sprintf(send_data, "[R]%s:%s\r\n", addr_str, rx_buffer);
  101.                 ESP_LOGI(TAG, "send_data: %s", send_data);
  102.                 dwin_screen_display(send_data, strlen(send_data));
  103.                 if(rx_buffer[0] == 't' && rx_buffer[1] == 'i' && rx_buffer[2] == 'm' && rx_buffer[3] == 'e' && rx_buffer[4] == ':' )
  104.                 {
  105.                     dwin_screen_datetime(&rx_buffer[5], 19);
  106.                 }

  107.                 // int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, sizeof(source_addr));
  108.                 // if (err < 0) {
  109.                 //     ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
  110.                 //     break;
  111.                 // }
  112.             }
  113.         }

  114.         if (sock != -1) {
  115.             ESP_LOGE(TAG, "Shutting down socket and restarting...");
  116.             shutdown(sock, 0);
  117.             close(sock);
  118.         }
  119.     }
  120.     vTaskDelete(NULL);
  121. }

  122. // Mount path for the partition
  123. const char *base_path = "/spiflash";

  124. // Handle of the wear levelling library instance
  125. static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;

  126. void wifi_write_flash()
  127. {
  128.     char write_data[65] = {0};
  129.     ESP_LOGI(TAG, "Opening file write");
  130.     FILE *f;
  131.    
  132.     f = fopen(device_filename, "wb");
  133.     if (f == NULL) {
  134.         ESP_LOGE(TAG, "Failed to open file for writing");
  135.         return;
  136.     }

  137.     sprintf(write_data, "%s,%s", wifi_ssid, wifi_pass);

  138.     fprintf(f, write_data);
  139.     fclose(f);
  140. }

  141. void app_main(void)
  142. {
  143.     //Initialize NVS
  144.     esp_err_t ret = nvs_flash_init();
  145.     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  146.       ESP_ERROR_CHECK(nvs_flash_erase());
  147.       ret = nvs_flash_init();
  148.     }
  149.     ESP_ERROR_CHECK(ret);

  150.     vTaskDelay(1000 / portTICK_PERIOD_MS);     //100ms

  151.     dwin_init();

  152.     vTaskDelay(2000 / portTICK_PERIOD_MS);     //100ms

  153.     ESP_LOGI(TAG, "Mounting FAT filesystem");
  154.     // To mount device we need name of device partition, define base_path
  155.     // and allow format partition in case if it is new one and was not formatted before
  156.     const esp_vfs_fat_mount_config_t mount_config = {
  157.             .max_files = 4,
  158.             .format_if_mount_failed = false,
  159.             .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
  160.     };
  161.     esp_err_t err;
  162.     if (EXAMPLE_FATFS_MODE_READ_ONLY){
  163.         err = esp_vfs_fat_spiflash_mount_ro(base_path, "storage", &mount_config);
  164.     } else {
  165.         err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &s_wl_handle);
  166.     }

  167.     if (err != ESP_OK) {
  168.         ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
  169.         return;
  170.     }

  171.     char line[128];
  172.    
  173.     ESP_LOGI(TAG, "Opening file write");

  174.     // Open file for reading
  175.     ESP_LOGI(TAG, "Reading file read");
  176.     FILE *f;
  177.     f = fopen(device_filename, "rb");
  178.     if (f != NULL) {
  179.         // ESP_LOGE(TAG, "Failed to open file for reading");
  180.         fgets(line, sizeof(line), f);
  181.         fclose(f);
  182.         // strip newline
  183.         char *pos = strchr(line, '\n');
  184.         if (pos) {
  185.             *pos = '\0';
  186.         }
  187.         ESP_LOGI(TAG, "Read from file: '%s'", line);

  188.         int split_cnt = 0;
  189.         while(line[split_cnt] != ',')
  190.         {
  191.             split_cnt++;
  192.         }

  193.         memcpy(wifi_ssid, line, split_cnt);
  194.         memcpy(wifi_pass, &line[split_cnt + 1], strlen(line) - split_cnt);

  195.         dwin_screen_wifi(line, strlen(line));   //给屏幕发送WIFI
  196.         // dwin_screen_wifi(line, strlen(line));   //给屏幕发送WIFI
  197.         // dwin_screen_wifi(line, strlen(line));   //给屏幕发送WIFI

  198.         wifi_ssid[split_cnt] = '\0';
  199.         wifi_pass[strlen(line) - split_cnt] = '\0';
  200.     }
  201.    
  202.     wifi_init_softap();
  203.    

  204.     xTaskCreate(udp_server_task, "udp_server", 4096, (void*)AF_INET, 5, NULL);
  205.     xTaskCreate(softap_check_ip_task, "softap_check_ip", 4096, (void*)AF_INET, 5, NULL);

  206. }
复制代码






演示视频:


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
二哲科技,欢迎联系,帮你解决问题,为你提供方案~
VX:erzhekeji
QQ:1002866443
回复

使用道具 举报

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

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-11-21 23:50 , Processed in 0.095666 second(s), 25 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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