51头文件1
51单片机头文件reg51.h详解

我们在用c语言编程时往往第一行就是头文件,51单片机为reg51.h或reg52.h,51单片机相对来说比较简单,头文件里面内容不多,像飞思卡尔、ARM 系列的单片机头文件往往内容就非常多,尽管如此,对一些初次接触单片机的朋友来说,51的头文件还是搞不太清楚,今天具体来说明一下。
1)“文件包含”处理概念所谓“文件包含”是指在一个文件内将另外一个文件的内容全部包含进来。
因为被包含的文件中的一些定义和命令使用的频率很高,几乎每个程序中都可能要用到,为了提高编程效率,减少编程人员的重得劳动,将这些定义和命令单独组成一个文件,如reg51.h,然后用#include<reg51.h>包含进来就可以了,这个就相当于工业上的标准零件,拿来直接用就可以了。
2)寄存器地址及位地址声明的原因reg51.h里面主要是一些特殊功能寄存器的地址声明,对可以位寻址的,还包括一些位地址的声明,如果如sfr P1=0x80; sfr IE=0xA8;sbit EA=0xAF等。
sfr P1 = 0x90这句话表示:P1口所对应的特殊功能寄存器P1在内存中的地址为0x80,sbit EA=0xAF这句话表示EA这一位的地址为0xAF。
注意这里出现了一个使用很频繁的sfr和sbit。
sfr 表示特殊功能寄存器的意思,它并非标准C 语言的关键字,而是Keil 为能直接访问80C51中的SFR 而提供了一个新的关键词,其用法是:sfr 特殊功能寄存器名=地址值(注意对于头文件里“特殊功能寄存器名”,用户实际上也可以修改的,如P1=0x80,也可改为A1=0x80,但sfr 和地址值则不能更改,否者会编译出错。
)sbit表示位的意思,它也是非标准C 语言的关键字,编写程序时如需操作寄存器的某一位(可位寻址的寄存器才能用)时,需定义一个位变量,此时就要要到sbit,如sbit deng=P1^0,sbit EA = 0xAF;需要注意的是,位定义时有些特殊,用法有三种:第一种方法:sbit 位变量名=寄存器位地址值第二种方法:sbit 位变量名=SFR 名称^寄存器位值(0-7)第三种方法:sbit 位变量名=SFR 地址值^寄存器位值如:sbit IT0=0x88 (1)说明:0x88是IT0 的位地址值sbit deng=P1^2 (2)说明:其中P1 必须先用sfr 定义好sbit EA=0xA8^7 (3)说明:0xA8 就是IE寄存器的地址值以上三种定义方法需注意的是 IT0 deng EA可由用户随便定义,但必须满足C语言对变量名的定义规则。
51单片机C语言头文件及其使用

