找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10113|回复: 30
收起左侧

一种利用串口51单片机远程升级 OTA

  [复制链接]
ID:450849 发表于 2020-2-15 18:29 | 显示全部楼层 |阅读模式
      想想来这个论坛挺久了,也在这学了不少东西,本着回馈论坛,回馈网友的心态,发一篇关于OTA的贴,不喜勿喷,随着现在科技的发展,市面上出现很多带wifi,蓝牙等智能产品,为满足人们对产品可以不断完善,诞生了这种远程升级的技术。      在此之前呢,做过一个stm32远程升级的项目,这种片子的代码地址偏移性很好,load程序和应用程序划分好就可以,后来就想51这种便宜的mcu,能不能也实现这个功能呢,这就有了这次的实验。
       废话不多说,先说说原理,OTA主要就三部分,一个是load程序,一个是应用程序,还有带升级的程序,三个分别存储在不同地址,我以flash 32K为例。如下图

捕获.PNG
为什么要这样划分地址呢。主要是因为51单片机的中断地址不能发生偏移(至少我不知道怎么偏移),所以我运行的程序必须在起始地址0x0.吧bootload程序放在了0x6000的位置。

     1,bootload程序设计,程序功能主要是判断有没有升级标志,有升级标志把APP2的文件拷贝到APP1,然后跳转到app1位置运行。如果没有升级标志直接跳转到app1.
    keil中设置1,BL51 locate 启动文件 ?C_C51STARTUP(0x6100) 需要特殊放置,这样才能保证每次启动后跳转的位置准确;
            设置2,target  EProm 0x6000;

load_keil_set2.PNG
load_keil_set.PNG


这样编译出来的 hex文件  就是下面这个样子。

捕获2.PNG


这个时候bootload程序算设计好了,可以直接烧录到MCU中。

2,应用程序 APP1设计,程序功能主要实现我们自己产品功能,以及接收保存远程发过来的程序。
keil中设置1,BL51 locate 启动文件 ?C_C51STARTUP(0x1000) 需要特殊放置,这样才能保证每次启动后跳转的位置准确;
         设置2,target  EProm 0x0;
捕获3.PNG



捕获4.PNG


这样就可以确保每次程序跳转正确。关键的在这里,因为每次要先运行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#写了一个小工具和一个模拟云服务器发送的 工具。
捕获5.PNG

捕获6.PNG


这样就完成了51 远程升级的全部工作。不喜勿喷,附上代码仅供学习参考。

//-------------------------------bootload----------------------------------------
#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"
#include "stdio.h"

#define USAR_APP_ADDR   0x1000

typedef void (*boot_fun)(void) ;//= USAR_APP_ADDR;


int cnt_500ms;
char goto_flag;
int i;
char str[10];

char temp1,temp2;

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);
        }  
    }
}



全部资料51hei下载地址:

bin+fifo.zip (50.72 KB, 下载次数: 141)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:695525 发表于 2020-2-20 11:34 | 显示全部楼层
不错,会玩!
回复

使用道具 举报

ID:450849 发表于 2020-2-21 08:09 | 显示全部楼层

过奖了
回复

使用道具 举报

ID:696374 发表于 2020-2-22 10:29 | 显示全部楼层
编译bootload时,
Memory Model选Large: variables in XDATA有何讲究,用Small可以吗?
不勾选Use On-chip ROM有何讲究?

编译App1时,
App1的起点放在0x1000有何讲究?可以放在其它处,例如0x100吗?
回复

使用道具 举报

ID:450849 发表于 2020-2-23 09:37 | 显示全部楼层
xyz_123 发表于 2020-2-22 10:29
编译bootload时,
Memory Model选Large: variables in XDATA有何讲究,用Small可以吗?
不勾选Use On-chi ...

Small:变量存储在内部ram里;
Large:变量存储在外部Ram里,使用16位间接寻址;所以程序大我们一般选 large
app1可以放置再0x100,这个地址避开中断向量就可以,个人愚见。
回复

使用道具 举报

ID:695961 发表于 2020-2-23 13:38 | 显示全部楼层
一直有一个疑问想问一下楼主

就是51单片机在运行的过程中可以读写程序区的flash吗?
回复

使用道具 举报

