关于STM32 IAP

转眼间天亮了......

然后就想起了一个朋友QQ的个性签名:年轻人总是要为一些自己认为有意义的事情而废寝忘食,通宵达旦,直至白发方休........

对了这篇文章一定会介绍的很详细,请细嚼慢咽.......嗯,我是这样认为的,,,,,,

上面是昨天写的,应该说是今天写的,,今天发现发现博客又不能复制粘贴图片了!!!!然后就睡了一觉,,麻烦。。。。是不是因为我写的博客有太多的图片而把我屏蔽了。能让人一目了然的就是图片。。。。

说一下自己是如何做的,,,

先说一下实现的功能

IAP程序的功能

再看自己的用户程序--用户程序自己也做了些设置

对了关于我为什么拷贝到Flash里面------自己用的单片机的RAM不够用,存不了用户程序,所以自己就定义了一个小点的数组(环形队列),串口一边接收,一边往Flash里面写,环形队列可是帮了大忙了,,,,

把IAP升级程序下进去,以后就直接通过串口发送自己的用户程序就行了...什么都不需要做了,先说一下操作过程吧!最后有自己的源码

IAP程序软件不需要任何配置

波特率太快的话,数据来不及写入Flash,环形队列容易溢出,,太慢的话,程序发送的慢。。。

用户程序软件需要一些配置

8006000告诉编译器我的用户程序打算在这里开始,你帮我设置一下吧,默认是在8000000开始的

0x1A000,就是告诉编译器我的程序空间有这么大。

我的用户程序里面也是设置的6000,这个一定要和程序设置的一样哈

关于这个我后面会说为什么这样设置。。。当然也可以百度一下。

其实我的本来是

20000换成十进制就是131072个字节  除以1024 等于128

由于我先把IAP程序下进去了,IAP程序也需要空间来运行,,,我就给了他6000 换成十进制就是24576  除以1024就是24K

我的总共是128K然后去掉IAP暂用的24K就是  128-24 = 104K  = 106496个字节   换成16进制就是 1A000

所以我上面写了1A000

对了如果您的板子是大容量的如果您非常明白就自己随意修改把,别忘了修改程序里的那个,,,

如果不是很明白按照上面修改就行,后面会让您明白

这个呢就是让Keil软件帮忙生成bin文件

F:\Keil4&&MDK4.70A\ARM\ARMCC\bin\fromelf.exe   --bin -o  .\Progect\Progect.bin  ..\Progect\output\Progect.axf

F:\Keil4&&MDK4.70A\ARM\ARMCC\bin\fromelf.exe   --bin -o这个是执行的命令,就是生成bin文件,根据自己的安装路径找哈

.\Progect\Progect.bin 就是告诉他把生成的bin文件放在哪个地方

..\Progect\output\Progect.axf 这个就是自己工程编译的时候产生的.axf文件,根据自己的找到

./当前目录

../上一级目录

../../上上一级目录

关于Bin文件和Hex文件

http://blog.sina.com.cn/s/blog_6b94d5680100lo2h.html

这是我的用户程序的Hex与Bin

咱们自己设置好写到哪里了,所以前头的就不需要了,后面的校验也不需要了,,不过呢应该向他那样加上校验,数据对了再写进去!!!!

好生成了bin文件

然后

假设修改了程序了,再升级

您再升级就再升级把!!

再升级

不要老是升级哈!!!玩坏了Flash可就不好玩了

自己用的F103RBT6单片机的RAM只有

5000 也就是20480个字节,,但是自己的程序已经超过了这个字节数

所以自己就不能先定义一个很大的数组然后然后把程序先存在里面了,列如很多都是:

u8 USART_RX_BUF[USART_REC_LEN]  __attribute__ ((at(0X20001000)));//接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.//把数据固定的存在以0X20001000为起始地址的RAM里面

自己呢就是用的环形队列一边接收,一边写入,,,关于环形队列可以看我的环形队列的文章,,,

