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[]="nrType 'W' download, Others run application program.nr ";
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,r16n"
"mov r31,r17n"); //将页地址p_address放入Z(R31:R30)寄存器
SPMCR = code; //寄存器SPMCSR中为操作码
asm("spmn"); //对指定Flash页进行操作
}
//填充Flash缓冲页中的一个字
void boot_page_fill(unsigned int address,int data)
{
asm("mov r30,r16n"
"mov r31,r17n" //Z寄存器中为填冲页内地址
"mov r0,r18n"
"mov r1,r19n"); //R1:R0 中为一个指令字
SPMCR = 0x01;
asm("spmn");
}
//等待一个Flash页的写完成
void wait_page_rw_ok(void)
{
while(SPMCR & 0x40)
{
while(SPMCR & 0x01);
SPMCR = 0x11;
asm("spmn");
}
}
//更新一个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 0x0000n"); //跳转到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] != '