51单片机 头文件详解教程
- 格式:doc
- 大小:54.50 KB
- 文档页数:8
我们在用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语言头文件及其使用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中没有定义,这就需要自己加进头文件(相关厂家已经把它们定义好了),当然也可以直接在程序中定义。
51单片机C语言学习笔记7:关于.c文件和.h文件2009-09-15 09:55:43| 分类:AVR与C51单片机技| 标签:|举报|字号大中小订阅1)h文件作用1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明;2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h)。
2)h文件里应该有什么常量,结构,类型定义,函数,变量申明。
3)h文件不应该有什么变量定义, 函数定义。
4)extern问题对于变量需要extern;对于函数不需要因为函数的缺省状态是extern的.如果一个函数要改变为只在文件内可见,加static。
5)include包含问题虽然申明和类型定义可以重复,不过推荐使用条件编译。
#ifndef _FILENAME_H,#define _FILENAME_H……#endif6)应该在那儿包含h文件在需要的地方.比如某个提供接口的h文件仅仅被1.c文件需要,那么就在1.c文件里包含。
编写的程序一般会有.H文件和相对应的.C文件,.H文件是声明所用,.C文件是其函数实现部分。
在调用时只要包含.H文件即可,我们没有听说过#include "delay.c"这类的程序,同时也不提倡使用这个形式。
在delay.h文件中://对调用的函数声明#ifndef __DELAY_H__#define __DELAY_H__extern void Delayms(unsigned int n);#endif在delay.c文件中://函数实现部分#include <delay.h>//for crystal 11.0592Mvoid Delayms(unsigned int n){unsigned int i,j;for(j=n;j>0;j--)for(i=112;i>0;i--);}在主程序main.c中#include <delay.h> //在主程序包含.h文件,不能包含.c文件……上述方法仍然要求每建立一个工程就需要把对应的头文件复制到工程的文件夹里,这样看来仍然是比较麻烦的,这时还有另外一中方法就是将做好的头文件放在一个文件夹中,然后将这个文件夹整体拷贝到..KEIL\C51\INC\下面,以后若需要使用某个头文件,就如使用KEIL自带的头文件一样方便了,在主函数mani()之前有一句#include 就可以在main()中使用其中的函数了。
单片机中用c编程时头文件reg51.h及reg52.h解析我们在用c语言编程是往往第一行就是reg51.h或者其他的自定义头文件,我们怎么样来理解呢?1)“文件包含”处理。
程序的第一行是一个“文件包含”处理。
所谓“文件包含”是指一个文件将另外一个文件的内容全部包含进来。
程序中包含REG51.h文件的目的是为了要使用P1 (还有其他更多的符号)这个符号,即通知C 编译器,程序中所写的P1 是指80C51 单片机的P1 端口而不是其它变量。
这是如何做到的呢?打开reg51.h 可以看到这样的一些内容:(此文件一般在C:\KEIL\C51\INC下 ,INC文件夹根目录里有不少头文件,并且里面还有很多以公司分类的文件夹,里面也都是相关产品的头文件。
如果我们要使用自己写的头文件,使用的时候只需把对应头文件拷贝到INC文件夹里就可以了。
)#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 CY = 0xD7; 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 PX0 = 0xB8;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 内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地址的对应关系。
自制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。
总的作用: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中头文件的写法一、头文件位置#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 文件,必然出错。
Keil头文件_intrins.h详解intrins.h在C51单片机编程中,头文件INTRINS.H的函数使用起来,就会让你像在用汇编时一样简便.内部函数描述_crol_ 字符循环左移_cror_ 字符循环右移_irol_ 整数循环左移_iror_ 整数循环右移_lrol_ 长整数循环左移_lror_ 长整数循环右移_nop_ 空操作8051 NOP 指令_testbit_ 测试并清零位8051 JBC 指令函数名: _crol_,_irol_,_lrol_原型: unsigned char _crol_(unsigned char val,unsigned char n);unsigned int _irol_(unsigned int val,unsigned char n);unsigned int _lrol_(unsigned int val,unsigned char n);举例:_crol_,_cror_:将char型变量循环向左(右)移动指定位数后返回_testbit_:相当于JBC bitvar测试该位变量并跳转同时清除。
_chkfloat_:测试并返回源点数状态。
就是汇编中的子函数。
_crol_,_cror_:如国二进制数为01010101 那么_crol_(1) 左移1位后将高位补低位。
结果10101010。
功能:_crol_,_irol_,_lrol_以位形式将val 左移n 位,该函数与8051“RLA”指令相关,上面几个函数不同于参数类型。
例:#includemain(){unsigned int y;C-5 1 程序设计 37y=0x00ff;y=_irol_(y,4);}函数名: _cror_,_iror_,_lror_原型: unsigned char _cror_(unsigned char val,unsigned char n);unsigned int _iror_(unsigned int val,unsigned char n);unsigned int _lror_(unsigned int val,unsigned char n);功能:_cror_,_iror_,_lror_以位形式将val 右移n 位,该函数与8051“RRA”指令相关,上面几个函数不同于参数类型。
8脚51单片机介绍及头文件-STC15F104E发布时间:2011-02-15 15:17:36上次买芯片无意间发现STC也有8个脚的单片机,在我印象中貌似只有ATMEAG有8只脚的。
于是乎买了几个回来,今天下了手册研究以下。
再次将心得写出来STC的8脚单片机有直插和SOP两种形式的封装,其中有6个IO口,剩下2个是VCC和GND ,不需要带晶振内部自带有时钟发生电路,在此要说明这种型号的单片机有专用的烧录软件,在宏晶官网都有下载。
这6个I O口实际上是我们普通单片机上的P3口,实际编程时也是使用P3.X来实现IO口操作。
唯一的不同就是没有硬件的串口,需要用到定时器来模拟(这点不好),但是下载电路和STC的串口下载电路时一样的。
不做修改。
这个有点费解?下载时用到的是串口形式的下载电路,硬件上使用时却没有串口。
杯具啊!关于IO口的复用功能,除P3.1没有复用功能外,其他引脚均有复用功能。
分别是5个外部中断,3个时钟输出,一个复位输入。
芯片默认是不需要复位电路的,上电自复位的。
可以通过软件来选择引脚作为复位脚。
同时在烧录软件上可以选择低压复位。
手册上说的是8种。
软件上只显示了6种-不解???让人惊喜的是烧录软件上提供硬件开启看门狗功能。
还可以选择看门狗分频级数。
还是蛮方便的嘛。
程序又少了几句话。
最后要说一点的是该种单片机以E结尾的都有EEPROM喔。
例如我买的STC15F104E。
有了这种小的单片机,大家以后做点简单的玩意也不拍浪费了。
好东西。
支持一下!特附上修改过的STC15F04 E头文件/*STC15F104E单片机特殊功能寄存器头文件*/#ifndef __REG52_H__#define __REG52_H__/* BYTE Registers */sfr P3 = 0xB0;sfr PSW = 0xD0;sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;/*BIT5 LVDF 低压检测标记位只要VCC小于芯片门槛电压自动置1 需软件清0 同时也是低压检测中断标记位BIT1 PD 为1进入掉电模式硬件清0BIT0 IDL 为1进入空闲模式硬件清0*/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;/* 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 ELVD = IE^6; //低压检测中断sbit ET1 = IE^3;sbit EX1 = IE^2;sbit ET0 = IE^1;sbit EX0 = IE^0;/* IP */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 T0 = P3^4;sbit INT1 = P3^3;sbit INT0 = P3^2;sbit TXD = P3^1;sbit RXD = P3^0;/*IO口的设置寄存器四种模式P3M0 P1M10 0 与普通的IO口一样0 1 设置为强推挽模式1 0 设置为高阻输入模式1 1 设置为高漏输出模式*/sfr P3M0=0XB2;sfr P3M1=0XB1;/*AUXR寄存器BIT7 T0X12 定时器0速度为传统12倍BIT6 T1X12 定时器1速度为传统12倍*/sfr AUXR=0X8E;//不可以位寻址的/*CLK_DIV时钟分频寄存器控制系统时钟的分频数。
C51编程中头文件的使用头文件在C51的编程中是不可缺少的部分。
本文将对keil C中常用头文件予以说明,并就如何编写头文件进行初步介绍。
一、C51常见本征函数库一些常见的头文件都是keil C自带的,在安装目录下的C51文件夹的INC中可以找到keilC中所有的芯片所对应的头文件。
51系列单片机在编程中常用的头文件有:AT89X51.H、INTRINS.H、ABSACC.H、MATH.H。
1、AT89X51.H——本征函数库头文件AT89X51.H是编程中必需要用到的专用寄存器文件。
它与INC中的头文件REG51.H所定义的内容是一样的。
主要用来定义特殊功能寄存器的位地址、程序状态寄存器的位地址、定时器/计数器控制寄存器的位地址、中断使能控制器位地址、单片机P3引脚特殊功能位地址、中断优先权控制寄存器位地址、串行口控制寄存器位地址。
Header 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 P0口锁存器的地址sfr P1 = 0x90 P1口锁存器的地址sfr P2 = 0xA0 P2口锁存器的地址sfr P3 = 0xB0 P3口锁存器的地址sfr PSW = 0xD0 程序状态字sfr ACC = 0xE0 累加器sfr B = 0xF0 B寄存器sfr SP = 0x81 堆栈指针sfr DPL = 0x82 数据指针低位sfr DPH = 0x83 数据指针高位sfr PCON = 0x87 电源控制寄存器sfr TCON = 0x88 定时器/计数器控制寄存器sfr TMOD = 0x89 定时器/计数器方式控制寄存器sfr TL0 = 0x8A 定时器/计数器0(低字节)sfr TL1 = 0x8B 定时器/计数器1(低字节)sfr TH0 = 0x8C 定时器/计数器0(高字节)sfr TH1 = 0x8D 定时器/计数器1(高字节)sfr IE = 0xA8 中断允许控制寄存器sfr IP = 0xB8 中断优先级控制寄存器sfr SCON = 0x98 串行控制寄存器sfr SBUF = 0x99 串行缓冲器BIT Register 程序状态寄存器的地址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 T1计数溢出标志位sbit TR1 = 0x8E T1计数运行控制位sbit TF0 = 0x8D T0计数溢出标志位sbit TR0 = 0x8C T0计数运行控制位sbit IE1 = 0x8B 中断1边沿标志sbit IT1 = 0x8A 中断1控制位sbit IE0 = 0x89 中断0边沿标志位sbit IT0 = 0x88 中断0控制位IE 中断使能控制器位地址sbit EA = 0xAF 总中断控标志位sbit ES = 0xAC 串行中断标志位sbit ET1 = 0xAB T1计数中断标志位sbit EX1 = 0xAA 外部中断1标志位sbit ET0 = 0xA9 T0计数中断标志位sbit EX0 = 0xA8 外部中断0标志位IP 中断优先权控制寄存器位地址sbit PS = 0xBC 串行中断优先标志位sbit PT1 = 0xBB 计数器1中断优先标志位sbit PX1 = 0xBA 外部中断1优先标志位sbit PT0 = 0xB9 计数器0中断优先标志位sbit PX0 = 0xB8 外部中断0优先标志位P3 单片机P3引脚特殊功能位地址sbit RD = 0xB7 外部数据存储器的写入控制信号sbit WR = 0xB6 外部数据存储器的读取控制信号sbit T1 = 0xB5 定时器1外部中断sbit T0 = 0xB4 定时器0外部中断sbit INT1 = 0xB3 外部中断0sbit INT0 = 0xB2 外部中断1sbit TXD = 0xB1 串行输出口sbit RXD = 0xB0 串行输入口SCON 串行口控制寄存器位地址sbit SM0 = 0x9F 串行口模式的选择位sbit SM1 = 0x9E 串行口模式的选择位sbit SM2 = 0x9D 允许模式2和3的多机通讯控制位sbit REN = 0x9C 允许串行接收位sbit TB8 = 0x9B 在模式2和3下传送第9数据位sbit RB8 = 0x9A 在模式2和3下存放第9数据位sbit TI = 0x99 传送中断标志位sbit RI = 0x98 接收中断标志位#endif2、INTRINS.H——本征函数库头文件INTRINS.H主要用来定义空操作、判断并清零和字符及数字的循环移动。
/*--------------------------------------------------------------------------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 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 TI = 0x99;sbit RI = 0x98;#endif--------------------------------------------------------------/*--------------------------------------------------------------------------REG52.HHeader file for generic 80C52 and 80C32 microcontroller.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.--------------------------------------------------------------------------*/#ifndef __REG52_H__#define __REG52_H__/* 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 IP = 0xB8;sfr SCON = 0x98;sfr SBUF = 0x99;/* 8052 Extensions */sfr T2CON = 0xC8;sfr RCAP2L = 0xCA;sfr RCAP2H = 0xCB;sfr TL2 = 0xCC;sfr TH2 = 0xCD;/* 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 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 T0 = P3^4;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 only sbit 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;#endif。
单⽚机中⽤c编程时头⽂件reg51.h及reg52.h解析单⽚机中⽤c编程时头⽂件reg51.h及reg52.h解析我们在⽤c语⾔编程是往往第⼀⾏就是reg51.h或者其他的⾃定义头⽂件,我们怎么样来理解呢?1)“⽂件包含”处理。
程序的第⼀⾏是⼀个“⽂件包含”处理。
所谓“⽂件包含”是指⼀个⽂件将另外⼀个⽂件的内容全部包含进来。
程序中包含REG51.h⽂件的⽬的是为了要使⽤P1 (还有其他更多的符号)这个符号,即通知C 编译器,程序中所写的P1 是指80C51 单⽚机的P1 端⼝⽽不是其它变量。
这是如何做到的呢?打开reg51.h 可以看到这样的⼀些内容:(此⽂件⼀般在C:/KEIL/C51/INC下 ,INC⽂件夹根⽬录⾥有不少头⽂件,并且⾥⾯还有很多以公司分类的⽂件夹,⾥⾯也都是相关产品的头⽂件。
如果我们要使⽤⾃⼰写的头⽂件,使⽤的时候只需把对应头⽂件拷贝到INC⽂件夹⾥就可以了。
)/*--------------------------------------------------------------------------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 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;/* 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熟悉80C51 内部结构的读者不难看出,这⾥都是⼀些符号的定义,即规定符号名与地址的对应关系。
我们在用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语言对变量名的定义规则。
INTRINS.H详细说明:c51中的intrins.h库函数 _crol_ 字符循环左移 _cror_ 字符循环右移 _irol_ 整数循环左移 _iror_ 整数循环右移_lrol_ 长整数循环左移 _lror_ 长整数循环右移_nop_ 空操作8051 NOP 指令_testbit_ 测试并清零位8051 JB C 指令-C51 in the library function intrins.h cycle _crol_ characters characters left _cror_ cycle shifted to right _irol_ the left circle _iror_ integer integer integer cycle shifted to right _lrol_ long cycle of the left circle _lror_ long integer _nop_ air operation shifted to right 8051 NOP instructions _testbit_ tested and cleared 8051 JBC-bit instruction/*--------------------------------------------------------------------------INTRINS.H 本征库函数00Intrinsic functions for C51.Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.--------------------------------------------------------------------------*/00extern void _nop_ (void); //空操作,相当于8051的NOP指令extern bit _testbit_ (bit); //测试并清零位,相当于8051的JBC指令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); //测试并返回源点数状态00/***************************************************************************详解00函数: _crol_,_irol_,_lrol_原型: unsigned char _crol_(unsigned char val,unsigned char n);unsigned int _irol_(unsigned int val,unsigned char n);unsigned int _lrol_(unsigned int val,unsigned char n);功能: _crol_,_irol_,_lrol_以位形式将变量val循环左移n位。
C51常用头文件在KEIL 中,对于单片机所使用的头文件,除了reg51 reg52以外,还有一些从各芯片制商的官网下载与reg51,reg52功能类似的头文件,需了解透外,还要对各类型单片机均可通用且相当有用的的头文件,做相应的了解。
因为,内部所包含的函数与宏定义,可以及大的方便我们编写应用程序1字符函数 ctype.h1 extern bit isalpha(char);功能:检查参数字符是否为英文字母,是则返回12 extern bit isalnum(char)功能:检查字符是否为英文字母或数字字符,是则返回13 extern bit iscntrl(char)功能:检查参数值是否在0x00~0x1f 之间或等于0x7f,是则返回14 extern bit isdigit(char)功能:检查参数是否为数字字符,是则返回15 extern bit isgraph(char)功能:检查参数值是否为可打印字符,是则返回1,可打印字符为0x21~0x7e 6 extern bit isprint(char)功能:除了与isgraph相同之外,还接受空格符0x207 extern bit ispunct(char)功能:不做介绍。
8 extern bit islower(char)功能:检查参数字符的值是否为小写英文字母,是则返回19 extern bit isupper(char)功能:检查参数字符的值是否为大写英文字母,是则返回110 extern bit isspace(char)功能:检查字符是否为下列之一,空格,制表符,回车,换行,垂直制表符和送纸。
如果为真则返回111 extern bit isxdigit(char)功能:检查参数字符是否为16进制数字字符,是则返回112 extern char toint(char)功能:将ASCII字符0~9 a~f(大小写无关)转换成对应的16进制数字,返回值00H~0FH13 extern char tolower(char)功能:将大写字符转换成小写形式,如字符变量不在A~Z之间,则不作转换而直接返回该字符14 extern char toupper(char)功能:将小写字符转换成大写形式,如字符变量不在a~z之间,则不作转换而直接返回该字符15 define toascii(c) ((c)&0x7f)功能:该宏将任何整形数值缩小到有效的ASCII范围之内,它将变量和0x7f相与从而去掉第7位以上的所有数位16 #define tolower(c) (c-‘A’+’a’)功能:该宏将字符与常数0x20 逐位相或17 #define toupper(c) ((c)-‘a’+’A’)功能:该宏将字符与常数0xdf 逐位相与2数学函数 math.hextern int abs (int val);extern char cabs (char val);extern long labs (long val);extern float fabs (float val);功能:返回绝对值。
51头文件详解/*--------------------------------------------------------------------------REG51.H //REG 就是Register(寄存器)的意思,对51单片机的操作就是对寄存器的操作Header file for generic 80C51 and 80C31 microcontroller.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.-------------------------------------------------------------------------------------------- 51单片机是8位地址的,用十六进制来表示就是两位十六进制数,所以下面看到的都是两位十六进制的地址关于位寻址及操作,有个简便方法判断,将字节地址换成10进制后能否被“8”整除,能被“8”整除的就能进行位操作,不能被“8”整除就不能,如P1地址为90H,10进制为144 144/8=18,能被整除,所以可以位操作。
再如TMOD地址为89H, 10进制为137 137/8=17.125,不能被整除,所以不可以位操作。
--------------------------------------------------------------------------------------------*/#ifndef __REG51_H__ //如果没有定义__REG51_H__,那么定义它#define __REG51_H__/* BYTE Register *//* -------------------------------------------------sfr 是special function register,特殊功能寄存器-------------------------------------------------*/sfr P0 = 0x80; // P0口sfr P1 = 0x90; // P1口sfr P2 = 0xA0; // P2口sfr P3 = 0xB0; // P3口sfr PSW = 0xD0; // Program Status Word,程序状态字sfr ACC = 0xE0; // 累加器sfr B = 0xF0; // 乘除法辅助寄存器sfr SP = 0x81; // Stack Point,堆栈指针sfr DPL = 0x82; // 数据指针(低8位)sfr DPH = 0x83; // 数据指针(高8位)sfr PCON = 0x87; // Power Control,电源控制和波特率选择sfr TCON = 0x88; // Timer Controller 定时器控制sfr TMOD = 0x89; // Timer Mode 定时器方式控制寄存器,不可寻址sfr TL0 = 0x8A; // 定时器0低8位sfr TL1 = 0x8B; // 定时器1低8位sfr TH0 = 0x8C; // 定时器0高8位sfr TH1 = 0x8D; // 定时器1高8位sfr IE = 0xA8; // Interrupt Enable 中断使能sfr IP = 0xB8; // Interrupt Priority 中断优先级控制sfr SCON = 0x98; // Seriel Controller 串行口控制寄存器,监视和控制51 芯片串行口的工作状态sfr SBUF = 0x99; // Serial Buffer,串行数据收/发缓冲器1/* BIT Register *//* PSW Program Status Word 程序状态字*//* --------------------------------------------------------------------------------------------- sbit定义特殊功能寄存器的位变量,映射到IO口(P1^1这种IO口的“位”)bit和int char差不多,只不过char=8位, bit=1位而已。
/**********************************51单片机头文件单片机头文件原理及内部接口技术王俊涛整理修改QQ:853210627page页码为郭天祥《新概念51单片机c语言教程》中页码将其复制到文本文档改扩展名为.h***********************************//*--------------------------------------------------------------------------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 */// 四个IO口全部能位寻址sfr P0 = 0x80; //三态双向IO口P0口//低8位地址总线/数据总线sfr P1 = 0x90; //准双向IO口P1口//用户专用sfr P2 = 0xA0; //准双向IO口P2口//高8位地址总线/无外部ram或rom时为用户IO口sfr P3 = 0xB0; //双功能//1.准双向IO口P3口//2.P30 RXD串行数据接受// P31 TXD串行数据发送// P32 外部中断0 信号申请// P33 外部中断1 信号申请// P34 定时/计数器T0 外部计数脉冲输入// P35 定时/计数器T1 外部计数脉冲输入// P36 WR 片外RAM写脉冲信号输入// P37 RD 片外ram读脉冲信号输入sfr PSW = 0xD0; // 可以位寻址//程序状态寄存器Program Status WORD ()程序状态信息//psw.7(CY) 进位标志//psw.6(AC) 辅助进位标志位低四位向高四位进位或借位时AC=1// 主要用于十进制调整//psw.5(F0) 用户可自定义的程序标志位//psw.4(RS1)//psw.3(RS0)// 工作寄存器选择位// 任一时刻只有一组寄存器在工作// 0 0 0区 00H~07H// 0 1 1区 08H~0fH// 1 0 2区 10H~17H// 1 1 3区 18H~1FH////psw.2(OV) 溢出标志位//psw.1( ) 保留为,不可使用//psw.0(P) 奇偶校验位sfr ACC = 0xE0; //累加器A 特殊功能寄存器可位寻址sfr B = 0xF0; //寄存器B 主要用于乘除运算sfr SP= 0x81; //堆栈指针寄存器SP 存放站定栈顶地址sfr DPL = 0x82; //sfr DPH = 0x83; //数据指针寄存器DPTR//对片外RAM及扩展IO进行存取用的地址指针sfr PCON = 0x87; //电源控制寄存器不能位寻址page131//管理单片机的电源部分包括上电复位、掉电模式、空闲模式等//单片机复位时PCON被全部清0//D7 SMOD该位与串口通信波特率有关// SMOD=0 串口方式1 2 3 波特率正常// SMOD=1 串口方式1 2 3 波特率加倍//D6 SMOD0//D5 LVDF//D4 P0F// 这三位STC特有功能//D3 GF1//D2 GF0// 两个通用工作标志位//D1 PD 掉电模式设定位// PD=0;正常工作模式// PD=1;进入掉电模式,// 由外部中断低电平触发或下降沿触发或硬件复位触发// 掉电模式中:外部晶振,cpu,定时器,串行口全部停止工作// 只有外部中断继续工作//D0 IDL 空闲模式设定位// IDL=0;正常工作状态// IDL=1;单片机进入空闲模式// 空闲模式中,除CPU不工作外,其余仍然继续工作// 可由任意个中断或硬件复位唤醒sfr TCON = 0x88; //定时器/计数器控制寄存器可以位寻址page70//D7 TF1 定时器1溢出标志位//D6 TR1 定时器1运行控制位//D5 TF0 定时器0溢出标志位//D4 TR0 定时器0运行控制位//D3 IE1 外部中断1请求标志//D2 IT1 外部中断1 触发方式选择位//D1 IE0 外部中断0请求标志//D0 IT0 外部中断0 触发方式选择位sfr TMOD = 0x89; //定时器/计数器工作方式寄存器不能位寻址//确定工作方式和功能page70//D7 GA TE 门控制位// GA TE=0;定时器/计数器由TRX(x=0,1)来控制// GA TE=1;定时器/计数器由TRX(x=0,1)// 和外部中断引脚(init0,1)来共同控制//D6 C/T 定时器、计数器选择位// 0 选择定时器模式// 1 选择计数器模式//D5 M1//D4 M0// M1 M0 工作方式// 0 0 方式0 13位定时器/计数器// 0 1 方式1 16位定时器/计数器// 1 0 方式2 8位自动重装定时器/计数器// 1 1 方式3 仅适用T0 分成两个8位计数器,T1停止计数//D3 GA TE 门控制位// GA TE=0;定时器/计数器由TRX(x=0,1)来控制// GA TE=1;定时器/计数器由TRX(x=0,1)// 和外部中断引脚(init0,1)来共同控制//D2 C/T 定时器、计数器选择位// 0 选择定时器模式// 1 选择计数器模式//D1 M1//D0 M0// M1 M0 工作方式// 0 0 方式0 13位定时器/计数器// 0 1 方式1 16位定时器/计数器// 1 0 方式2 8位自动重装定时器/计数器// 1 1 方式3 仅适用T0 分成两个8位计数器,T1停止计数sfr TL0 = 0x8A; //定时器/计数器0高8位容器加1 计数器sfr TL1 = 0x8B; //定时器/计数器1高8位容器sfr TH0 = 0x8C; //定时器/计数器0低8位容器sfr TH1 = 0x8D; //定时器/计数器1低8位容器sfr IE = 0xA8; //中断允许寄存器可以位寻址//D7 EA 全局中断允许位//D6 NULL//D5 ET2 定时器/计数器2中断允许位interrupt 5//D4 ES 串行口中断允许位interrupt 4//D3 ET1 定时器/计数器1中断允许位interrupt 3//D2 EX1 外部中断1中断允许位interrupt 2//D1 ET0 定时器/计数器0中断允许位interrupt 1//D0 EX0 外部中断0中断允许位interrupt 0sfr IP= 0xB8; //中断优先级寄存器可进行位寻址//D7 NULL//D6 NULL//D5 NULL//D4 PS 串行口中断定义优先级控制位// 1 串行口中断定义为高优先级中断// 0 串行口中断定义为低优先级中断////D3 PT1// 1 定时器/计数器1中断定义为高优先级中断// 0 定时器/计数器1中断定义为低优先级中断//D2 PX1// 1 外部中断1定义为高优先级中断// 0 外部中断1定义为低优先级中断//D1 PT0// 1 定时器/计数器0中断定义为高优先级中断// 0 定时器/计数器0中断定义为低优先级中断//D0 PX0// 1 外部中断0定义为高优先级中断// 0 外部中断0定义为低优先级中断sfr SCON = 0x98; //串行口控制寄存器可以进行位寻址page134//D7 SM0//D6 SM1// SM0 SM1 串行口工作方式// 0 0 同步移位寄存器方式// 0 1 10位异步收发(8位数据),波特率可变(定时器1溢出率控制)// 1 0 11位异步收发(9位数据),波特率固定// 1 1 11异步收发(9位数据),波特率可变(定时器1溢出率控制)//D5 SM2 多机通信控制位主要用于方式2和方式3//D4 REN 允许串行接收位//D3 TB8 方式2,3中发送数据的第9位//D2 RB8 方式2,3中接受数据的第9位//D1 TI 发送中断标志位//D0 RI 接受中断标志位sfr SBUF = 0x99; //串行数据缓冲区/*****************************************************************************下面是位寻址区上面做过解释的就不在下面一一解释了******************************************************************************/ /* BIT Register *//* PSW */sbit CY= 0xD7;sbit AC = 0xD6;sbit F0 = 0xD5;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 TB8 = 0x9B; sbit RB8 = 0x9A; sbit TI = 0x99; sbit RI = 0x98;#endif。