51单片机C语言头文件及其使用2007-05-29 16:33很多初学单片机者往往对C51的头文件感到很神秘,而为什么要那样写,甚至有的初学者喜欢问,P1口的P为什么要大写,不大写行不行呢?其实这样的问题,看过本文后,就会明白。
其实这个是在头文件中用sfr定义的,现在定义好了的是这样的sfr P1 = 0x90;,也就是说,到底大写,还是小写,就是在这里面决定的。
这就说明,如果你要用小写,就得在头文件中改为小写。
其实它都是为了编程序方便才这样写的,在程序编译时,就会变成相应的地址(如P1就变成了0x90)。
还有一点就是,现在有很多改进型的单片机,它们有很多新增的特殊功能寄存器在标准的reg51.h或reg52.h中没有定义,这就需要自己加进头文件(相关厂家已经把它们定义好了),当然也可以直接在程序中定义。
下面是一个标准的C51头文件:(此文件一般在C:\KEIL\C51\INC下,INC文件夹根目录里有不少头文件,并且里面还有很多以公司分类的文件夹,里面也都是相关产品的头文件。
如果我们要使用自己写的头文件,使用的时候只需把对应头文件拷贝到INC文件夹里就可以了。
)/* BYTE Registers */sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;sfr PSW = 0xD0;sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;sfr PCON = 0x87;sfr TCON = 0x88;sfr TMOD = 0x89;sfr TL0 = 0x8A;sfr TL1 = 0x8B;sfr TH0 = 0x8C;sfr TH1 = 0x8D;sfr IE = 0xA8;sfr IP = 0xB8;sfr SCON = 0x98;sfr SBUF = 0x99;/* 8052 Extensions */sfr T2CON = 0xC8;sfr RCAP2L = 0xCA;sfr RCAP2H = 0xCB;sfr TL2 = 0xCC;/* BIT Registers */ /* PSW */sbit CY = PSW^7;sbit AC = PSW^6;sbit F0 = PSW^5;sbit RS1 = PSW^4;sbit RS0 = PSW^3;sbit OV = PSW^2;sbit P = PSW^0; //8052 only/* TCON */sbit TF1 = TCON^7;sbit TR1 = TCON^6;sbit TF0 = TCON^5;sbit TR0 = TCON^4;sbit IE1 = TCON^3;sbit IT1 = TCON^2;sbit IE0 = TCON^1;sbit IT0 = TCON^0;/* IE */sbit EA = IE^7;sbit ET2 = IE^5; //8052 onlysbit ES = IE^4;sbit ET1 = IE^3;sbit EX1 = IE^2;sbit ET0 = IE^1;sbit EX0 = IE^0;/* IP */sbit PT2 = IP^5;sbit PS = IP^4;sbit PT1 = IP^3;sbit PX1 = IP^2;sbit PT0 = IP^1;sbit PX0 = IP^0;/* P3 */sbit RD = P3^7;sbit WR = P3^6;sbit T1 = P3^5;sbit INT1 = P3^3;sbit INT0 = P3^2;sbit TXD = P3^1;sbit RXD = P3^0;/* SCON */sbit SM0 = SCON^7;sbit SM1 = SCON^6;sbit SM2 = SCON^5;sbit REN = SCON^4;sbit TB8 = SCON^3;sbit RB8 = SCON^2;sbit TI = SCON^1;sbit RI = SCON^0;/* P1 */sbit T2EX = P1^1; // 8052 onlysbit T2 = P1^0; // 8052 only/* T2CON */sbit TF2 = T2CON^7;sbit EXF2 = T2CON^6;sbit RCLK = T2CON^5;sbit TCLK = T2CON^4;sbit EXEN2 = T2CON^3;sbit TR2 = T2CON^2;sbit C_T2 = T2CON^1;sbit CP_RL2 = T2CON^0;还有一点就是,现在有很多改进型的单片机,它们有很多新增的特殊功能寄存器在标准的reg51.h或reg52.h中没有定义,这就需要自己加进头文件(相关厂家已经把它们定义好了),当然也可以直接在程序中定义。
C51常用头文件

C51常用头文件C51常用头文件1.字符处理函数本类别函数用于对单个字符进行处理,包括字符的类别测试和字符的大小写转换头文件 ctype.h函数列表<>函数类别函数用途详细说明字符测试是否字母和数字 isalnum是否字母 isalpha是否控制字符 iscntrl是否数字 isdigit是否可显示字符(除空格外) isgraph是否可显示字符(包括空格) isprint是否既不是空格,又不是字母和数字的可显示字符 ispunct是否空格 isspace是否大写字母 isupper是否16进制数字(0-9,A-F)字符 isxdigit字符大小写转换函数转换为大写字母 toupper转换为小写字母 tolower2.地区化本类别的函数用于处理不同国家的语言差异。
头文件 local.h函数列表函数类别函数用途详细说明地区控制地区设置 setlocale数字格式约定查询国家的货币、日期、时间等的格式转换localeconv3.数学函数本分类给出了各种数学计算函数,必须提醒的是ANSI C标准中的数据格式并不符合IEEE754标准,一些C语言编译器却遵循IEEE754(例如frinklin C51)头文件 math.h函数列表函数类别函数用途详细说明错误条件处理定义域错误(函数的输入参数值不在规定的范围内)值域错误(函数的返回值不在规定的范围内)三角函数反余弦 acos反正弦 asin反正切 atan反正切2 atan2余弦 cos正弦 sin正切 tan双曲函数双曲余弦 cosh双曲正弦 sinh双曲正切 tanh指数和对数指数函数 exp指数分解函数 frexp乘积指数函数 fdexp自然对数 log以10为底的对数 log10浮点数分解函数 modf幂函数幂函数 pow平方根函数 sqrt整数截断,绝对值和求余数函数求下限接近整数 ceil绝对值 fabs求上限接近整数 floor求余数 fmod4.本分类函数用于实现在不同底函数之间直接跳转代码。
自制51常用头文件(黑色护眼版)

#define LCD_GO_HOME
0x02 // AC=0,光标、画面回HOME位
//设置显示、光标及闪烁开、关
#define LCD_DISPLAY_ON
0x0C // 显示开
#define LCD_DISPLAY_OFF
0x08 // 显示关
#define LCD_CURSOR_ON
0x0A // 光标显示
LCM_RW = 0; LCM_E = 0; LCM_E = 0;
// 若晶振速度太高可以在这后加小的延时 // 延时
LCM_E = 1;
}
/***************************************************** 函 数 名:void WriteCommandLCM() 功 能:向LCM1602中写入指令 说 明:向LCM中写入指令;如果BuysC=0时,忽略忙检测,如果BuysC=1时,不忽略忙检测 入口参数:WCLCM,BuysC 返 回 值:无
void Delay_LCD(void)
{ uint TempCyc = 5552; // 放入延时数据
while(TempCyc--)
{
;
}
}
/***************************************************** 函 数 名:uchar ReadStatusLCM() 功 能:读忙状态 说 明:判断LCM的工作状态;也可以不用此函数,用一段延时程序代替 入口参数:无 返 回 值:LCM_Data
*****************************************************/
//LCM初始化
51单片机常用头文件(LCD1602)

自制51单片机常用头文件(LCD1602)C51 2008-09-24 20:11:05 阅读946 评论0 字号:大中小订阅/*--------------------------------------------------------------------------LCD1602.HThe user function is C51.Copyright (c) 1988-2004 Keil Elektronik GmbH sum zhaojun All rights reserved.--------------------------------------------------------------------------*/#ifndef __LCD1602_H__#define __LCD1602_H__/*连接线图:---------------------------------------------------| LCM-----51 | LCM-----51 | LCM------51 || ----------------------------------------------- || DB0-----P0.0 | DB4-----P0.4 | RS-------P2.0 || DB1-----P0.1 | DB5-----P0.5 | RW-------P2.1 || DB2-----P0.2 | DB6-----P0.6 | E--------P2.2 || DB3-----P0.3 | DB7-----P0.7 | VLCD接1K电阻到GND |---------------------------------------------------*//****************** LCD1602指令 ***********************************///输入方式设置#define LCD_AC_AUTO_INCREMENT 0x06 // 数据读、写操作后,AC自动增一#define LCD_AC_AUTO_DECREASE 0x04 // 数据读、写操作后,AC自动减一#define LCD_MOVE_ENABLE 0x05 // 数据读、写操作,画面平移#define LCD_MOVE_DISENABLE 0x04 // 数据读、写操作,画面不动#define LCD_GO_HOME 0x02 // AC=0,光标、画面回HOME位//设置显示、光标及闪烁开、关#define LCD_DISPLAY_ON 0x0C // 显示开#define LCD_DISPLAY_OFF 0x08 // 显示关#define LCD_CURSOR_ON 0x0A // 光标显示#define LCD_CURSOR_OFF 0x08 // 光标不显示#define LCD_CURSOR_BLINK_ON 0x09 // 光标闪烁#define LCD_CURSOR_BLINK_OFF 0x08 // 光标不闪烁//光标、画面移动,不影响DDRAM#define LCD_LEFT_MOVE 0x18 // LCD显示左移一位#define LCD_RIGHT_MOVE 0x1C // LCD显示右移一位#define LCD_CURSOR_LEFT_MOVE 0x10 // 光标左移一位#define LCD_CURSOR_RIGHT_MOVE 0x14 // 光标右移一位//工作方式设置#define LCD_DISPLAY_DOUBLE_LINE 0x38 // 两行显示#define LCD_DISPLAY_SINGLE_LINE 0x30 // 单行显示#define LCD_CLEAR_SCREEN 0x01 // 清屏/***********************LCD1602地址相关******************************/#define LINE1_HEAD 0x80 // 第一行DDRAM起始地址#define LINE2_HEAD 0xc0 // 第二行DDRAM起始地址#define LINE1 0 // 第一行#define LINE2 1 // 第二行#define LINE_LENGTH 8 // 每行的最大字符长度/***********************LCD1602接线引脚定义**************************/#define LCM_RS P2_0 // 数据/命令选择信号#define LCM_RW P2_1 // 读/写选择信号#define LCM_E P2_2 // 使能信号#define LCM_Data P0 // 显示数据端口#define Busy 0x80 // 用于检测LCM状态字中的Busy标识#define uchar unsigned char#define uint unsigned int//================================ LCM1602控制部分========================================================= /*****************************************************函数名:void Delay_LCD(void)功能:5ms延时说明:LCD显示延时入口参数:无返回值:无*****************************************************/ void Delay_LCD(void){uint TempCyc = 5552; // 放入延时数据while(TempCyc--){;}/*****************************************************函数名:uchar ReadStatusLCM()功能:读忙状态说明:判断LCM的工作状态;也可以不用此函数,用一段延时程序代替入口参数:无返回值:LCM_Data*****************************************************///读状态uchar ReadStatusLCM(void){LCM_Data = 0xFF; // LCM数据口先置1LCM_RS = 0;LCM_RW = 1;LCM_E = 0;LCM_E = 0;LCM_E = 1;while (LCM_Data & Busy) // 检测忙信号.如果忙,则不执行{}return (LCM_Data); // 不忙返回读取数据}/***************************************************** 函数名:void WriteDataLCM()功能:向LCM1602中写入数据说明:将形参WDLCM中的数据写入LCM中入口参数:WDLCM返回值:无*****************************************************/ //写数据void WriteDataLCM(uchar WDLCM){ReadStatusLCM(); // 检测忙LCM_Data = WDLCM; // 写入数据到LCMLCM_RS = 1;LCM_RW = 0;LCM_E = 0; // 若晶振速度太高可以在这后加小的延时 LCM_E = 0; // 延时}/*****************************************************函数名:void WriteCommandLCM()功能:向LCM1602中写入指令说明:向LCM中写入指令;如果BuysC=0时,忽略忙检测,如果BuysC=1时,不忽略忙检测入口参数:WCLCM,BuysC返回值:无*****************************************************///写指令void WriteCommandLCM(uchar WCLCM,BuysC) // BuysC为0时忽略忙检测{if (BuysC){ReadStatusLCM(); // 根据需要检测忙}LCM_Data = WCLCM; // 写入指令LCM_RS = 0;LCM_RW = 0;LCM_E = 0;LCM_E = 1;}/*****************************************************函数名:void LCMInit()功能:初始化LCM1602说明:LCM在工作前先要对显示屏初始化,否则模块无法正常工作入口参数:无返回值:无*****************************************************///LCM初始化void LCMInit(void){LCM_Data = 0;WriteCommandLCM(LCD_DISPLAY_DOUBLE_LINE,0); // 三次显示模式设置,不检测忙信号Delay_LCD();WriteCommandLCM(LCD_DISPLAY_DOUBLE_LINE,0); // 0x38指令表示:8位数据显示模式,俩行多显示Delay_LCD();WriteCommandLCM(LCD_DISPLAY_DOUBLE_LINE,0);Delay_LCD();WriteCommandLCM(LCD_DISPLAY_DOUBLE_LINE,1); // 显示模式设置,开始要求每次检测忙信号WriteCommandLCM(LCD_DISPLAY_OFF,1); // 关闭显示WriteCommandLCM(LCD_CLEAR_SCREEN,1); // 显示清屏WriteCommandLCM(LCD_AC_AUTO_INCREMENT,1); // 显示光标移动设置WriteCommandLCM(LCD_DISPLAY_ON,1); // 显示开及光标设置}/*****************************************************函数名:void DisplayOneChar()功能:按指定坐标中写入数据说明:X-横坐标,Y-纵坐标,DData为ASCII值入口参数:X,Y,DData返回值:无*****************************************************///按指定位置显示一个字符void DisplayOneChar(uchar X, uchar Y, uchar DData){Y &= 0x01;X &= 0x0F; // 限制X不能大于15,Y不能大于1 if (Y){X |= LINE2_HEAD; // 当要显示第二行时地址码:0xc0}X |= LINE1_HEAD; // 第一行的地址码:0x80WriteCommandLCM(X, 0); // 这里不检测忙信号,发送地址码WriteDataLCM(DData);}/*在LCD1602中使用此函数,在DIPS082中使用下面的函数/*****************************************************函数名:void DisplayListChar(uchar x,uchar y,uchar *DData) 功能:向指定坐标中写入字符串(在LCD1602中使用此函数) 说明:X-横坐标,Y-纵坐标入口参数:X,Y,*DData返回值:无*****************************************************//按指定位置显示字符串void DisplayListChar(uchar x,uchar y,uchar *DData){if (y == LINE1) // 判断是否写入第1行{if (x < LINE_LENGTH) // 写入位数{WriteCommandLCM(LINE1_HEAD+x,0); // 写入第1行地址for (; x<LINE_LENGTH&&*DData!='\0'; x++){WriteDataLCM(*(DData++)); // 写入数据}if(*DData != '\0') // 判断数据是否写完{x = 0; // 没写完写入第2行y = LINE2;}}}if (y == LINE2) // 判断是否写入第2行{WriteCommandLCM(LINE2_HEAD+x,0); // 写入第2行地址for (; x<LINE_LENGTH&&*DData!='\0'; x++) // 判断数据是否写完{WriteDataLCM(*(DData++)); // 写入数据}}}*//*****************************************************函数名:void DisplayListChar(uchar X, uchar Y, uchar code *DData)功能:向指定坐标中写入字符串(在DIPS082中使用此的函数) 说明:X-横坐标,Y-纵坐标入口参数:X,Y,*DData返回值:无*****************************************************///按指定位置显示一串字符 ***原来的遇到空格0x20就不显示***void DisplayListChar(uchar X, uchar Y, uchar code *DData) {uchar ListLength,j;ListLength = strlen(DData); // strlen:读取字符串的长度Y &= 0x1;X &= 0xF; // 限制X不能大于15,Y不能大于1if (X <= 0x0F) // X坐标应小于0xF{for(j=0; j<ListLength; j++){DisplayOneChar(X, Y, DData[j]); // 显示单个字符X++; // 横坐标加1,纵坐标不变}}}/***************************************************** 函数名:void Mychar()功能:自定义字符--CGRAM说明:LCM1602字符库中没有温度符号,自定义温度符号入口参数:无返回值:无/*****************************************************/ void Mychar(void){//---------自定义字符代码--00H------闹铃符号------------- WriteCommandLCM(0x40,1); //第1行WriteDataLCM(0x01);//WriteCommandLCM(0x41,1); //第2行WriteDataLCM(0x1b);//WriteCommandLCM(0x42,1); //第3行WriteDataLCM(0x1d);//WriteCommandLCM(0x43,1); //第4行WriteDataLCM(0x19);//WriteCommandLCM(0x44,1); //第5行WriteDataLCM(0x1d);//WriteCommandLCM(0x45,1); //第6行WriteDataLCM(0x1b);//WriteCommandLCM(0x46,1); //第7行WriteDataLCM(0x01);//WriteCommandLCM(0x47,1); //第8行WriteDataLCM(0x00);////---------自定义字符代码--01H-------温度符号------------ WriteCommandLCM(0x48,1); //第1行WriteDataLCM(0x02);//WriteCommandLCM(0x49,1); //第2行WriteDataLCM(0x05);//WriteCommandLCM(0x4a,1); //第3行 1------**--WriteDataLCM(0x05);// 2----**--**WriteCommandLCM(0x4b,1); //第4行 3----**--**WriteDataLCM(0x02);// 4------**--WriteCommandLCM(0x4c,1); //第5行 5----------WriteDataLCM(0x00);// 6----------WriteCommandLCM(0x4d,1); //第6行 7----------WriteDataLCM(0x00);// 8----------WriteCommandLCM(0x4e,1); //第7行WriteDataLCM(0x00);//WriteCommandLCM(0x4f,1); //第8行WriteDataLCM(0x00);////---------自定义字符代码--02H-------当前时间------------WriteCommandLCM(0x50,1); //第1行WriteDataLCM(0x1f);//WriteCommandLCM(0x51,1); //第2行WriteDataLCM(0x11);//WriteCommandLCM(0x52,1); //第3行WriteDataLCM(0x15);//WriteCommandLCM(0x53,1); //第4行WriteDataLCM(0x11);//WriteCommandLCM(0x54,1); //第5行WriteDataLCM(0x1b);//WriteCommandLCM(0x55,1); //第6行WriteDataLCM(0x0a);//WriteCommandLCM(0x56,1); //第7行WriteDataLCM(0x1f);//WriteCommandLCM(0x57,1); //第8行WriteDataLCM(0x00);////----------------------------------------------- }#endif。
自制51单片机常用头文件