http://www.cnblogs.com/yangfengwu/p/6822984.html

就再说一下自己的程序的一些地方

串口接收的

voidUSART1_IRQHandler(void)//串口1中断服务程序{

u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收中断(接收到的数据必须是0x0d 0x0a结尾){

Res=USART_ReceiveData(USART1);//读取接收到的数据PutData(&Res,1);//把数据存入队列Usart1RecCnt ++;//数据个数}

}

用的系统定时器中断来检测的串口空闲,判断接没接收到一条完整的数据--方法呢是看到人家的一种方法,感觉比自己以前的好,所以直接拿过来用了

关于单片机空闲中断可以看一下自己以前的

http://www.cnblogs.com/yangfengwu/p/6746403.html

/*系统定时器中断*/voidSysTick_Handler(void)

{

SysTickCnt++;

SysTickCnt1++;

SysTickCnt2++;if(SysTickCnt1>=10)//每隔10毫秒检测一次

{

SysTickCnt1=0;if(Usart1RecCnt)//如果接收到数据了

{if(IdleCnt ==Usart1RecCnt)//10ms时间数据没了变化

{

Usart1RecCntCopy=Usart1RecCnt;//拷贝数据个数

Usart1RecCnt=0;//清零数据个数

IdleCnt=0;//清零

Usart1Flage=1;//接收到一条数据//rbDelete(&pRb);测试的时候销毁//rbCreate(&pRb,ReceBuff,USART_REC_LEN);//创建接收环形队列}else{

IdleCnt=Usart1RecCnt;

}

}

}

}

我的IAP的接收的数据往Flash里面写和用户程序的往Flash里面写有一点不同,其实用户程序的往Flash里面写的程序是后期的改进...

先看我的IAP的

if(rbCanRead(&pRb)>1)//如果环形队列里面的数据个数大于1

{

rbRead(&pRb, &ReadDat,2);//读取两个数据ReadDat16 = (u16)ReadDat[1]<<8;

ReadDat16= ReadDat16|ReadDat[0];

STMFLASH_Write(addr2,&ReadDat16,1);

addr2+=2;

}

if(rbCanRead(&pRb)>1)

因为一次性要往Flash里面写16位数据,所以才会判断数据个数大于一个的时候再往里面写.

虽然现在程序没有问题,但是我还在想如果程序的个数是奇数个就完啦!但是好像程序的个数总是偶数个....其实可以在判断接收完成的里面

做一下判断,如果数据还残留一个,那就写进去....

好,那就看一下判断接收完程序

if(Usart1Flage ==1)//数据接收完成{

addr2= FLASH_APP2_ADDR;//存储数据的地址Usart1Flage =0;//清零if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.{

printf("准备执行APP代码!!\r\n");

UserDataAddr= FLASH_DATA_ADDR;//存储其余的数据地址ReadDat16 =0x55;//写入标志告诉IAP程序有可更新的用户程序STMFLASH_Write(UserDataAddr,&ReadDat16,1);

UserDataAddr+=2;

printf("写入0x55标志!!\r\n");

ReadDat16= (u16)((Usart1RecCntCopy>>16)&0xffff);//存储接收到多少数据高位STMFLASH_Write(UserDataAddr,&ReadDat16,1);

UserDataAddr+=2;

ReadDat16= (u16)(Usart1RecCntCopy&0xffff);//存储接收到多少数据低位STMFLASH_Write(UserDataAddr,&ReadDat16,1);

UserDataAddr+=2;

Usart1RecCntCopy=0;

printf("开始复位重启!!\r\n");

Reset_MCU();

}else{

printf("非FLASH应用程序,无法执行!\r\n");

}//printf("Cnt=%d\r\n",Usart1RecCntCopy);//for(i=0;i>8)<=15)//{//printf("0%x ",ReadDat16>>8);//}//else//{//printf("%x ",ReadDat16>>8);//}//}//addr1 = FLASH_APP1_ADDR;//for(i=0;i<40;i++)//{//STMFLASH_Erase(addr1,1024);//擦除FLASH_APP1_ADDR地址以及以上40页//addr1 +=2048;//}//addr1 = FLASH_APP1_ADDR;}

