没有合适的资源?快使用搜索试试~ 我知道了~
首页8051单片机Keil C51编程实战与技巧解析
8051单片机Keil C51编程实战与技巧解析
需积分: 10 1 下载量 158 浏览量
更新于2024-07-20
收藏 1.03MB PDF 举报
"keil c51 语言使用技巧及实战" 本书主要针对Intel 80C51及其派生的51系列单片机,旨在介绍如何高效利用C51语言进行单片机开发,同时提供了实用的技巧和实战案例。书中强调的是如何简化8051工程和开发流程,而非全面教授8051嵌入式系统的解决方案。作者假设读者已具备C语言和8051汇编的基础知识,因此没有深入讲解这两种语言的基本概念。 在内容方面,书中通过具体的项目讨论来阐述遇到的问题,并在适当的地方给出了源代码示例。所有代码都可在配套光盘中找到,但需要注意的是,这些代码可能需要根据具体应用进行调整后才能直接用于实际项目。此外,书中提到,即使只有8051的汇编程序,也可以从书中获益,只需将C语言程序转换为汇编语言。 作者推荐使用Keil C51作为开发工具,认为它提供了优秀的支持,并且本书特别针对Keil C的扩展进行了详细讲解。不过,对于使用其他开发工具(如Archimedes和Avocet)的读者,虽然需要对书中的一些特定指令进行调整,但仍能从中获取有价值的信息。 书中还包含了一些硬件相关的章节,提供简化的硬件图,以帮助读者理解软件与硬件之间的接口。这些图虽然不详尽,但足以让读者理解基本的系统工作原理。 本书旨在作为一个工具书,帮助读者了解在特定硬件和软件设计下8051的性能表现,激发设计灵感,提高开发效率。通过阅读本书,读者不仅可以掌握更多的8051编程技巧,还能学习如何更好地利用C51语言进行单片机开发,从而提升自己的设计能力。
资源详情
资源推荐
![](https://csdnimg.cn/release/download_crawler_static/9526791/bg10.jpg)
广州周立功单片机发展有限公司 Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
16
第二章 用 C 对 8051编程
1 为什么要用高级语言
当设计一个小的嵌入式系统时 一般我们都用汇编语言 在很多工程中 这是一个很
好的方法
因为 代码一般都不超过 8K 而且都比较简单 如果硬件工程师要同时设计软
件和硬件
经常会采用汇编语言来做程序 我的经验告述我 硬件工程师一般不熟系像 C
一类的高级语言
使用汇编的麻烦在于它的可读性和可维护性 特别当程序没有很好的标注的时候 代
码的可重用性也比较低
如果使用 C 的话 可以很好的解决这些问题
用 C 编写的程序 因为 C 语言很好的结构性和模块化 更容易阅读和维护 而且由于
模块化
用 C 语言编写的程序有很好的可移植性 功能化的代码能够很方便的从一个工程
移植到另一个工程
从而减少了开发时间
用 C 编写程序比汇编更符合人们的思考习惯 开发者可以更专心的考虑算法而不是考
虑一些细节问题
这样就减少了开发和调试的时间
使用像 C 这样的语言 程序员不必十分熟系处理器的运算过程 这意味着对新的处理
器也能很快上手
不必知道处理器的具体内部结构 使得用 C 编写的程序比汇编程序有更
好的可移植性
很多处理器支持 C 编译器
所有这些并不说明汇编语言就没了立足之地 很多系统 特别是实时时钟系统都是用
C 和汇编语言联合编程
对时钟要求很严格时 使用汇编语言成了唯一的方法 除此之外
根据我的经验 包括硬件接口的操作都应该用 C 来编程 C 的特点就是 可以使你尽量少
地对硬件进行操作
是一种功能性和结构性很强的语言
2 C 语言的一些要点
这里不是教你如何使用 C 语言
关于 C 语言的书有很多 像 Kernighan 和 Ritchie 所
著的 C 编程语言等
这本书被认为是 C 语言的权威著作 Keil 的 C51 完全支持 C 的标准指
令和很多用来优化 8051 指令结构的 C 的扩展指令
我们将复习关于 C 的一些概念 如结构 联合和类型定义 可能会使一些人伤脑筋
2.1 结构
结构是一种定义类型
它允许程序员把一系列变量集中到一个单元中 当某些变量相
关的时候使用这种类型是很方便的
例如 你用一系列变量来描述一天的时间 你需要定
义时
分 秒三个变量
unsighed char hour,min,sec;
还要定义一个天的变量
unsighed int days;
通过使用结构
你可以把这四个变量定义在一起 给他们一个共同的名字 声明结构
的语法如下
struct time_str{
unsigned char hour,min,sec;
unsigned int days;
}time_of_day;
这告述编译器定义一个类型名为 time_str 的结构
并定义一个名为 time_of_day 的结
构变量
变量成员的引用为结构 变量名.结构成员
time_of_day.hour=XBYTE[HOURS];
time_of_day.days=XBYTE[DAYS];
![](https://csdnimg.cn/release/download_crawler_static/9526791/bg11.jpg)
广州周立功单片机发展有限公司 Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
17
time_of_day.min=time_of_day.sec
curdays=time_of_day.days;
成员变量和其它变量是一样的
但前面必须有结构名 你可以定义很多结构变量 编
译器把他们看成新的变量
例如
struct time_str oldtime,newtime;
这样就产生了两个新的结构变量
这些变量都是相互独立的 就像定义了很多 int 类
型的变量一样
结构变量可以很容易的复制
oldtime=time_of_day;
这使代码很容易阅读
也减少了打字的工作量 当然 你也可以一句一句的复制
oldtime.hour=newtime.hour;
oldtime.days=newtime.days-1;
在 Keil C 和大多数 C 编译器中
结构被提供了连续的存储空间 成员名被用来对结构
内部进行寻址
这样 结构 time_str 被提供了连
续 5 个字节的空间
空间内的变量顺序和定义时
的变量顺序一样
如表 0-1:
如果你定义了一个结构类型
它就像一个变量
新的变量类型
你可建立一个结构数组 包含结构
的结构
和指向结构的指针
2.2 联合
联合和结构很相似
它由相关的变量组成 这些变量构成了联合的成员 但是这些成
员只能有一个起作用
联合的成员变量可以是任何有效类型 包括 C 语言本身拥有的类型
和用户定义的类型
如结构和联合 一个定义联合的类型如下
union time_type {
unsigned long secs_in_year;
struct time_str time;
}mytime;
用一个长整形来存放从这年开始到现在的秒数
另一个可选项是用 time_str 结构来存
储从这年开始到现在的时间
不管联合包含什么 可在任何时候引用他的成员 如下例
mytime.secs_in_year=JUNEIST;
mytime.time.hour=5;
curdays=mytime.time.days;
像结构一样
联合也以连续的空间存储 空间大小等于联合中最大的成员所需的空间
Offset Member Bytes
0 Secs_in_year 4
0 Mytime 5
表 0-2
因为最大的成员需要 5 个字节
联合的存储大小为 5 个字节 当联合的成员为
secs_in_year 时
第 5 个字节没有使用
联合经常被用来提供同一个数据的不同的表达方式 例如 假设你有一个长整型变量
用来存放四个寄存器的值
如果希望对这些数据有两种表达方法 可以在联合中定义一个
长整型变量
同时再定义一个字节数组 如下例
union status_type{
unsigned char status[4];
Offset Member Bytes
0 hour 1
1 min 1
2 sec 1
3 days 2
表
0-1
![](https://csdnimg.cn/release/download_crawler_static/9526791/bg12.jpg)
广州周立功单片机发展有限公司 Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
18
unsigned long status_val;
}io_status;
io_status.status_val=0x12345678;
if(i0_status.status[2]&0x10){
…
}
2.3 指针
指针是一个包含存储区地址的变量
因为指针中包含了变量的地址 它可以对它所指
向的变量进行寻址
就像在 8051 DATA 区中进行寄存器间接寻址和在 XDATA 区中用 DPTR
进行寻址一样
使用指针是非常方便的 因为它很容易从一个变量移到下一个变量 所以
可以写出对大量变量进行操作的通用程序
指针要定义类型 说明指向何种类型的变量 假设你用关键字 long 定义一个指针 C
就把指针所指的地址看成一个长整型变量的基址
这并不说明这个指针被强迫指向长整型
的变量
而是说明 C 把该指针所指的变量看成长整型的 下面是一些指针定义的例子
unsigned char *my_ptr,*anther_ptr;
unsigned int *int_ptr;
float *float_ptr;
time_str *time_ptr;
指针可被赋予任何已经定义的变量或存储器的地址
My_ptr=&char_val;
Int_ptr=&int_array[10];
Time_str=&oldtime;
可通过加减来移动指针
指向不同的存储区地址 在处理数组的时候 这一点特别有
用
当指针加 1 的时候 它加上指针所指数据类型的长度
Time_ptr=(time str *) (0x10000L); //指向地址 0
Time_ptr++; //指向地址 5
指针间可像其它变量那样互相赋值
指针所指向的数据也可通过引用指针来赋值
time_ptr=oldtime_ptr //两个指针指向同一地址
*int_ptr=0x4500 //把 0X4500 赋给 int_ptr 所指的变量
当用指针来引用结构或联合的成员时
可用如下方法
time_ptr->days=234;
*time_ptr.hour=12;
还有一个指针用得比较多的场合是链表和树结构
假设你想产生一个数据结构 可以
进行插入和查询操作
一种最简单的方法就是建立一个双向查询树 你可以像下面那样定
义树的节点
struct bst_node{
unsigned char name[20]; //存储姓名
struct bst_node *left,
,,
, right; //分别指向左
右子树的指针
};
可通过定位新的变量
并把他的地址赋给查询树的左指针或右指针来使双向查询树变
长或缩短
有了指针后 对树的处理变得简单
![](https://csdnimg.cn/release/download_crawler_static/9526791/bg13.jpg)
广州周立功单片机发展有限公司 Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
19
2.4 类型定义
在 C 中进行类型定义就是对给定的类型一个新的类型名
换句话说就是给类型一个新
的名字
例如 你想给结构 time_str 一个新的名字
typedef struct time_str{
unsigned char hour,min,sec;
unsigned int days;
}time_type;
这样
就可以像使用其它变量那样使用 time_type 的类型变量
time_type time,*time_ptr,time_array[10];
类型定义也可用来重新命名 C 的标准类型
typedef unsigned char UBYTE;
typedef char *strptr;
strptr name;
使用类型定义可使你的代码的可读性加强
节省了一些打字的时间 但是很多程序员
大量的使用类型定义
别人再看你的程序时就十分困难了
3 Keil C 和 ANSI C
下面将介绍 Keil C 的主要特点和它与 ANSI C 的不同之处
并给你一些对 8051使用C
的启发
Keil 编译器除了少数一些关键地方外 基本类似于 ANSI C 差异主要是 Keil 可以让
户针对 8051 的结构进行程序设计
其它差异主要是 8051 的一些局限引起的
3.1 数据类型
Keil C 有 ANSI C 的所有标准数据类型
除此之外 为了更加有利的利用 8051 的结构
还加入了一些特殊的数据类型 下表显示了标准数据类型在 8051 中占据的字节数 注意
整型和长整型的符号位字节在最低的地址中
除了这些标准数据类型外 编译器还支持
一种位数据类型
一个位变量存在于内部 RAM
的可位寻址区中
可像操作其它变量那样对位
变量进行操作
而位数组和位指针是违法的
3.2 特殊功能寄存器
特殊功能寄存器用 sfr 来定义
而 sfr16 用来定义 16 位的特殊功能寄存器如 DPTR
通过名字或地址来引用特殊功能寄存器 地址必须高于 80H 可位寻址的特殊功能寄存器
的位变量定义用关键字 sbit
SFR 的定义如列表 0-1所示 对于大多数 8051成员 Keil
提供了一个包含了所有特殊功能寄存器和他们的位的定义的头文件
通过包含头文件可以
很容易的进行新的扩展
列表 0-1
sfr SCON=0X98; //定义 SCON
sbit SM0=0X9F; //定义 SCON 的各位
sbit SM1=0X9E;
sbit SM2=0X9D;
sbit REN=0x9C;
sbit TB8=0X9B;
数据类型
大小
char/unsigned char 8 bit
int/unsigned char 16 bit
long/unsigned long 32 bit
float/double 32 bit
generic pointer 24 bit
表
0-3
![](https://csdnimg.cn/release/download_crawler_static/9526791/bg14.jpg)
广州周立功单片机发展有限公司 Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
20
sbit RB8=0X9A;
sbit TI=0X99;
sbit RI=0X98;
4 存储类型
Keil 允许使用者指定程序变量的存储区
这使使用者可以控制存储区的使用 编译器
可识别以下存储区
存储区 描述
DATA RAM 的低 128 个字节 可在一个周期内直接寻址
BDATA DATA 区的 16 个字节的可位寻址区
IDATA RAM 区的高 128 个字节 必须采用间接寻址
PDATA 外部存储区的 256 个字节 通过 P0 口的地址对其寻址
使用指令 MOVX @Rn,需要两个指令周期
XDATA 外部存储区 使用 DPTR 寻址
CODE 程序存储区 使用 DPTR 寻址
4.1 DATA 区
对 DATA 区的寻址是最快的
所以应该把使用频率高的变量放在 DATA 区 由于空间有
限
必须注意使用 DATA 区除了包含程序变量外 还包含了堆栈和寄存器组 DATA 区的声
明如列表 0-2
列表 0-2
unsigned char data system_status=0;
unsigned int data unit_id[2];
char data inp_string[16];
float data outp_value;
mytype data new_var;
标准变量和用户自定义变量都可存储在 DATA 区中
只要不超过 DATA 区的范围 因为
C51 使用默认的寄存器组来传递参数
你至少失去了 8 个字节 另外 要定义足够大的堆
栈空间
当你的内部堆栈溢出的时候 你的程序会莫名其妙的复位 实际原因是 8051系列
微处理器没有硬件报错机制
堆栈溢出只能以这种方式表示出来
4.2 BDATA 区
你可以在 DATA 区的位寻址区定义变量
这个变量就可进行位寻址 并且声明位变量
这对状态寄存器来说是十分有用的 因为它需要单独的使用变量的每一位 不一定要用位
变量名来引用位变量
下面是一些在 BDATA 段中声明变量和使用位变量的例子
列表 0-3
unsigned char bdata status_byte;
unsigned int bdata status_word;
unsigned long bdata status_dword;
sbit stat_flag=status_byte^4;
if(status_word^15){
…
}
stat_flag=1;
编译器不允许在 BDATA 段中定义 float 和 double 类型的变量
如果你想对浮点数的每
剩余184页未读,继续阅读
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/default.jpg!1)
雪狼315
- 粉丝: 0
- 资源: 5
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
最新资源
- 多模态联合稀疏表示在视频目标跟踪中的应用
- Kubernetes资源管控与Gardener开源软件实践解析
- MPI集群监控与负载平衡策略
- 自动化PHP安全漏洞检测:静态代码分析与数据流方法
- 青苔数据CEO程永:技术生态与阿里云开放创新
- 制造业转型: HyperX引领企业上云策略
- 赵维五分享:航空工业电子采购上云实战与运维策略
- 单片机控制的LED点阵显示屏设计及其实现
- 驻云科技李俊涛:AI驱动的云上服务新趋势与挑战
- 6LoWPAN物联网边界路由器:设计与实现
- 猩便利工程师仲小玉:Terraform云资源管理最佳实践与团队协作
- 类差分度改进的互信息特征选择提升文本分类性能
- VERITAS与阿里云合作的混合云转型与数据保护方案
- 云制造中的生产线仿真模型设计与虚拟化研究
- 汪洋在PostgresChina2018分享:高可用 PostgreSQL 工具与架构设计
- 2018 PostgresChina大会:阿里云时空引擎Ganos在PostgreSQL中的创新应用与多模型存储
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)