本文参考了STC的官方例程,根据官方例程来进行讲解IAP的详细操作

一、内部FLASH的规划

STC不同型号的单片机,内部FLASH的规划大不相同,详细的使用规格书都有介绍,以下我只截图规格书当中我需要的部分进行讲解

1、首先是规格书当中STC8H8K64单片机的内部使用空间划分

FLASH 空间中,从地址 0000H 开始的连续 62.5K 字节的空间为用户程序区。当满足特定的下载条 件时,需要用户将 PC 跳转到用户 ISP 程序区,此时可对用户程序区进行擦除和改写,以达到更新用户 程序的目的。(只有0.5K的ISP空间所以实际使用代码是参考了官方例程的)

二、程序的基本框架

实际使用的程序框架如图所示:

三、复位程序

以下是官方代码

#include "reg51.h"typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef void (* FARPROC)(BYTE *);     #define FOSC 22118400L                  //系统时钟频率
#define BAUD (65536 - FOSC/4/115200)     //定义串口波特率/* 定义串口相关SFR */
sfr AUXR = 0x8E;                        //波特率发生器控制寄存器
sfr BRT = 0x9C;                         //波特率发生器定时器sfr T2H = 0xd6;
sfr T2L = 0xd7;void (*Isp_Check)(BYTE *) = 0xfa00;      //定义指针函数
BYTE cnt7f;                             //Isp_Check内部使用的变量void uart() interrupt 4 using 1         //串口中断服务程序
{if (TI) TI = 0;                     //发送完成中断if (RI)                             //接收完成中断{Isp_Check(&cnt7f);              //ISP检测RI = 0;                         //清接收完成标志}
}void main()
{SCON = (SCON & 0x3f) | 0x50; T2L  = BAUD;T2H  = BAUD>>8;AUXR |= 0x15;ES = 1;                             //使能串口中断EA = 1;                             //打开全局中断开关while (1){P0++;}
}

官方代码复位的主要用到以下三段代码用来复位

typedef void (* FARPROC)(BYTE *);

void (*Isp_Check)(BYTE *) = 0xFA00;      //定义指针函数

这是重定义了一下指针函数使其指向地址0XFA00,也就是用户ISP区,实际使用的时候只需要满足条件后调用

Isp_Check(&cnt7f);

即可进入用户ISP区,这里操作较为简单不做其他介绍

PS:规格书上也标注了调用   IAP_CONTR=0x60 即可软件复位,然后通过ISP的方式进行升级,这种也是可以的,就和重新上电烧程序的方式一致,这里不多做介绍,感兴趣的可以去官网看看有例程介绍

四、IAP升级代码

以下是官方例程,可以根据自己使用来修改协议(笔者是自己更改了串口、协议来进行升级,这个看个人需求)