后边屏蔽的是测试的时候,看一下写入的数据,然后和源数据对比一下,看一下写入的对不对

if(((*(vu32*)(FLASH_APP2_ADDR+4))&0xFF000000)==0x08000000)

这句话

先问一个问题,怎么知道接收过来的是用户程序呢????要是别的数据怎么办???,,必须有一个判断依据才行对吧!!

就必须找到用户程序中永恒不变的变量....

然后呢,我是看别人的程序说,数据的第一个4个字节为栈顶地址,数据的第二个4字节为复位中断向量的入口地址

FLASH_APP2_ADDR+4指针就移动到了IAP升级程序的E9或者说电压电流采集程序的D5上

(*(vu32*)(FLASH_APP2_ADDR+4))然后强制型的转成32位的,然后取出来,就是IAP升级程序的E9 20 00 08

或者说电压电流采集程序的D5 7E 00 08

还有一件事就是STM32是小端模式,,,,所谓小端模式就是低位在低地址,高位在高地址

举个例子

把60000存到STM32的Flash的,60000转换成16进制是EA60  EA是高8位,60是低八位,,存到Flash里面就是60EA这样存的

60存到了低地址,EA存到了高地址,,,,,当然有小端模式就有大端模式,,,大端模式就是低位在高地址,高位在低地址,电脑就是这样...

说到这里就要说一下共用体

typedef union Resolver_I{longData;charData_Table[4];

}Resolver_iData;

typedef union Resolver_f{floatData;charData_Table[4];}Resolver_fData;

Resolver_iData Resolver_7758;  //解析7758数据

Resolver_fData Resolver_Usart; //解析串口数据

一个整形数据快速的转换成16进制存到数组里面

Resolver_7758.Data = 60000;

那么Resolver_7758.Data_Table[0] = 0x60;

Resolver_7758.Data_Table[1] = 0xEA;

Resolver_7758.Data_Table[2] = 0x00;

Resolver_7758.Data_Table[3] = 0x00;

一个浮点型的数据转换成16进制存到数组里面--其实也是按照IEEE754规约来计算的

Resolver_Usart.Data = 220.5;

那么Resolver_Usart.Data_Table[0] = 0x00;

Resolver_Usart.Data_Table[1] = 0x80;

Resolver_Usart.Data_Table[2] = 0x5C;

Resolver_Usart.Data_Table[3] = 0x43;

所以说上面的数据取出来就是08 00 20 E9然后&0xFF000000 肯定就等于 0x08000000啦

其实这样还有一个原因是因为32的地址是从08000000开始的,复位中断向量的地址的最高两位肯定是08啦!!!!

然后还有个if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.

这个......难道栈顶地址的最高位就是20......以后等看到相关的资料再说吧

有人这样介绍的--仔细看,细细品味....

http://blog.csdn.net/yx_l128125/article/details/12992773

对了说一下中断向量表

就从我的MSP430的文章中摘抄过来

原文地址

http://www.cnblogs.com/yangfengwu/p/6064129.html

突然想起来一句话,知识是相通的....

32也有中断向量表,就像上面的430的似的,

只不过呢!32的中断函数的入口地址是可以改变的!!!(F0好像固定,但是看过一篇文章好像也能通过某种方式改改)

我们写入IAP程序后单片机内部就有了一个中断向量表,这个呢是其内部一开始的固定的,

如果跳转到用户程序,用户程序肯定会有自己的中断函数吧!如串口,,定时器,,等等,,,,如果不改变中断向量表的话!!!产生的中断

