AVR-atmega16 BOOTLoader 程序

发布者:WhisperingWave最新更新时间:2017-01-03 来源: eefocus关键字:AVR  atmega16  BOOTLoader 手机看文章 扫描二维码
随时随地手机看文章

本程序参照马潮mega128的编写。可支持485或232接口。变异软件ICCAVR,上位机软件应用超级终端或avrubd等,Xmodem,9600,8,1,n

#include

#include

#include

#define SPM_PAGESIZE 128     //M16的一个Flash页为128字节(64字),共128页 

#define BAUD 9600            //波特率采用9600bps 

#define CRYSTAL 14745600     //系统时钟 ?? M Hz

//计算和定义M16的波特率设置参数

#define BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/(16*(unsigned long)BAUD)-1)

#define BAUD_H (unsigned char)(BAUD_SETTING>>8)

#define BAUD_L (unsigned char)BAUD_SETTING

//定义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_RECIEVING_WAIT_CHAR 'C'

//定义接收缓冲区长度

#define DATA_BUFFER_SIZE SPM_PAGESIZE

//485使能

#define    USART_TX_ENABLE() {asm("sbi 0x12,2"); asm("nop");}  //485发送使能 D口 pin2

#define    USART_RX_ENABLE() {asm("cbi 0x12,2"); asm("nop");}  //485接收使能

//定义全局变量

const char startupString[]="\n\rType 'W' download, Others run application program.\n\r\0";

char data[DATA_BUFFER_SIZE];

unsigned int address = 0;

// //外部喂狗函数

// void Kick_Dog(void)

// {

    // asm("sbi 0x18,5");

    // asm("nop");

    // asm("nop");

    // asm("nop");

    // asm("nop");

    // asm("nop");

    // asm("cbi 0x18,5");

// }

//擦除(code=0x03)和写入(code=0x05)一个Flash页

void boot_page_ew(unsigned int p_address,char code)

{

    asm("mov r30,r16\n"

        "mov r31,r17\n");  //将页地址p_address放入Z(R31:R30)寄存器

    SPMCR = code;          //寄存器SPMCSR中为操作码

    asm("spm\n");          //对指定Flash页进行操作

}

//填充Flash缓冲页中的一个字

void boot_page_fill(unsigned int address,int data)

{

    asm("mov r30,r16\n"

        "mov r31,r17\n"  //Z寄存器中为填冲页内地址

        "mov r0,r18\n"

        "mov r1,r19\n"); //R1:R0 中为一个指令字

    SPMCR = 0x01;

    asm("spm\n");

}

//等待一个Flash页的写完成

void wait_page_rw_ok(void)

{

    while(SPMCR & 0x40)

    {

        while(SPMCR & 0x01);

        SPMCR = 0x11;

        asm("spm\n");

    }

}

//更新一个Flash页的完整处理

void write_one_page(void)