#include "reg51.h"
#include "absacc.h"/*定义常数*/#define FOSC 22118400L                  //系统时钟频率
#define BAUD (65536 - (FOSC/4/115200))    //定义串口波特率#define MAX_SIZE 118                    //用户程序最大的可用扇区数#define ENABLE_IAP 0x80               //使能IAP功能/* 定义串口相关SFR */
sfr AUXR        = 0x8E;                  //波特率发生器控制寄存器
sfr WDT_CONTR   = 0xC1;                 //看门狗控制寄存器
sfr IAP_DATA    = 0xC2;                 //IAP数据寄存器
sfr IAP_ADDRH   = 0xC3;                 //IAP高地址寄存器
sfr IAP_ADDRL   = 0xC4;                 //IAP低地址寄存器
sfr IAP_CMD   = 0xC5;                 //IAP命令寄存器
sfr IAP_TRIG    = 0xC6;                 //IAP命令触发寄存器
sfr IAP_CONTR   = 0xC7;                 //IAP控制寄存器
sfr IAP_TPS   = 0xF5;                 //IAP等待时间控制寄存器sfr T2H = 0xd6;
sfr T2L = 0xd7;
//?PR?_ISP_CHECK?ISP(0xEE00),?PR?ISP_SOFTRESET?ISP(0xEF38),?PR?_ISP_SENDUART?ISP(0xEF3C),?PR?ISP_RECVUART?ISP(0xEF49),?PR?_ISP_RECVBLOCK?ISP(0xEF5B),?C?LIB_CODE(0xEF72)typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef struct
{BYTE cmd;WORD addr;WORD len;BYTE chk;
} CBW;void Isp_Check(BYTE *p);
BYTE Isp_RecvUart();
void Isp_RecvBlock(BYTE *p, BYTE n);
void Isp_SendUart(BYTE dat);
void Isp_SoftReset();BYTE cnt7f;                             //Isp_Check内部使用的变量,接收7F的计数器,当连续接收到16次7F后进入ISP下载模式
CBW cbw;                                //串口命令块
BYTE sum;                               //校验和变量
BYTE buf[64];                           //数据缓冲区/*------------------------------------------------串口中断服务程序
------------------------------------------------*/
void uart() interrupt 4
{if (TI) TI = 0;                     //发送完成中断if (RI)                             //接收完成中断{Isp_Check(&cnt7f);              //ISP检测RI = 0;                         //清接收完成标志}
}void main()
{SCON = (SCON & 0x3f) | 0x50; T2L  = BAUD;T2H  = BAUD>>8;AUXR |= 0x15;ES = 1;                             //使能串口中断EA = 1;                             //打开全局中断开关while (1);
}/*------------------------------------------------串口ISP命令序列检测模块
------------------------------------------------*/
void Isp_Check(BYTE *p)
{BYTE i;WORD j;if (SBUF != 0x7f)                   //检测串口数据是否为7F{*p = 0;                         //若不是7F,则清7F计数值}else{(*p)++;                         //若是7F,则7F计数值+1if (*p >= 16)                   //判断7F是否已连续接收到16次{                               //若>=16次,则进入ISP下载模式IE = 0;                     //关闭所有中断PSW = 0;                    //ISP模块使用第0组寄存器SP = 0x5f;                  //重置ISP模块的堆栈指针RI = 0;                     //清除串口接收标志TI = 1;                     //置串口发送标志Isp_SendUart(0x5a);         //返回5A 69到PC,表示ISP模块已准备就绪Isp_SendUart(0x69);while (1)                   //ISP下载模式,主循环{sum = 0;                //清校验和值if ((Isp_RecvUart() == 0x5a) &&     //判断命令头是否为5A,69(Isp_RecvUart() == 0x69)){Isp_RecvBlock((BYTE *)&cbw, 6); //接收6字节的命令序列if (sum != 0)                   //判断命令序列是否正确{Isp_SoftReset();            //若命令出错,则程序复位}switch (cbw.cmd){case 0:                         //0号命令为擦除命令IAP_ADDRL = 0;              //从第0扇区开始擦除IAP_ADDRH = 0;IAP_CONTR = ENABLE_IAP;     //使能IAP功能IAP_TPS = 23;IAP_CMD = 3;                //擦除命令if (cbw.len > MAX_SIZE)     //判断擦除扇区数是否超出范围{cbw.len = MAX_SIZE;}while (cbw.len--)           //判断是否擦除完成{WDT_CONTR = 0x17;       //清看门狗IAP_TRIG = 0x5a;        //触发ISP命令IAP_TRIG = 0xa5;IAP_ADDRH += 2;         //目标地址+512}Isp_SendUart(0);            //正确返回break;case 1:                         //1号命令为编程命令sum = 0;                    //清除校验和值Isp_RecvBlock(buf, 64);     //接收64字节的编程数据Isp_RecvUart();             //接收校验和if (sum != 0)               //判断数据是否正确{Isp_SoftReset();        //若数据出错,则程序复位}IAP_CONTR = ENABLE_IAP;     //使能IAP功能IAP_TPS = 23;IAP_CMD = 2;                //编程命令j = cbw.addr;               //编程目标地址for (i=0; i<64; i++)        //编程64字节数据{WDT_CONTR = 0x17;       //清看门狗IAP_DATA = buf[i];      //将当前数据送IAP数据寄存器IAP_ADDRL = j;          //目标地址送IAP地址寄存器IAP_ADDRH = j >> 8;IAP_TRIG = 0x5a;        //触发ISP命令IAP_TRIG = 0xa5;j++;                    //目标地址+1}j = cbw.addr;               //校验目标地址for (i=0; i<64; i++)        //校验64字节数据{WDT_CONTR = 0x17;       //清看门狗if (buf[i] != CBYTE[j]) //源数据与目标数据进行比较break;              //不相等,则编程出错j++;                    //校验下一个字节}Isp_SendUart(!(i == 64));   //校验成功返回0; 否则返回1break;default:Isp_SoftReset();            //接收到非法命令时,复位系统break;}}}}}
}/*------------------------------------------------接收1字节串口数据出口参数: ACC (接收到的数据)
------------------------------------------------*/
BYTE Isp_RecvUart()
{BYTE dat;while (!RI)                         //等待接收完成{WDT_CONTR = 0x17;               //清看门狗}dat = SBUF;                         //读取串口数据RI = 0;                             //清除标志sum += dat;                         //计算校验和return dat;                         //返回接收到的串口数据
}/*------------------------------------------------接收一块串口数据入口参数: R0 (数据缓冲区地址)R7 (缓冲区长度)
------------------------------------------------*/
void Isp_RecvBlock(BYTE *p, BYTE n)
{while (n--)                         //检测长度{*p = Isp_RecvUart();            //接收1字节,并保存到缓冲区p++;                            //缓冲区地址+1}
}/*------------------------------------------------发送1字节串口数据 入口参数: ACC (待发送的数据)
------------------------------------------------*/
void Isp_SendUart(BYTE dat)
{while (!TI)                         //等待前一个数据发送完成{WDT_CONTR = 0x17;               //清看门狗}TI = 0;                             //清除标志SBUF = dat;                         //发送当前数据
}/*------------------------------------------------软件复位
------------------------------------------------*/
void Isp_SoftReset()
{IAP_CONTR = 0x20;                   //用户程序区复位
}
#ifndef __ABSACC_H__
#define __ABSACC_H__#define CBYTE ((unsigned char volatile code  *) 0)
#define DBYTE ((unsigned char volatile data  *) 0)
#if !defined (__CX2__)
#define PBYTE ((unsigned char volatile pdata *) 0)
#endif
#define XBYTE ((unsigned char volatile xdata *) 0)#define CWORD ((unsigned int volatile code  *) 0)
#define DWORD ((unsigned int volatile data  *) 0)
#if !defined (__CX2__)
#define PWORD ((unsigned int volatile pdata *) 0)
#endif
#define XWORD ((unsigned int volatile xdata *) 0)#if defined (__CX51__) || defined (__CX2__)
#define FVAR(object, addr)   (*((object volatile far *) (addr)))
#define FARRAY(object, base) ((object volatile far *) (base))
#define FCVAR(object, addr)   (*((object const far *) (addr)))
#define FCARRAY(object, base) ((object const far *) (base))
#else
#define FVAR(object, addr)    (*((object volatile far *) ((addr)+0x10000L)))
#define FCVAR(object, addr)   (*((object const far *) ((addr)+0x810000L)))
#define FARRAY(object, base)  ((object volatile far *) ((base)+0x10000L))
#define FCARRAY(object, base) ((object const far *) ((base)+0x810000L))
#endif#if defined (__CX2__)
#define HBYTE ((unsigned char volatile huge *)  0)
#define HWORD ((unsigned int volatile huge *)  0)
#define HVAR(object, addr)   (*((object volatile huge *) (addr)))
#define HARRAY(object, base) ((object volatile huge *) (base))
#endif#define CVAR(object, addr)   (*((object volatile code *) (addr)))
#define CARRAY(object, base) ((object volatile code *) (base))
#define DVAR(object, addr)   (*((object volatile data *) (addr)))
#define DARRAY(object, base) ((object volatile data *) (base))
#define XVAR(object, addr)   (*((object volatile xdata *) (addr)))
#define XARRAY(object, base) ((object volatile xdata *) (base))#endif

