⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m128_bootloader.c

📁 LCD的显示
💻 C
字号:
/***************************************************** 
Compiler:   ICC-AVR 6.31 
Target:     Mega128 
Crystal:    16Mhz 
Used:       T/C0,USART0 
*****************************************************/ 
#include <iom128v.h> 
#include <lcd.h>
#define SPM_PAGESIZE 256              /* M128的一个Flash页为256字节(128字) */
#define BAUD 38400                   /* 波特率采用38400bps */
#define CRYSTAL 16000000             /* 系统时钟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        /* 定义接收缓冲区长度 */ 
//定义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_RECIEVING_WAIT_CHAR 'C' 

/* 定义全局变量   \n:换行  \r:换行后下行垂直对齐 \0:空一行*/

const char startupString[]="Press 'd' download, Press 'e' write eepom \n\rOthers run app.\n\r\0"; 
char data[DATA_BUFFER_SIZE]; //256
long address = 0; 

char temp=0;
char load_flag=0;
char wdee_flag=0;
char start_flag=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[i]+(data[i+1]<<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) //最高位为1
            crc = crc << 1 ^ 0x1021; //先左移,然后与多项式(0x1021)异或
        else 
            crc = crc << 1; //最高位为0的话,直接左移
        } while(--i); 
    } 
    return (crc); 
} 
/******************************************************************************/
//退出Bootloader程序,从0x0000处执行应用程序 
void quit(void) 
{ 
     uart_putchar('\n'); 
     uart_putchar('O');
	 uart_putchar('K'); 
     uart_putchar(0x0d); // '\'
	 uart_putchar(0x0a); // '\n'
     while((UCSR0A&0x20)==0); //等待发送完(比较重要)

     MCUCR = 0x01; 
     MCUCR = 0x00;            //将中断向量表迁移到应用程序区头部 
     RAMPZ = 0x00;            //RAMPZ清零初始化 
     asm("jmp 0x0000\n");     //跳转到Flash的0x0000处,执行用户的应用程序 
} 
/*************************************/
 void  ee_write(char adr,char dat)
 {
  SPMCSR&= 0xfe; //禁止写flash
  while(EECR&0x02);       //EEWE=1则等待
  
  EEARH=0;
  EEARL=adr;   //写地址
  EEDR=dat;    //写数据

  EECR|=0x04;  //EEMWE置1
  EECR|=0x02;  //EEWE置1

 }
////////////////////////////////////////////////////////////////////////////////
/******************************************************************************/
/* 主程序 */
void main(void) 
{ 
    int i = 0; 
    unsigned char timercount = 0; 
    unsigned char packNO = 1; 
    int bufferPoint = 0; 
    unsigned int crc; 
	
	init_io();    //点D1
	asm("cli\n"); //关中断
	
	CBI(PORTG,B_L); //开背光
	
	init_lcd();
	
	disp_boot();//显示启动界面
	
//初始化M128的USART0 
    UBRR0H = BAUD_H;     
    UBRR0L = BAUD_L;         //Set baud rate 
    UCSR0B = 0x18;           //Enable Receiver and Transmitter 
    UCSR0C = 0x0E;           //Set frame format: 8data, 2stop bit 
//初始化M128的T/C0,15ms自动重载 
    OCR0 = 0xEA; 
    TCCR0 = 0x0F;     
	
	
//向PC机发送开始提示信息 

    while(startupString[i]!='\0') 
    { 
        uart_putchar(startupString[i]); 
        i++; 
    } 
			
//3秒种等待PC下发"d",否则退出Bootloader程序,从0x0000处执行应用程序 
    while(1) 
    { 
	    temp=uart_getchar();
		
        if(temp == 'd')
		{
		 uart_putchar('d');
		 uart_putchar('\r');
		 uart_putchar('\n');
		 load_flag=1;
		 break;
		}
		if(temp == 'e')  
		{
		 uart_putchar('e');
		 uart_putchar('\r');
		 uart_putchar('\n');
		 wdee_flag=1;
		 break;
		}
        if (TIFR & 0x02)                     //timer0 over flow 
        { 
		  TIFR = TIFR|0x02; 
		  
          if (++timercount > 100) 
		  {
		   timercount=0;
		   quit();                            //200*15ms = 3s 
		  } 
        } 
     } 
		
	  disp_load(); //显示开始下载程序
	  
                   //每秒向PC机发送一个控制字符"C",等待控制字〈soh〉 
      while(uart_getchar()!=XMODEM_SOH)        //receive the start of Xmodem 
       { 
         if(TIFR & 0x02)                   //timer0 over flow 
         { 
		    TIFR=TIFR | 0x02;  
            if(++timercount > 67)                       //wait about 1 second 
            { 
              uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);  //send a "C" 
			  
			  uart_putchar('\r');
			  uart_putchar('\n');
              timercount=0; 
            } 
         } 
       } 	
	   	  
      do       //开始接收数据块 
	  { 
        if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar())))  //核对数据块编号正确 
         {   
            for(i=0;i<128;i++)             //接收128个字节数据 
            { 
              data[bufferPoint]= uart_waitchar(); 
              bufferPoint++;     //最大256
            } 
            crc = (uart_waitchar()<<8); 
            crc += uart_waitchar();           //接收2个字节的CRC效验字 
			
            if(calcrc(&data[bufferPoint-128],128)==crc)    //CRC校验验证 
            {       //正确接收128个字节数据 
			  if(load_flag)
	          {	
                while(bufferPoint >= SPM_PAGESIZE) //正确接受256个字节的数据 
                {                             
                  write_one_page();           //收到256字节写入一页Flash中 
                  address += SPM_PAGESIZE;    //Flash页加1 (256==>0x100)
                  bufferPoint = 0; 
                }     
			  }	
			  else if(wdee_flag) //写eeprom
			  {
			    while(bufferPoint >= SPM_PAGESIZE) //正确接受256个字节的数据 
				{
				  for(temp=0;temp<255;temp++)
				  ee_write(address,data[temp]);
				  address+=SPM_PAGESIZE;
				  bufferPoint=0;
				  uart_putchar(XMODEM_CAN);    
				  quit();    //退出
				 }
			  }
			  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处执行应用程序 
} 
/******************************************************************************/
////////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -