说明:
1.本例程参考正点原子的IAP的代码。
2.本例程基于STM32F103C8T6单片机编写。
3.本例程使用USART1进行程序下载,波特率115200。
4.串口输出”Bootloder“字样后,请在3s内通过串口将APP的.bin文件传入单片机,之后会自动烧写并启动APP。若3s内未传入.bin文件或传入的文件有误,则会自动原来的启动APP。.bin文件最大只能15KByte。
5.STM32F103C8T6拥有128KByte的flash和20KByte的sram。本程序将0x0800 0000 - 0x0800 FFFF作为Bootloder空间,将0x0801 0000 - 0x0801 FFFF作为APP空间。
6.APP程序需要将flash中的向量表偏移0x10000。
工程源码下载(fci5), 工程使用 Keil uVision5 创建 ,密码 fci5 。
XCOM V2.6下载(48cm),密码 48cm 。
程序源码:
main.c
#include "delay.h"
#include "usart.h"
#include "flash.h"
#include "iap.h"
/***********************************************
* 支持最大15KByte的APP *
* *
* 0x0800 0000 - 0x0800 FFFF 为Bootloder空间 *
* 0x0801 0000 - 0x0801 FFFF 为APP空间 *
* *
***********************************************/
int main ()
{
u8 flag_update = 0; //升级完成后置1
u16 t = 0;
u16 oldcount = 0;
u16 applen = 0;
//初始化
delay_init();
USART1_Init(115200);
delay_ms(20);
printf("Bootloderrn");
while(1)
{
if(USART1_RX_CNT) //如果接收到了数据
{
if(oldcount == USART1_RX_CNT) //如果新周期内没收到数据,则认为接收完成
{
applen = USART1_RX_CNT;
oldcount = 0;
USART1_RX_CNT = 0;
if(((*(vu32*)(0x20001000+4)) & 0xFF000000) == 0x08000000) //判断是否为0x08XXXXXX,(是否为APP数据)
{
printf("APP len : %drn",applen);
//开始升级APP
printf("Updating...rn");
iap_write_appbin(FLASH_APP1_ADDR,USART1_RX_BUF,applen); //写入flash
flag_update = 1;
printf("Updae success !!!rn");
}
else printf("APP data error!!!rn");
}
else oldcount = USART1_RX_CNT; //更新接收到的字节数
}
if(flag_update || (t == 300 & USART1_RX_CNT == 0)) //如果升级APP完成或3s内没收到正确的APP数据,则启动APP
{
printf("APP Startrnrn");
iap_load_app(FLASH_APP1_ADDR);
}
t++;
delay_ms(10);
}
}
delay.h
#ifndef _DELAY_H
#define _DELAY_H
#include "stm32f10x.h"
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
delay.c
#include "delay.h"
static u8 fac_us = 0; //us延时倍乘数
static u16 fac_ms = 0; //ms延时倍乘数
void delay_init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCL/8
fac_us = SystemCoreClock/8000000; //为系统时钟的1/8
fac_ms = (u16)fac_us * 1000;
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = nus * fac_us;//时间加数
SysTick->VAL = 0x00;//清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开始倒数
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器、
SysTick->VAL = 0x00;//清空计数器
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = (u32)nms * fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0x00;//清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器
SysTick->VAL = 0x00;//清空计数器
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "stm32f10x.h"
#include "stdarg.h"
#define PRINTF_USARTx USART1 //USARTx 映射到 printf
#define EN_USART1_RX 1 //1使能接收,0失能接收。
#define USART1_REC_LEN 15*1024 //最大接收15KByte
extern u8 USART1_RX_BUF[USART1_REC_LEN]; //USART1 储存接收到的数据
extern u16 USART1_RX_STA; //USART1 接收状态即接收到的有效数据个数
extern u16 USART1_RX_CNT;
void USART1_Init(unsigned int BaudRate); //USART1用户初始化函数
void printf1(u8 *data,...);
int fputc(int ch, FILE *f);
void _sys_exit(int x);
static char *itoa(int value,char *string,int radix);
#endif
usart.c
#include "usart.h"
/*******************************************************************************************************************************************/
/* USART1 */
/*******************************************************************************************************************************************/
void USART1_Init(unsigned int BaudRate)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
/*初始化USART1的Tx、Rx引脚*/
//PA9 复用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//PA10浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStruct);
// PA9outAF_PP(); //PA9 复用推挽输出
// PA10inFLOATING();//PA10浮空输入
USART_InitStructure.USART_BaudRate = BaudRate; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收/发模式
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启接收中断
USART_Cmd(USART1, ENABLE);
//中断设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //中断分组1:1位抢占优先级,3位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
/*****************************************************
如果开启了接收
*****************************************************/
#if EN_USART1_RX //如果开启了USART1接收
u8 USART1_RX_BUF[USART1_REC_LEN] __attribute__ ((at(0x20001000))); //接收缓冲,最大USART1_REC_LEN个字节。 设定起始地址为0x20001000
u16 USART1_RX_STA = 0; //接收状态标记
u16 USART1_RX_CNT = 0; //接收的字节数
void USART1_IRQHandler(void)
{
u8 res;
if(USART1->SR & (1<<5))
{
res = USART1->DR;
if(USART1_RX_CNT
{
USART1_RX_BUF[USART1_RX_CNT] = res;
USART1_RX_CNT++;
}
}
}
#endif
/*******************************************************************************************************************************************/
/* 以下代码实现printf输出(无需MircoLIB) */
/*******************************************************************************************************************************************/
/*****************************************************
*function: 写字符文件函数
*param1: 输出的字符
*param2: 文件指针
*return: 输出字符的ASCII码
******************************************************/
int fputc(int ch, FILE *f)
{
while((USART1->SR & 0x40) == 0);
USART1->DR = (u8) ch;
return ch;
}
/********** 禁用半主机模式 **********/
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x=x;
}
/*******************************************************************************************************************************************/
/* itoa */
/*******************************************************************************************************************************************/
static char *itoa(int value,char *string,int radix)
{
int i,d;
int flag = 0;
char *ptr = string;
if(radix != 10)
{
*ptr = 0;
return string;
}
if(!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
if(value < 0)
{
*ptr++ = '-';
value *= -1;
}
for(i=10000;i>0;i /= 10)
{
d = value / i;
if(d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
*ptr = 0;
return string;
}
/*******************************************************************************************************************************************/
/* 用户自定义的USART1输出函数 printf1 */
/*******************************************************************************************************************************************/
void printf1(u8 *data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap,data);
while( *data != 0)
{
if( *data == 0x5C ) // ''
{
switch ( *++data )
{
case 'r':
USART_SendData(USART1,0x0D);
data++;
break;
case 'n':
USART_SendData(USART1,0x0A);
data++;
break;
default:
data++;
break;
}
}
else if( *data == '%' )
{
switch ( *++data )
{
case 's': //字符串
s = va_arg(ap,const char *);
for(;*s;s++)
{
USART_SendData(USART1,*s);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
data++;
break;
case 'd':
d = va_arg(ap,int);
itoa(d,buf,10);
for(s = buf;*s;s++)
{
USART_SendData(USART1,*s);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
data++;
break;
default:
data++;
break;
}
}
else USART_SendData(USART1,*data++);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
flash.h
#ifndef _FLASH_H
#define _FLASH_H
#include "stm32f10x.h"
/*********************** 移植 *************************/
#define FLASH_SIZE 128 //FLASH容量(KByte)
#define FLSAH_EN_WRITE 1 //1使能写入,0失能写入
/******************************************************/
#define FLSAH_BASH 0x08000000
//判断页大小
#if FLASH_SIZE < 256
#define SECTOR_SIZE 1024
#else
#define SECTOR_SIZE 2048
#endif
//提供给用户的函数
void FLASH_Write(u32 Addr,u16 *pBuff,u16 len);
u16 FLASH_ReadHalfWord(u32 faddr); //读取一个半字(16位)
void FLASH_Read(u32 Addr,u16 *pBuff,u16 len); //读出一段数据(16位)
void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len); //不检查的写入
#endif
falsh.c
#include "flash.h"
u16 FLASH_BUF[SECTOR_SIZE/2]; //1KByte
//提供给用户的函数
void FLASH_Write(u32 Addr,u16 *pBuff,u16 len)
{
u32 Sector_Number; //第几扇区
u32 Sector_Relative; //扇区内偏移地址(按16位计算)
u32 Sector_Remain; //扇区内剩余地址(按16位计算)
u32 OffAddr; //减去0x08000000后的地址
u16 i;
//判断地址合理性
if(Addr
=(FLASH_BASE+1024*FLASH_SIZE))return;
FLASH_Unlock();
OffAddr = Addr - FLASH_BASE;
Sector_Number = OffAddr/SECTOR_SIZE;
Sector_Relative = (OffAddr%SECTOR_SIZE)/2;
Sector_Remain = SECTOR_SIZE/2-Sector_Relative;
//如果一页能够写完
if(len <= Sector_Remain) Sector_Remain = len;
//写入
while(1)
{
//整页读出
FLASH_Read(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2);
for(i=0;i
{
if(FLASH_BUF[Sector_Relative+i] != 0xFFFF) break; //需要擦除
}
if(i
{
FLASH_ErasePage(Sector_Number*SECTOR_SIZE+FLASH_BASE);
//替换数据
for(i=0;i
{
FLASH_BUF[Sector_Relative+i] = pBuff;
}
//写入FLASH
FLASH_Writ_NoCheck(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2);
}
else
{
FLASH_Writ_NoCheck(Addr,pBuff,Sector_Remain);
}
if(len == Sector_Remain) break; //写入结束
else
{
Sector_Number++; //页+1
Sector_Relative = 0; //页内偏移0
pBuff += Sector_Remain; //更新传入的数组指针
Addr += Sector_Remain*2; //写地址偏移
len -= Sector_Remain; //更新写长度
if(len>(SECTOR_SIZE/2)) Sector_Remain = SECTOR_SIZE/2;
else Sector_Remain = len;
}
}
FLASH_Lock();
}
//读取一个半字(16位)
u16 FLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr;
}
//读出一段数据(16位)
void FLASH_Read(u32 Addr,u16 *pBuff,u16 len)
{
u16 i;
for(i=0;i
{
pBuff = FLASH_ReadHalfWord(Addr);
Addr += 2;
}
}
#if FLSAH_EN_WRITE //如果使能了写
//不检查的写入
void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len)
{
u16 i;
for(i=0;i
{
FLASH_ProgramHalfWord(Addr,pBuff);
Addr += 2;
}
}
#endif
iap.h
#ifndef _IAP_H
#define _IAP_H
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "flash.h"
#define FLASH_APP1_ADDR 0x08010000 //第一个应用程序起始地址
typedef void (*iapfun) (void); //定义一个函数类型的参数(?)
void iap_load_app(u32 addr); //执行flash里的app程序
void iap_load_appsram(u32 addr); //执行sram里的app程序
void iap_write_appbin(u32 addr,u8 *buf,u32 len); //将程序写入到指定flash地址
#endif
iap.c
#include "iap.h"
/*******************************************************
0x0800 0000 - 0x0800 FFFF 为Bootloder空间
0x0801 0000 - 0x0801 FFFF 为APP空间
*******************************************************/
iapfun jump2app; //(?)
u16 iapbuf[1024]; //按2KByte合并接收到的数据,然后写入flash
//将程序写入到指定flash地址
void iap_write_appbin(u32 addr,u8 *buf,u32 len)
{
u16 t;
u16 i = 0;
u16 temp;
u32 fwaddr = addr;
u8 *dfu = buf;
for(t=0;t
{
//将8位数据合并为16位数据
temp = (u16)dfu[1]<<8;
temp += (u16)dfu[0];
dfu += 2;
iapbuf[i++] = temp; //将合并完成的16位数据储存在数组中
if(i == 1024) //合并的数据填满iapbuf缓冲区后,开始写入falsh
{
i=0;
FLASH_Write(fwaddr,iapbuf,1024);
fwaddr += 2048;
}
}
if(i)FLASH_Write(fwaddr,iapbuf,i); //将最后一些内容写入flash
}
//执行flash里的app程序
void iap_load_app(u32 addr)
{
if(((*(vu32*)addr) & 0x2FFE0000) == 0x20000000) //检查栈顶地址是否合法(?)
{
jump2app = (iapfun)*(vu32*)(addr + 4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)addr); //初始化app栈顶指针(用户区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP
}
}
说明:
1.本例程参考正点原子的IAP的代码。
2.本例程基于STM32F103C8T6单片机编写。
3.本例程使用USART1进行程序下载,波特率115200。
4.串口输出”Bootloder“字样后,请在3s内通过串口将APP的.bin文件传入单片机,之后会自动烧写并启动APP。若3s内未传入.bin文件或传入的文件有误,则会自动原来的启动APP。.bin文件最大只能15KByte。
5.STM32F103C8T6拥有128KByte的flash和20KByte的sram。本程序将0x0800 0000 - 0x0800 FFFF作为Bootloder空间,将0x0801 0000 - 0x0801 FFFF作为APP空间。
6.APP程序需要将flash中的向量表偏移0x10000。
工程源码下载(fci5), 工程使用 Keil uVision5 创建 ,密码 fci5 。
XCOM V2.6下载(48cm),密码 48cm 。
程序源码:
main.c
#include "delay.h"
#include "usart.h"
#include "flash.h"
#include "iap.h"
/***********************************************
* 支持最大15KByte的APP *
* *
* 0x0800 0000 - 0x0800 FFFF 为Bootloder空间 *
* 0x0801 0000 - 0x0801 FFFF 为APP空间 *
* *
***********************************************/
int main ()
{
u8 flag_update = 0; //升级完成后置1
u16 t = 0;
u16 oldcount = 0;
u16 applen = 0;
//初始化
delay_init();
USART1_Init(115200);
delay_ms(20);
printf("Bootloderrn");
while(1)
{
if(USART1_RX_CNT) //如果接收到了数据
{
if(oldcount == USART1_RX_CNT) //如果新周期内没收到数据,则认为接收完成
{
applen = USART1_RX_CNT;
oldcount = 0;
USART1_RX_CNT = 0;
if(((*(vu32*)(0x20001000+4)) & 0xFF000000) == 0x08000000) //判断是否为0x08XXXXXX,(是否为APP数据)
{
printf("APP len : %drn",applen);
//开始升级APP
printf("Updating...rn");
iap_write_appbin(FLASH_APP1_ADDR,USART1_RX_BUF,applen); //写入flash
flag_update = 1;
printf("Updae success !!!rn");
}
else printf("APP data error!!!rn");
}
else oldcount = USART1_RX_CNT; //更新接收到的字节数
}
if(flag_update || (t == 300 & USART1_RX_CNT == 0)) //如果升级APP完成或3s内没收到正确的APP数据,则启动APP
{
printf("APP Startrnrn");
iap_load_app(FLASH_APP1_ADDR);
}
t++;
delay_ms(10);
}
}
delay.h
#ifndef _DELAY_H
#define _DELAY_H
#include "stm32f10x.h"
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
delay.c
#include "delay.h"
static u8 fac_us = 0; //us延时倍乘数
static u16 fac_ms = 0; //ms延时倍乘数
void delay_init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCL/8
fac_us = SystemCoreClock/8000000; //为系统时钟的1/8
fac_ms = (u16)fac_us * 1000;
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = nus * fac_us;//时间加数
SysTick->VAL = 0x00;//清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开始倒数
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器、
SysTick->VAL = 0x00;//清空计数器
}
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD = (u32)nms * fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0x00;//清空计数器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器
SysTick->VAL = 0x00;//清空计数器
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "stm32f10x.h"
#include "stdarg.h"
#define PRINTF_USARTx USART1 //USARTx 映射到 printf
#define EN_USART1_RX 1 //1使能接收,0失能接收。
#define USART1_REC_LEN 15*1024 //最大接收15KByte
extern u8 USART1_RX_BUF[USART1_REC_LEN]; //USART1 储存接收到的数据
extern u16 USART1_RX_STA; //USART1 接收状态即接收到的有效数据个数
extern u16 USART1_RX_CNT;
void USART1_Init(unsigned int BaudRate); //USART1用户初始化函数
void printf1(u8 *data,...);
int fputc(int ch, FILE *f);
void _sys_exit(int x);
static char *itoa(int value,char *string,int radix);
#endif
usart.c
#include "usart.h"
/*******************************************************************************************************************************************/
/* USART1 */
/*******************************************************************************************************************************************/
void USART1_Init(unsigned int BaudRate)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
/*初始化USART1的Tx、Rx引脚*/
//PA9 复用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//PA10浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStruct);
// PA9outAF_PP(); //PA9 复用推挽输出
// PA10inFLOATING();//PA10浮空输入
USART_InitStructure.USART_BaudRate = BaudRate; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收/发模式
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启接收中断
USART_Cmd(USART1, ENABLE);
//中断设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //中断分组1:1位抢占优先级,3位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
/*****************************************************
如果开启了接收
*****************************************************/
#if EN_USART1_RX //如果开启了USART1接收
u8 USART1_RX_BUF[USART1_REC_LEN] __attribute__ ((at(0x20001000))); //接收缓冲,最大USART1_REC_LEN个字节。 设定起始地址为0x20001000
u16 USART1_RX_STA = 0; //接收状态标记
u16 USART1_RX_CNT = 0; //接收的字节数
void USART1_IRQHandler(void)
{
u8 res;
if(USART1->SR & (1<<5))
{
res = USART1->DR;
if(USART1_RX_CNT
{
USART1_RX_BUF[USART1_RX_CNT] = res;
USART1_RX_CNT++;
}
}
}
#endif
/*******************************************************************************************************************************************/
/* 以下代码实现printf输出(无需MircoLIB) */
/*******************************************************************************************************************************************/
/*****************************************************
*function: 写字符文件函数
*param1: 输出的字符
*param2: 文件指针
*return: 输出字符的ASCII码
******************************************************/
int fputc(int ch, FILE *f)
{
while((USART1->SR & 0x40) == 0);
USART1->DR = (u8) ch;
return ch;
}
/********** 禁用半主机模式 **********/
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x=x;
}
/*******************************************************************************************************************************************/
/* itoa */
/*******************************************************************************************************************************************/
static char *itoa(int value,char *string,int radix)
{
int i,d;
int flag = 0;
char *ptr = string;
if(radix != 10)
{
*ptr = 0;
return string;
}
if(!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
if(value < 0)
{
*ptr++ = '-';
value *= -1;
}
for(i=10000;i>0;i /= 10)
{
d = value / i;
if(d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
*ptr = 0;
return string;
}
/*******************************************************************************************************************************************/
/* 用户自定义的USART1输出函数 printf1 */
/*******************************************************************************************************************************************/
void printf1(u8 *data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap,data);
while( *data != 0)
{
if( *data == 0x5C ) // ''
{
switch ( *++data )
{
case 'r':
USART_SendData(USART1,0x0D);
data++;
break;
case 'n':
USART_SendData(USART1,0x0A);
data++;
break;
default:
data++;
break;
}
}
else if( *data == '%' )
{
switch ( *++data )
{
case 's': //字符串
s = va_arg(ap,const char *);
for(;*s;s++)
{
USART_SendData(USART1,*s);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
data++;
break;
case 'd':
d = va_arg(ap,int);
itoa(d,buf,10);
for(s = buf;*s;s++)
{
USART_SendData(USART1,*s);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
data++;
break;
default:
data++;
break;
}
}
else USART_SendData(USART1,*data++);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
flash.h
#ifndef _FLASH_H
#define _FLASH_H
#include "stm32f10x.h"
/*********************** 移植 *************************/
#define FLASH_SIZE 128 //FLASH容量(KByte)
#define FLSAH_EN_WRITE 1 //1使能写入,0失能写入
/******************************************************/
#define FLSAH_BASH 0x08000000
//判断页大小
#if FLASH_SIZE < 256
#define SECTOR_SIZE 1024
#else
#define SECTOR_SIZE 2048
#endif
//提供给用户的函数
void FLASH_Write(u32 Addr,u16 *pBuff,u16 len);
u16 FLASH_ReadHalfWord(u32 faddr); //读取一个半字(16位)
void FLASH_Read(u32 Addr,u16 *pBuff,u16 len); //读出一段数据(16位)
void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len); //不检查的写入
#endif
falsh.c
#include "flash.h"
u16 FLASH_BUF[SECTOR_SIZE/2]; //1KByte
//提供给用户的函数
void FLASH_Write(u32 Addr,u16 *pBuff,u16 len)
{
u32 Sector_Number; //第几扇区
u32 Sector_Relative; //扇区内偏移地址(按16位计算)
u32 Sector_Remain; //扇区内剩余地址(按16位计算)
u32 OffAddr; //减去0x08000000后的地址
u16 i;
//判断地址合理性
if(Addr
=(FLASH_BASE+1024*FLASH_SIZE))return;
FLASH_Unlock();
OffAddr = Addr - FLASH_BASE;
Sector_Number = OffAddr/SECTOR_SIZE;
Sector_Relative = (OffAddr%SECTOR_SIZE)/2;
Sector_Remain = SECTOR_SIZE/2-Sector_Relative;
//如果一页能够写完
if(len <= Sector_Remain) Sector_Remain = len;
//写入
while(1)
{
//整页读出
FLASH_Read(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2);
for(i=0;i
{
if(FLASH_BUF[Sector_Relative+i] != 0xFFFF) break; //需要擦除
}
if(i
{
FLASH_ErasePage(Sector_Number*SECTOR_SIZE+FLASH_BASE);
//替换数据
for(i=0;i
{
FLASH_BUF[Sector_Relative+i] = pBuff;
}
//写入FLASH
FLASH_Writ_NoCheck(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2);
}
else
{
FLASH_Writ_NoCheck(Addr,pBuff,Sector_Remain);
}
if(len == Sector_Remain) break; //写入结束
else
{
Sector_Number++; //页+1
Sector_Relative = 0; //页内偏移0
pBuff += Sector_Remain; //更新传入的数组指针
Addr += Sector_Remain*2; //写地址偏移
len -= Sector_Remain; //更新写长度
if(len>(SECTOR_SIZE/2)) Sector_Remain = SECTOR_SIZE/2;
else Sector_Remain = len;
}
}
FLASH_Lock();
}
//读取一个半字(16位)
u16 FLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr;
}
//读出一段数据(16位)
void FLASH_Read(u32 Addr,u16 *pBuff,u16 len)
{
u16 i;
for(i=0;i
{
pBuff = FLASH_ReadHalfWord(Addr);
Addr += 2;
}
}
#if FLSAH_EN_WRITE //如果使能了写
//不检查的写入
void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len)
{
u16 i;
for(i=0;i
{
FLASH_ProgramHalfWord(Addr,pBuff);
Addr += 2;
}
}
#endif
iap.h
#ifndef _IAP_H
#define _IAP_H
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "flash.h"
#define FLASH_APP1_ADDR 0x08010000 //第一个应用程序起始地址
typedef void (*iapfun) (void); //定义一个函数类型的参数(?)
void iap_load_app(u32 addr); //执行flash里的app程序
void iap_load_appsram(u32 addr); //执行sram里的app程序
void iap_write_appbin(u32 addr,u8 *buf,u32 len); //将程序写入到指定flash地址
#endif
iap.c
#include "iap.h"
/*******************************************************
0x0800 0000 - 0x0800 FFFF 为Bootloder空间
0x0801 0000 - 0x0801 FFFF 为APP空间
*******************************************************/
iapfun jump2app; //(?)
u16 iapbuf[1024]; //按2KByte合并接收到的数据,然后写入flash
//将程序写入到指定flash地址
void iap_write_appbin(u32 addr,u8 *buf,u32 len)
{
u16 t;
u16 i = 0;
u16 temp;
u32 fwaddr = addr;
u8 *dfu = buf;
for(t=0;t
{
//将8位数据合并为16位数据
temp = (u16)dfu[1]<<8;
temp += (u16)dfu[0];
dfu += 2;
iapbuf[i++] = temp; //将合并完成的16位数据储存在数组中
if(i == 1024) //合并的数据填满iapbuf缓冲区后,开始写入falsh
{
i=0;
FLASH_Write(fwaddr,iapbuf,1024);
fwaddr += 2048;
}
}
if(i)FLASH_Write(fwaddr,iapbuf,i); //将最后一些内容写入flash
}
//执行flash里的app程序
void iap_load_app(u32 addr)
{
if(((*(vu32*)addr) & 0x2FFE0000) == 0x20000000) //检查栈顶地址是否合法(?)
{
jump2app = (iapfun)*(vu32*)(addr + 4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)addr); //初始化app栈顶指针(用户区的第一个字用于存放栈顶地址)
jump2app(); //跳转到APP
}
}
举报