一种利用串口51单片机远程升级 OTA
资料下载地址:一种利用串口51单片机远程升级 OTA
OTA主要就三部分,一个是load程序,一个是应用程序,还有带升级的程序,三个分别存储在不同地址,我以flash 32K为例。如下图
为什么要这样划分地址呢。主要是因为51单片机的中断地址不能发生偏移(至少我不知道怎么偏移),所以我运行的程序必须在起始地址0x0.吧bootload程序放在了0x6000的位置。
1,bootload程序设计,程序功能主要是判断有没有升级标志,有升级标志把APP2的文件拷贝到APP1,然后跳转到app1位置运行。如果没有升级标志直接跳转到app1.
keil中设置1,BL51 locate 启动文件 ?C_C51STARTUP(0x6100) 需要特殊放置,这样才能保证每次启动后跳转的位置准确;
设置2,target EProm 0x6000;
这样编译出来的 hex文件 就是下面这个样子。
这个时候bootload程序算设计好了,可以直接烧录到MCU中。
2,应用程序 APP1设计,程序功能主要实现我们自己产品功能,以及接收保存远程发过来的程序。
keil中设置1,BL51 locate 启动文件 ?C_C51STARTUP(0x1000) 需要特殊放置,这样才能保证每次启动后跳转的位置准确;
设置2,target EProm 0x0;
这样就可以确保每次程序跳转正确。关键的在这里,因为每次要先运行bootload 所以需要在0x0 位置 跳转到bootload地址是0x6100,再有boot程序跳转到我们的0x1000 这样成正常运行,看起来很复杂,其中只有两个关键地址,0-->0x6100 -->0x1000 , 就这两步骤。
3,然后再来说说升级文件的打包制作,首先呢需要把 02 10 00 改成 02 61 00.
在bin文件前面插入256个字节,升级文件信息。
a,0-3字节 文件版本号
b 4-7字节 文件长度
c 8-11字节 文件类型
d 12-13字节 文件的CRC校验(校验只对程序文件,不包括插入的信息)
e 10-255 0xff
我这里用C#写了一个小工具和一个模拟云服务器发送的 工具。
void main(void)
{system_clock_set(0);_hal_gpio_init();_MCU_TIMER_Init();_mcu_uart1_init();EA = 0;uart1_send("boot run .. \r\n");uart1_send("boot addr 0x6000 main addr 0x6100..\r\n");uart1_send(__DATE__);uart1_send("\r\ngo to app run addr:0x1000 \r\n");uart1_send("-----------------------------------\r\n");// Ssp_WriteByte(EEPOM_ADDR,0xaa,mFLASH);i = Read_FlashByte(EEPOM_ADDR);//检查是否有升级if(i==0xaa){uart1_send("Updata......\r\n");for( i=0;i<10;i++){Ssp_EraseBlock(APP_ADDR + i*0x400,mFLASH);}uart1_send("EraseBlock OK \r\n");for(i=0;i<0x2800;i++){Ssp_WriteByte(i,Read_FlashByte(APP_BACK_ADDR+i),mFLASH);}uart1_send("WriteBlock OK \r\n");Ssp_EraseBlock(EEPOM_ADDR,mFLASH);Ssp_WriteByte(EEPOM_ADDR,0,mFLASH);for(i=0;i<0x2800;i++){temp1 = Read_FlashByte(APP_BACK_ADDR+i);temp2 = Read_FlashByte(APP_ADDR+i);if( temp1 != temp2)//APP_ADDR{uart1_send("index: ");sprintf(str,"%d",i);uart1_send(str);uart1_send("Updata Error.....\r\n");while(1);}}}((void(code*)(void))USAR_APP_ADDR)();while(1);}//-----------------------app1---------------------------------------------------#include "hal_clock.h"
#include "hal_gpio.h"
#include "hal_pwm.h"
#include "hal_timer.h"
#include "hal_interrupt.h"
#include "hal_adc.h"
#include "hal_uart.h"
#include "WIFI_JD780.h"
#include "IR.h"
#include "Buzz.h"
#include "hal_ssp.h"//0x0000-0x27ff app main 0x1000 10K
//0x2800-0x4fff app-back 10K
//0x5000-0x5fff eerom 2 k
//0x6000-0x7fff boot main 0x6100 8 k//?C_C51STARTUP(0x1000)code unsigned char mcu_sf_ver[5] ="1.09";
code unsigned char mcu_hw_ver[5] ="1.00";int send_time;void main(void)
{system_clock_set(0);_hal_gpio_init();_MCU_PWM_Init();_MCU_TIMER_Init();_mcu_uart1_init();_MCU_IRQ_Init();_wifi_init();IR_ExtInit();_mcu_adc_init();BUZ_Init();BUZ_PLAY_OFF();EA = 0;uart1_send("-----------------------------------\r\n");uart1_send("welcome to app world ..............\r\n");uart1_send(__DATE__);uart1_send("-----------------------------------\r\n");uart1_send("software ver :");uart1_send(mcu_sf_ver);uart1_send("\r\n");EA = 1;while(1){_MCU_TIMER_Driver();if(F_10ms){F_10ms =0; IR_Process();_user_wifi_data_drives();if(IR_KeyCode.bits.Power){IR_KeyCode.bits.Power = 0;BUZ_PLAY_KEY();//SBUF = 'C';SBUF = Read_FlashByte(0x2800);Ssp_EraseBlock(0x2800,mFLASH);SBUF = Read_FlashByte(0x2800);}if(IR_KeyCode.bits.Auto){IR_KeyCode.bits.Auto = 0;BUZ_PLAY_KEY(); SBUF = 'W';//ssp_write_flash_nbyte(APP_BACK_ADDR,"1234567890",10);//ssp_write_flash_nbyte(APP_BACK_ADDR+20,"1234567890",10);}BUZ_Run();//ADC_GetAD_12bit(1);} }
}