ID:450849 发表于 2020-2-23 17:04 | 显示全部楼层
chinayanhui 发表于 2020-2-23 13:38
一直有一个疑问想问一下楼主

就是51单片机在运行的过程中可以读写程序区的flash吗?

51系列有很多品牌,具体要看规格书
回复

使用道具 举报

ID:163391 发表于 2020-2-23 18:53 | 显示全部楼层
这个有意思
回复

使用道具 举报

ID:527324 发表于 2020-2-23 22:13 来自手机 | 显示全部楼层
正好需要!!!
回复

使用道具 举报

ID:450849 发表于 2020-2-28 00:02 | 显示全部楼层
百度 “51 OTA”,竟然发现有被复制到别人的论坛。
回复

使用道具 举报

ID:699613 发表于 2020-2-28 15:58 | 显示全部楼层
楼主真的很用心呀
回复

使用道具 举报

ID:94449 发表于 2020-2-28 21:51 | 显示全部楼层
不错资料,学习下。
回复

使用道具 举报

ID:731155 发表于 2020-5-12 23:07 | 显示全部楼层
51也能串口升级,会玩
回复

使用道具 举报

ID:450849 发表于 2020-7-24 20:41 来自手机 | 显示全部楼层
hei51com 发表于 2020-5-12 23:07
51也能串口升级,会玩

多谢夸奖
回复

使用道具 举报

ID:385637 发表于 2020-7-25 18:32 | 显示全部楼层
高手,这是高手
回复

使用道具 举报

ID:246441 发表于 2020-12-3 19:20 | 显示全部楼层
高手啊,启动跳转改.A51好像可以跳吧
回复

使用道具 举报

ID:115923 发表于 2020-12-5 10:11 | 显示全部楼层
C51  代码不全, 无法实现楼主 说的 功能,   不信 , 你们 试一试 ,
楼主 ,也就是 一个 方向 ,  方案,  想专研的人 可以考虑 安装这个思路去实现,  但是不一定会成功,  说了
这只是方案!
回复

使用道具 举报

ID:246441 发表于 2020-12-27 02:20 | 显示全部楼层
楼上试,代码不全嘛,我没有51单片机,有的话我也来试了
回复

使用道具 举报

ID:156923 发表于 2021-6-30 10:21 | 显示全部楼层
存在风险哦
回复

使用道具 举报

ID:450849 发表于 2021-7-1 09:10 来自手机 | 显示全部楼层
yuanyijie 发表于 2021-6-30 10:21
存在风险哦

什么风险呢?
回复

使用道具 举报

ID:156923 发表于 2021-7-3 09:13 | 显示全部楼层

从APP2拷贝数据到APP1的时候,刚好擦除了扇区0而还没写入时,突然掉电了,怎么能跳转到BOOTLOAD(0X6000)程序呢位置呢?
回复

使用道具 举报

ID:156923 发表于 2021-7-3 09:18 | 显示全部楼层
                INTERRUPT_OFFSET EQU 0X0600 ;中断偏移量


                CSEG    AT      0X0000;绝对地址
                               
?C_STARTUP:     LJMP    STARTUP1

                                ;中断向量地址
                                ORG      0X0003;相对地址(偏移地址)
                                LJMP     INTERRUPT_OFFSET + $    ;INT0中断
                               
                                ORG      0X000B       
                                LJMP     INTERRUPT_OFFSET + $         ;T0中断
                               
                                ORG      0X0013  
                                LJMP     INTERRUPT_OFFSET + $    ;INT1中断
                               
                                ORG      0X001B  
                                LJMP     INTERRUPT_OFFSET + $    ;T1中断
                               
                                ORG      0X0023          
                                LJMP     INTERRUPT_OFFSET + $         ;UART1中断
                               
                                ORG      0X002B
                                LJMP     INTERRUPT_OFFSET + $    ;WDT中断
                               
                                ORG      0X0033
                                LJMP     INTERRUPT_OFFSET + $    ;LVD中断
                               
                                ORG      0X003B
                                LJMP     INTERRUPT_OFFSET + $    ;UART2中断
                               
                                ORG      0X0043
                                LJMP     INTERRUPT_OFFSET + $         ;SPI中断
                               
                                ORG      0X004B
                                LJMP     INTERRUPT_OFFSET + $    ;IIC中断
                               
                                ORG      0X0053
                                LJMP     INTERRUPT_OFFSET + $    ;T3中断
                               
                                ORG      0X005B
                                LJMP     INTERRUPT_OFFSET + $    ;T4中断
                               
                                ORG      0X0063
                                LJMP     INTERRUPT_OFFSET + $    ;PWM中断
                               
                                ORG      0X006B
                                LJMP     INTERRUPT_OFFSET + $    ;T5中断
                               
                                ORG      0X0073
                                LJMP     INTERRUPT_OFFSET + $    ;CTK中断
                               
                                ORG      0X007B
                                LJMP     INTERRUPT_OFFSET + $    ;ADC中断
                               
                                ORG      0X0083
                                LJMP     INTERRUPT_OFFSET + $    ;INT2-INT7中断
                               
                                ORG      0X008B
                                LJMP     INTERRUPT_OFFSET + $    ;INT8-17中断

                                ORG      0X0093
                                LJMP     INTERRUPT_OFFSET + $    ;P2INT中断
                               
                                RSEG    ?C_C51STARTUP;自动分配地址
               
                                ;CSEG    AT      0X0700;指定APP起始地址


