an123927 发表于 2011-6-19 13:24:17

请教马老师:BootLoader程序能和用户程序一起烧写吗?

马老师,请问BootLoader程序能和用户程序一起烧写到单片机去执行吗?
是不是只能先烧写引导程序,再更新用户程序?
如果可以,怎样才能实现和用户程序一起写进去呢?程序上是不是要有哪些改动?
本人是个菜鸟级的,刚接触AVR半年时间,希望能够详细解答,用的是M64,现在有一批板子需要生产,而后续程序需要不断升级,请教下有没有什么方法能够在生产时一次性将BootLoader程序和用户程序一起烧到芯片上,望高手能够指点,非常感谢!!!

machao 发表于 2011-6-19 23:01:53

点击此处下载 ourdev_650331IIE23C.doc(文件大小:69K) (原文件名:HEX文件格式.doc)

参考上面的对HEX文件的介绍,把2段HEX文件拼成1个。
使用文本编辑器就可以了,注意把第一段HEX最后一行的表示结束的去掉。

an123927 发表于 2011-6-20 22:28:41

回复【1楼】machao
-----------------------------------------------------------------------

谢谢马老师,先下来看看,不会的再请教了,感谢!

an123927 发表于 2011-6-21 12:39:19

我在执行引导程序时,总是先执行quit函数,即超级终端总是先收到OK,再收到Type 'd'提示,如果原先就有用户程序,则发完OK之后就直接执行用户程序了,都不能升级程序,请问这是什么原因呢,是不是熔丝位设置的不对啊?
我用的是M64,8M晶振,通讯格式改为一位停止位,只是做了简单的修改,程序如下,熔丝位的配置如图,

/*****************************************************
采用串行接口实现Boot_load应用的实例
华东师大电子系 马 潮 2004.07
Compiler:   ICC-AVR 6.31
Target:   Mega128
Crystal:   16Mhz
Used:   T/C0,USART0
*****************************************************/

/*****************************************************
Compiler:   ICC-AVR 7
Target:   Mega64
Crystal:   8Mhz
Used:   T/C0,USART0
*****************************************************/


#include <iom64v.h>
#define SPM_PAGESIZE 256         //M128的一个Flash页为256字节(128字)
//#define BAUD 38400         //波特率采用38400bps
//#define CRYSTAL 8000000         //系统时钟16MHz
//计算和定义M128的波特率设置参数
//#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

#define DATA_BUFFER_SIZE SPM_PAGESIZE   //定义接收缓冲区长度
//定义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'
//定义全局变量
const char startupString[]="Type 'd' download, Others run app.\n\r\0";
char data;
long address = 0;
//unsigned char jmpcounter = 0;

