用户注册 | 登录 | 帮助中心 | 网站地图 | 加入收藏 | English

网站首页 产品列表 软件下载 技术资料 付款方式 发货查询 关于我们 淘宝商城 论坛
搜索 高级/组合搜索
网站文章
所有文章
站内新闻
单片机工具资料
汇编程序实例
C语言程序实例
单片机提高资料
单片机初学资料
单片机软件下载
单片机技术资料
  您的位置: 首页 >> 文章列表 >> AVR BootLoader应用范例
AVR BootLoader应用范例

作者:单片机爱好者  转载自:单片机工具之家  发布日期:2011-4-17

M128 Boot_load应用的实例

#include <avr/io.h>
#include <avr/delay.h>
//时钟定为外部晶体7.3728MHz,F_CPU=7372800 使用USART,115200bps
#include <avr/boot.h>

#include <avr/crc16.h>

//管脚定义
#define PIN_RXD       0 //PD0
#define PIN_TXD       1 //PD1

//常数定义
//#define SPM_PAGESIZE    128       //M16的一个Flash页为128字节(64字)
#define DATA_BUFFER_SIZE  SPM_PAGESIZE  //定义接收缓冲区长度
#define BAUDRATE      115200      //波特率采用115200bps
//#define F_CPU       7372800     //系统时钟7.3728MHz

//定义Xmoden控制字符
#define XMODEM_NUL      0x00
#define XMODEM_SOH      0x01
#define XMODEM_STX      0x02
#define XMODEM_EOT      0x04
#define XMODEM_ACK      0x06
#define XMODEM_NAK      0x15
#define XMODEM_CAN      0x18
#define XMODEM_EOF      0x1A
#define XMODEM_WAIT_CHAR  'C'

//定义全局变量
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      0x1800      //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      //完成


void (*reset)(void) = 0x0000 ; 

//长延时 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<SPM_PAGESIZE;i+=2)        //将数据填入Flash缓冲页中
    {
        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<<RXC))
        {
            *ptr++=UDR;       //如果接收到数据,读出
            count++;
            if (count>=len)
            {
                break;        //够了?退出
            }
        }
        if(TIFR & (1<<OCF2))    //T2溢出 1ms
        {
            TIFR|=(1<<OCF2);    //清除标志位
            timeout--;        //倒计时
        }
    }
    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(void)
{
    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<<PIN_TXD);              //串口的输出
    GICR = (1<<IVCE);
    GICR = (0<<IVCE)|(1<<IVSEL);        //将中断向量表迁移到Boot区头部
asm volatile("cli": : );            //关全局中断
    //这个BootLoader没有使用中断。

    //初始化USART 115200 8, n,1  PC上位机软件(超级终端)也要设成同样的设置才能通讯
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //异步,8位数据,无奇偶校验,一个停止位,无倍速
    UBRRL = (F_CPU/BAUDRATE/16-1)%256;      //设定波特率
    UBRRH = (F_CPU/BAUDRATE/16-1)/256;
    UCSRA = 0x00;
    UCSRB = (1<<RXEN)|(1<<TXEN);        //使能接收,使能发送
    //初始化T/C0,CTC模式,256分频,1ms自动重载
   TCNT2 = 0xE4;
    OCR2 = 28;
    TCCR2 = (1<<WGM21)|(1<<CS22)|(0<<CS21)|(0<<CS20);
    //CTC模式下,溢出标志是输出比较匹配OCF0,对应的中断是输出比较匹配中断;

    //向PC机发送开始提示信息
//    put_s(" ");
   put_s("请在3秒钟内按下[d]键");
    //put_s("如需更新用户程序,请在3秒钟内按下[d]键,否则3秒后运行用户程序");

    //3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序
    c=0;
    get_data(&c,1,10000);            //限时3秒,接收一个数据
    if ((c=='d')||(c=='D'))
    {
        STATUS=ST_WAIT_START;         //并且数据='d'或'D',进入XMODEM
        put_s("BIN檔,最大6KB");
    }
    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("用户程序升级OK");
                break;
            case XMODEM_CAN:          //收到取消符CAN
                put_c(XMODEM_ACK);        //回应PC机
                STATUS=ST_OK;
            //put_s("警告:用户取消升级!");
                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
        }
    }

    //退出Bootloader程序,从0x0000处执行应用程序
    put_s("LET'S GO!");
    delay_ms(500);                //很奇怪,见顶部的说明
    loop_until_bit_is_set(UCSRA,UDRE);      //等待结束提示信息回送完成
    GICR = (1<<IVCE);
    GICR = (0<<IVCE)|(0<<IVSEL);        //将中断向量表迁移到应用程序区头部
    /* 无论BootLoader是否使用中断,将中断向量表迁移到应用程序区头部,会增强程序的健壮性*/
    boot_rww_enable();             //RWW区读允许,否则无法马上执行用户的应用程序
    reset();
   
//asm volatile("rjmp 0x0000": : );          //跳转到Flash的0x0000处,执行用户的应用程序
}

【版权声明】
  1. 任何网站转载本站内容必需注明“来源:单片机工具之家”。
  2. 本网转载自其它媒体的信息,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。
  3. 未经本站明确许可,任何网站不得非法盗链软件下载连接及抄袭本网站原创内容资源。
  4. 违反上述声明者,本网将追究其相关法律责任。谢谢!


关于我们
网站介绍
联系我们
付款方式
银行汇款
货到付款
发货方式
快递运输
上门自提
售后服务
退换货政策
质保承诺
购买方式
购物流程
在线订购

公司名称:深圳市乾龙盛电子科技有限公司    网站名称:单片机工具之家
公司地址:广东省深圳市宝安区龙华镇民治路潜龙花园惠宁阁13-G   联系电话:0755-28187975  13715306011  传真:0755-28187976
展销柜台:广东省深圳市福田区新亚洲电子商城二期三楼N3D033室(华强电子世界附件)【查看地图】   联系电话:0755-82543360
:淘宝商店   :qls@cxqmcu.com   :qls@cxqmcu.com
销售点击Q我:243355504 (唐永红)先生   技术支持点击Q我:443935535 (钟先生)
网站版权:单片机工具之家  粤ICP备09028690号