一、开启串口,并配置好数据读写接口

#define RX2_BUF_SIZE         (1024)
#define TX2_BUF_SIZE        (512)
#define TXD2_PIN            (GPIO_NUM_12)
#define RXD2_PIN            (GPIO_NUM_13)
#define UART_RTS_PIN        (GPIO_NUM_2)int  uart_init_115200(void)
{uart_config_t uart_config = {.baud_rate = 115200,.data_bits = UART_DATA_8_BITS,.parity = UART_PARITY_DISABLE,.stop_bits = UART_STOP_BITS_1,.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,.rx_flow_ctrl_thresh = 122,.source_clk = UART_SCLK_APB,};ESP_LOGI("RS485", "Start RS485 application test and configure UART.");// Install UART driver (we don't need an event queue here)// In this example we don't even use a buffer for sending data.ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, RX2_BUF_SIZE * 2,0, 0, NULL, 0));// Configure UART parametersESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));// Set UART pins as per KConfig settingsESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, TXD2_PIN, RXD2_PIN, UART_RTS_PIN, UART_PIN_NO_CHANGE));// Set RS485 half duplex modeESP_ERROR_CHECK(uart_set_mode(UART_NUM_2, UART_MODE_RS485_HALF_DUPLEX));// Set read timeout of UART TOUT featureESP_ERROR_CHECK(uart_set_rx_timeout(UART_NUM_2, 3));return 0;
}int rs485_write(void *src, size_t size)
{
//  gpio_set_level(UART_RTS_PIN,1);
//  ss_delay_ms(1);int ret = uart_write_bytes(UART_NUM_2,src,size);
//  ss_delay_ms( size + 1 );
//  gpio_set_level(UART_RTS_PIN,0);return ret;
}int rs485_read(void* buf, uint32_t length)
{
//  gpio_set_level(UART_RTS_PIN,0);
//  ss_delay_ms(1); int ret = uart_read_bytes(UART_NUM_2,buf, length, 20);
//  ss_delay_ms(length + 10 );return ret;
}

二、配置串口升级uart_update.h文件

#ifndef _UART_UPDATE_H_
#define _UART_UPDATE_H_#define PACKET_SEQNO_INDEX      (1)
#define PACKET_SEQNO_COMP_INDEX (2)#define PACKET_HEADER           (3)
#define PACKET_TRAILER          (2)
#define PACKET_OVERHEAD         (PACKET_HEADER + PACKET_TRAILER)
#define PACKET_SIZE             (128)
#define PACKET_1K_SIZE          (1024)#define FILE_NAME_LENGTH        (256)
#define FILE_SIZE_LENGTH        (16)#define SOH                     (0x01)  /* start of 128-byte data packet */
#define STX                     (0x02)  /* start of 1024-byte data packet */
#define EOT                     (0x04)  /* end of transmission */
#define ACK                     (0x06)  /* acknowledge */
#define NAK                     (0x15)  /* negative acknowledge */
#define CA                      (0x18)  /* two of these in succession aborts transfer */
#define CRC16                   (0x43)  /* 'C' == 0x43, request 16-bit CRC */#define ABORT1                  (0x41)  /* 'A' == 0x41, abort by user */
#define ABORT2                  (0x61)  /* 'a' == 0x61, abort by user */#define NAK_TIMEOUT             (0x100000)
#define MAX_ERRORS              (5)#define IS_AF(c)             ((c >= 'A') && (c <= 'F'))
#define IS_af(c)             ((c >= 'a') && (c <= 'f'))
#define IS_09(c)             ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c)        IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c)        IS_09(c)
#define CONVERTDEC(c)        (c - '0')
#define CONVERTHEX_alpha(c)  (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c)        (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))extern int Ymodem_Receive ();#define ss_delay_ms(time)     vTaskDelay(time / portTICK_PERIOD_MS);#endif  /* _UART_UPDATE_H_ */

三、配置串口升级uart_update.c 文件,需要的头文件自己添加,替换#include "include.h"即可

