📄 main.c
字号:
/*******************************************************************************
程序名称:引导程序,通过串行口加载HEX程序文件到片外RAM并运行
硬件接法:P1.2控制交流蜂鸣器发声
片外接16KB RAM,地址范围0x8000~0xBFFF
功能描述:通过串行口加载HEX程序文件,转换成BIN格式并保存在片外RAM中;
加载完毕后蜂鸣器鸣叫,并等待按下K4;
K4按下后,跳转到RAM去执行程序。
*******************************************************************************/
#include <REG52.h>
#include <ABSACC.H>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
//定义I/O端口
sbit BUZZER = P1^2; //交流蜂鸣器
sbit K4 = P3^5; //按键,按下时输入低电平
//设置晶振频率
#define MCLK 11059200L
//设置波特率
#define BaudRate 4800L
//外部中断INT0入口
void INT0_ISR() interrupt 0
{
#pragma asm
LJMP 0x8003
#pragma endasm
}
//定时器T0中断入口
void T0_ISR() interrupt 1
{
#pragma asm
LJMP 0x800B
#pragma endasm
}
//外部中断INT1入口
void INT1_ISR() interrupt 2
{
#pragma asm
LJMP 0x8013
#pragma endasm
}
//定时器T1中断入口
void T1_ISR() interrupt 3
{
#pragma asm
LJMP 0x801B
#pragma endasm
}
//串行口收发中断入口
void Serial_ISR() interrupt 4
{
#pragma asm
LJMP 0x8023
#pragma endasm
}
//定时器T2中断入口
void T2_ISR() interrupt 5
{
#pragma asm
LJMP 0x802B
#pragma endasm
}
//串行口初始化
void UartInit()
{
//串行口设置:8位UART,允许接收,TI置位
SCON = 0x52;
//波特率加倍
PCON |= 0x80;
//设置定时器T1为8位自动重装模式
TMOD &= 0x0F;
TMOD |= 0x20;
//设置定时器T1的初值
TH1 = 256 - ( MCLK / 12 ) / (16 * BaudRate );
TL1 = TH1;
//启动定时器T1
TR1 = 1;
}
//定义联合整型结构,为访问整型变量的字节部分提供了方便
typedef union
{
unsigned int i;
struct
{
unsigned char H;
unsigned char L;
}CharPart;
}UnionInt;
//定义Intel HEX记录的结构
typedef struct
{
unsigned char ll; //长度
unsigned int aaaa; //地址
unsigned char tt; //记录类型,0-数据,1-终止
char dd[32]; //数据
char cc; //校验和
unsigned int BootAddr; //启动地址
}CIntelHEX;
/*******************************************************************************
函数:AnalyseHEX()
功能:分析一条HEX记录(把Intel HEX记录的文本转换成IntelHEX结构)
参数:hex[]是记录的文本一行内容
转换后的结果保存在IntelHEX结构中
返回:1-转换成功
0-HEX记录文本中有错误
*******************************************************************************/
bit AnalyseHEX(CIntelHEX idata *IntelHEX, char pdata *hex)
{
unsigned char i;
unsigned char j;
unsigned char t;
unsigned char n;
unsigned char cc;
UnionInt x;
//检查冒号
if ( hex[0] != ':' ) return 0;
//检查长度
t = (toint(hex[1])<<4) + toint(hex[2]);
if ( t > 32 ) return 0;
n = 2 * t + 11;
if ( n != strlen(hex) ) return 0;
IntelHEX->ll = t;
cc = t;
//提取地址
t = (toint(hex[3])<<4) + toint(hex[4]);
cc += t;
x.CharPart.H = t;
t = (toint(hex[5])<<4) + toint(hex[6]);
cc += t;
x.CharPart.L = t;
IntelHEX->aaaa = x.i;
//提取记录类型
t = (toint(hex[7])<<4) + toint(hex[8]);
if ( (t==0) || (t==1) )
{
cc += t;
IntelHEX->tt = t;
}
else
{
return 0;
}
//提取数据
i = 9;
if ( t == 0 )
{
j = 0;
n = IntelHEX->ll;
do
{
t = (toint(hex[i++])<<4);
t += toint(hex[i++]);
cc += t;
IntelHEX->dd[j++] = t;
} while ( --n != 0 );
}
//提取校验和
t = (toint(hex[i++])<<4);
t += toint(hex[i++]);
cc += t;
IntelHEX->cc = t;
//检查校验和
if ( cc == 0 )
return 1;
else
return 0;
}
//蜂鸣器鸣叫
void Beep()
{
unsigned int n;
TMOD &= 0xF0; //T0设置在方式1,即16位定时器(不改变T1的模式)
TMOD |= 0x01;
n = 800;
do
{
TH0 = 0xFC; //设置T0初值=65536-(11059200/12)/(2*f)
TL0 = 0x66; //f为发声频率(500Hz)
TR0 = 1; //启动定时器
while ( !TF0 ); //等待定时器溢出
TR0 = 0; //停止定时器
TF0 = 0; //清除溢出标志
BUZZER = !BUZZER; //翻转I/O口,产生方波振荡,使蜂鸣器发声
} while ( --n != 0 );
BUZZER = 1;
}
/*******************************************************************************
函数:Delay()
功能:延时0.01s~2.56s
参数:t>0时,延时(t*0.01)s
t=0时,延时2.56s
说明:定时10ms的定时器初值=65536-0.01/(1/(f/12)),其中f为晶振频率
*******************************************************************************/
void Delay(unsigned char t)
{
TMOD &= 0xF0; //T0设置在方式1,即16位定时器(不改变T1的模式)
TMOD |= 0x01;
do
{
TH0 = 0xDC; //设置定时器初值(定时10ms)
TL0 = 0x00;
TR0 = 1; //启动定时器
while ( !TF0 ); //等待定时器溢出
TR0 = 0; //停止定时器
TF0 = 0; //清除溢出标志
} while ( --t != 0 ); //循环t次
}
//跳到RAM执行程序
void GotoRam()
{
//下载完毕后,发送OK、蜂鸣器鸣叫
printf("OK, press K4 to executing.\r\n");
Beep();
//等待按键K4按下,当K4抬起时,才运行RAM程序
while ( K4 );
Delay(40);
while ( !K4 );
//复位重要SFR寄存器
IE = 0x00;
TCON = 0x00;
TMOD = 0x00;
IP = 0x00;
SCON = 0x00;
//恢复堆栈指针SP默认值;跳到RAM地址0x8000处
#pragma asm
MOV SP, #0x07
LJMP 0x8000
#pragma endasm
}
/*******************************************************************************
函数:GetString()
功能:从串行口读入一行HEX记录
参数:*s-字符缓冲区,保存读入的数据
size-最大限制长度
*******************************************************************************/
void GetString(char pdata *s, unsigned char size)
{
char c;
unsigned char n;
n = 0;
for (;;)
{
c = _getkey();
if ( (c==':') || isxdigit(c) )
{
if ( n < size )
{
s[n++] = c;
}
}
else if ( c == '\n' )
{
s[n] = '\0';
return;
}
}
}
//主程序
void main()
{
unsigned char n;
unsigned char i;
unsigned int addr;
CIntelHEX idata IntelHEX;
char pdata buf[76];
UartInit();
printf("Ready\r\n");
for (;;)
{
GetString(buf,sizeof(buf)-1); //从串行口读入一行HEX记录
if ( AnalyseHEX(&IntelHEX,buf) ) //分析HEX记录,转换成BIN格式
{
switch ( IntelHEX.tt )
{
case 0x00: //HEX类型:数据
//保存BIN代码到RAM
addr = IntelHEX.aaaa;
n = IntelHEX.ll;
for ( i=0; i<n; i++ )
{
XBYTE[addr+i] = IntelHEX.dd[i];
}
break;
case 0x01: //HEX类型:结束
//跳到RAM中运行程序代码
GotoRam();
break;
default:
break;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -