<笔记>STM32&4G模组实现OTA升级

前言

  这是一个STM32&4G模组配合实现的OTA升级教程。硬件平台是小熊派的开发板+自己其他项目上的4G模组(型号为:SIMCOM7600CE)。软件是在STM32里面编写裸机程序,使用了状态机编程,主业务是用AT指令连接MQTT平台,OTA升业务是用HTTP下载将要升级的BIN文件。

Drawn By:67373UPUP

第一步OTA升级的大概思路

  前提条件,我使用的是STM32L431RCTC这个芯片。这个芯片的内部Flash是256K。那我们将256K分为3块。

第一部分: Boot_Loader 起始地址: 0x0800F000 大小为:60K 占30页
第二部分:Application_1 起始地址: 0x0800F000 大小为:90K 占45页
第三部分:Application_2 起始地址: 0x08025800 大小为:90K 占45页

4G模块怎么装到CENTOS系统 4g模块升级_HTTP

  OTA升级的程序包含三部分,分别命名为BOOT,APP1,APP2。(名字自己随便取,本例程我是为了方便理解这样子取的,这三部分的程序本质上还是嵌入式程序,和我们平常编写的程序没有什么区别)

( 1 ) BOOT:主要实现的功能是开机检查是否有升级的标志位。
  如果没有升级的标志位,那就把程序的指针跳转到APP1的地址,正常启动APP1的业务逻辑。
  如果 有升级的标志位,BOOT会先把APP1占据的内部Flash清空,然后将APP2的内容搬运到APP1内,搬运完成后清除升级的标志位以及重启单片机,重启后BOOT先运行,检测到没有升级的标志位。那就把程序的指针跳转到APP1的地址,正常启动APP1的业务逻辑。

( 2 )APP1里存的是主业务逻辑的程序。(如果没有升级的标志位,每次BOOT启动后下一个就会运行APP1)

( 3 )APP2里存的是将要升级的业务逻辑的程序。(APP2内只负责存储将要升级的BIN文件,程序永远不会跳转到这里)

4G模块怎么装到CENTOS系统 4g模块升级_HTTP_02

第二步OTA本地升级测试
BOOT的程序大致分为以下几块

1,内部Flash的读写。(内部Flash的读写的不展开了,具体参考源码)

2,搬运APP的BIN文件到APP1的位置。

/**
	* @bieaf 进行程序的覆盖
	* @detail 1.擦除目的地址
	* @detail 2.源地址的代码拷贝到目的地址
	* @detail 3.擦除源地址
	*
	* @param  搬运的源地址
	* @param  搬运的目的地址
	* @return 搬运的程序大小
	*/
void MoveCode(unsigned int src_addr, unsigned int des_addr, unsigned int byte_size)
{
    /*1.擦除目的地址*/
    printf("> Start erase des flash......\r\n");
    Erase_page(des_addr, (byte_size/PageSize));
    printf("> Erase des flash sucessfully......\r\n");

    /*2.开始拷贝*/
    uint8_t temp[1024];
    printf("> Start copy......\r\n");
    for(int i = 0; i < byte_size/1024; i++)
    {
        ReadFlash((src_addr + i*1024), temp, 1024);
        WriteFlash((des_addr + i*1024), temp, 1024);
    }
    printf("> Copy sucessfully......\r\n");

    /*3.擦除源地址*/
    printf("> Start erase src flash......\r\n");
    Erase_page(src_addr, (byte_size/PageSize));
    printf("> Erase src flash sucessfully......\r\n");
}

3,开机判断启动方式

/**
	* @bieaf 进行BootLoader的启动
	* @return none
	*/