五、KEIL中定位IAP升级代码的方法

这是最后一步,这里函数定位结束后IAP就可以使用了,这里参考了官方文档,具体定位方法如下:

下面以演示程序进行说明

演示程序中有ReadIAP、ProgramIAP和EraseIAP三个函数

最终目的是将这三个函数都定位到0x8000之后

第一步:新建一个项目“Demo”,并将源文件“Demo.C”添加到项目中

第二步:直接编译,并打开编译后生成的“Demo.M51”文件

从M51文件的“CODE MEMORY”信息中,可以看到3个函数的链接名称、链接地址和函数长度

ReadIAP的链接名称为“?PR?_READIAP?DEMO”,链接地址为“0003H”,长度为16H字节

ProgramIAP的链接名称为“?PR?_PROGRAMIAP?DEMO”,链接地址为“0019H”,长度为16H字节

EraseIAP的链接名称为“?PR?_ERASEIAP?DEMO”,链接地址为“0044H”,长度为14H字节

第三步:根据M51中函数的长度信息计算出各个函数重定位的地址,

ReadIAP的重定位的地址为0x8000

ProgramIAP的重定位的地址为0x8016

EraseIAP的重定位的地址为0x802C

第四步:打开项目选项中的“BL51 Locate”属性页

在上图的“Code”域中输入下列语句

“?PR?_READIAP?DEMO(0x8000), ?PR?_PROGRAMIAP?DEMO(0x8016), ?PR?_ERASEIAP?DEMO(0x802C)”

以上参考了官方文档  WWW.STCMCU.COM ; Tel: 0755-82948412, Mobile:139-2280,5190

关于STC8H8K64U单片机IAP升级过程相关推荐

  1. 关于STM32单片机IAP升级中if(((*(__IO uint32_t*)ulAddr_App) 0x2FFE0000) == 0x20000000)语句的理解

    没有标题 初见if(((*(__IO uint32_t*)ulAddr_App) & 0x2FFE0000) == 0x20000000) 语句理解 语句功能 为什么ulAddr_App里存的 ...

  2. STM32F103C8T6单片机IAP升级

    关于IAP升级的方法和原理,网上已经有很多资料了,这块就不再说了,现在就将bootloader和app配置方法整理如下: APP程序就是一个简单的LED闪烁. APP设置为从FLASH中启动: STM ...

  3. STC51单片机实现IAP远程升级过程分享

    STC51单片机实现IAP远程升级过程分享 1.STC内部ISP更新机制 2.了解51单片机IAP分区 3.IAP分区的调用流程与IAP部分源码: 4.IAP步骤总结 5.源码下载 关于STC单片机I ...

  4. 差分升级 增量升级 单片机 STM32 IAP升级OTA升级,物联网车联网可用

    差分升级 增量升级 单片机 STM32 IAP升级OTA升级,物联网车联网可用 介绍博客 https://blog.csdn.net/zhou74281/article/details/1177776 ...

  5. 51单片机IAP在线升级

    51单片机IAP在线升级 爱矽半导体E85F3325单片机IAP在线升级教程,此处可查看更新及demo下载 文章目录 前言 一.ROM资源 二.KEIL有关知识 1.BL51连接器: 2.LX51连接 ...

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

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

  7. iap升级问题 stm32f103r8_STM32的基于串口的IAP固件升级与加密

    大家好,我是川楠,最近,在问答频道上看到有人对IAP升级心存疑惑.恰好,我本人在这方面的做过功课,也实战使用到很多的项目上,所以我就来为大家做个抛砖引玉吧. 本次例程,我用的是STM32F103VET ...

  8. 完成MSP430的IAP升级程序(总结)

    这几天测试写好的IAP升级程序,真是一个糟,能将程序下载进去,但无法运行. 经过各种测试,修改终于找到了问题的原因,现在大致总结下我在写IAP程序的时候 遇到的问题和解决方案.首先要实现单片机的IAP ...

  9. 嵌入式开发<单片机软件升级>

    嵌入式开发<单片机软件升级> 前言 一.单片机软件升级方式 二.IAP升级原理 1.FLASH区域划分 2. FLASH各个区域作用 三.IAP软件BOOT设计 1. 第一种设计方法 2. ...

  10. LPC11U3x系列IAP升级 BootLoader分析

    首先要明确LPC11Uxx系列的程序执行开始地址是0x00000000, 从0x0开始的512字节大小的存储空间存放的是中断向量表,之后便是程序,数据一般存放在8KB大小的SRAM中.(具体可参考LP ...

最新文章

  1. Android系统--TouchEvent的处理流程
  2. 人工智能,机器学习,深度学习入门好文,强烈推荐
  3. 第6章-一阶多智体系统一致性-->6.3 连续时间含时滞多智能体系统一致性
  4. 2021夏季每日一题 【week7 完结】
  5. 宝鸡文理学院c语言试题,宝鸡文理学院试题电子电磁场与电磁波A
  6. TinyXml帮助文档
  7. day15 Ui自动化元素的定位
  8. C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)
  9. ABAP BYPASSING BUFFER 及 表缓存,缓冲概念 SAP
  10. 软件测试面试题:什么是Ramp up?你如何设置?
  11. 黑客攻防---从零开始认识黑客,简单认知
  12. 刚刚涉足神经网络,基于TensorFlow2.0以实现鸢尾花分类为例总结神经网络代码实现的几个步骤,附代码详细讲解
  13. Python通讯录案例
  14. Java SE 8 Archive Downloads (JDK 8u202 and earlier)
  15. SQLyog连接linux数据库问题
  16. 【代码实现】数学游戏:最后一个说30就输的数学游戏
  17. python修炼之pip基本命令
  18. PTX-TK-PEG-NH2 紫杉醇-酮缩硫醇-聚乙二醇-氨基的制备
  19. 苹果下一代iPhone曝光
  20. 基于python下django框架 实现校园教室图书馆座位预约系统详细设计

热门文章

  1. linux下mysql命令大全_linux下mysql命令大全
  2. 几个分形的matlab实现1,基于MATLAB实现分形图形的绘制.doc
  3. 远程访问用户 Kindle---通过电子书实现控制
  4. 绝对值编码器的调整方法有哪些?
  5. 使用Easychm3.9打包chm出现js错误弹窗问题
  6. html js格式化,Js/html格式化在线工具
  7. 电子商业汇票知识问答题
  8. 单片机初始化WIFI模块
  9. 南京大学计算机考研的重点,南京大学计算机考研
  10. 居家小二拉新活动H5页面