Atmega32的Bootloader程序,下面是源码。
在使用时需要将熔丝位进行配置:
1.编程BOOTSZ0、BOOTSZ1和BOOTRST三处,然后通过下载器将BOOTLOADER的hex下载到单片机中,重启后就从BOOTLOADER处运行了。
2.注意本例子使用的是内部8MHz和9600的波特率。
3.启动后可以看到:
然后按下‘D’键进入Bootloader等待下载。
#include
#include
#include
#include
#include
//IO定義
#define PIN_RXD 0 //PD0
#define PIN_TXD 1 //PD1
//常數定義
#define SPM_PAGESIZE 128
#define DATA_BUFFER_SIZE SPM_PAGESIZE
#define BAUDRATE 9600
#undef F_CPU
#define F_CPU 8000000
//定義xmodem控制字符
#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;
unsigned long FlashAddress; //FLASH地址
#define BootAdd 0x7000 //Boot区的首地址(应用区的最高地址)
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 //完成
#define PROG_START 0x0000
//延時
void delay_ms(unsigned int t)
{
while(t--)
{
_delay_ms(1);
}
}
void write_one_page(void)
{
unsigned char i;
unsigned char *buf;
unsigned int w;
boot_page_erase(FlashAddress);
boot_spm_busy_wait();
buf=&strXMODEM.Xdata[0];
for(i=0;i { w=*buf++; w+=(*buf++)<<8; boot_page_fill(i,w); } boot_page_write(FlashAddress); 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); //结尾发送回车换行 } 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< timeout--; } }while (timeout); return count; } 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 = 0; unsigned char i; unsigned int crc; WDTCR &= ~(1< DDRD=(1< GICR = (1< GICR = (0< cli(); UCSRC = (1< UBRRL = (F_CPU/BAUDRATE/16-1)%256; //设定波特率 UBRRH = (F_CPU/BAUDRATE/16-1)/256; UCSRA = 0x00; UCSRB = (1< OCR0 = 28; TCCR0 = (1< //CTC模式下,溢出标志是输出比较匹配OCF0,对应的中断是输出比较匹配中断; put_c(0x0c); put_c(0x0c); put_c(0x0c); //超級終端清屏 put_s("User want updata the programme,please touch [d]rnOtherwise the MCU run the old programme.rn"); get_data(&c,1,3000); //限时3秒,接收一个数据 if ((c=='d')||(c=='D')) { STATUS=ST_WAIT_START; //并且数据='d'或'D',进入XMODEM put_s("Please use xmodem transmit the *.bin file."); } else { STATUS=ST_OK; //退出Bootloader程序 } 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); 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("Updata the programme success."); break; case XMODEM_CAN: //收到取消符CAN put_c(XMODEM_ACK); //回应PC机 STATUS=ST_OK; put_s("Warning! It canceled by user to updata the programme."); 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; if(calcrc(&strXMODEM.Xdata[0],128)!=crc) { put_c(XMODEM_NAK); //CRC错误,要求重发当前数据块 continue; } //正确接收128个字节数据,刚好是M16的一页 if (FlashAddress { //如果地址在应用区内 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("The programme is out of the flash,cancle transmitted. "); break; } put_c(XMODEM_ACK); //回应已正确收到一个数据块 BlockCount++; //数据块累计加1 } } put_s("LET'S GO!"); loop_until_bit_is_set(UCSRA,UDRE); //等待结束提示信息回送完成 GICR = (1< GICR = (0< /* 无论BootLoader是否使用中断,将中断向量表迁移到应用程序区头部,会增强程序的健壮性*/ boot_rww_enable (); //RWW区读允许,否则无法马上执行用户的应用程序 asm volatile("jmp 0x0000"); //跳转到Flash的0x0000处,执行用户的应用程序 }
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』