我做的是把BOOTLOAD程序放在0X0000-0X0600处的,使用XMODEM协议进行下载
回复

使用道具 举报

ID:450849 发表于 2021-7-3 16:47 来自手机 | 显示全部楼层
yuanyijie 发表于 2021-7-3 09:13
从APP2拷贝数据到APP1的时候,刚好擦除了扇区0而还没写入时,突然掉电了,怎么能跳转到BOOTLOAD(0X6000)程序 ...

有道理
回复

使用道具 举报

ID:450849 发表于 2021-7-3 16:47 来自手机 | 显示全部楼层
yuanyijie 发表于 2021-7-3 09:18
INTERRUPT_OFFSET EQU 0X0600 ;中断偏移量



有道理,受教了
回复

使用道具 举报

ID:163099 发表于 2021-10-25 13:03 来自手机 | 显示全部楼层
请问怎么read和write单片机flash
回复

使用道具 举报

ID:981261 发表于 2021-11-15 19:45 | 显示全部楼层
yuanyijie 发表于 2021-7-3 09:18
INTERRUPT_OFFSET EQU 0X0600 ;中断偏移量

你好!我正在自学做一个51单片机用1K xmodem升级的项目,请问可以请教源码吗?谢谢!
回复

使用道具 举报

ID:1047140 发表于 2022-10-10 14:19 | 显示全部楼层
你好 远程升级那部分有完整的代码吗  能分享下吗
回复

使用道具 举报

ID:539106 发表于 2022-10-10 14:31 | 显示全部楼层
have a look
回复

使用道具 举报

ID:526108 发表于 2022-10-10 20:54 | 显示全部楼层
我也做过IAP51单片机在线升级功能,大致国过程和你的差不多,但比你的简单
我的项目比较大,需要用到64KROM,所以外置EEPROM,有更新先下载到EEPROM并验证一次
ROM划分两部分APP区(地址从0x0000开始)和UPDATE区,UPDATE只负责把EEPROM中的新APP程序写入单片机APP区,验证升级和程序下载命令等都在APP中,这样就能随时更新下载验证指令了。
UPDATE区程序需要偏置到单片机FLASH末尾处,同时APP区也备份UPDATE程序,用来验证是否正确。需要升级时使用指针函数跳转到UPDATE区,升级完单片机复位即可。
回复

使用道具 举报

ID:1047140 发表于 2022-10-27 09:33 | 显示全部楼层
yuanyijie 发表于 2021-7-3 09:18
INTERRUPT_OFFSET EQU 0X0600 ;中断偏移量

你好 能否请教下怎么做 最近在做51单片机升级
回复

使用道具 举报

ID:961114 发表于 2022-10-27 10:30 | 显示全部楼层
hongshi123 发表于 2022-10-27 09:33
你好 能否请教下怎么做 最近在做51单片机升级

新站STCAI
还是从 STC-ISP V6.90T 以上版本的 ISP烧录/辅助开发工具包一体化软件的//资料下载// 专栏 中下载 开源的 C语言代码, 开源的原理图

51hei截图20221027102901.jpg
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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