AVR BootLoader应用范例
//定义全局变量
struct str_XMODEM
{
unsigned char SOH; //起始字节
unsigned char BlockNo; //数据块编号
unsigned char nBlockNo; //数据块编号反码
unsigned char Xdata[128]; //数据128字节
unsigned char CRC16hi; //CRC16校验数据高位
unsigned char CRC16lo; //CRC16校验数据低位
}
strXMODEM; //XMODEM的接收数据结构
unsigned long FlashAddress; //FLASH地址
#define BootAdd 0x3800 //Boot区的首地址(应用区的最高地址)
/* GCC里面地址使用32位长度,适应所有AVR的容量*/
unsigned char BlockCount; //数据块累计(仅8位,无须考虑溢出)
unsigned char STATUS; //运行状态
#define ST_WAIT_START 0x00 //等待启动
#define ST_BLOCK_OK 0x01 //接收一个数据块成功
#define ST_BLOCK_FAIL 0x02 //接收一个数据块失败
#define ST_OK 0x03 //完成
//长延时 max 65536ms
void delay_ms(unsigned int t)
{
while(t--)
{
_delay_ms(1);
}
}
//更新一个Flash页的完整处理
void write_one_page(void)
{
unsigned char i;
unsigned char *buf;
unsigned int w;
boot_page_erase(FlashAddress); //擦除一个Flash页
boot_spm_busy_wait(); //等待页擦除完成
buf=&strXMODEM.Xdata[0];
for(i=0;i
w =*buf++;
w+=(*buf++)<8;
//boot_page_fill(FlashAddress+i, w); //原句
boot_page_fill(i, w); //只是低7位(128字节/页)有效
}
boot_page_write(FlashAddress); //将缓冲页数据写入一个Flash页
boot_spm_busy_wait(); //等待页编程完成
}
//发送采用查询方式
void put_c(unsigned char c) //发送采用查询方式
{
loop_until_bit_is_set(UCSRA,UDRE);
UDR=c;
}
//发送字符串
void put_s(unsigned char *ptr)
{
while (*ptr)
{
put_c(*ptr++);
}
put_c(0x0D);
put_c(0x0A); //结尾发送回车换行
}
//接收指定字节数据(带超时控制,Timer0的1ms时基)
// *ptr 数据缓冲区
// len 数据长度
// timeout 超时设定,最长65.536S
// 返回值 已接收字节数目
unsigned char get_data(unsigned char *ptr,unsigned char len,unsigned int timeout)
{
unsigned count=0;
do
{
if (UCSRA & (1
*ptr++=UDR; //如果接收到数据,读出
count++;
if (count>=len)
{
break; //够了?退出
}
}
if(TIFR & (1
TIFR|=(1
}
}
while (timeout);
return count;
}
//计算CRC16
unsigned int calcrc(unsigned char *ptr, unsigned char count)
{
unsigned int crc = 0;
while (count--)
{
crc =_crc_xmodem_update(crc,*ptr++);
}
return crc;
}
//主程序
//int main() __attribute__((section(".stephen_bootloader"))); //stephen_bootloader
int main()
{
unsigned char c;
unsigned char i;
unsigned int crc;
//考虑到BootLoader可能由应用程序中跳转过来,所以所用到的模块需要全面初始化
DDRA=0x00;
DDRB=0x00;
DDRC=0x00;
PORTA=0xFF; //不用的管脚使能内部上拉电阻。
PORTB=0xFF;
PORTC=0xFF;
PORTD=0xFF;
DDRD=(1
//这个BootLoader没有使用中断。
//初始化USART 115200 8, n,1 PC上位机软件(超级终端)也要设成同样的设置才能通讯
UCSRC = (1
UBRRH = (F_CPU/BAUDRATE/16-1)/256;
UCSRA = 0x00;
UCSRB = (1
OCR0 = 28;
TCCR0 = (1
//向PC机发送开始提示信息
put_s("************************************************************");
//put_s(" ");
put_s("IC ATMega16 Firmware 智能升级引导程序(Bootloader)VER20070107");
put_s(" 使用Windows2000/xp 超级终端 串口发送 9600bps,8-N-1 ");
put_s("如需更新用户程序,请在3秒钟内按下[d]键,否则3秒后运行用户程序 ");
put_s(">");
//3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序
c=0;
get_data(&c,1,3000); //限时3秒,接收一个数据
if ((c==d)||(c==D))
{
STATUS=ST_WAIT_START; //并且数据=d或D,进入XMODEM
put_s("请选择BIN文件,使用XMODEM协议传输,最大14KB");
}
else
{
STATUS=ST_OK; //退出Bootloader程序
}
//进入XMODEM模式
FlashAddress=0x0000;
BlockCount=0x01;
while(STATUS!=ST_OK) //循环接收,直到全部发完
{
if (STATUS==ST_WAIT_START)
{//XMODEM未启动
put_c(XMODEM_WAIT_CHAR); //发送请求XMODEM_WAIT_CHAR
}
i=get_data(&strXMODEM.SOH,133,1000); //限时1秒,接收133字节数据
if(i)
{
//分析数据包的第一个数据 SOH/EOT/CAN
switch(strXMODEM.SOH)
{
case XMODEM_SOH: //收到开始符SOH
if (i>=133)
{
STATUS=ST_BLOCK_OK;
}
else
{
STATUS=ST_BLOCK_FAIL; //如果数据不足,要求重发当前数据块
put_c(XMODEM_NAK);
}
break;
case XMODEM_EOT: //收到结束符EOT
put_c(XMODEM_ACK); //通知PC机全部收到
STATUS=ST_OK;
put_s(" 用户程序升级成功!");
break;
case XMODEM_CAN: //收到取消符CAN
put_c(XMODEM_ACK); //回应PC机
STATUS=ST_OK;
put_s("警告:用户取消升级,用户程序可能不完整");
break;
default: //起始字节错误
put_c(XMODEM_NAK); //要求重发当前数据块
STATUS=ST_BLOCK_FAIL;
break;
}
}
if (STATUS==ST_BLOCK_OK) //接收133字节OK,且起始字节正确
{
if (BlockCount != strXMODEM.BlockNo)//核对数据块编号正确
{
put_c(XMODEM_NAK); //数据块编号错误,要求重发当前数据块
continue;
}
if (BlockCount !=(unsigned char)(~strXMODEM.nBlockNo))
{
put_c(XMODEM_NAK); //数据块编号反码错误,要求重发当前数据块
continue;
}
crc=strXMODEM.CRC16hi<8;
crc+=strXMODEM.CRC16lo;
//AVR的16位整数是低位在先,XMODEM的CRC16是高位在先
if(calcrc(&strXMODEM.Xdata[0],128)!=crc)
{
put_c(XMODEM_NAK); //CRC错误,要求重发当前数据块
continue;
}
//正确接收128个字节数据,刚好是M16的一页
if (FlashAddress<(BootAdd-SPM_PAGESIZE))
{ //如果地址在应用区内
write_one_page(); //将收到128字节写入一页Flash中
FlashAddress+=SPM_PAGESIZE; //Flash页加1
}
else
{
put_c(XMODEM_CAN); //程序已满,取消传送
put_c(XMODEM_CAN);
put_c(XMODEM_CAN);
STATUS=ST_OK;
put_s(" 程序已满,取消传送!");
break;
}
put_c(XMODEM_ACK); //回应已正确收到一个数据块
BlockCount++; //数据块累计加1
}
}
AVRBootloade 相关文章:
- AVR Bootloader应用介绍(11-27)
- CRC校验---之avrbootloader(11-13)
- AVR之BOOTLOADER技术详解(11-13)
- AVR_M8 BootLoader应用范例(11-13)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)