void Start_BootLoader(void)
{
	 printf("\r\n");
	 printf("***********************************\r\n");
	 printf("*                                 *\r\n");
	 printf("*           BootLoader            *\r\n");
	 printf("*                                 *\r\n");
	 printf("***********************************\r\n");	
	 printf("> Choose a startup method......\r\n");	
	switch(Read_Start_Mode())									//读取是否启动应用程序
	{
		case Startup_Normal:										//正常启动
		{
			printf("> Normal start......\r\n");
			break;
		}
		case Startup_Update:										//升级再启动
		{
			printf("> Start update......\r\n");	
			MoveCode(Application_2_Addr, Application_1_Addr, Application_Size);
			printf("> Update sucessfully......\r\n");
			break;
		}
		default:																//启动失败
		{
			printf("> Error:%X!!!......\r\n", Read_Start_Mode());
			return;			
		}
	}	
	/* 跳转到应用程序 */
	// __disable_irq() ;  //很重要!经测试STM32F4必要!  貌似F105也需要   L431 裸机 却不需要  RTOS需要
	printf("> Start up......\r\n\r\n");
	IAP_ExecuteApp(Application_1_Addr);
}

4,跳转运行程序到APP1的地址。

/** @bieaf 	采用汇编设置栈的值
	* @return none	返回值
	*/
__asm void MSR_MSP (uint32_t ulAddr)
{
    MSR MSP, r0 //set Main Stack value			                   
    BX r14
}

/** @bieaf 	程序跳转函数
	* @return none	返回值
	*/
typedef void (*Jump_Fun)(void);
void IAP_ExecuteApp (uint32_t App_Addr)
{
	Jump_Fun JumpToApp; 
    
	if (((*(__IO uint32_t *)App_Addr) & 0x2FFE0000) == 0x20000000)	//检查栈顶地址是否合法.
	{ 
		JumpToApp = (Jump_Fun) * (__IO uint32_t *)(App_Addr + 4);	//用户代码区第二个字为程序开始地址(复位地址)		
		MSR_MSP( * (__IO uint32_t *) App_Addr);	//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		JumpToApp();	//跳转到APP
	}else{
	printf("There is None APP to jump,ERROR!!!\r\n");
	}
}

5,设置BOOT程序的ROM地址以及大小

4G模块怎么装到CENTOS系统 4g模块升级_4G模块怎么装到CENTOS系统_03


6,用ST-Link下载时设置为全擦除内部Flash

4G模块怎么装到CENTOS系统 4g模块升级_嵌入式_04

APP1的程序

1,需要在main主程序的第一行更改中断向量表地址到0x800F000U。

2,将升级的标志位设为0xAA。

3,在升级标志位设为0xAA之前硬延迟10S,这一步的目的是有充足的时间将APP2的BIN文件刷进板子里。(在实际的项目中不会有这个东西)

4,将LED的闪烁配置为1s闪烁一次。(这是测试程序,故只配置了一个闪烁的LED灯来关注实验现象)

5,设置APP1程序的ROM地址以及大小

4G模块怎么装到CENTOS系统 4g模块升级_4G_05


6,用ST-Link下载时不要设置为全擦除内部Flash

4G模块怎么装到CENTOS系统 4g模块升级_嵌入式_06

APP2的程序

1,需要在main主程序的第一行更改中断向量表地址到0x800F000U。

2,需要将User的一下内容配置一下,这一步的目的是生成BIN文件。(别死搬硬抄,结合自己的工程微调一下)

C:\Program Files\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin --output .\APP\APP.bin .\APP*.axf

4G模块怎么装到CENTOS系统 4g模块升级_嵌入式_07


然后每次编译后就可以在自己电脑的工程文件夹里找到app.bin文件。

4G模块怎么装到CENTOS系统 4g模块升级_嵌入式_08

3,将LED的闪烁配置为50ms闪烁一次。(这是测试程序,故只配置了一个闪烁的LED灯来关注实验现象)

4,设置APP2程序的ROM地址以及大小

4G模块怎么装到CENTOS系统 4g模块升级_HTTP_09

测试步骤

1,步骤1:先用ST-link将BOOT的程序刷进板子内。

2,步骤2:再用ST-link将APP1的程序双进板子内。

3,步骤3:将APP2的BIN文件通过工具STM32CubeProgrammer刷进板子内。(经测试这一步以后程序会陷入假死机状态,原因未明,知道的大神可以给我留言解释下,谢谢了)

4G模块怎么装到CENTOS系统 4g模块升级_4G_10

