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

📄 bootldr-cn.c.bak

📁 根据HI-TECH PICC18原版BOOTLOADER改进的适合PIC18F4580的BOOTLOADER程序。对HEX文件有要求
💻 BAK
字号:

#pragma psect text=bootldr 
#include <pic18.h>
#include "bootldr.h"

/*
#if defined(MPLAB_ICD)
__CONFIG(4,DEBUGEN & LVPDIS);	// 必须 ICD2 设置
__CONFIG(6,UNPROTECT);			// 允许对FLASH写入
#else
__CONFIG(6,WPB & UNPROTECT);	// BOOTLOADER自保护
#endif
*/

__CONFIG(1,IESODIS&FCMDIS&HS); 
//__CONFIG(1,0x32FF);     // 0011,0010,1111,1111
//振荡器为HS(20M),系统振荡器时钟转换选择禁止,故障保护时钟监视器禁止
//CONFIG1H(IESO,FCMEN,-,-,FOSC3,FOSC2,FOSC1,FOSC0)
//IESO: Internal/External Oscillator Switchover bit, 0=Oscillator Switchover mode disabled
//FCMEN:Fail-Safe Clock Monitor Enable bit,0=Fail-Safe Clock Monitor disabled
//FOSC=0010=HS oscillator
//低8位保留

__CONFIG(2,WDTDIS&WDTPS32K&BORV28&BOREN&PWRTEN);
//__CONFIG(2,0xFEF6);		// 1110,1110, 1111,0110
//监视定时器WDT禁止,掉电锁定复位硬件使能,复位电压为2.8V,上电定时器使能
//CONFIG2H(-,-,-,WDTPS3,WDTPS2,WDTPS1,WDTPS0,WDTEN),看门狗定标和允许位)
//WDTEN=0,狗定标禁止
//CONFIG2L(-,-,-,BORV1,BOVR0,BOREN1,BOREN0,/PWRTEN)
//BORV1:BOVR0=10=2.8V
//BOREN1:BOREN0=11=Brown-out Reset enabled in hardware only(SBOREN is disabled)
///BORTEN=0=Power-up Timer Enable

__CONFIG(3,MCLREN&LPT1DIS&PBADDIS);
//__CONFIG(3,0xF9FF);  	// 1111,1001,1111,1111
//选定B口为数字通道,低电压定时器1振荡禁止高功率,MCLR使能
//CONFIG3H(MCLRE,-,-,-,-,LPT1OSC,PBADEN,-)
//MCLRE:MCLR Pin Enable bit=1=MCLR pin enabled;RE3 input pin disabled
//LPT1OSC:高功率振荡器1,1=低功率,0=高功率
//PBADEN:PB口AD允许位=0,禁止AD
//低8位保留

__CONFIG(4,DEBUGEN&XINSTDIS&BBSIZ1K&LVPDIS&STVREN);
//__CONFIG(4,0xFF2B);   //调试使能(1111,1111,0010,1011)
//使能RB6、RB7为专用调试器接口,堆栈溢出复位使能,低压编程禁止
//CONFIG4L(/DEBUG,XINST,-,BBSIZ,-,LVP,-,STVREN)
///DEBUG:0=调试,RB6/RB7用于ICD,
//XINST:Extended Instruction Set Enable bit=Legacy mode
//BBSIZ:0=1K words (2 Kbytes) boot block
//LVP:0=单电源 ICSP 禁止
//STVREN:1=Stack full/underflow will cause Reset
//高8位保留


#if defined(ERRATA_4000_BOUNDARY)
#error Command line option -NOERRATA must be specified when compiling this code for this device.
#endif


/* 原型函数 */
void checksum(void);
void putch(unsigned char);
void puts(const char *s);
unsigned char gx(void);
unsigned char g2x(void);
void zap(void);
void table_write(void);
void flash8(void);
void clear_buffer(void);

persistent near unsigned char buff[8];	/* 8 字节发热缓冲,用于写入程序存储器 */
persistent near unsigned char DO_NOT_INCREMENT;
persistent near unsigned char cksum,rectype,bcount;
persistent near unsigned char delay_time;
persistent near unsigned char index;
persistent near unsigned short erase;

#ifdef VERBOSE 
persistent near unsigned char START_MSG[] = "HI-TECH Software (C)2002\n";
persistent near unsigned char DOWNLOAD_MSG[] = "\rDownload-";
#endif