/**  ******************************************************************************* @file    uart_update.c * @author  wst* @version V1.0.0* @date    19-08-2022* @brief   Main program body*******************************************************************************  * 主要功能是串口升级,需要配合串口使用,与OTA升级流程类似,只是获取的方式不一样**/#include "include.h"   unsigned char FileName[200];/*** @brief  Send a byte* @param  c: Character* @retval 0: Byte sent*/
static unsigned int  Send_Byte (unsigned char c)
{ss_rs485_write(&c,1);debug_print("---%d -",c);return 0;
}
static unsigned int  Send_2Byte (unsigned char c1,unsigned char c2)
{char c_str[2];c_str[0] = c1;c_str[1] = c2;ss_rs485_write(c_str,2);debug_print("---%02X - %02X----",c_str[0],c_str[1]);return 0;
}/*** @brief  Update CRC16 for input byte* @param  CRC input value * @param  input byte* @retval Updated CRC value*/
unsigned short UpdateCRC16(unsigned short crcIn, unsigned char byte)
{unsigned int  crc = crcIn;unsigned int  in = byte|0x100;do{crc <<= 1;in <<= 1;if(in&0x100){++crc;}if(crc&0x10000){crc ^= 0x1021;}} while(!(in&0x10000));return (crc&0xffffu);
}/*** @brief  Cal CRC16 for YModem Packet* @param  data* @param  length* @retval CRC value*/
unsigned short Cal_CRC16(const unsigned char* data, unsigned int  size)
{unsigned int  crc = 0;const unsigned char* dataEnd = data+size;while(data<dataEnd){crc = UpdateCRC16(crc,*data++);}crc = UpdateCRC16(crc,0);crc = UpdateCRC16(crc,0);return (crc&0xffffu);
}/*** @brief  Convert a string to an integer* @param  inputstr: The string to be converted* @param  intnum: The intger value* @retval 1: Correct*         0: Error*/
unsigned int  String2Int(unsigned char *inputstr, int *intnum)
{unsigned int  i = 0, res = 0;unsigned int  val = 0;if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X')){if (inputstr[2] == '\0'){return 0;}for (i = 2; i < 11; i++){if (inputstr[i] == '\0'){*intnum = val;/* return 1; */res = 1;break;}if (ISVALIDHEX(inputstr[i])){val = (val << 4) + CONVERTHEX(inputstr[i]);}else{/* return 0, Invalid input */res = 0;break;}}/* over 8 digit hex --invalid */if (i >= 11){res = 0;}}else /* max 10-digit decimal input */{for (i = 0;i < 11;i++){if (inputstr[i] == '\0'){*intnum = val;/* return 1 */res = 1;break;}else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0)){val = val << 10;*intnum = val;res = 1;break;}else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0)){val = val << 20;*intnum = val;res = 1;break;}else if (ISVALIDDEC(inputstr[i])){val = val * 10 + CONVERTDEC(inputstr[i]);}else{/* return 0, Invalid input */res = 0;break;}}/* Over 10 digit decimal --invalid */if (i >= 11){res = 0;}}return res;
}/*** @brief  Receive a packet from sender* @param  data   数据缓存* @param  length * @param  timeout* * @retval 0: 正常返回*         -1: 接收数据头错误*         -2:补码、校验错误*         -3:发送端中断数据*          4:接收完成*         255: 数据为空*/
static int Receive_Packet (unsigned char *data, int *length, unsigned int  timeout)
{unsigned short i, packet_size, computedcrc;char name_dat[200]={0};*length = 0;unsigned char  test_num = 0,recv_delay_num=0;char c=0x43;static char first_read_flag=1;if(first_read_flag==1)  //第一次,启动下载,获取固件名,大小{  first_read_flag=2;  ss_rs485_read(data, 133);  //清空串口内部缓存memset(data,0,133);ss_delay_ms(10);while((strstr(name_dat,".bin")==NULL) && (strstr(name_dat,".Bin")==NULL) && (strstr(name_dat,".BIN")==NULL)){ss_rs485_write(&c,1);  //开始需要发送 “C” 启动下载ss_delay_ms(80);memset(data,0,134);ss_rs485_read( data, 133);// for(i=0;i<133;i++)//     printf("%02x ",data[i]);// printf("\n ");if(data[0] != 0){if((data[0]!=SOH)&&(data[0]!=STX)&&(data[0]!=EOT)&&(data[0]!=CA)&&(data[0]!=ABORT1)&&(data[0]!=ABORT2)) //判断数据头是否正确{return -1;}for(i=0;i<128;i++){name_dat[i] = data[i+3];}printf("---->%s \n",name_dat);}test_num++;if(test_num >=4)   //连续 n 次不正确,判断为数据为空  return 255;   //不进行升级}} else if(first_read_flag == 2)//第 2--n次,获取固件包{first_read_flag=0;  ss_delay_ms(10);Send_2Byte(ACK,CRC16);     memset(data,0,PACKET_1K_SIZE + PACKET_OVERHEAD);ss_delay_ms(120);while(ss_rs485_read( data, PACKET_1K_SIZE + PACKET_OVERHEAD)<=0){Send_2Byte(0x00,0x00);   //故障情况下使用ss_delay_ms(120);recv_delay_num++;if(recv_delay_num>=3)break;}// for(i=0;i<PACKET_1K_SIZE + PACKET_OVERHEAD;i++)//     printf("%02x ",data[i]);// printf("\n ");if((data[0]!=SOH)&&(data[0]!=STX)&&(data[0]!=EOT)&&(data[0]!=CA)&&(data[0]!=ABORT1)&&(data[0]!=ABORT2))//判断数据头错误{return -1; }}else{Send_Byte(ACK);memset(data,0,PACKET_1K_SIZE + PACKET_OVERHEAD);ss_delay_ms(100);ss_rs485_read( data, PACKET_1K_SIZE + PACKET_OVERHEAD);// for(i=0;i<PACKET_1K_SIZE + PACKET_OVERHEAD;i++)//     printf("%02x ",data[i]);// printf("\n ");if((data[0]!=SOH)&&(data[0]!=STX)&&(data[0]!=EOT)&&(data[0]!=CA)&&(data[0]!=ABORT1)&&(data[0]!=ABORT2))//判断数据头错误{return -1; }        }switch (data[0]){case SOH: //接收 128B 包packet_size = PACKET_SIZE;//   //检测序号补码是是否正确if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)){return -2;   //补码错误}computedcrc = Cal_CRC16(&data[PACKET_HEADER], (unsigned int )packet_size);//计算CRC16码if (computedcrc != (unsigned short)((data[packet_size+3]<<8) | data[packet_size+4]))//检测CRC16校验码{return -2;//校验错误}*length = packet_size;return 0;   //成功接收数据case STX:  //接收 1KB 包packet_size = PACKET_1K_SIZE;//检测序号补码是是否正确if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)){return -2;//补码错误}computedcrc = Cal_CRC16(&data[PACKET_HEADER], (unsigned int )packet_size);//计算CRC16码if (computedcrc != (unsigned short)((data[packet_size+3]<<8) | data[packet_size+4]))//检测CRC16校验码{return -2;//校验错误}*length = packet_size;return 0;case EOT:return 4;  //升级完成,结束数据case CA:if ((ss_rs485_read(&c, 1) >= 1) && (c == CA)){*length = -1;return 0;}else{return -2;}case ABORT1:return -3;//中断数据case ABORT2:return -3;//中断数据default: return -1;//数据头错误}
}//异常处理,连接http服务器失败等异常
static void __attribute__((noreturn))  task_fatal_error()
{ESP_LOGE("UART_UPDATE", "Exiting task due to fatal error...");while (1) {ss_delay_ms(1000);}
}/*** @brief  Receive a file using the ymodem protocol* @param  buf: Address of the first byte* @retval The size of the file*   * @retval 0: 正常返回*         -1: 接收数据头错误*         -2:补码、校验错误*         -3:发送端中断数据*          4:接收完成*         255: 数据为空*/int Ymodem_Receive()
{                  unsigned char packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;unsigned char buf[1024];int i,  packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;esp_err_t err;/* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */esp_ota_handle_t update_handle = 0 ;const esp_partition_t *update_partition = NULL;const esp_partition_t *configured = esp_ota_get_boot_partition();const esp_partition_t *running = esp_ota_get_running_partition();if (configured != running) {ESP_LOGI("UART_UPDATE", "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",configured->address, running->address);ESP_LOGI("UART_UPDATE", "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");}ESP_LOGI("UART_UPDATE", "Running partition type %d subtype %d (offset 0x%08x)",running->type, running->subtype, running->address);update_partition = esp_ota_get_next_update_partition(NULL);ESP_LOGI("UART_UPDATE", "Writing to partition subtype %d at offset 0x%x",update_partition->subtype, update_partition->address);assert(update_partition != NULL);for (session_done = 0, errors = 0, session_begin = 0; ;)//死循环直至文件数据包全部发送完成{for (packets_received = 0, file_done = 0, buf_ptr = buf; ;){                switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT)){case 0://成功接收到1K{errors = 0;switch (packet_length)   // packet_length  = 0, -1, 128,  1024{/* Abort by sender */case -1:  //接收失败Send_Byte(ACK);  //回复return -1;/* End of transmission */case 0:Send_Byte(ACK);//回复file_done = 1;break;/* Normal packet */default:   //接收成功if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)){//序号00(文件名)Send_Byte(NAK);                                        }else{if (packets_received == 0)//文件名(首包){/* Filename packet */if (packet_data[PACKET_HEADER] != 0)//文件名字{/* Filename packet has valid data */for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);){FileName[i++] = *file_ptr++;//保存文件名}FileName[i++] = '\0';//字符串形式for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < (FILE_SIZE_LENGTH - 1));){file_size[i++] = *file_ptr++;//文件大小}file_size[i++] = '\0';String2Int(file_size, &size);//Convert a string to an integerdebug_print("uart update : file name :%s , size :%d \n",FileName,size);/* Test the size of the image to be sent *//* Image size is greater than Flash size */if (size > 0x100000)//1MB{/* End session */Send_2Byte(CA,CA);                                            debug_print("case size:\n");return -1;}err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);if (err != ESP_OK) {ESP_LOGE("UART_UPDATE", "esp_ota_begin failed (%s)", esp_err_to_name(err));esp_ota_abort(update_handle);task_fatal_error();}ESP_LOGI("UART_UPDATE", "esp_ota_begin succeeded");
//                                        ss_delay_ms(10);// Send_Byte(ACK);// Send_Byte(CRC16);}/* Filename packet is empty, end session */else{Send_Byte(ACK);file_done = 1;session_done = 1;break;}}/* Data packet */else  //文件信息保存完后开始接收数据{                                debug_print("esp_ota_write\r\n");memcpy(buf, packet_data + PACKET_HEADER, packet_length);err = esp_ota_write( update_handle, (const void *)buf, packet_length);if (err != ESP_OK) {/* End session */Send_2Byte(CA,CA);                                      esp_ota_abort(update_handle);task_fatal_error();}// else// {//     Send_Byte(ACK);// }// binary_file_length += packet_length;//    ESP_LOGI("UART_UPDATE", "Written image length %d", binary_file_length);                                                                                                                 }packets_received ++;                                }}break;}case -1: //数据头错误Send_2Byte(CA,CA);debug_print("case -1:\n");return -1;case -2://检验、补码错误{                                  errors ++;                    if (errors > MAX_ERRORS){Send_2Byte(CA,CA);return -2;}debug_print("------%d\n",errors);Send_Byte(NAK); //发送非应答,让发送端重新发送此包数据                      break;}    case -3: //中断数据Send_2Byte(CA,CA);debug_print("case -3:\n");return -3;case 4: //完成ss_delay_ms(25);Send_2Byte(ACK,CRC16);ss_delay_ms(60);Send_Byte(ACK);// ss_delay_ms(50);// Send_Byte(ACK);err = esp_ota_end(update_handle);if (err != ESP_OK) {if (err == ESP_ERR_OTA_VALIDATE_FAILED) {ESP_LOGE("UART_UPDATE", "Image validation failed, image is corrupted");}ESP_LOGE("UART_UPDATE", "esp_ota_end failed (%s)!", esp_err_to_name(err));task_fatal_error();}err = esp_ota_set_boot_partition(update_partition);if (err != ESP_OK) {ESP_LOGE("UART_UPDATE", "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));task_fatal_error();}ESP_LOGI("UART_UPDATE", "Prepare to restart system!");esp_restart();                    return size;case 255:   //不进行升级return 255;}if (file_done != 0){break;}}if (session_done != 0) //文件发送完成{break;}}return (int)size;
}

四、在main函数调用

void app_main(void)
{while (1){             uart_init_115200();//初始化RS485 115200nvs_data_init();Ymodem_Receive();//串口升级ss_delay_ms(10000);}
}

五、使用hypertrm.exe 进行串口下载

配置页面

发送即可

ESP32 串口升级相关推荐

  1. ESP32串口转WiFi双天线ESP32-S模组

    ▌ESP32小模块 1.外置管脚功能图 安信可原厂直销 WiFi+蓝牙模块ESP32串口转WiFi双天线ESP32-S模组 2.自动下载电路 参考下载电路分析 ESP8266专题-ESP8266自动下 ...

  2. 瑞萨单片机iap串口升级boot程序与app程序合并的工程构建-学习记录

    MCU型号: R7F0C004 编辑软件:CS+ for CC boot区程序地址分配:0x0000-0x1ffff app区程序地址分配: 0x2000-0xfffff 复制一份常规的app程序,然 ...

  3. ESP32串口通信 双机串口通信

    ESP32串口 ESP32双机串口通信 环顾论坛居然无使用uart进行双击通信的案例或者讲解!!! 还是自己摸索吧!环境依旧是arduino(熟练使用ESP32后必得用vs code,这个IDE居然有 ...

  4. STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现

    文章目录 一.YModem协议简介 二.YModem的数据格式 1.起始帧的数据格式 2.数据帧的数据格式 3.结束帧的数据格式 4.文件传输过程 三.基于Ymodem协议串口升级程序的实现过程 1. ...

  5. 串口升级华为S2300系列交换机

     串口升级华为S2300系列交换机升级固件 华为2300系列交换机,固件版本较旧,没有web支持. 下载好固件.bootrom.web文件,用串口线连接交换机. 1升级bootrom,交换机上电启 ...

  6. 杰理之测试盒对耳串口升级功能【篇】

    使用条件1.测试盒硬件版本为v2.2以上,且固件版本为v2.1.7以上,可以支持对耳测试接口.2.对耳LDO引脚支持串口通讯(与串口IO合绑)且LDOIN电容需小于103的样机,可以通过测试盒串口转接 ...

  7. ESP32 OTA升级之HTTP OTA

    ESP32 OTA升级之 HTTP OTA 文章目录 ESP32 OTA升级之 HTTP OTA 1. 前言 2. 搭建http本地服务器 2. HTTP OTA 3. 补充学习 1. 前言 在所有电 ...

  8. ESP32 OTA升级框架

    ESP32 SPI Flash 内有与升级相关的(至少)四个分区:OTA data.Factory App.OTA_0.OTA_1.其中 FactoryApp 内存有出厂时的默认固件. 首次进行 OT ...

  9. ESP32串口API

    翻自:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/api-reference/peripherals/uart.html UART ...

最新文章

  1. excel单元格斜线_如何用EXCEL做一套田字格模板?在家给小孩练习写字
  2. 【Android RTMP】RTMP 直播推流服务器搭建 ( Ubuntu 18.04.4 虚拟机 )
  3. Dispatch Queue 之 Invoke 当前队列
  4. Android性能优化-App后台优化
  5. 委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别...
  6. 明天开始放假了[2.5-2.13],春节期间计划
  7. 【算法学习】将MSRCR中的模糊处理由FFT修改为时域纯高斯模糊
  8. 区块链应用如何实现资金盘分红
  9. Python中计算二重积分
  10. 计算机组装实验硬盘分区方法,硬盘怎么分区和格式化 史上最详细的硬盘分区方法大全 (全文)...
  11. win10用户账户控制怎么设置白名单
  12. Java基本控制流程的理解之输出三角形和乘法表
  13.  一个复数可以用实部和虚部两部分组成,a1 = 1.2 + 3.4i,其中1.2是实部,3.4是虚部。定义一个结构体ComplexNumber,包含imaginary和real两个成员变量,能够表示
  14. Mysql—索引③:优化篇(不仅仅是索引)
  15. Linux基础入门 -用户与文件操作
  16. 【ubuntu常规使用】修改分辨率
  17. HTML基本知识点——图片标记
  18. IFE_js_task02
  19. 局域网计算机配置扫描系统,fly42局域网计算机配置检测系统
  20. CentOS7安装可移植Prometheus+grafana--pushgateway及自定义监控

热门文章

  1. html导出excel 隐藏部分,html导出Excel方法
  2. AdaBoost算法搭建信用卡精准营销模型
  3. 第一范式 第二范式 第三范式 BC范式
  4. 多项目版本管理:monorepo 策略
  5. 部署Weblogic10.3.6
  6. Alertmanager 报警规则
  7. C#获取网络时间(初学者)
  8. CameraSR----Camera Lens Super-Resolution个人笔记
  9. javascript幻灯片播放(随机)
  10. 华硕驱动问题,(触摸板可以用,可是手势不可以用,很多方法都试了,还是本机自带的东西好用)