4,复位开发板,,经过十秒后开发板的LED灯会满闪。同时根据程序也可知道升级标志位已经写好了。
5,复位开发板,就能发现LED灯快闪了。表示升级完成。

第三步OTA升级的完全体

  这一步的主要工作就算是把4G的联网驱动完善。我们需要一个平台来供我们下载BIN文件,(平台需要找软件开发,我不会。我用的是公司的所以我不可能公开出来的)

1,首先我们先写联网驱动。(采用有限的状态机编程,状态机是参考的正道老师的教程)

以下是完整联网+升级部分的代码,每次开机就会往我的平台(47.98.183.97:1884)上发送模组的信号值。

/*设置CAT1状态的枚举变量*/
typedef enum
{
    CAT1_IDIE = 0,
    CAT1_SEND,
    CAT1_WAIT,
    CAT1_ACCESS
} teCAT1_TaskStatus;


/*设置AT指令集的枚举变量*/
typedef enum
{
    //AT_RST,
    AT,
    ATE0,
    AT_CGSN,
    AT_CCID,
    AT_CEREG,
    AT_CGATT,
    AT_CSQ_1,
    AT_CMQTTSTART,
    AT_CMQTTACCQ,
    AT_CMQTTCONNECT,
    AT_CSQ_2,
    AT_CMQTTTOPIC,
    AT_TOPIC,
    AT_CMQTTPAYLOAD,
    AT_MESSAGE,
    AT_CMQTTPUB,
		/*HTTP相关指令*/
		AT_HTTPINIT_1,
		AT_HTTPPARA_VERSION,
		AT_HTTPACTION_1,
		AT_HTTPREAD_1,
		AT_HTTPTERM_1,	
		AT_HTTPINIT_2,
		AT_HTTPPARA_DATA,
		AT_HTTPACTION_2,
		AT_HTTPREAD_2,
		AT_HTTPTERM_2,
} teATCmdNum;

/*设置模组状态的枚举变量*/
typedef enum
{
    SUCCESS_REC = 0,
    TIME_OUT,
    NO_REC
} teATStatus;

/*设置AT指令集的结构体*/
typedef struct
{
    char *ATSendStr;
    char *ATRecStr;
    uint16_t TimeOut;
    teATStatus ATStatus;
    uint8_t RtyNum;
} tsATCmds;
/*入网AT指令集*/
tsATCmds ATCmds[] =
{
    /* 下面是关于连接MQTT的指令集*/
    //{"AT+CRESET\r\n","PB DONE",5000,NO_REC,3},
    {"AT\r\n","OK",1000,NO_REC,3},															//AT指令测试
    {"ATE0\r\n","OK",1000,NO_REC,3},														//关闭回显
    {"AT+CGSN\r\n","OK",1000,NO_REC,3},													//查询Imei
    {"AT+CCID\r\n","OK",1000,NO_REC,3},													//查询ICCID
    {"AT+CEREG?\r\n","OK",1000,NO_REC,100},											//查询当前GPRS注册状态
    {"AT+CGATT?\r\n","OK",1000,NO_REC,3},												//查询当前GPRS附着状态
    {"AT+CSQ\r\n","OK",1000,NO_REC,3},													//查询信号值
    {"AT+CMQTTSTART\r\n","+CMQTTSTART: 0",2000,NO_REC,3},				//开启MQTT连接
    {"AT+CMQTTACCQ=0,\"clientid01\"\r\n","OK",2000,NO_REC,3},		//注册MQTT的ClientID
    {"AT+CMQTTCONNECT=0,\"tcp://47.98.183.97:1884\",120,1,\"admin\",\"public\"\r\n","+CMQTTCONNECT: 0,0",3000,NO_REC,3},	//设置IP port username password keepalive
    {"AT+CSQ\r\n","OK",1000,NO_REC,3},													//查询CSQ
    {"AT+CMQTTTOPIC=0,",">",2000,NO_REC,3},											//设置topic
    {topic_buffer,"OK",3000,NO_REC,3},													//topic内容
    {"AT+CMQTTPAYLOAD=0,",">",2000,NO_REC,3},										//设置发送报文
    {message_buffer,"OK",3000,NO_REC,5},												//msg内容
    {"AT+CMQTTPUB=0,1,60\r\n","+CMQTTPUB: 0,0",3000,NO_REC,5},	//发送报文
    /* 下面是关于查询版本号的AT指令集*/
    {"AT+HTTPINIT\r\n","OK",1000,NO_REC,3},											//开启HTTP服务
    {"AT+HTTPPARA=\"URL\",\"http://47.98.248.24:8888/getVersion?device_id=123456\"\r\n","OK",1000,NO_REC,3},	//设置HTTP参数
    {"AT+HTTPACTION=0\r\n","+HTTP_PEER_CLOSED",1000,NO_REC,3},				//操作HTTP方法
    {"AT+HTTPREAD=0,100\r\n","+HTTPREAD:0",1000,NO_REC,3},			//读取HTTP服务回复
    {"AT+HTTPTERM\r\n","OK",1000,NO_REC,3},											//关闭HTTP服务
    /* 下面是关于下载BIN文件的AT指令集*/
    {"AT+HTTPINIT\r\n","OK",1000,NO_REC,3},											//开启HTTP服务
    {"AT+HTTPPARA=\"URL\",\"http://47.98.248.24:8888/download1?device_id=123456&version=3.0.0\"\r\n","OK",3000,NO_REC,3},	//设置HTTP参数
    {"AT+HTTPACTION=0\r\n","+HTTPACTION:",3000,NO_REC,3},				//操作HTTP方法
    {"AT+HTTPREAD=0,1024\r\n","+HTTPREAD:",3000,NO_REC,3},			//读取HTTP服务回复
    {"AT+HTTPTERM\r\n","OK",1000,NO_REC,3},											//关闭HTTP服务
};