/*************************************************************
*			采用汇编将比C的代码更加紧缩
*************************************************************/

/*
#asm
psect intcode							// 重定向高级中断到新的程序地址	
	goto	PROG_START+8	
psect intcodelo							// 重定向低级中断到新的程序地址
	goto	PROG_START+0x18			
#endasm



#ifndef VERBOSE
global _checksum
_checksum:
	call	_g2x		// 读校验和字节
	movf	_cksum,w,c
	btfss	status,2,c	// 如果校验失败.
	reset				// 复位
	return
#endif
*/
#asm

psect intcode	// redirect interrupts to new routine addresses
	goto	PROG_START+8
	
#ifndef VERBOSE
/* Sqeeze the checksum function in between the ISR redirection
 * instructions for even tighter code!
 * Will not fit if VERBOSE mode is enabled, in which case
 * the C version will be used. */
global _checksum
_checksum:
	call	_g2x		// read the checksum byte
	movf	_cksum,w,c
	btfss	status,2,c	// if it doesn't add up...
	reset			// reset
	return
#endif
	
psect intcodelo	// redirect low priority interrupts to new routine addresses
	goto	PROG_START+0x18

#endasm



#ifndef VERBOSE
/*******************************************************************
*						输出1字节到串口
*******************************************************************/
void
putch(unsigned char byte)
{
	while(!TRMT);			// 当发送寄存器空时,TRMT=1 
	TXREG = byte;			//输出1字节 
}

/*******************************************************************
*						输出1串字节到串口
*******************************************************************/
void
puts(const char *s)
{	
	while(s && *s)		
	putch(*s++);	
}


/*********************************************************************
* 						检查校验和字节
* 	如果不用冗长方式, 可使用像上面给出的checksum()函数,将紧缩代码
**********************************************************************/
void
checksum(void){
	g2x();
	if(cksum)		// 如果校验和不等于0,错误校验,重启 
		RESET();
	putch('\r');	// 用换行来应答接收每个HEX字节
}	
#endif


/*********************************************************************
* 				从串口得到4 bit的 HEX数字
**********************************************************************/
unsigned char gx(void)
{
	while(!RCIF);
	EEDATA=RCREG;
	#ifdef VERBOSE
	if(!TRMT)			// Echo RX nibbles to output. If high speed RX, some 
		TXREG=EEDATA;	// nibbles mightn't be TXed but will still be programmed.
	#endif
	if(EEDATA>='A')
	return ((EEDATA - (unsigned char)'A')+10);
	return (EEDATA - '0');
}


/*********************************************************************
* 				将接收到的16进制数字并计算校验
**********************************************************************/
unsigned char g2x(void)
{
	unsigned char temp = (gx()<<4);
	temp += gx();
	cksum+=temp;
	return temp;
}

/* 初始化写内存 */
void
zap(void){
	WREN=1;
	EECON2=0x55;
	EECON2=0xAA;
	WR=1;
	NOP();
	while(WR);
	WREN=0;
}

/* 从RAM传递字节到 flash 寄存器 */
void
table_write(void){
	if(DO_NOT_INCREMENT)	// 地址已经载入 TBLPTR, 不需要预先增加
		asm("tblwt*");
	else
		asm("tblwt+*");	// 否则 TBLPTR 需要预先增加
	DO_NOT_INCREMENT=0;
}

/* 写 8 字节缓冲区到 FLASH */
void
flash8(void){
	if(DO_NOT_INCREMENT)
		TBLPTRL&=0xF8;	// 指向 8 字节块
	for(index=0;index<8;)
	{	
		TABLAT = buff[index++];
		table_write();
	}
	zap();
}

void
clear_buffer(void){
	buff[0] = buff[1] = buff[2] = FILL_BYTE;	// 填充清除字节
	buff[3] = buff[4] = buff[5] = FILL_BYTE;	
	buff[6] = buff[7] = FILL_BYTE;
}