//擦除(code=0x03)和写入(code=0x05)一个Flash页
void boot_page_ew(long p_address,char code)
{
asm("mov r30,r16\n"
    "mov r31,r17\n");
//    "out 0x3b,r18\n");         //将页地址放入Z寄存器和RAMPZ的Bit0中
SPMCSR = 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");         //R0R1中为一个指令字
SPMCSR = 0x01;
asm("spm\n");
}
//等待一个Flash页的写完成
void wait_page_rw_ok(void)
{
    while(SPMCSR & 0x40)
{
      while(SPMCSR & 0x01);
      SPMCSR = 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<SPM_PAGESIZE;i+=2)         //将数据填入Flash缓冲页中
{
    boot_page_fill(i, data+(data<<8));
}
boot_page_ew(address,0x05);             //将缓冲页数据写入一个Flash页
wait_page_rw_ok();                   //等待写入完成
}      
//从RS232发送一个字节
void uart_putchar(char c)
{
while(!(UCSR0A & 0x20));
UDR0 = c;
}
//从RS232接收一个字节
int uart_getchar(void)
{
unsigned char status,res;
if(!(UCSR0A & 0x80)) return -1;   //no data to be received
status = UCSR0A;
res = UDR0;
if (status & 0x1c) return -1;   // If error, return -1
return res;
}
//等待从RS232接收一个有效的字节
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)
{
//        static unsigned char jmpcounter = 0;
//        if(++jmpcounter <= 1)
//        {
//                asm("jmp 0x7C00");
//        }
        PORTF |= 0x01;
//        while(1);
uart_putchar('O');
uart_putchar('K');
uart_putchar(0x0d);
uart_putchar(0x0a);
while(!(UCSR0A & 0x20));         //等待结束提示信息回送完成

//while(1);

MCUCR = 0x01;
MCUCR = 0x00;             //将中断向量表迁移到应用程序区头部
//RAMPZ = 0x00;             //RAMPZ清零初始化
asm("jmp 0x0000");         //跳转到Flash的0x0000处,执行用户的应用程序
}
//主程序
void main(void)
{
int i = 0;
unsigned char timercount = 0;
unsigned char packNO = 1;
int bufferPoint = 0;
unsigned int crc;

DDRF |= 0x01;
PORTF &= ~0x01;
//jmpcounter ++;

//初始化M128的USART0

UCSR0B = 0x00; //disable while setting baud rate
UCSR0A = 0x00;
UCSR0C = 0x06;
UBRR0L = 0x0C; //set baud rate lo
UBRR0H = 0x00; //set baud rate hi
UCSR0B = 0x18;


//UBRR0H = 0x00;   
//UBRR0L = 0x06;
//UBRR0H = BAUD_H;   
//UBRR0L = BAUD_L;         //Set baud rate
//UCSR0B = 0x18;         //Enable Receiver and Transmitter
//UCSR0C = 0x06;         //Set frame format: 8data, 2stop bit
//初始化M128的T/C0,15ms自动重载 //M648MHz,30ms
OCR0 = 0xEA;
TCCR0 = 0x0F;   
//向PC机发送开始提示信息
while(startupString!='')
{
    uart_putchar(startupString);
    i++;
}
//3秒种等待PC下发“d”,否则退出Bootloader程序,从0x0000处执行应用程序
while(1)
{
    if(uart_getchar()== 'd') break;
    if (TIFR & 0x02)               //timer0 over flow
    {
            PORTF ^= 0x01;
           
//          if (++timercount > 200) quit();   //200*15ms = 3s
      if (++timercount > 100)
      {
//              jmpcounter ++;
              quit();    //100*30ms = 3s
      }
      TIFR = TIFR|0x02;
    }
}
//每秒向PC机发送一个控制字符“C”,等待控制字〈soh〉
while(uart_getchar()!=XMODEM_SOH)   //receive the start of Xmodem
{
      if(TIFR & 0x02)             //timer0 over flow
    {
//      if(++timercount > 67)               //wait about 1 second
      if(++timercount > 34)               //wait about 1 second
      {
              PORTF &= ~0x01;
          uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);   //send a "C"
          timercount=0;
      }
      TIFR=TIFR | 0x02;
    }
}
//开始接收数据块
do
{
    if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))
    {   //核对数据块编号正确
      for(i=0;i<128;i++)         //接收128个字节数据
      {
          data= uart_waitchar();
          bufferPoint++;   
      }
      crc = (uart_waitchar()<<8);
      crc += uart_waitchar();         //接收2个字节的CRC效验字
      if(calcrc(&data,128)==crc)   //CRC校验验证
      {   //正确接收128个字节数据
          while(bufferPoint >= SPM_PAGESIZE)
          {   //正确接受256个字节的数据
            write_one_page();         //收到256字节写入一页Flash中
            address += SPM_PAGESIZE;   //Flash页加1
            bufferPoint = 0;
          }   
          uart_putchar(XMODEM_ACK);   //正确收到一个数据块
          packNO++;               //数据块编号加1
      }
      else
      {
          uart_putchar(XMODEM_NAK);   //要求重发数据块
      }
    }
    else
    {
      uart_putchar(XMODEM_NAK);         //要求重发数据块
    }
}while(uart_waitchar()!=XMODEM_EOT);         //循环接收,直到全部发完
uart_putchar(XMODEM_ACK);               //通知PC机全部收到

if(bufferPoint) write_one_page();         //把剩余的数据写入Flash中
quit();         //退出Bootloader程序,从0x0000处执行应用程序
}




http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650780H0AK82.JPG
图一,ICC设置 (原文件名:1.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650781J5K44F.JPG
图二,ICC设置 (原文件名:2.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650782PDZW6C.JPG
图三,熔丝位配置 (原文件名:3.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650783LTDHXF.JPG
图四,熔丝位配置 (原文件名:4.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650784NC9T0R.JPG
图五,熔丝位配置 (原文件名:5.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650785YSGU8W.JPG
图六,熔丝位配置 (原文件名:6.JPG)

http://cache.amobbs.com/bbs_upload782111/files_41/ourdev_650786MVHZKZ.JPG
图七,超级终端输出 (原文件名:7.JPG)

an123927 发表于 2011-6-21 21:09:14

问题解决了,是由于刚设完波特率就发送数据,波特率还没稳定,发送的数据不对,加一段延时就好了
页: [1]
查看完整版本: 请教马老师:BootLoader程序能和用户程序一起烧写吗?