/* AT指令发送处理逻辑 */
void ATSend(teATCmdNum ATCmdNum)
{
    //清空接收缓存区
    memset(Lpuart1type.Lpuart1RecBuff,0,LPUART1_REC_SIZE);
    ATCmds[ATCmdNum].ATStatus = NO_REC;
    ATRecCmdNum = ATCmdNum;
    printf("\r\n当前命令码:%d\r\n",ATCmdNum);
    /* 设置topic的长度 */
    if(ATCmdNum == AT_CMQTTTOPIC)
    {
        memset(topic_buffer,0x00,sizeof(topic_buffer));
        sprintf(topic_buffer,"dev/%s",Imei_buffer);
        sprintf(send_buffer,"%s%d\r\n",ATCmds[ATCmdNum].ATSendStr,strlen(topic_buffer));
        HAL_UART_Transmit(&hlpuart1,(uint8_t*)send_buffer,strlen(send_buffer),0xFF);
        printf("send_buffer:%s\r\n",send_buffer);
        memset(send_buffer,0x00,strlen(send_buffer));
    }
    /* 设置msg的长度 */
    else if(ATCmdNum == AT_CMQTTPAYLOAD)
    {
        memset(message_buffer,0x00,sizeof(message_buffer));
        sprintf(message_buffer,"{\"CSQ\":%s}",CSQ_buffer);
        sprintf(send_buffer,"%s%d\r\n",ATCmds[ATCmdNum].ATSendStr,strlen(message_buffer));
        HAL_UART_Transmit(&hlpuart1,(uint8_t*)send_buffer,strlen(send_buffer),0xFF);
        printf("send_buffer:%s",send_buffer);
        memset(send_buffer,0x00,sizeof(send_buffer));
    }
    else
    {
        HAL_UART_Transmit(&hlpuart1,(uint8_t*)ATCmds[ATCmdNum].ATSendStr,strlen(ATCmds[ATCmdNum].ATSendStr),0xff);
        printf("send:%s",ATCmds[ATCmdNum].ATSendStr);
    }
    //打开超时定时器
    SetTime(&TimeCAT1,ATCmds[ATCmdNum].TimeOut);

}