岂不是跑到了IAP那边去了,IAP那边有自己的中断函数,,,乱了,彻底乱了,,,,,所以必须得让中断向量表改变改变,好让自己产生的

中断,执行自己的中断函数......

那就加一句话,或者修改一个地方

再看我的用户程序的一个地方,,感觉自己罗嗦了

if(AppFlage ==1)//接收到更新程序{if(rbCanRead(&pRb)>1)

{

rbRead(&pRb, &ReadDat,2);//读取两个数据ReadDat16 = (u16)ReadDat[1]<<8;

ReadDat16= ReadDat16|ReadDat[0];

STMFLASH_Write(addr2,&ReadDat16,1);

addr2+=2;

}

}elseif(AppFlage ==0)

{if(rbCanRead(&pRb)==8)

{

rbRead(&pRb, &TestData,8);//读取数据if(TestData[3] ==0x20&& TestData[7] ==0x08)//判断是否是更新程序{

AppFlage=1;//要更新程序for(i=0;i<4;i++)//先写入这八位数据{

ReadDat16= (u16)TestData[(i<<1)+1]<<8;

ReadDat16= ReadDat16|TestData[i<<1];

STMFLASH_Write(addr2,&ReadDat16,1);

addr2+=2;

}

}

}

}

毕竟是用户程序,串口1可能要参与别的通信,,,所以自己加了一个判断是否是要更新程序的数据,,,是的话才往Flash里面写

自己的源码

链接:http://pan.baidu.com/s/1bJtc78密码:nobu

这两天发现了自己程序的Bug

1,如果用户程序主函数加入延时,那么程序就来不及读出然后写到Flash里面,串口却不停的往环形队列里面写,从而造成环形队列溢出....

再者如果写入的时候,设置的串口助手的波特率太快,,,,同样也会造成环形队列溢出(就是往环形队列写的太快了)....

自己把写Flash的程序放在了定时器里面,50Us进入一次的定时器,看着网上说往Flash写一个字节大约16Us,,,,加上其余的程序整体应该不会超过50Us

如果有溢出程序不在往环形队列里面写了

voidUSART1_IRQHandler(void)//串口1中断服务程序{

u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收中断(接收到的数据必须是0x0d 0x0a结尾){

Res=USART_ReceiveData(USART1);//读取接收到的数据if(Overflow==0)

{if(PutData(&Res,1) == -1)

{

Overflow=1;

}

}

Usart1RecCnt++;

}

}

最后接收完如果判断溢出过,直接复位重启,复位重启更方便直接...

if(Usart1Flage ==1)//串口1接收完成{

addr2=FLASH_APP2_ADDR;

Usart1Flage=0;if(Overflow==1)//如果中途溢出了{

printf("程序中途溢出,准备复位重启!!\r\n");

Reset_MCU();//复位重启CPU}

2,如果写了一些后,突然因为某些原因停止了写入,,,,,本想在程序中观察末尾有什么固定的数据没有,,,,或者自己最后加一些标志位

但是这个现在程序好像能判断出来....但是自己一直没有明白程序为什么可以判断出来............应该判断不出来的......

后来一想现在反正是自己去更新程序,真不行可以直接烧,,,,就先放一放,,,,

更改后的

链接:http://pan.baidu.com/s/1slnWFVJ密码:mts7

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎...
    杨奉武阅读 3,123评论 0 1
  • 姓名:莫益彰 学号:16030140019 【嵌牛导读】:串口通信是指外设和计算机间,通过数据信号线 、地线、控制...
    换个名字消消毒阅读 1,572评论 1 5
  • 实验环境依然是windows + CubeMX + Keil v5。 实验连接图 连接图与Lab3基本一致,ST-...
    lmzqwer2阅读 1,666评论 0 4
  • 相博超妈妈 2017年9月25 这两天公司太忙了,晚上回来七点了,相博超在他奶奶家已经吃饭了,我光给他检查作业...
    一年级四班相博超妈妈阅读 259评论 0 1