void
main(void){
#if defined(_18F242) || defined(_18F252) || defined(_18F442) || defined(_18F452)
	PIE1=0;	// 这些型号需要的错误校正
#endif

	init_comms();	// 初始化串口

/*******************************************************************************
* 如果串口没有响应,Bootloader 将等待一个设定的时间后,运行原来的固有的程序
*******************************************************************************/

#ifdef VERBOSE
	puts(START_MSG);
#else
	TXREG='\n';
#endif

	// 某些型号的问题,需要清除这些寄存器
	INTCON3=0;	// Also serves to disable interrupts
	PIE2=0;
	INTCON=0;

	T0CON = 0x94;	// 使用这个值产生1秒延时
	for(delay_time=BOOT_TIMEOUT; delay_time ; --delay_time)
	{
		if (RCIF)
			break;
//========================================================
			#ifdef VERBOSE									//  冗长方案
				puts(DOWNLOAD_MSG);						//  给用户一个倒数计秒
				putch('0'+delay_time);
//------------------------------------------------------
			#else														//  压缩方案
				TXREG=('0'+delay_time);
				while(!TRMT);
				TXREG='\r';
			#endif
//========================================================
		while(!TMR0IF);							// 等待定时器0超时
		TMR0IF=0;
	}
	
	T0CON=0xFF;		// 再次停止定时器

	if (!RCIF)		// 如果没有下载到HEX文件, 恢复运行原来程序 /
		{
			(*((void(*)(void))PROG_START))();
		}

	TXREG=':';					// 立即请求你下载一个新的程序

	TBLPTRU=0;
	erase=PROG_START;
	
	while(1)						//清除原来的程序,准备下载的程序使用
	{
		TBLPTRL=(unsigned char)erase;
		TBLPTRH=(unsigned char)(erase>>8);
		EECON1=0x90;			// 准备FLASH删除
		zap();
		erase+=64;
//---------------------------------------------------------
#ifdef UPPER_ADDRESS_BYTE
		if(CARRY)
			TBLPTRU++;
		if(TBLPTRU==UPPER_ADDRESS_BYTE)
#endif
		if(erase==MEM_TOP)
			break;
	}
//---------------------------------------------------------



#ifdef UPPER_ADDRESS_BYTE
	TBLPTRU=0;
#endif

/**********************************************************
* 					通过串口接收HEX文件,然后写到程序空间 
**********************************************************/
	for(;;)		// l循环
	{
		while (RCREG!=':');				// 等待 HEX 文件开始
#ifdef VERBOSE
		putch(':');
#endif		
		cksum = bcount = g2x();		// 取数据长度
#if EEPROM_SIZE > 256
		EEADRH = TBLPTRH = g2x();		// 取地址
#else
		TBLPTRH = g2x();
#endif
		TBLPTRL = EEADR = g2x();
		
		DO_NOT_INCREMENT = 1;
		rectype = g2x();	// 取数据类型
		
		switch(rectype)
		{
			case DATA:	// 数据记录 

#if (PROG_START > 0x200) || defined(__PIC18FX520)	// 保护bootloader避免被改写
				if( (FLASH) && (TBLPTRU==0) && (TBLPTRH < (unsigned char)(PROG_START>>8)) )	// 保护bootloader避免被改写
					break;		
#endif

			clear_buffer();
				while(bcount--)
				{	
					TABLAT = EEDATA = buff[(EEADR&7)] = g2x();	// 取数据

					if((CONFIG)||(EEPROM))
					{
						if(CONFIG)				// EEPROM和配置字节 每次写1个字节
							table_write();
						zap();
					}
					else
						if((EEADR&7)==7)	// IDLOCs和程序每次写8个字节
						{
							flash8();
							clear_buffer();
						}
					EEADR++;
				}	
				if(((EEADR&7)!=0)&&(FLASH))
                                        flash8();

				checksum();
				break;

			case END:														// 文件结束
				checksum();
				TXREG=')';											  //提示升级成功
				(*((void(*)(void))PROG_START))(); // 运行新程序
				break;

			case EXTEND_ADDRESS:	// 扩展地址记录
				while(bcount--)
				{
					EEADR=g2x();	// 是 EE, Config 或 ID 数据
				}
				
				EEPGD=1;
				if(EEADR==0xF0)
					EEPGD=0;	// 选择EEPROM
					
				CFGS=0;
				if((EEADR&0xF0)==0x30)
					CFGS=1;		// 写配置寄存器
					
				TBLPTRU=EEADR;
				checksum();

				break;
		}
	}
}

⌨️ 快捷键说明

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