{

    int i;

    boot_page_ew(address,0x03);  //擦除一个Flash页

    wait_page_rw_ok();           //等待擦除完成

    for(i=0; i

    {

        boot_page_fill(i, ((int)data[i]+(((int)data[i+1])<<8)));

    }

    boot_page_ew(address,0x05); //将缓冲页数据写入一个Flash页

    wait_page_rw_ok();          //等待写入完成

}

//从串口发送一个字节

void uart_putchar(char c)

{

    while(!(UCSRA & 0x20));

    UDR = c;

}

//从串口接收一个字节

int uart_getchar(void)

{

    unsigned char status,res;

    if(!(UCSRA & 0x80)) return -1; //no data to be received

    status = UCSRA;

    res = UDR;

    if (status & 0x1c) return -1; // If error, return -1

    return res;

}

//等待从串口接收一个有效的字节

char uart_waitchar(void)

{

    int c;

    while((c = uart_getchar()) == -1);

    return (char)c;

}

//计算CRC

int calcrc(char *ptr, int count)

{

    int crc = 0;

    char i;

    while (--count >= 0)

    {

        crc = crc ^ (int) *ptr++ << 8;

        i = 8;

        do

        {

            if (crc & 0x8000)

            {

                crc = crc << 1 ^ 0x1021;

            }

            else

            {

                crc = crc << 1;

            }

        }

        while(--i);

    }

    return (crc);

}

//退出Bootloader程序,从0x0000处执行应用程序

void quit(void)

{

    USART_TX_ENABLE();

    uart_putchar(0x0d);

    uart_putchar(0x0a);

    uart_putchar('O');

    uart_putchar('K');

    uart_putchar(0x0d);

    uart_putchar(0x0a);

   

    while(!(UCSRA & 0x40)); //等待结束提示信息回送完成

    UCSRA |=0x40;

    USART_RX_ENABLE();

    

    MCUCR = 0x00;

GICR  = 0x00;

    

    asm("jmp 0x0000\n");     //跳转到Flash的0x0000处,执行用户的应用程序

}

// 端口初始化

void port_init(void)

{

    PORTA = 0x00;

    DDRA  = 0x00;

    PORTB = 0x00;

    DDRB  = 0x00;

    PORTC = 0x00; //m103 output only

    DDRC  = 0x00;

    PORTD = 0x00;

    DDRD  = 0x06;   //--pin3为485收发控制线------------------------------

}

//主程序

void main(void)

{

    int i = 0;

    char a ,b ;

    unsigned int timercount = 0;

    unsigned char packNO = 1;

    int bufferPoint = 0;

    unsigned int crc;

    //Kick_Dog(); //喂狗

    //初始化M16端口,确保端口状态确定

    port_init();

    //初始化M16的USART

    UCSRB = 0x00;

    UCSRA = 0x00;

    UCSRC = BIT(URSEL) | 0x06;

    UBRRH = BAUD_H;

    UBRRL = BAUD_L; //Set baud rate

    UCSRB = 0x18;   //Enable Receiver and Transmitter

    USART_RX_ENABLE(); //模块初始化为接收状态

    //初始化M16的T/C0

    //TIMER0 initialize - prescale:1024

// WGM: Normal

// desired value: 15mSec

// actual value: 14.976mSec (0.2%)

    TCCR0 = 0x00; //stop

    TCNT0 = 0x16; //set count

    OCR0  = 0xEA;  //set compare

    TCCR0 = 0x05; //start timer

    //Kick_Dog(); //喂狗

    //向PC机发送开始提示信息

    USART_TX_ENABLE();

    while(startupString[i] != '\0')

    {

        uart_putchar(startupString[i]);

        i++;

    }

    while(!(UCSRA & 0x40));

    UCSRA |=0x40;  //清位

    USART_RX_ENABLE();

    //Kick_Dog(); //喂狗

    //10秒种等待PC下发"W",否则退出Bootloader程序,从0x0000处执行应用程序

    while(1)

    {

        //Kick_Dog(); //喂狗

        if((uart_getchar() == 'W')||(uart_getchar() == 'w')||(uart_getchar() == 'd')) // 'W'--‘w’-‘d’--------------------------------

        {

            break;

        }

        if (TIFR & 0x02) //timer0 over flow

        {

            if (++timercount > 667)

            {

                quit(); //667*15ms = 10s

            }

            TIFR = TIFR|0x02; //clear interrupt

        }

    }

    //每秒向PC机发送一个控制字符"C",等待控制字

    while(uart_getchar() != XMODEM_SOH) //receive the start of Xmodem

    {

        if(TIFR & 0x02) //timer0 over flow

        {

            //Kick_Dog(); //喂狗

            if(++timercount > 67) //wait about 1 second

            {

                USART_TX_ENABLE();

                uart_putchar(XMODEM_RECIEVING_WAIT_CHAR); //send a "C" , crc verify.

                while(!(UCSRA & 0x40));

                UCSRA |=0x40;

                USART_RX_ENABLE();

                timercount=0;

            }

            TIFR=TIFR | 0x02;

        }

    }

    //当接收到后,开始接收数据块

    do

    {

        //核对数据块编号正确

        if ((packNO == uart_waitchar()) && (packNO == (~uart_waitchar())))

        {

            //Kick_Dog(); //喂狗

            //接收128个字节数据

            for(i=0; i<128; i++)

            {

                data[bufferPoint]= uart_waitchar();

                bufferPoint++;

            }

            //接收2个字节的CRC效验字

            crc = (uart_waitchar()<<8);

            crc += uart_waitchar();

            //Kick_Dog(); //喂狗

            //CRC校验验证

            if(calcrc(&data[bufferPoint-128],128) == crc)  //正确接收128个字节数据  -----------------------

            {

                while(bufferPoint >= SPM_PAGESIZE)  //接收128个字节后,写入flash

                {

                    //Kick_Dog(); //喂狗

                    write_one_page();        //收到128字节写入一页Flash中

                    address += SPM_PAGESIZE; //Flash页加1

                    bufferPoint = 0;

                }

                USART_TX_ENABLE();

                uart_putchar(XMODEM_ACK); //send ack。正确收到一个数据块

                while(!(UCSRA & 0x40));

                UCSRA |=0x40;

                USART_RX_ENABLE();

                //Kick_Dog(); //喂狗

                packNO++;                 //数据块编号加1

            }

            else

            {

                USART_TX_ENABLE();

                uart_putchar(XMODEM_NAK); //要求重发数据块

                while(!(UCSRA & 0x40));

                UCSRA |=0x40;

                USART_RX_ENABLE();

            }

        }

        else

        {

            USART_TX_ENABLE();

            uart_putchar(XMODEM_NAK);     //要求重发数据块

            while(!(UCSRA & 0x40));

            UCSRA |=0x40;

            USART_RX_ENABLE();

        }

    }

    while(uart_waitchar() != XMODEM_EOT);  //循环接收,直到全部发完

    //通知PC机全部收到

    USART_TX_ENABLE();

    uart_putchar(XMODEM_ACK);

    while(!(UCSRA & 0x40));

    UCSRA |=0x40;

    USART_RX_ENABLE();

    //Kick_Dog(); //喂狗

    //把剩余的数据写入Flash中

    if(bufferPoint) write_one_page();

    //退出Bootloader程序,从0x0000处执行应用程序

    quit();

}


关键字:AVR  atmega16  BOOTLoader 引用地址:AVR-atmega16 BOOTLoader 程序

上一篇:一个基于ATMEGA128的直流电机抱死程序
下一篇:嵌入式C语言编程与AVR技巧(一)——C语言环境访问MCU寄存器

推荐阅读最新更新时间:2024-03-16 15:28

AVR单片机读PS2鼠标
如果该程序已验证过的,用的是AVR系列单片机的IO口模拟PS2协议。 #include iom8v.h #include macros.h #include myh.h //MOUSE //时钟接CLK:5--INT0--PD2 #define PINMCLK (PIND&BIT2) #define PRTMCLK_H {DDRD&=NBIT2;PORTD|=BIT2;} #define PRTMCLK_L {DDRD|=BIT2;PORTD&=NBIT2;} //数据接DAT:1--PC4 #define PINMDAT (PINC&BIT4) #define PRTMDAT_H {DDRC&=N
[单片机]
如何解决AVR单片机烧写过程中弄错熔丝位而造
在AVR单片机烧写的过程中,难免有弄错熔丝位的时候,结果是AVR单片机无法读写了!这时我们该怎么办呢,将昂贵的芯片丢掉,再用一块新的。其实这一般是没有必要的,写错熔丝位而导致单片机不能读写,一般不外乎(个人愚见)设设置错了时钟模式,比如说本来是用内部晶振的,结果弄成了外部晶振,而单片机的外部有没有接晶振,这时单片机没有了时钟信号,当然就没有办法在读写了,估计大家也猜到了怎么办了吧,是的,就是由外部提供时钟源。 有第一张图的时钟选择,我们就知道我们得准备多种时钟源: 高频石英/陶瓷晶振,这个直接接在 单片机 晶振位置就可以了,注意频率不要太高,4~5M的就可以了,不放心的话,接两个20P~30P的电容也行! 低频晶振,和
[单片机]
如何解决<font color='red'>AVR</font>单片机烧写过程中弄错熔丝位而造
AVR单片机熔丝位的配置操作及相关解决措施
用户使用并行编程方式、ISP编程方式、JTAG编程方式都可以对AVR的熔丝位进行配置,但不同的编程工具软件提供对熔丝位的配置方式(指人机界面)也是不同的。有的是通过直接填写熔丝位位值(如:CVAVR、PonyProg2000和SLISP等),有的是通过列出表格选择(如AVR STUDIO、BASCOM-AVR)。前者程序界面比较简单,但是需要用户在仔细查询操作,会引起一些意想不到的后果,如造成芯片无法正常运行,无法再次定入ISP编程模式等。建议用户对AVR的熔丝位进行配置时,选择用户表格选择方式界面的编程软件,如BASCOM-AVR。不过版主使用的是前者PonyProg2000。 对AVR熔丝位的配置操作是比较细致的工作,用户往往
[单片机]
<font color='red'>AVR</font>单片机熔丝位的配置操作及相关解决措施
8位共阳数码管74HC595芯片AVR单片机控制 proteus仿真及源码
刚入门AVR单片机一段时间,感觉资料很少,所以进度很慢,刚才百度到这里来,现上传一个数码管的程序来和大家分享,高手就跳过吧,初学可以下载来做参考 proteus仿真原理图: 单片机源程序: /* * smg8_avr.h * * Created: 2017/3/16 1:54:20 * Author: lyl */ #ifndef SMG8_AVR_H_ #define SMG8_AVR_H_ #include lyl_avr.h //数码管端口定义 #define smgPORT PORTA #define smgPORT_DDR DDRA #define DS PA5//串行数据输入端口 #define S
[单片机]
8位共阳数码管74HC595芯片<font color='red'>AVR</font>单片机控制 proteus仿真及源码
马潮老师关于正确配置AVR熔丝位的建议
对AVR熔丝位的配置是比较细致的工作,用户往往忽视其重要性,或感到不易掌握。下面给出对AVR熔丝位的配置操作时的一些要点和需要注意的相关事项。有关ATmega128熔丝位的具体定义和功能请查看本书相关章节,在附录中将给出一个完整的汇总表。 (1)在AVR的器件手册中,对熔丝位使用已编程(Programmed)和未编程(Unprogrammed)定义熔丝位的状态,“Unprogrammed”表示熔丝状态为“1”(禁止);“Programmed”表示熔丝状态为“0”(允许)。因此,配置熔丝位的过程实际上是“配置熔丝位成为未编程状态“1”或成为已编程状态“0””。 (2)在使用通过选择打钩“√”方式确定熔丝位状态值的编程工具软件时,
[单片机]
AVR I2C(TWI)程序
/********************************************************************* 目 的: 建立I2C操作库 目标系统: 基于AVR单片机 应用软件: ICCAVR 版 本: Version 1.0 *********************************************************************/ /*01010101010101010101
[单片机]
AVR EEPROM 读写实验
iccavr教程之 ATMEGA8 中有1024字节的SRAM 、8096字节的FLASH 和 512字节的EEPROM,他们之间的区别是,FLASH是用来保存你的程序代码的,在程序运行过程中,程序本身不可以修改其内容,掉电内容不会丢失,只在烧写 单片机 时修改。SRAM 是保存程序运行过程中产生的临时数据,例如你定义的变量都保存在这里。1K 大小的空间,可以让你随意的定义变量,一般情况下不用担心不够用,只要你能记得住。与 51单片机 相比,这一点要好得多。在51里只有128 或256 字节的空间,而PIC系列更是少的可怜,往往要省着使用。SRAM具有掉电数据丢失的特点,如果想要在开机时得到上一次掉电时的一些数据,这些数据就不能
[单片机]
轻触式开关电路在AVR单片机中的应用
引 言: 单键开关电路已经广泛应用于PDA、手机和电子词典等数码产品中,其实现方式多种多样。一般可采用RS触发器、计数器以及采用555集成电路等等。在单片机的一些实际应用中,以上的实现方式会增加整个电路的复杂度,不能达到简洁、实用的效果。本文将介绍一种可以在单片机应用中实现的,简易、稳定的轻触式单键开关电路。 1 电路原理 如图1所示,DC-DC为一个带有关断控制端的直流稳压电源芯片,MCU是一个单片机。当按下S1时,Q1和D1导通,稳压芯片工作,为单片机供电。单片机马上将相应的I/O引脚置为输出高,这时Q1和Q2导通,整个电路进入工作状态。而后单片机再将这个I/O引脚设置为输入,由于上拉电阻R4的存在,Q1和Q2一直导通。
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved