本程序参照马潮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(); }
上一篇:一个基于ATMEGA128的直流电机抱死程序
下一篇:嵌入式C语言编程与AVR技巧(一)——C语言环境访问MCU寄存器
推荐阅读最新更新时间:2024-03-16 15:28