自制51单片机常用头文件
#ifndef __COM_H__
#define __COM_H__
#define uchar unsigned char
#define uint unsigned int
#define XTAL 11059200 // CUP 晶振频率
#define baudrate 9600 // 通信波特率
void sendmsg(uint ps)
{
SBUF = ps; // 要发送的字符放入缓冲区
while(TI == 0); // 一直等等,直到发送完数据为止
TI = 0;
}
uint rcvmsg(void) //调用此函数前,要先调用RI,查看是否收到数据,确定已收到的话,再调用此函数
{
RI=0; //要先将RI=0再返回,否则,返回后,RI=0这句就不执行了。
return SBUF;
}
void initcom(void)
{
TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率
TH1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate)));
TL1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate))); // 定时器1赋初值
SM0 = 0; //串口工作方式控制
SM1 = 1; //串口工作方式控制 //这两个共同控制了串口工作方式为 0;
REN = 1; //串口接收允许
PCON = 0x00;
TR1 = 1; //允许串口接收
ES = 0; //关闭串口中断
}
#endif。
关于51单片机启动程序和头文件的深入学习

总的作用:STARTUP.A51//启动文件. 清理RAM.设置堆栈等.即执行完start.a51后跳转到.c文件的main 函数<reg51.h> //特殊寄存器的字节地址和位地址,sfr定义字节变量、sbit定义位变量,用通俗名作为变量名,并赋地址值,从而用名称来使用这些特殊寄存器。
<intrins.h> //定义了一些外部函数,在C51单片机编程中,头文件INTRINS.H的函数使用起来,就会让你像在用汇编时一样简便.特别需要注意的概念:地址与地址值:“地址是存放值的内存空间对应的门牌号码。
地址值是门牌号对应内存空间里存放内容。
通俗讲,一栋楼房, 101号房间什么都没只有1个人。
这个人是值。
101是地址。
房间是内存空间。
”启动程序详细解释;STARTUP.A51:用户上电初始化程序;------------------------------------------------------------------------------;; 用户定义需上电初始化的内存空间;; 使用以下EQU命令可定义在CPU复位时需用0进行初始化的内存空间;; ;IDATA 存储器的空间的绝对起始地址总是0.IDATALENEQU 80H ; 需用0进行初始化的IDATA存储器空间的字节数;XDATASTARTEQU 0H ; XDATA存储器空间的绝对起始地址XDATALENEQU 0H ; 需用0进行初始化的XDATA存储器的空间字节数.;PDATASTARTEQU 0H ; PDATA存储器的空间的绝对起始地址PDATALENEQU 0H ; 需用0进行初始化的PDATA存储器的空间字节数.;; 注意: IDATA 存储器的空间在物理上包括了8051单片机的DATA和BIT存储器空间.; 听说至少要保证与C51编译器运行库有关的存储器的空间进行0初始化不知是否;------------------------------------------------------------------------------;; 再入函数模拟初始化;; 以下用EQU指令定义了再入函数模拟堆栈指针的初始化;; 使用SMALL存储器模式时再入函数的堆栈空间.IBPSTACKEQU 0 ; 使用SMALL存储器模式再入函数时将其设置成1. IBPSTACKTOPEQU 0FFH+1 ; 将堆栈顶设置为最高地址+1.;; 使用LARGE存储器模式时再入函数的堆栈空间.XBPSTACKEQU 0 ; 使用LARGE存储器模式再入函数时将其设置成1. XBPSTACKTOPEQU 0FFFFH+1; 将堆栈顶设置为最高地址+1.;; 使用COMPACT存储器模式时再入函数的堆栈空间.PBPSTACKEQU 0 ; 使用COMPACT存储器模式再入函数时将其设置成1. PBPSTACKTOPEQU 0FFFFH+1; 将堆栈顶设置为最高地址+1.;;------------------------------------------------------------------------------;; 使用COMPACT存储器模式时64K字节XDATA存储器空间的分页定义;; 以下用EQU指令定义PDATA类型变量在XDATA存储器空间的页地址; 使用EQU指令定义PFAGE时必须与L51连接定位器PDATA指令的控制参数一致;PPAGEENABLEEQU 0 ; 使用PDATA类型变量时将其设置成1.PPAGEEQU 0 ; 定义页号.;;------------------------------------------------------------------------------NAME?C_STARTUP ; 模块名为?C_STAUTUP?C_C51STARTUPSEGMENT CODE ; 代码?STACKSEGMENT IDATA ; 堆栈RSEG?STACK ; 堆栈DS 1EXTRNCODE (?C_START) ; 程序开始地址PUBLIC?C_STARTUPCSEGAT 0x8000 ; 定义用户程序的起始地址,用MON51仿真器时可能有用?C_STARTUP:LJMP STARTUP1RSEG?C_C51STARTUPSTARTUP1:;; 初始化串口MOVSCON,#40HMOVTMOD,#20HMOVTH1,#0fdHSETBTR1CLRTI; 单片机上电IDATA内存清零如果不需要上电清零IDATA可以注销IF到IFEDN之间的话句; 或者修改IDTALEN的长度为了具有掉电保护功能不知IDTALEN多长为好IFIDATALEN <> 0MOVR0,#IDATALEN - 1CLR AIDATALOOP:MOV @R0,ADJNZR0,IDATALOOPENDIF;; 单片机上电XDATA内存清零如果不需要上电清零XDATA可以注销IF到IFEDN之间的话句; 或者修改XDATALEN的长度IFXDATALEN <> 0MOVDPTR,#XDATASTARTMOVR7,#LOW (XDATALEN)IF(LOW (XDATALEN)) <> 0MOVR6,#(HIGH (XDATALEN)) +1ELSEMOVR6,#HIGH (XDATALEN)ENDIFCLR AXDATALOOP:MOVX @DPTR,AINCDPTRDJNZR7,XDATALOOPDJNZR6,XDATALOOPENDIF;; 送PDATA存储器页面高位地址IFPPAGEENABLE <> 0MOVP2,#PPAGEENDIF;; 单片机上电PDATA内存清零如果不需要上电清零XDATA可以注销IF到IFEDN之间的话句; 或者修改PDATALEN的长度IFPDATALEN <> 0MOVR0,#PDATASTARTMOVR7,#LOW (PDATALEN)CLR APDATALOOP:MOVX @R0,AINCR0DJNZR7,PDATALOOPENDIF;; 设置使用SMALL存储器模式时再入函数的堆栈空间.IFIBPSTACK <> 0EXTRNDATA (?C_IBP)MOV?C_IBP,#LOW IBPSTACKTOPENDIF;; 设置使用LARGE存储器模式时再入函数的堆栈空间.IFXBPSTACK <> 0EXTRNDATA (?C_XBP)MOV?C_XBP,#HIGH XBPSTACKTOPMOV?C_XBP+1,#LOW XBPSTACKTOPENDIF;; 设置使用COMPACT存储器模式时再入函数的堆栈空间.IFPBPSTACK <> 0EXTRNDATA (?C_PBP)MOV?C_PBP,#LOW PBPSTACKTOPENDIF;; 设置堆栈的起始地址MOVSP,#?STACK-1 ; 例如MOV SP,#4FH;;This code is required if you use L51_BANK.A51 with Banking Mode 4; 如果你的程序使用了Mode 4 程序分组技术请启动下面的程序,不会吧你的程序超过64K 利害;EXTRN CODE (?B_SWITCH0);CALL ?B_SWITCH0 ; init bank mechanism to code bank 0; 程序从第一组bank 0 块开始执行; 跳转到用户程序MAIN函数LJMP?C_STARTEND总之,在KEIL中,汇编是从ORG 000H开始启动,那么它在C51中是如何启动MAIN()函数的呢?实际上是C51中有一个启启动程序STARTUP.A51,它总是和C程序一起编译和链接的.启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:z 定义内部RAM大小、外部RAM大小、可重入堆栈位置z 清除内部、外部或者以此页为单元的外部存储器z 按存储模式初使化重入堆栈及堆栈指针z 初始化8051硬件堆栈指针z 向main( )函数交权头文件详解/*--------------------------------------------------------------------------REG51.HHeader file for generic 80C51 and 80C31 microcontroller.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.--------------------------------------------------------------------------*/#ifndef __REG51_H__#define __REG51_H__/* BYTE Register */ sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;sfr PSW = 0xD0; sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A;sfr TL1 = 0x8B;sfr TH0 = 0x8C;sfr TH1 = 0x8D;sfr IE = 0xA8;sfr IP = 0xB8;sfr SCON = 0x98; sfr SBUF = 0x99;/* BIT Register */ /* PSW */sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0;/* TCON */sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88;/* IE */sbit EA = 0xAF;sbit ES = 0xAC;sbit ET1 = 0xAB;sbit EX1 = 0xAA;sbit ET0 = 0xA9;sbit EX0 = 0xA8;/* IP */sbit PS = 0xBC;sbit PT1 = 0xBB;sbit PX1 = 0xBA;sbit PT0 = 0xB9;sbit PX0 = 0xB8;/* P3 */sbit RD = 0xB7;sbit WR = 0xB6;sbit T1 = 0xB5;sbit T0 = 0xB4;sbit INT1 = 0xB3;sbit INT0 = 0xB2;sbit TXD = 0xB1;sbit RXD = 0xB0;/* SCON */sbit SM0 = 0x9F;sbit SM1 = 0x9E;sbit SM2 = 0x9D;sbit REN = 0x9C;sbit TB8 = 0x9B;sbit RB8 = 0x9A;sbit TI = 0x99;sbit RI = 0x98;#endif/*-------------------------------------------------------------------------- INTRINS.HIntrinsic functions for C51.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved.--------------------------------------------------------------------------*/#ifndef __INTRINS_H__#define __INTRINS_H__extern void _nop_ (void);extern bit _testbit_ (bit);extern unsigned char _cror_ (unsigned char, unsigned char);extern unsigned int _iror_ (unsigned int, unsigned char);extern unsigned long _lror_ (unsigned long, unsigned char);extern unsigned char _crol_ (unsigned char, unsigned char);extern unsigned int _irol_ (unsigned int, unsigned char);extern unsigned long _lrol_ (unsigned long, unsigned char);extern unsigned char _chkfloat_(float);#endif关于sfr、sbit://如同int、char...sfr 似乎不是标准C 语言的关键字,而是Keil 为能直接访问80C51 中的SFR 而提供了一个新的关键词,其用法是:sfrt 变量名=地址值。
C51中头文件的写法