/* AT指令接收处理逻辑 */
void ATRec(void)
{
    if(Lpuart1type.Lpuart1RecFlag)
    {
        if(strstr((const char*)Lpuart1type.Lpuart1RecBuff,ATCmds[ATRecCmdNum].ATRecStr) != NULL)
        {
            ATCmds[ATRecCmdNum].ATStatus = SUCCESS_REC;
        }
        printf("收到数据:%s",Lpuart1type.Lpuart1RecBuff);
        Lpuart1type.Lpuart1RecFlag = 0;
        Lpuart1type.Lpuart1RecLen = 0;
    }
}
/* 初始化CAT1 */
void CAT1_Init(void)
{
    Start_4G();
    CAT1_TaskStatus = CAT1_SEND;
    ATCurrentCmdNum = AT;
    ATNextCmdNum = ATE0;
}

/* AT指令交互逻辑 */
void CAT1_Task(void)
{
    while(1)
    {
        switch(CAT1_TaskStatus)
        {
        case CAT1_IDIE: //空闲态
            return;
        case CAT1_SEND:
            if(ATCurrentCmdNum !=ATNextCmdNum)
            {
                CurrentRty = ATCmds[ATCurrentCmdNum].RtyNum;
            }
            ATSend(ATCurrentCmdNum);
            CAT1_TaskStatus = CAT1_WAIT;

            return;
        case CAT1_WAIT:	//等待态,等待CAT1返回的信息
            ATRec();	//调用接收函数
            if(ATCmds[ATRecCmdNum].ATStatus == SUCCESS_REC)
            {
                printf("当前码:%d\r\n",ATCurrentCmdNum);
                if(ATCurrentCmdNum == AT_CGSN)	//如果AT指令为查询IMEI
                {
                    ATCurrentCmdNum += 1;
                    ATNextCmdNum = ATCurrentCmdNum+1;
                    CAT1_TaskStatus = CAT1_SEND;
                    memset (CSQ_buffer,0x00,sizeof(CSQ_buffer));
                    Find_string((char*)Lpuart1type.Lpuart1RecBuff, "\r\n", "\r\n", Imei_buffer);
                    printf("Imei_buffer=%s\r\n",Imei_buffer);
                    break;
                }
                else if(ATCurrentCmdNum == AT_CSQ_2)	//如果AT指令为查询CSQ
                {
                    ATCurrentCmdNum += 1;
                    ATNextCmdNum = ATCurrentCmdNum+1;
                    CAT1_TaskStatus = CAT1_SEND;
                    memset(CSQ_buffer,0x00,sizeof(CSQ_buffer));
                    Find_string((char*)Lpuart1type.Lpuart1RecBuff, " ", ",", CSQ_buffer);
                    printf("CSQ_buffer=%s\r\n",CSQ_buffer);
                    break;
                }
                else if(ATCurrentCmdNum == AT_HTTPREAD_1)	//如果AT指令为查询版本号
                {
                    ATCurrentCmdNum += 1;
                    ATNextCmdNum = ATCurrentCmdNum+1;
                    CAT1_TaskStatus = CAT1_SEND;
                    memset(Version_buffer,0x00,sizeof(Version_buffer));
                    Find_string((char*)Lpuart1type.Lpuart1RecBuff, "{", "}", Version_buffer);
                    printf("Version_buffer=%s\r\n",Version_buffer);
                    if(strcmp(Version_buffer,"\"version\":\"3.0.0\"") == 0)
                    {
                        printf("硬件版本和云端版本一致,无需升级!\r\n");
                    }
                    else
                    {
                        Update_Task();
                    }
                    break;
                }
                else if(ATCurrentCmdNum == AT_HTTPACTION_2)	//如果AT指令为读取BIN文件长度
                {
                    ATCurrentCmdNum += 1;
                    ATNextCmdNum = ATCurrentCmdNum+1;
                    CAT1_TaskStatus = CAT1_SEND;
                    memset (Bin_len,0x00,sizeof(Bin_len));
                    Find_string((char*)Lpuart1type.Lpuart1RecBuff, "200,", "\r\n", Bin_len);
                    printf("Bin_len=%s\r\n",Bin_len);
                    break;
                }
                else if(ATCurrentCmdNum == AT_HTTPREAD_2)	//如果AT指令为下载BIN文件
                {

                    int len = 0;
                    long compare_len = 0;

                    memset(Msg_Len,0x00,sizeof(Msg_Len));
                    Find_string((char*)Lpuart1type.Lpuart1RecBuff, "DATA,", "\r\n", Msg_Len);
                    compare_len = atoi(Msg_Len);
                    printf("Find_Buf:%lu\r\n",compare_len);
                    if(Erase_flag == 1)	//仅仅开始是擦除flash一次
                    {
                        Erase_flag = 0;
                        Erase_page(Application_2_Addr, 45); //擦除45页  90K
                    }
                    len = strstr((char *)Lpuart1type.Lpuart1RecBuff, Msg_Len) - (char*)Lpuart1type.Lpuart1RecBuff + strlen(Msg_Len) + 2;
                    printf("offset address is: %d\r\n",len);
									if(compare_len == 1024)
									{
											memset (Bin_len,0x00,sizeof(Bin_len));
											for(long b = 0; b < 1024; b++)
											{
													Bin_buffer[b] = Lpuart1type.Lpuart1RecBuff[len+b];
											}
											/* 接下来将固件写进flash内 */
											printf("烧录第%d包...................\r\n",addr_count);
											WriteFlash((Application_2_Addr+(addr_count)*1024), (uint8_t *)(&Bin_buffer[0]), 1024);
											addr_count++;
											ATNextCmdNum = ATCurrentCmdNum;
											CAT1_TaskStatus = CAT1_SEND;
									}
									else if(compare_len < 1024)
									{
											memset (Bin_len,0x00,sizeof(Bin_len));
											for(int b = 0; b < 1024; b++)
											{
													Bin_buffer[b] = Lpuart1type.Lpuart1RecBuff[len+b];
											}
											/* 接下来将固件写进flash内  */

											printf("烧录第%d包...................\r\n",addr_count);
											WriteFlash((Application_2_Addr+(addr_count)*1024), (uint8_t *)(&Bin_buffer[0]), compare_len);
											addr_count = 0;
											Erase_flag =1;
											reboot_flag = 1;
											ATCurrentCmdNum += 1;
											ATNextCmdNum = ATCurrentCmdNum+1;
											CAT1_TaskStatus = CAT1_SEND;
									}
                    break;
                }
                else if(ATCurrentCmdNum == AT_CMQTTPUB)	//表示发送msg成功
                {
                    CAT1_TaskStatus = CAT1_ACCESS;
                    break;
                }
                else if(ATCurrentCmdNum == AT_HTTPTERM_1)	//表示查询版本号成功
                {
                    CAT1_TaskStatus = CAT1_ACCESS;
                    break;
                }
                else if(ATCurrentCmdNum == AT_HTTPTERM_2)	//表示下载BIN文件成功
                {
                    CAT1_TaskStatus = CAT1_ACCESS;
                    break;
                }
                else
                {
                    ATCurrentCmdNum += 1;
                    ATNextCmdNum = ATCurrentCmdNum+1;
                    CAT1_TaskStatus = CAT1_SEND;
                    break;
                }
            }
            else if(CompareTime(&TimeCAT1))//表示发送超时
            {
                printf("TimeOut:%s\r\n",Lpuart1type.Lpuart1RecBuff);
                ATCmds[ATRecCmdNum].ATStatus = TIME_OUT;
                if(CurrentRty > 0)
                {
                    CurrentRty--;
                    ATNextCmdNum = ATCurrentCmdNum;
                    CAT1_TaskStatus = CAT1_SEND;
                    break;
                }
                else
                {
                    CAT1_Init();
                    return;
                }
            }
            return;
        case CAT1_ACCESS:	//成功态
            CAT1_TaskStatus = CAT1_IDIE;
            break;
        default:
            return;
        }
    }
}

设置按键1和按键2 分别是升级和查询版本号。

/* 外部中断触发 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

    /* 判断哪个引脚触发了中断 */
    switch(GPIO_Pin)
    {
    case GPIO_PIN_2:
        ExitFlag = 1;
        break;
    case GPIO_PIN_3:
        ExitFlag = 2;
        break;
    default:
        break;
    }
}

void KEY_Task(void)
{
    if(ExitFlag == 1)
    {
        ExitFlag = 0;
        Update_Task();
    }
    else if(ExitFlag == 2)
    {
        ExitFlag = 0;
        Get_Version();
    }
}

下面是升级部分的具体代码以及流程图如下。

4G模块怎么装到CENTOS系统 4g模块升级_指令集_11

else if(ATCurrentCmdNum == AT_HTTPREAD_2)	//如果AT指令为下载BIN文件
{

    int len = 0;
    long compare_len = 0;

    memset(Msg_Len,0x00,sizeof(Msg_Len));
    Find_string((char*)Lpuart1type.Lpuart1RecBuff, "DATA,", "\r\n", Msg_Len);
    compare_len = atoi(Msg_Len);
    printf("Find_Buf:%lu\r\n",compare_len);
    if(Erase_flag == 1)	//仅仅开始是擦除flash一次
    {
        Erase_flag = 0;
        Erase_page(Application_2_Addr, 45); //擦除45页  90K
    }
    len = strstr((char *)Lpuart1type.Lpuart1RecBuff, Msg_Len) - (char*)Lpuart1type.Lpuart1RecBuff + strlen(Msg_Len) + 2;
    printf("offset address is: %d\r\n",len);
    if(compare_len == 1024)
    {
        memset (Bin_len,0x00,sizeof(Bin_len));
        for(long b = 0; b < 1024; b++)
        {
            Bin_buffer[b] = Lpuart1type.Lpuart1RecBuff[len+b];
        }
        /* 接下来将固件写进flash内 */
        printf("烧录第%d包...................\r\n",addr_count);
        WriteFlash((Application_2_Addr+(addr_count)*1024), (uint8_t *)(&Bin_buffer[0]), 1024);
        addr_count++;
        ATNextCmdNum = ATCurrentCmdNum;
        CAT1_TaskStatus = CAT1_SEND;
    }
    else if(compare_len < 1024)
    {
        memset (Bin_len,0x00,sizeof(Bin_len));
        for(int b = 0; b < 1024; b++)
        {
            Bin_buffer[b] = Lpuart1type.Lpuart1RecBuff[len+b];
        }
        /* 接下来将固件写进flash内  */

        printf("烧录第%d包...................\r\n",addr_count);
        WriteFlash((Application_2_Addr+(addr_count)*1024), (uint8_t *)(&Bin_buffer[0]), compare_len);
        addr_count = 0;
        Erase_flag =1;
        reboot_flag = 1;
        ATCurrentCmdNum += 1;
        ATNextCmdNum = ATCurrentCmdNum+1;
        CAT1_TaskStatus = CAT1_SEND;
    }
}

测试步骤

步骤1:通过ST-Link将BOOT刷进单片机

步骤2:通过ST-Link将APP1刷进单片机,刷完程序,单片机会自动重启并上报CSQ的值,如下图所示。

4G模块怎么装到CENTOS系统 4g模块升级_4G模块怎么装到CENTOS系统_12

步骤3:复制一份APP1的代码,重命名为APP2,将上报信号的CSQ改成BSQ,如下所示。

sprintf(message_buffer,"{\"BSQ\":%s}",CSQ_buffer);

步骤4:将APP2上传到OTA平台上
步骤4:按下按键2,查询版本号是否一致
步骤5:按下按键1,升级程序。通过串口信息判断是否升级完成,如果打印以下信息就表示升级完成了。(通过4G模组下载BIN文件时显示下载数据有乱码是正常现象,因为BIN文件时二进制。)

[16:58:39.108]收←◆
当前命令码:21
send:AT+HTTPINIT
DMA_len:6
收到数据:
OK
当前码:21

当前命令码:22
send:AT+HTTPPARA="URL","http://47.98.248.24:8888/download1?device_id=123456&version=3.0.0"
收到数据:
OK
当前码:22

当前命令码:23
send:AT+HTTPACTION=0
DMA_len:6
收到数据:
OK

[16:58:39.671]收←◆DMA_len:28
收到数据:
+HTTPACTION: 0,200,15364
当前码:23
Bin_len=15364

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:39.776]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
x当前码:24
Find_Buf:1024

[16:58:41.432]收←◆erase success
offset address is: 30
烧录第0包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:41.548]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
??当前码:24
Find_Buf:1024
offset address is: 30
烧录第1包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:41.670]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
0?齥Kw?3wF当前码:24
Find_Buf:1024
offset address is: 30
烧录第2包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:41.793]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
`)?)?hA魛Q`h!魛Q`hA魛a`当前码:24
Find_Buf:1024
offset address is: 30
烧录第3包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:41.918]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
旞%`当前码:24
Find_Buf:1024
offset address is: 30
烧录第4包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.040]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
朇_陥(当前码:24
Find_Buf:1024
offset address is: 30
烧录第5包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.162]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
€1砒?砒惖鼻奥耄?4
Find_Buf:1024
offset address is: 30
烧录第6包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.285]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
醝 ?@@? h`???当前码:24
Find_Buf:1024
offset address is: 30
烧录第7包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.409]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
#?h€ ?h@饊p(`鑘@饊p鑐??F??鼻奥耄?4
Find_Buf:1024
offset address is: 30
烧录第8包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.533]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
a F??hi蒀I	粤h蒀I詏餈a F当前码:24
Find_Buf:1024
offset address is: 30
烧录第9包...................

当前命令码:24
send:AT+HTTPREAD=0,1024
收到数据:
OK

[16:58:42.658]收←◆DMA_len:1063
收到数据:
+HTTPREAD: DATA,1024
觖8? 鄃匄pP  `g p絼鴓P hhA魛q` h乭A?乣 h乭A餈乣当前码:24
Find_Buf:1024
offset address is: 24
烧录第10包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.784]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
鄅ih荔@圔??(?(?(??h??hI当前码:24
Find_Buf:1024
offset address is: 30
烧录第11包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:42.910]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
奰慀$I?hJhl"魛CJ`l滨€?hJhCl"衾CJ`慀$	?hJh€l"舻鼻奥耄?4
Find_Buf:1024
offset address is: 30
烧录第12包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:43.038]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
 h纈6甑鼻奥耄?4
Find_Buf:1024
offset address is: 30
烧录第13包...................

当前命令码:24
send:AT+HTTPREAD=0,1024

[16:58:43.161]收←◆DMA_len:1069
收到数据:
OK

+HTTPREAD: DATA,1024
当前码:24
Find_Buf:1024
offset address is: 30
烧录第14包...................

当前命令码:24
send:AT+HTTPREAD=0,1024
DMA_len:31
收到数据:
OK

+HTTPREAD: DATA,4
	=当前码:24
Find_Buf:4
offset address is: 27
烧录第15包...................

当前命令码:25
send:AT+HTTPTERM

***********************************
*                                 *
*           BootLoader            *
*                                 *
***********************************
> Choose a startup method......
> Start update......
> Start erase des flash......
Bank_1
识别的初始页数:30  共删除45页

[16:58:44.228]收←◆Erase sucessfully!
> Erase des flash sucessfully......
> Start copy......

[16:58:45.277]收←◆> Copy sucessfully......
> Start erase src flash......
Bank_1
识别的初始页数:75  共删除45页

[16:58:46.275]收←◆Erase sucessfully!
> Erase src flash sucessfully......
> Update sucessfully......
> Start up......

system init is complect!

[16:58:46.791]收←◆wait 14s for 4G power on !

6,升级成功需要手动断电重启。(因为程序里没写重启4G模组部分的驱动。如果不重启单片机和4G交互数据会出错。后期读者可以在开机时加上复位的AT指令来解决。)

7,重启后等待4G模组组网。然后就会发现报的数据变成了BSQ,如下图所示,表示升级成功。

4G模块怎么装到CENTOS系统 4g模块升级_4G_13

注意事项

  这只是个OTA升级的demo版程序。可以借鉴,但不要拿来主义。就不能重启这一个问题在项目上就是致命的。我写这个笔记的主要目的还是记录下OTA升级的一套完整流程,以防后期自己忘记了。