C51中头文件的写法一、头文件位置#include ; 优先在系统默认路径查找头文件#include“xxx.h”有现在项目路径查找头文件二、#ifndef和#endif通常形式为#ifndef _xxxx_h_#define _xxxx_h_.........(头文件具体内容)#endif这样的写法表示,如果_xxxx_h_还没有被定义,那么头文件内容将被执行,如果已经定义过了,那么头文件内容就不执行了。
作用在于,如果某头文件被不同c文件同时调用,那么里面的内容不至于因为重复定义而出错,因为不管调用几次头文件,其内容只有在第一次出现时被执行,同时定义一个_xxxx_h_,以后再次调用时,头文件内容被忽略。
三、函数和宏假设有如下文件 main.caaa.caaa.h其中,,aaa.c里面有一个宏X,一个函数Y,且函数Y 中使用了Xaaa.h里面申明了函数Ymain.c里包含了aaa.h文件,调用了函数Y,但没有定义宏X那么,编译时不会出错,这表示,函数Y中出现宏X 时,它会在自身所在的c文件,即aaa.c里面查找宏变化1:如上情况不变,但是在main.c里面将整个函数Y重新写一遍编译出错,提示 “error C202: 'X': undefined identifier”说明此时函数Y在main.c文件中找不到宏X,因此提示为未定义的符号变化2:将aaa.c中的宏剪切到main.c,其余情况不变编译出错,同样提示“error C202: 'X': undefined identifier”结论:函数中如果出现宏,那么该函数能且只能在其自身所在的c文件中查找该宏,如果二者不在同个c 文件,必然出错。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我们在用c语言编程是往往第一行就是reg51.h,我们怎么样来理解呢?打开reg51.h 可以看到这样的一些内容:
#ifndef __REG51_H__
#define __REG51_H__
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
sfr PSW = 0xD0;
sfr ACC = 0xE0;
sfr B = 0xF0;
sfr SP = 0x81;
sfr DPL = 0x82;
sfr DPH = 0x83;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0 = 0x8A;
sfr TL1 = 0x8B;
sfr TH0 = 0x8C;
sfr TH1 = 0x8D;
sfr IE = 0xA8;
sfr IP = 0xB8;
sfr SCON = 0x98;
sfr SBUF = 0x99;
sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0; sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88; sbit EA = 0xAF; sbit ES = 0xAC; sbit ET1 = 0xAB; sbit EX1 = 0xAA; sbit ET0 = 0xA9; sbit EX0 = 0xA8; sbit PS = 0xBC; sbit PT1 = 0xBB; sbit PX1 = 0xBA; sbit PT0 = 0xB9;
sbit RD = 0xB7;
sbit WR = 0xB6;
sbit T1 = 0xB5;
sbit T0 = 0xB4;
sbit INT1 = 0xB3;
sbit INT0 = 0xB2;
sbit TXD = 0xB1;
sbit RXD = 0xB0;
sbit SM0 = 0x9F;
sbit SM1 = 0x9E;
sbit SM2 = 0x9D;
sbit REN = 0x9C;
sbit TB8 = 0x9B;
sbit RB8 = 0x9A;
sbit TI = 0x99;
sbit RI = 0x98;
#endif
熟悉80C51 内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地址的对应关系。
注意其中有
sfr P1 = 0x90;
这样的一行,即定义P1 与地址0x90 对应,P1 口的地址就是0x90。
从这里还可以看到一个频繁出现的词:sfr
sfr是Keil 为能直接访问80C51 中的SFR 而提供了一个新的关键词,其用法是:sfrt 变量名=地址值。