求一个程序,两个89C51单片机中断程序连接,用串口通信使按下其中一个单片机中断程序的键另一个单片机中断程序的灯亮灭,反之亦然

51单片机串口连接
51单片机串口连接
51单片机串口连接
51单片机串口连接
51单片机串口连接知识来自于造价通云知平台上百万用户的经验与心得交流。
造价通即可以了解到相关51单片机串口连接最新的精华知识、热门知识、相关问答、行业资讯及精品资料下载。同时,造价通还为您提供材价查询、测算、、等建设行业领域优质服务。手机版访问:
&&&&为规范钢筋加工、使用行为,保障工程质量,根据质检总局、住房城乡建设部、工商总局《关于进一步加强建筑钢筋质量监管严惩“瘦身”钢筋等违法行为的通知》文件要求,近日,陕西省住建厅就加强建筑工程使用钢筋质量管理工作提出具体要求。
&&&&《国务院关于取消一批职业资格许可和认定事项的决定》(国发〔2016〕5号)文件要求,江苏省工程造价信息网造价员登录系统现已关闭,同时停止办理造价员变更、补办、验证、注销等相关事项。
&&&&日前,住房和城乡建设部在渝组织召开了互联网+工程造价信息服务专题研讨会,住建部标准定额司、标准定额研究所、重庆、北京、广东等省市造价管理机构及我市建设、施工、造价咨询和软件企业代表共计30余人出席了会议。会议由住建部标准定额研究所胡传海副所长主持。
&&&&据记者获悉,为进一步推行工程保证担保制度,促进市场公平竞争,预防拖欠工程款等问题的发生,北京市住建委对《关于进一步规范房地产开发项目工程保证担保的暂行办法》(京建法〔号)进行了修订,重新制发了《关于进一步规范房地产开发项目工程保证担保的办法》。
&&&&根据《国家统计局关于批准执行工程招标代理机构统计报表制度的函》(国统制[2016]83号),2017年继续执行《工程招标代理机构统计报表制度》(以下简称《统计报表制度》)。为做好2017年工程招标代理机构统计工作,现将有关事项通知如下。
&&&&为切实做好冬季安全生产工作,减少和避免恶劣气候条件对生产、生活造成的不利因素,提前做好冬季安全生产各项防范措施,预防各类事故的发生,11月16日,滕州市造价处组织全体干部职工召开安全生产工作会议,安排部署冬季安全生产工作。
&&&&根据陕西省住建厅《关于整顿和规范预拌商品混凝土市场秩序的通知》和延安市住建局《关于对全市预拌商品混凝土企业进行专项检查的通知》文件要求,为确保工程质量和建筑结构安全,规范全市预拌商品混凝土市场。10月13日至30日,延安市住建局对全市预拌混凝土企业进行了检查。
&&&&为贯彻落实《新时期产业工人队伍建设改革方案》《国务院办公厅关于促进建筑业持续健康发展的意见》和《国务院办公厅关于全面治理拖欠农民工工资问题的意见》,加快培育新时期建筑业产业工人队伍,我部研究起草了《关于培育新时期建筑产业工人队伍的指导意见》(征求意见稿)。
&&&&为贯彻落实《国务院办公厅关于促进建筑业持续健康发展的意见》(国办发[2017]19号),加快促进建筑产业升级,增强产业建造创新能力,我部组织编制了《建筑业10项新技术(2017版)》,现印发给你们,请做好推广应用工作,全面提升建筑业技术水平。
&&&&日前,惠州市房管局发布《关于贯彻落实〈惠州市住宅专项维修资金管理实施细则〉有关规定的通知》(以下简称“通知”),对住宅维修资金的缴存、监管和使用问题予以规范。
更新、更全、更专业的建设行业内容尽在造价通官方微信公众号!
关于造价通
造价通-中国首个建设行业大数据服务平台!国家《建设工程人工材料设备机械数据标准》参编单位和数据提供方!拥有全国最大的材料价格数据信息系统,云造价数据管理系统,行业资讯系统,工程指标系统,造价指数系统等等,数据已覆盖全国600多个城市等。
51单片机串口连接相关专题
分类检索:
增值电信业务经营许可证B2-您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
毕业设计(论文)-数字存储式自动应答录音系统设计.doc 47页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
需要金币:200 &&
你可能关注的文档:
··········
··········
东华理工大学
毕业设计(论文)
数字存储式自动应答录音系统
Dynamic Chinese Character
Dot-matrix Display Screen
二零零年六月
数字存储式自动应答录音系统是将微电子技术﹑A/D转换技术﹑信息处理等技术综合一体的现代新技术,它与传统的电话机紧密结合成为一种新的通讯工具,广泛应用于家庭、办公等场所。
数字存储式自动应答录音系统主要由A/D转换芯片、存储芯片以及完成功能控制的单片机控制部分组成。该系统可以用于电脑自动应答、数字点歌、自动音频服务等方面。数字存储式自动应答录音机由于功能多,使用方便而备受用户的欢迎,也是电话机中近年高速发展的新型科技产品。
本系统是针对数字存储式自动应答录音系统进行研究的。为了阐明用单片机控制录音的方法,对录音模块单元如何进行、A/D怎么转换,消息怎样存储进行了研究。本文在给出数字存储式自动应答录音硬件设计的基础上,详细分析了数字存储式自动应答录音系统的软件控制方法。本系统介绍用单片机进行控制,利用ISD2590芯片设计实现的一种数字式自动答录系统。该系统具有一定程度的智能化,且实现简单,具有较大的可扩充性。
关键词:单片机; ISD2590芯片; 录音; 双音多频(DTMF)
The digital memory type auto answer recording channel is the microelectron technology,It with the traditional telephone in close integration with into one kind of recent communication facilities, widely applies to place and so on family, work.。
The digital memory type auto answer recording channel mainly by the A/D transformation chip, the memory chip as well as completes the
function control the monolithic integrated circuit control section to be composed. This system may use in aspect and so on computer auto answer, digital song, automatic audio frequency service. The digital memory type auto answer tape recorder are many as a result of the function, the easy to operate prepares user's welcome, also was in the telephone the recent years high speed development new technical product.。
This system is aims at the digital memory type auto answer recording channel to conduct the research. In order to expound with the monolithic integrated circuit control sound recording method, how to records the module unit to carry on, A/D how transforms, how did the news save has conducted the research. This article in produces in the foundation which the digital memory type auto answer sound recording hardware designs, multianalysis numeral memory type auto answer recording channel software control method。This syste
正在加载中,请稍后...21ic官方微信-->
后使用快捷导航没有帐号?
请完成以下验证码
查看: 8226|回复: 13
求两个51单片机双机串行通信的c语言程序
&&已结帖(20)
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
主题帖子积分
专家等级:结帖率:84%
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
两片AT89s52,双机串行通信程序,要发送字符串变量(一个数组)。
并且不能发乱了,因为接收机还有其他中断
, , , , , ,
主题帖子积分
初级工程师, 积分 2319, 距离下一级还需 681 积分
初级工程师, 积分 2319, 距离下一级还需 681 积分
主题帖子积分
专家等级:结帖率:91%
主题帖子积分
初级工程师, 积分 2319, 距离下一级还需 681 积分
初级工程师, 积分 2319, 距离下一级还需 681 积分
什么意思,哪个东西没有好几个中断要处理。。
还直接求程序了?
总结前半辈子,计划后半辈子。。
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
主题帖子积分
专家等级:结帖率:84%
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
什么意思,哪个东西没有好几个中断要处理。。
还直接求程序了?
linbei1988 发表于
就是要双机通信的程序啦。
但是不能要学习板带的视频里那种,没有握手什么的。只能做通信的程序。
主题帖子积分
中级工程师, 积分 4710, 距离下一级还需 290 积分
中级工程师, 积分 4710, 距离下一级还需 290 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
中级工程师, 积分 4710, 距离下一级还需 290 积分
中级工程师, 积分 4710, 距离下一级还需 290 积分
模拟I2C或SPI,网上很多这种源码
主题帖子积分
高级工程师, 积分 5864, 距离下一级还需 2136 积分
高级工程师, 积分 5864, 距离下一级还需 2136 积分
主题帖子积分
专家等级:结帖率:96%
主题帖子积分
高级工程师, 积分 5864, 距离下一级还需 2136 积分
高级工程师, 积分 5864, 距离下一级还需 2136 积分
两片AT89s52
直接用串口多好 中断实现
世间奇景,昙花一现,过眼云烟,余香留世。
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
主题帖子积分
专家等级:结帖率:84%
主题帖子积分
中级技术员, 积分 102, 距离下一级还需 198 积分
中级技术员, 积分 102, 距离下一级还需 198 积分
A给B发送数据,握手信号之后用不用清一下SBUF。如果不清楚是不是握手信号一直有效啊。
主题帖子积分
助理工程师, 积分 1042, 距离下一级还需 958 积分
助理工程师, 积分 1042, 距离下一级还需 958 积分
主题帖子积分
专家等级:结帖率:58%
主题帖子积分
助理工程师, 积分 1042, 距离下一级还需 958 积分
助理工程师, 积分 1042, 距离下一级还需 958 积分
哈哈, 好像挺简单的。
主题帖子积分
高级技术员, 积分 869, 距离下一级还需 131 积分
高级技术员, 积分 869, 距离下一级还需 131 积分
主题帖子积分
专家等级:结帖率:11%
主题帖子积分
高级技术员, 积分 869, 距离下一级还需 131 积分
高级技术员, 积分 869, 距离下一级还需 131 积分
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
自己试试看
主题帖子积分
中级技术员, 积分 105, 距离下一级还需 195 积分
中级技术员, 积分 105, 距离下一级还需 195 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
中级技术员, 积分 105, 距离下一级还需 195 积分
中级技术员, 积分 105, 距离下一级还需 195 积分
#include&reg52.h&
void main()
TMOD=0X02;
if(temp==1)
if(TI==1);
void ser () interrupt 4
主题帖子积分
中级技术员, 积分 273, 距离下一级还需 27 积分
中级技术员, 积分 273, 距离下一级还需 27 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
中级技术员, 积分 273, 距离下一级还需 27 积分
中级技术员, 积分 273, 距离下一级还需 27 积分
//**************************发送*************************
#include &reg51.h&
& &
unsigned char b[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void init(void)
{
& & SCON = 0x50;& && && && &// 串行口工作方式1,允许接收
& & PCON = 0x00;& && && && &// 波特率不倍增
& & TMOD = 0x20;& && && && &// 定时器1工作于8位自动重载模式, 用于产生波特率
& & TH1 =0xf4 ;
& & TL1 =0xf4;& && && && & // T1赋初值,11.0592M晶振,波特率2400
& & TR1 = 1;& && && && && & // 启动定时器1
ES=1;
}
void main(void)
{
a=P1&0x0f;
SBUF=a;
}
void zd() interrupt 4& &//当进入中断,要么RI=1,要么TI=1
{
{
&&RI=0;
&&a=SBUF;
&&P2=b[a];
else TI=0;
}
//*********************接收*******************
#include &reg51.h&
& &
unsigned char b[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void init(void)
{
& & SCON = 0x50;& && && && &// 串行口工作方式1,允许接收
& & PCON = 0x00;& && && && &// 波特率不倍增
& & TMOD = 0x20;& && && && &// 定时器1工作于8位自动重载模式, 用于产生波特率
& & TH1 =0xf4 ;
& & TL1 =0xf4;& && && && &&&// T1赋初值,波特率2400
& & TR1 = 1;& && && && && & // 启动定时器1
ES=1;
}
void main(void)
{
init();
while(1)
{
P2=b[a];
}
}
void zd() interrupt 4
{
{
&&RI=0;
&&a=SBUF;
&&SBUF=a+1;&&//加1后,在返回到主机
else TI=0;
}
复制代码
主题帖子积分
中级工程师, 积分 3499, 距离下一级还需 1501 积分
中级工程师, 积分 3499, 距离下一级还需 1501 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
中级工程师, 积分 3499, 距离下一级还需 1501 积分
中级工程师, 积分 3499, 距离下一级还需 1501 积分
楼主想得太复杂了,完全可以简单化的。你就让两块单片机的串口始终处于接收状态,发送数据时先发送握手数据,可以是一个字节或多个字节,收到握手数据之后,进行判断是不是握手信号,如果是就进入正式接收数据,如果不是就让串口继续等待接收。需要注意的是,发送方在发出握手数据之后要做一定的延时,让接收方有判断握手数据的时间,之后再发送正式数据。
学好单片机收入不会低!
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
实习生, 积分 9, 距离下一级还需 41 积分
实习生, 积分 9, 距离下一级还需 41 积分
小弟是一个学会计后转行学习单片机的新手 刚刚接触到单片机互相通信这一部分知识 有幸看到前辈分享的代码,十分感谢 祝前辈越做越好成为高级大神
主题帖子积分
高级技术员, 积分 865, 距离下一级还需 135 积分
高级技术员, 积分 865, 距离下一级还需 135 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
高级技术员, 积分 865, 距离下一级还需 135 积分
高级技术员, 积分 865, 距离下一级还需 135 积分
这个应该好写吧,不太难,就是串口收发,用中断
精华达人奖章
等级类勋章
湍急之河流
发帖类勋章
时间类勋章
技术高手奖章
人才类勋章
突出贡献奖章
等级类勋章
沉静之湖泊
发帖类勋章
时间类勋章
技术领袖奖章
人才类勋章
无冕之王奖章
等级类勋章
时间类勋章
社区建设奖章
等级类勋章
时间类勋章
欢快之小溪
发帖类勋章
技术奇才奖章
人才类勋章
热门推荐 /3单片机C语言开发基础 - 异步社区
单片机C语言开发基础
单片机C语言开发基础
单片微型计算机(Single Chip Micro Computer)现已正名为微控制器(MCU,Micro Controller Unit),单片机的称谓只是其习惯称呼。它把组成微型计算机的各功能部件(包括中央处理单元CPU、随机存储器RAM、只读存储器ROM、I/O接口电路、定时器/计数器以及串行口等)集成在一块电路芯片上。由于单片机的硬件结构与指令系统的功能都是按工业控制要求而设计的,因此常用在工业检测、控制装置中。
MCS-51单片机硬件基础
MCS-51是指美国Intel公司生产的一系列单片机的总称。这一系列单片机包括很多种,如、、等。其中8051是最早、最典型的产品,该系列其他单片机都是以8051为核心发展起来的,都具有8051的基本结构和软件特征。8051单片机内部包含了作为微型计算机所必需的基本功能部件,各部件相互独立地集成在同一块芯片上。其基本功能特性如下:
32条双向可独立寻址的I/O线;
4KB程序存储器(ROM),外部可扩充至64KB;
128B数据存储器(RAM),外部可扩充至64KB;
两个16位定时/计数器;
5个中断源;
全双工的串行通信口;
具有布尔运算能力。
下面详细介绍8051单片机的基本工作原理和内部各功能模块等基础知识。
标准8051单片机有几种不同的封装形式。本书以目前市场上最常见,也是最廉价的PDIP40(塑料双列直插40引脚)封装的8051为主要描述对象,其引脚排列如图1-1所示。
8051单片机引脚图
40个引脚功能说明如下。
(1)主电源引脚VSS和VCC。
VSS(20脚):地线。
VCC(40脚):5V电源。
(2)外接晶振引脚XTAL1和XTAL2。
XTAL1(19脚):外接晶体引线端。当使用芯片内部时钟时,此端用于外接石英晶体和微调电容;当使用外部时钟时,对于HMOS单片机,此引脚接地;对于CHMOS单片机,此引脚作为外部振荡信号的输入端。
XTAL2(18脚):外接晶体引线端。当使用芯片内部时钟时,此端用于外接石英晶体和微调电容;当采用外部时钟时,对于HMOS单片机,此引脚接外部振荡源;对于CHMOS单片机,该引脚悬空不接。
(3)控制或与其他电源复用引脚RST/VPD、ALE/、和/VPP。
RST/VPD(9脚):复位信号。当输入的复位信号延续2个机器周期以上高电平即为有效,用以完成单片机的复位初始化操作。在VCC发生故障、降低到低电平规定值掉电期间,此引脚可接上备用电源VPD(电压范围+5V ± 0.5V),由VPD向内部RAM供电,以保持内部RAM中的数据。
ALE/(30脚):地址锁存控制信号。在系统扩展时,ALE用于控制把P0口输出的低8位地址锁存器锁存起来,以实现低位地址和数据的隔离。此外由于ALE是以晶振六分之一的固定频率输出的正脉冲,因此可作为外部时钟或外部定时脉冲使用。对于EPROM型单片机(如8751)或Flash型单片机(如AT89C51),在EPROM或Flash编程期间,此引脚接收编程脉冲(功能)。
(29脚):外部程序存储器读选通信号。在读外部ROM时有效(低电平),以实现外部ROM单元的读操作。
/VPP(31脚):访问程序存储控制信号。当信号为低电平时,对ROM的读操作限定在外部程序存储器;而当信号为高电平时,则对ROM的读操作是从内部程序存储器开始,并可延至外部程序存储器。对于EPROM(或Flash)型单片机,在EPROM编程期间,此引脚上加12.75V或21V的编程电源(VPP)。
(4)输入/输出引脚P0口、P1口、P2口、P3口。
P0口(P0.0~P0.7、39脚~32脚):8位双向并行I/O接口。扩展片外存储器或I/O口时,作为低8位地址总线和8位数据总线的分时复用接口,它为双向三态。P0口能以吸收电流的方式驱动8个LSTTL负载。
P1口(P1.0~P1.7、1脚~8脚):8位准双向并行I/O接口。P1口每一位都可以独立设置成输入输出位。P1口能驱动(吸收或输出电流)4个LSTTL负载。
P2口(P2.0~P2.7、21脚~28脚):8位准双向并行I/O接口。扩展外部数据、程序存储器时,作为高8位地址输出端口。P2口可以驱动(吸收或输出电流)4个LSTTL负载。
P3口(P3.0~P3.7、10脚~17脚):8位准双向并行I/O口。P3口除了作为一般的准双向口使用外,每个引脚还有特殊功能。P3口能驱动(吸收或输出电流)4个LSTTL负载。
51单片机功能结构
这里主要介绍组成8051系列单片机的基本功能结构,如图1-2所示。
8051单片机内部功能模块结构框图
从图1-2中可以看到,8051单片机主要包含中央处理器(CPU)、程序存储器(ROM)、数据存储器(RAM)、定时器/计数器、并行接口、串行接口和中断系统几大功能模块及数据总线、地址总线和控制总线等,将在后面的小节中详细介绍。
此外,8051单片机还有8位内部总线,作为数据、地址及控制信号传输的高速通道,负责将各个外围模块以及核心区域的各功能部件(累加器A、算术/逻辑运算单元ALU、程序计数器PC、程序状态字寄存器PSW、数据指针DPTR、ROM、RAM、特殊功能寄存器SFR等)联系起来。
中央处理器(CPU)
中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码,CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入/输出功能等操作。它由运算器、控制器(定时控制部件)和专用寄存器组3部分部件组成。
1.运算器(ALU)
运算器的功能是进行算术运算和逻辑运算。可以对半字节、单字节等数据进行操作,既能够完成加、减、乘、除等四则运算,也可以完成加1、减1、BCD码十进制调整、比较等算术运算和与、或、异或、求补、循环等逻辑运算。
8051运算器还包含有一个布尔处理器,用来处理位操作,以进位标志位C为累加器,可执行置位、复位、取反、等于1转移、等于0转移、等于1转移且清0以及进位标志位与其他可寻址的位之间进行数据传送等位操作。也能使进位标志位与其他可寻址的位之间进行逻辑与、或操作。
(1)时钟电路。
8051片内设有一个由反向放大器所构成的振荡电路,XTAL1和XTAL2分别为振荡电路的输入和输出端,时钟可以由内部方式产生或外部方式产生。内部方式时钟电路如图1-3所示。在XTAL1和XTAL2引脚上外接定时元件,内部振荡电路就产生自激振荡。定时元件通常采用石英晶体和电容组成的并联谐振回路。晶振频率可以在1.2MHz~12MHz之间选择,电容在5pF~30pF之间选择,电容的大小可起频率微调作用。
外部方式的时钟很少用,若要用时,只要将XTAL1接地,XTAL2接外部振荡器就行,如图1-4所示。对外部振荡信号无特殊要求,只要保证脉冲宽度,一般采用频率低于12MHz的方波信号。
内部方式时钟电路
外部方式时钟电路
时钟频率越高,单片机控制器的控制节拍就越快,运算速度也越快,但同时消耗的功率也更大,对外界的干扰也更强。因此,不同型号、不同场合的单片机所需要的时钟频率是不一样的。
(2)振荡周期、时钟周期、机器周期和指令周期。
一条指令译码产生的一系列微操作信号在时间上有严格的先后次序,这种次序就是计算机的时序。8051的主要时序将在后续章节中介绍,这里先介绍其基本时序周期。
振荡周期是为单片机提供时钟信号的振荡源的周期,是时序中最小的时间单位。
时钟周期是振荡源信号经二分频后形成的时钟脉冲信号。
机器周期是完成一个基本操作所需的时间。一个机器周期包含6个时钟周期,也就等于12个振荡周期。
指令周期是指CPU执行一条指令所需要的时间,是时序中的最大时间单位。由于单片机执行不同指令所需的时间不同,因此不同指令所包含的机器周期数也不相同,一个指令周期通常含有1~4个机器周期。
振荡周期、时钟周期、机器周期和指令周期的关系如图1-5所示。
8051单片机各种周期之间的关系
3.专用寄存器组
专用寄存器组主要用来指示当前要执行的内存地址、存放操作数和指示指令执行后的状态等,是任何一台计算机的CPU不可或缺的组成部件。8051的专用寄存器组主要包括累加器(ACC)、通用寄存器(B)、程序状态字(PSW)、堆栈指示器(SP)、数据指针(DPTR)和程序计数器(PC)等,下面分别对这些寄存器进行介绍。
(1)累加器(ACC)。
累加器是最常用的特殊功能寄存器,是一个二进制8位寄存器,运算大部分单操作数指令的操作数取自累加器,双操作数指令的一个操作数取自累加器。加、减、乘、除算术运算指令的运算结果都存放在累加器ACC或A、B寄存器中。指令系统中用A或ACC作为累加器的助记符。
【实例1】使用累加器进行简单加法运算:
A,#02H ;A←02H
A,#06H ;A←A+06H
A,#02H”是把加数2预先送到累加器A,为指令“ADD
A,#06H”的执行做准备,因此,指令“ADD
A,#06H”执行前累加器A中为加数2,在执行后变为两数之和8。
(2)通用寄存器(B)。
B寄存器是乘除法指令中常用的寄存器。乘法指令的两个操作数分别取自A和B,其结果存放在B(高8位)、A(低8位)寄存器中。除法指令中,被除数取自A,除数取自B,商数存放于A,余数存放于B。在其他指令中,B寄存器可作为RAM中的一个单元来使用。
【实例2】使用B寄存器进行简单乘法运算:
A,#02H ; A←2
B,#06H ; B←6
AB BA←A*B=6*2
前面两条是传送指令,是进行乘法前的准备指令,乘法指令执行前累加器A和通用寄存器B中分别存放了两个乘数,乘法指令执行后,积的高8位自动存放在B中,低8位自动存放在A中。
(3)程序状态字(PSW)。
程序状态字是一个8位寄存器,包含了程序的状态信息,寄存器各位代表的含义如图1-6所示。
程序状态字各位的含义
其中PSW1未用。其他各位说明如下。
CY(Carry):进位标志。在执行某些算术和逻辑指令时,可以被硬件或软件置位或清零。具体地说在加法运算时,若累加器A中最高位A.7有进位,则CY=1,否则CY=0;在减法运算时,若A.7有借位,则CY=1,否则CY=0;CPU在进行移位操作时也会影响这个标志位。在布尔处理机中被认为是位累加器,其重要性相当于一般中央处理机中的累加器A。
AC(Auxiliary Carry):辅助进位标志。当进行加法或减法操作而产生由低4位数(BCD码一位)向高4位数进位或借位时,AC将被硬件置位,否则就被清零。AC被用于BCD码调整。
F0(Flag zero):用户标志位。F0是用户定义的一个状态标志,用软件来使其置位或清零。该标志状态一经设定,可由软件测试F0,以控制程序的流向。
RS1,RS0(Registers Selection):寄存器区选择控制位。8051共有8个8位工作寄存器,分别命名为R0~R7。工作寄存器R0~R7常常被用来进行程序设计,但其在RAM中的实际物理地址是可以根据需要选定的。RS1和RS0就是为了这个目的提供给用户使用的,用户通过改变RS1和RS0的状态可以方便地决定R0~R7的实际物理地址。可以用软件来置位或清零以确定工作寄存器区。RS1和RS0与寄存器区的对应关系如表1-1所示。
表1-1 通过RS1和RS0选择工作寄存器组
R0~R7的组号
R0~R7的物理地址
OV(Overflow):溢出标志。可以指示运算过程中是否发生了溢出,当执行算术指令时由硬件置位或清零。溢出标志常用于作加减运算时OV=1表示加减运算的结果超出了目的寄存器A所能表示的带符号数(2的补码)的范围(-128~+127)。当执行加法指令ADD时,位6向位7有进位而位7不向CY进位时,或位6不向位7进位而位7向CY进位时,溢出标志OV置位,否则清零。无符号数乘法指令的执行结果也会影响溢出标志:若置于累加器A和寄存器B的两个数的乘积超过255时,OV=1,否则OV=0。此积的高8位放在B内,低8位放在A内。因此,OV=0意味着只要从A中取得乘积即可,否则要从B、A寄存器对中取得乘积。除法指令也会影响溢出标志:当除数为0时,OV=1,否则OV=0。
P(Parity):奇偶标志。每个指令周期都由硬件来置位或清“0”,以表示累加器A中值为1的位数的奇偶数。若1的位数为奇数,P置“1”,否则P清“0”。P 标志位对串行通信中的数据传输有重要的意义,在串行通信中常用奇偶校验的办法来检验数据传输的可靠性。在发送端可根据P的值对数据的奇偶置位或清零。通信协议中规定采用奇偶校验的办法,则P=0时,应对数据(假定由A取得)的奇偶位置位,否则就清零。
【实例3】通过设置RS1、RS0选择工作寄存器区1:
PSW.4 ; PSW.4←0
PSW.5 ; PSW.5←1
(4)堆栈指针(SP)。
栈指针SP一个8位特殊功能寄存器,其作用为指示堆栈顶部在内部RAM中的位置。系统复位后,SP初始化为07H,使得堆栈事实上由08H单元开始。考虑到08H~1FH单元分属于工作寄存器区1~3,若程序设计中要用到这些区,则最好把SP值设置为1FH或更大的值,SP的初始值越小,堆栈深度就可以越深。堆栈指针的值可以由软件改变,因此堆栈在内部RAM中的位置比较灵活。
(5)数据指针(DPTR)。
数据指针DPTR是一个16位特殊功能寄存器,其高位字节寄存器用DPH表示,低位字节寄存器用DPL表示,既可以作为一个16位寄存器DPTR来处理,也可以作为两个独立的8位寄存器DPH和DPL来处理。DPTR主要用来存放16位地址,当对64KB外部存储器寻址时,可作为间址寄存器使用。
【实例4】使用数据指针DPTR访问外部数据数据存储器:
DPTR, #data16 ; DPTR←data16
MOVX A, @ DPTR A←((DPTR))
MOVX @ DPTR, A (DPTR)←A
(6)程序计数器(PC)。
程序计数器(PC)用来存放即将要执行的指令地址,共16位,可对64KB的程序存储器直接寻址。读取存储在外部程序存储器中的指令时,PC内容的低8位经P0口输出,高8位经P2口输出。
【实例5】使用程序计数器PC查表:
A, #A←data
A, @ A+DPTR PC←(PC)+1 ,A←((A)+(PC))
存储器结构
MCS-51单片机的存储器编址方式采用与工作寄存器、I/O口锁存器统一编址的方式,程序存储器和数据存储器空间是互相独立的,各有自己的寻址系统和控制信号,物理结构也不同。程序存储器为只读存储器(ROM),数据存储器为随机存储器(RAM)。
从物理地址空间看,MCS-51有4个存储器地址空间,即片内程序存储器和片外程序存储器以及片内数据存储器和片外数据存储器,其组织结构如图1-7所示。
8051存储器组织结构
1.程序存储器
程序存储器用来存放程序和表格常数。程序存储器以程序计数器PC作地址指针,通过16位地址总线,可寻址的地址空间为64KB。片内、片外统一编址。
在片内,带有4KB的ROM/EPROM程序存储器。因此当接高电平时,将从内部ROM开始运行整个程序,其中外部程序存储器地址空间为1000H-FFFFH。若将接低电平,可用于调试外部ROM内的程序,即把要调试的程序放在与内部ROM空间重叠的外部程序存储器内,进行调试和修改。
在程序存储器中有些特殊的单元在使用中应加以注意。其中一组特殊单元是0000H~0002H单元,系统复位后,PC为0000H,单片机从0000H单元开始执行程序,该单元是系统执行程序的起始地址,通常在该单元中存放一条跳转指令,而用户程序从跳转地址开始存放程序。
另一组特殊单元是0003H~002AH,这40个单元专门用于存放中断处理程序,按中断的类型被均匀地分为5段,其定义如下。
0003H~000AH:外部中断0中断地址区。
000BH~0012H:定时/计数器0中断地址区。
0013H~001AH:外部中断1中断地址区。
001BH~0022H:定时/计数器1中断地址区。
0023H~002AH:串行中断地址区。
2.数据存储器
MCS-51单片机的数据存储器无论在物理上或逻辑上都分为两个地址空间,一个为内部数据存储器,访问内部数据存储器用MOV指令;另一个为外部数据存储器,访问外部数据存储器用MOVX指令。
MCS-51系列单片机各芯片内部都有数据存储器,是最灵活的地址空间,分成物理上独立的且性质不同的几个区。8051内部有128个8位用户数据存储单元和128个专用寄存器单元,这些单元是统一编址的,专用寄存器只能用于存放控制指令数据。所以,用户能使用的RAM只有00H~7FH(0~127)单元组成的128字节地址空间,可存放读写的数据或运算的中间结果;80H~FFH(128~255)单元组成的高128字节地址空间的特殊功能寄存器(又称SFR)区只能访问,而不能用于存放用户数据。
单片机将80H~FFH(128~255)单元组成的高128字节地址空间作为RAM区。
对于片内RAM的低128字节(00H~7FH)还可以分成工作寄存器区、可位寻址区和一般RAM区3个区域,其功能特点如下。
工作寄存器区:在00H~1FH安排了四组工作寄存器,每组占用8个RAM字节,记为R0~R7。在某个时刻,CPU只能使用其中的一组工作寄存器,工作寄存器的选择由程序状态字(PSW)中的两位来确定。
可位寻址区:占用20H~2FH 16字节,从20H单元的第0位到2FH单元的第7位至共128位,位地址00H~7FH分别与之对应。这个区域除了可作为一般的RAM单元按字节读写外,还可对每个字节的每一位进行操作,一般存放需要按位操作的数据。
一般RAM区:地址为30H~7FH,共80字节,可作为一般用途的RAM,如存放程序变量等。
特殊功能寄存器中只有一部分是定义了的,对其他没有定义的地址进行操作会导致不确定的结果。8051内部特殊功能寄存器符号及地址如表1-2所示,其中带“*”号的特殊功能寄存器都是可以位寻址的,并可以用“寄存器名.位”来表示,如ACC.0、B.7等。
MCS-51可以扩展64KB外部数据存储器,这对很多应用领域已足够使用,对外部数据存储器的访问采用MOVX指令,用间接寻址方式,R0、R1和DPTR都可用作间址寄存器。
8051特殊功能寄存器一览表
物 理 地 址
通用寄存器
程序状态字
数据存储器指针低8位
数据存储器指针高8位
中断优先级控制器
中断允许控制器
定时器方式选择
定时器控制
定时器0高8位
定时器0低8位
定时器1高8位
定时器1低8位
串行口控制器
串行数据缓冲器
电源控制及波特率选择
定时/计数器
8051片内有两个16位的可编程定时器/计数器T0和T1,用于定时或计数产生中断控制程序执行,它们各由两个独立的8位寄存器组成,用于存放定时或计数时的时间常数。T0由两个8位寄存器TH0和TL0组成,其中TH0为高8位,TL0为低8位。和T0类同,T1也由TH1和TL1两个8位寄存器组成,其中TH1为高8位,TL1为低8位。TH0、TL0、TH1和TL1均为SFR特殊功能寄存器,用户可以通过指令对他们进行数据存取。
T0和T1有定时器和计数器两种工作模式,在每种模式下又分为若干工作方式。在定时器模式下,T0和T1通过对每个机器周期的计数,即一个机器周期定时器加1,当定时器的数值与TH0/1和TL0/1中的时间常数相等时,执行指定动作。在计数器模式下,T0和T1的计数脉冲可以从P3.4和P3.5引脚上输入,在输入引脚的电平由高到低出现跳变时计数器加1。对T0和T1的控制由两个8位特殊功能寄存器完成:一个称为定时器方式选择寄存器TMOD,用于确定是定时器工作模式还是计数器工作模式;另一个叫做定时器控制寄存器TCON,用于决定定时器或计数器的启动、停止以及进行中断控制。
I/O端口也叫做I/O通道或I/O通路,是MCS-51单片机对外部实现控制和信息交换的必经之路。I/O端口有串行和并行之分,串行I/O端口一次只能传送一位二进制信息,并行I/O端口一次能传送一组二进制信息。
MCS-51单片机有P0、P1、P2、P3等4个8位双向I/O端口,每一条I/O线都能独立地用做输入和输出,其内部结构和功能如下。
P0口:P0的位结构如图1-8所示。电路中包含一个数据输出锁存器和两个三态数据输入缓冲器,另外还有一个数据输出的驱动和控制电路。这两组端口用来作为CPU与外部数据存储器、外部程序存储器和I/O扩展口的总线接口,而不像P1、P3直接用做输出口。该8位都为漏级开路输出,每个引脚可以驱动8个LS型TTL负载且内部没有上拉电阻,执行输出功能时外部必须接上拉电阻(10k即可);若要执行输入功能,必须先输出高电平方能读取该端口所连接的外部数据;若系统连接外部存储器,则P0可作为地址总线(A0~A7)及数据总线(D0~D7)。
P0口的位结构
P1口:P1的位结构如图1-9所示。P1口为8位准双向口,每一位均可单独定义为输入或输出口,当作为输出口时1写入锁存器,=0,T2截止,内部上拉电阻将电位拉至“1”,此时该端口输出为1;当0写入锁存器时,=1,T2导通,输出为0。作为输入口时,锁存器置1,=0,T2截止,此时该位既可以把外部电路拉成低电平,也可由内部上拉电阻拉成高电平。需要说明的是,作为输入口使用时有两种情况,其一是首先是读锁存器的内容,进行处理后再写到锁存器中,这种操作即读—修改—写操作,如JBC(逻辑判断)、CPL(取反)、INC(递增)、DEC(递减)、ANL(与逻辑)和ORL(逻辑或)等指令均属于这类操作;其二是读P1口线状态时打开三态门G2将外部状态读入CPU。
P1口的位结构
P2口:P2的位结构如图1-10所示,电路结构与P0口相似,但内部有30k上拉电阻,执行输出功能时不必连接外部上拉电阻。每个引脚可以驱动4个LS型TTL负载;若要执行输入功能,必须先输出高电平方能读取该端口所连接的外部数据;若系统连接外部存储器的地址线超过8条时,则P2口可作为地址总线(A15~A8)引脚。
P2口的位结构
P3口:P3的位结构如图1-11所示,内部有30k上拉电阻,执行输出功能时不必连接外部上拉电阻。该8位都为漏级开路输出,每个引脚可以驱动4个LS型TTL负载。若要执行输入功能,必须先输出高电平,方能读取该端口所连接的外部数据。
P3口的位结构
在实际应用中,P3口的第二功能更为重要,表1-3列出了P3口的各位的第二功能。
表1-3 P3口各位的第二功能
第 二 功 能
通用寄存器
程序状态字
数据存储器指针低8位
数据存储器指针高8位
每个I/O端口内部都有一个8位数据输出锁存器和一个8位数据输入缓冲器,4个数据输出锁存器与端口号P0、P1、P2和P3同名,都是特殊功能寄存器。因此,CPU数据从并行I/O端口输出时可以得到锁存,数据输入时可以得到缓冲。
4个并行I/O端口作为通用I/O口使用时,共有写端口、读端口和读引脚3种操作方式。写端口实际上就是输出数据,是将累加器A或其他寄存器中数据传送到端口锁存器中,然后由端口自动从端口引脚线上输出。读端口不是真正的从外部输入数据,而是将端口锁存器中输出数据读到CPU的累加器。读引脚才是真正的输入外部数据的操作,是从端口引脚线上读入外部的输入数据。
8051有一个全双工的可编程串行I/O端口。这个串行I/O端口既可以在程序控制下将CPU的8位并行数据编程串行数据一位一位地从发送数据线TXD发送出去,也可以把串行接收到的数据变成八位并行数据送给CPU,而且这种串行发送和串行接收可以单独进行,也可以同时进行。
8051串行发送和串行接收利用了P3口的第二功能,即利用P3.1引脚作为串行数据的发送线TXD,利用P3.0引脚作为串行数据的接收线RXD,如表1-3所示。串行I/O口的电路结构还包括串行口控制器SCON、电源及波特率选择寄存器PCON和串行数据缓存器SBUF等,这些寄存器都属于特殊功能寄存器(SFR)。其中PCON和SCON用于设置串行口工作方式和确定数据的发送和接收波特率,串行数据缓冲器SBUF用于存放欲发送或已接收的数据。SBUF实际上由两个相互独立的发送缓冲器和接收缓冲器组成,当要发送的数据传送到SBUF时,进的是发送缓冲器;当要从SBUF读数据时,则取自接收缓冲器,取走的是刚接收到的数据。
8051的中断系统可以接受5个独立的中断源的中断请求,这5个中断源即2个外部中断、2个定时器/计数器中断和1个串行口中断。
外部中断源产生的中断请求信号可以从P3.2和P3.3引脚上输入,有电平或边沿两种触发方式;内部中断源T0和T1的两个中断是在其从全“1”变为全“0”溢出时自动向中断系统提出的;内部串行口中断源的中断请求是在串行口每发送完一个8位二进制数据或接收到一组输入数据(8位)后自动向中断系统提出的。
8051的中断系统主要由IE(Interrupt Enable,中断允许)控制器和中断优先级控制器IP等电路组成。其中,IE用于控制5个中断源中哪些中断请求被允许向CPU提出,哪些中断源的中断请求被禁止,IP用于控制5个中断源的中断请求的优先级。
MCS-51单片机属总线型结构,其总线通常分为地址总线、数据总线和控制总线等3种,其功能分别如下。
地址总线(AB):地址总线宽度为16位,由P0口经地址锁存器提供低8位地址(A0~A7);P2口直接提供高8位地址(A8~A15),地址信号是由CPU发出的单方向信号。
数据总线(DB):数据总线宽度为8位,用于传送数据和指令,由P0口提供。
控制总线(CB):随时掌握各种部件的状态,并根据需要向有关部件发出命令。
在访问外部存储器时,P2口输出高8位地址,P0输出低8位地址,由ALE(地址锁存允许)信号将P0口(地址/数据总线)上的低8位锁存到外部地址锁存器中,从而为P0口接收数据做准备。
在访问外部程序存储器指令时,(外部程序存储器选通)信号有效;在访问外部数据存储器指令时,由P3口自动产生读/写(/)信号,通过P0口对外部数据存储器单元进行读/写操作。
Keil Vision2
MCS-51单片机的开发除了需要硬件的支持以外,同样离不开软件。CPU真正可执行的是机器码,用汇编语言或C等高级语言编写的源程序必须转换为机器码才能运行,转换的方法有手工汇编和机器汇编两种,前者目前已极少使用。机器汇编是指通过汇编软件将源程序变为机器码的编译方法。这种汇编软件称为编译器。本节将向大家介绍目前十分流行的Keil Vision2。
Keil Vision2集成开发环境介绍
Keil Vision2是一个集成开发环境(Intergrated Development Environment,IDE),它包括编译器、汇编器、实时操作系统、项目管理器和调试器等。它可以用于编写、调试和软仿真所有的51内核控制器,也可以和IDE连接进行芯片的在线调试。同时C编译器保留了汇编代码高效、快速的特点,可以作为许多编程工具的第三方支持。因此,它无疑是8051开发用户的首选。
当使用Vision2的开发工具进行项目开发时,项目的开发流程和其他软件开发项目的流程极其相似,一般遵循下面的几步。
(1)创建一个项目,从器件库中选择目标器件,配置工具设置。
(2)用C语言或汇编语言创建源程序。
(3)用项目管理生成应用。
(4)修改源程序中的错误。
(5)测试、连接应用。
用带有Vision集成开发环境的Keil Vision2工具进行软件开发的流程如图1-12所示。
用Keil Vision2进行应用软件开发的流程图
使用Keil Vision2进行开发
对Keil Vision2软件及其集成开发环境有了整体认识后,本小节将详细介绍如何使用Keil Vision2软件来进行单片机程序的开发。
1.建立工程
首先启动Keil Vision2软件的集成开发环境,如图1-13所示。几秒钟后出现编辑界面,程序窗口的左边会出现一个工程管理窗口,如图 1-14 所示。该窗口中有 3 个标签,分别是“Files”、“Regs”和“Books”,这3个标签页分别显示当前项目的文件结构、CPU的寄存器及部分特殊功能寄存器的值(调试时才出现)和所选CPU的附加说明文件,如果是第一次启动Keil Vision2,则这3个标签页全是空的。
启动Keil Vision2时的屏幕
使用菜单“File/New”或者单击工具栏的新建文件按钮,即可在项目窗口的右侧打开一个新的文本编辑窗口,在该窗口中输入源程序代码,然后保存该文件,注意必须加上扩展名“.c”。源文件不一定使用Keil Vision2 自带的文本编辑器编写,可以使用任意文本编辑器编写。
在项目开发中,并不仅是有一源程序就行了,还要为这个项目选择CPU(Keil Vision2支持数百种CPU,这些CPU的特性不完全相同),确定编译、汇编、连接的参数,指定调试的方式。有一些项目还会由多个文件组成,为管理和使用方便,Keil Vision2使用工程(Project)这一概念,将这些参数设置和所需的所有文件都加在一个工程中,对工程里的MAIN.C文件进行编译、连接,这样生成的代码才有意义。
Vision2的工程管理窗口
选择“Project/New Project”菜单,弹出一个对话框,如图1-15所示。
创建新工程对话框
要求给将要建立的工程起一个名字,不需要扩展名,单击“保存”按钮,然后出现第二个对话框,如图1-16所示。这个对话框要求选择目标CPU,从图中可以看出Keil Vision2支持的CPU种类繁多,几乎所有目前流行的芯片厂家的CPU型号都包括其中。选择时,单击所选厂家前面的“+”号,展开之后选择所需要的CPU类型即可。
选择目标器件对话框
选好以后回到主界面,此时在工程窗口的文件页中,出现了“Target 1”,“Target 1”的前面有一个“+”号,单击“+”号展开,可以看到下一层的“Source Group 1”,这时的工程还是一个空的工程,里面什么文件也没有,需要手动把编写好的源程序文件输入。单击“Source Group 1”使其反白显示,然后单击鼠标右键,出现一个下拉菜单,如图1-17所示。
工程中添加文件页面
选择其中的“Add Files to Group‘Source Group 1’”选项,出现如图1-18所示的“添加源文件”对话框。
添加源文件对话框
注意该对话框下面的“文件类型”默认为“C Source files (*.C)”,也就是以C为扩展名的文件,找到并选中需要加入的文件,将文件拖入到项目中,此后还可以继续加入其他需要的文件。
2.工程的设置
Vision2允许用户为目标硬件设置选项。先单击左边“Project”窗口的“Target 1”,然后选择菜单“Project/Options for Target‘Target 1’”,即出现工程设置对话框,此对话框共有8个选项卡,绝大部分设置取默认值即可。
(1)Target选项卡。
单击Target选项卡,如图1-19所示。
工程设置中的“Target”选项卡
其中各参数设置如下。
Xtal(MHz):用于设置单片机的工作频率,默认设置是所选目标CPU的最高可用频率值,该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置为开发的硬件所用的晶振频率。
Memory Model:用于设置数据存储空间的类型,有3个选择项:“Small”指变量存储在内部RAM里;“Compact”指变量存储在外部RAM里,使用8位间接寻址;“Large”指变量存储在外部RAM里,使用16位间接寻址。
Code Rom Size:用于设置ROM空间的使用,同样也有3个选项值:“Small”模式,表示只使用不超过2KB的程序空间;“Compact”模式,表示函数的代码量不能超过2KB,整个程序可以使用64KB的程序空间;“Large”模式,程序和函数可用全部的64KB空间。
Operating:用于选择是否使用操作系统,Keil Vision2提供了两种操作系统:RTX-51 Tiny和RTX-51 Full。一般情况下不使用操作系统,即使用该项的默认值:“None”。
Off-chip Code memory:用于确定系统外扩ROM的地址范围,如果没有外接ROM不要填任何数据。
off-chip XData memory:用于确定系统外展RAM的地址范围,如果没有外接RAM不要填任何数据。
(2)Output选项卡。
单击Output选项卡,如图1-20所示。
工程设置中的“Output”选项卡
Output选项卡的设置比较多,下面逐一介绍。
Select Folder for Objects:用于选择最终的目标文件所在的文件夹,默认是与工程文件在同一个文件夹中。
Name of Executable:用于指定最终产生的目标文件夹的名字,默认与工程的名字相同,这两项一般不需要更改。
Debug Information:用于产生调试信息,这些信息用于调试。如果需要对程序进行调试,应当选中该项。
Browse Information:用于产生浏览信息,该信息可以用菜单“View/Browse”来查看,这里取默认值。
Creat Hex File:用于生成可执行代码文件,扩展名为“.HEX”,默认情况下该项未被选中,如果要需要生成HEX文件,必须选中该项。
Create Library:生成库文件。选中该选项时将生成lib库文件,根据用户的需要是否生成库文件,一般的应用是不生成库文件的。
(3)Listing选项卡。
“Listing”选项卡用于调整生成的列表文件选项。在汇编或编译完成后将产生.lst的列表文件,在连接完成后也将产生.m51的列表文件,该选项卡用于对列表文件的内容和形式进行细致的调节。其中比较常用的选项是“C Compile Listing”下的“Assemble Code”项,选中该项可以在列表文件中生成C语言源程序所对应的汇编代码。
(4)C 51选项卡。
用于对Keil Vision2的MCS-51单片机的编译过程进行控制,其中比较常用的是“Code Optimization”组,如图1-21所示。
工程设置中的C 51选项卡中的Code Optimization组
该组中“Level”是优化等级,MCS-51在对源程序进行编译时,可以对代码进行多至9级优化,默认使用第8级,一般不必修改。如果在编译中出现一些问题,可以降低优化级别试一试。
“Emphasis”是选择编译优先方式,第一项是代码量优化(最终生成的代码量最小),第二项是速度优先(最终生成的代码速度最快),第三项是默认选项。默认的是速度优先,可根据需要更改。
设置完成后单击“确定”按钮返回主界面,工程文件设置完毕。
编译与连接
在工程建立并设置好以后,接下来的工作就是对工程进行编译。如果一个项目包含多个源程序文件,并且已经编译,则当只修改了某一个文件时,没有必要全部再编译一次,可选择“Project/Build Target”(),仅对修改过的文件进行编译,然后和已被编译过的文件进行连接。如果对所有原程序全部进行编译连接,可选择“Rebuild all Target Files()”。推荐按F7键或单击快捷按钮,仅对修改过的文件进行编译连接。
编译是通过单击快捷按钮(或者)进行的,如果源文件没有语法错误,将生成.OBJ文件,同时如果设置正确,OH51.HEX文件会被调用来生成HEX代码。源文件没有语法错误并不能保证就是正确可行的,能不能实现需要的功能还需进行调试。调试是一项复杂的工作,好的调试工具这时将起到至关重要的作用。有关Keil Vision2的调试器环境和调试方法将在后文做详细介绍。
利用编程环境通过编程器将可执行的.HEX文件写入到51芯片的程序存储器ROM里,然后插入到目标硬件系统上电就可以执行。编程器的种类繁多,但使用方法大多相同(界面有些区别),具体过程本书不作介绍。
dScope for Windows的使用
在开发产品时,软件仿真是芯片不具有在线调试接口时的首要步骤(8051低端单片机不具备此功能,F系列的Soc除外),可以用软件模拟仿真器(Simulator)对应用程序进行软件模拟调试。另外,现在应用程序的开发往往由几个人共同开发的情形较多,因此直接用硬件方法调试软件会带来一定的困难。Keil Vision2提供了一种软件仿真器dScope,为MCS-51单片机应用程序的调试带来了极大的方便。本小节将详细介绍dScope for Windows的使用方法。
1.如何启动
如果源程序代码编译成功,那么运行dScope可以对MCS-51应用程序进行软件仿真调试Simulator。为了运行dScope,在图1-22所示的“Option for Target”对话框的“Debug”选项卡中要选中“Use Simulator”单选项。“Load Application at Startup”复选框用于在dScope启动时能够调用自己应用程序的OMF文件,因此也要选中这个复选框。如果不选中此复选框而运行了dScope,则要手动装载应用程序。
“Options for Target”对话框中的“Debug”选项卡
“Run to main()”选项用于选择在dScope启动后,是否从C源程序的main()函数开始,因此推荐选中此复选框。
“Use”选项中的监控软件“Keil Vision2 Monitor”,具有把已经编译好的代码下载到用户目标硬件系统后,监控硬件目标系统的功能。该监控软件通过RS-232串口实时地实现Keil Vision2的dScope和硬件目标系统相互联系的强大功能。这里由于使用软件仿真,所以不选取。
在编译源程序代码时,出现警告仍然可以写入芯片进行调试,但出现错误就不可以进行调试了,然后就应该执行dScope。dScope一词是Debug和Scope的合成语。图1-23中Keil Vision2执行菜单文件工具栏中带有红色“d”字的按钮,就是启动dScope的快捷按钮。
Keil Vision2执行菜单
进入调试状态后,界面与编辑界面相比有明显的变化,“Debug”菜单项中原来不能用的命令现在已可以使用了,工具栏中会多出一个用于运行和调试的工具条,如图1-24所示。
Keil Vision2 dScope 执行菜单
2.如何调试
调试是在源文件编辑、编译无误之后才得以进行的,主要是反复修改程序并检验编写的程序是否能够可靠地实现预期目标的过程。在做开发计划时,通常就把开发周期和调试周期同等对待。
程序调试时,必须明确两个重要的概念,即单步执行与全速运行。全速运行是指一程序行执行完以后紧接着执行下一程序行,中间不停止,这样可以看到该段程序执行的总体效果,即最终结果正确还是错误,但如果程序错误,则难以确认错误出现的位置。单步执行是每次执行一行程序,执行完该行程序即停止,等待命令执行下一行程序,此时可以观察该程序行执行完以后得到的结果,是否与我们写该程序行所想要得到的结果相同,由此可以找到程序中的问题所在。程序调试中,这两种运行方式都要用到。
使用菜单“Step”或相应的快捷按钮或使用快捷键F11,可以单步执行程序。使用菜单“Step Over”或相应的快捷按钮或使用快捷键F10,可以以过程单步形式执行命令。所谓过程单步,是指将汇编语言中的子程序或高级语言中的函数作为一个语句来全速执行。
通过单步执行程序,可以找出一些问题的所在,但是仅依靠单步执行来查错有时是困难的,或虽能查出错误但效率很低,为此必须辅以其他方法。比如在循环次数很多的循环子程序中,单步执行方法就不再合适,这时候可以使用“单步执行到函数外”命令(),或者“运行到光标所在行”命令()来跳出循环子程序。还有个办法就是在单步执行到循环子程序的时候,不再使用单步命令F11()而采用过程单步F10()命令,这样就不会进入循环子程序内部。灵活使用这几种方法,可以大大提高调试的效率。
在进入Keil Vision2的调试环境以后,如果发现程序有错,可以直接对源程序进行修改,但是要实现重新编译,必须先退出调试环境,然后重新编译、连接后再次进入调试。如果只是需要对某些程序进行作测试,或仅需要对源程序进行临时的修改,这样的过程未免有些麻烦,可以采用Keil Vision2软件提供的在线汇编的方法。将光标定位于需要修改的程序行上,选择菜单“Debug/Inline Assembly”,会弹出如图 1-25 所示的对话框,在“Enter New Instruction”后面的编辑框内直接输入需更改的程序语句,输入完成以后回车将自动指向下一条语句,可以继续修改,如果不再需要修改,可以单击右上角的关闭按钮关闭窗口。
Keil Vision2在线汇编窗口
程序调试时,一些程序行必须满足一定的条件才能被执行(如程序中某变量达到一定的值、按键被按下、串口接收到数据、有中断产生等),这些条件往往是异步发生或难以预先设定的,这类问题使用单步执行的方法是很难调试的,这时就需要使用到程序调试中的另一种非常重要的方法——断点设置。
断点设置的方法有很多种,常用的是在某一程序行设置断点,设置好断点后可以全速运行程序,一旦执行到该程序行即停止,可在此观察有关变量值,以确定问题所在。在程序行设置/删除断点的方法是将光标定位于需要设置断点的程序运行,使用菜单“Debug/Insert/Remove Breakpoint”()设置或删除断点(也可以用鼠标在该行双击实现同样的功能)。其他几个选项的意义为:
“Debug/Enable/Disable Breakpoint”()是指开启或暂停光标所在行的断点功能,“Debug/Disable All Breakpoint”()暂停所有的断点,“Debug/Kill All Breakpoint”()清除所有的断点设置。
3.调试窗口
Keil Vision2软件在调试程序时提供了多个窗口,主要包括输出窗口(Output Window)、观察窗口(Watch & Call Stack Window)、存储器窗口(Memory Window)、反汇编窗口(Disassembly Window)和串行窗口(Serial Window)等。进入调试模式后,可以通过菜单“View”下的相应命令打开或关闭这些窗口。
在进入调试模式之前,工程窗口的寄存器页面是空白的,进入调试模式以后,此页面就会显示出当前模拟状态下单片机寄存器的值,如图1-26所示。
Keil Vision2工程窗口寄存器页面
寄存器页面包括了当前的工作寄存器组和系统寄存器,系统寄存器有一些是实际存在的寄存器(如A、B、DPTR、SP、PSW等),有一些是实际中并不存在或虽然存在却不能对其进行操作的(如PC、Status等)。每当程序中执行到对某寄存器的操作时,该寄存器会以反色(蓝底白字)显示,用鼠标单击然后按下F2键,即可修改该值。
图1-27所示是调试模式下的输出窗口、存储器窗口和观察窗口。
Keil Vision2调试窗口(命令窗口、存储器窗口、观察窗口)
进入调试程序后,输出窗口自动切换到“Command”页(命令窗口)。输出窗口可以输入调试命令,同时可以输出调试信息,调试命令以文本的形式输入,详细的命令语句可以参照“Getting Started with Vision2”的说明,大约有30个命令,这里不做详细介绍。
存储器窗口可以显示系统中各种内存中的值,通过在Address后的编辑框内输入“字母:数字”即可显示相应内存值,其中字母可以是C、D、I和X,它们分别代表代码存储空间、直接寻址的片内存储空间、间接寻址的片内存储空间和扩展的外部RAM空间。数字代表想要查看的地址。如输入“D:5”,即可观察到地址0x05开始的片内RAM单元值,键入“C:0”即可显示从0开始的ROM单元中的值,即查看程序的二进制代码。该窗口的显示值可以以各种形式显示,如十进制、十六进制、字符型等。
改变显示方式的方法是:按鼠标右键,在弹出的快捷菜单中选择,该菜单用分隔条分成3部分,其中第一部分与第二部分的3个选项为同一级别,选中第一部分的任意选项,内容将以整数形式显示;而选中第二部分的“ASCII”项将以字符型显示,选中“Float”项内容将以相邻4字节组成的浮点数形式显示,选中“Double”项内容将以相邻8字节组成的双精度形式显示。第一部分又有多个选项,其中“Decimal”项是一个开关,如果选中该选项,则窗口中的值将以十进制的形式显示,否则按默认的十六进制方式显示。“Unsigned”和“Signed”后分别有3个选项:Char,Int,Long,分别代表以单字节方式显示、相邻双字节组成整型数方式显示、相邻4字节组成长整型方式显示,而“Unsigned”和“Signed”则分别代表无符号形式和有符号形式,至于究竟从哪一个单元开始相邻单元则与设置有关。第三部分的“Modify Memory at X:xx”用于更改鼠标处的内存单元值,选中该项即出现如图1-28所示的对话框,可以在对话框中输入要修改的内容。
修改内存单元对话框
观察窗口是很重要的一个窗口,工程窗口中仅可观察到工作寄存器和有限的系统寄存器,如A、B、DPTR等,如果需要观察其他寄存器的值或者在高级语言编程时需要直接观察变量,就要借助于观察窗口了。比如如果想要观察程序中某个临时变量tmp在单步工作时的变化情况,就可以在观察窗口中按F2键,然后键入变量名tmp,这样在程序运行的时候会看到tmp变量的即时值。一般情况下,仅在单步执行时才对变量值的变化感兴趣,全速运行时,变量的值是不变的,只有在程序停下来之后,才会将这些最新的变化反映出来。但是,在一些特殊的场合也可能需要在全速运行时观察变量的变化,此时可以选择“View/Periodic Window Updata”菜单,确认该项处于被选中状态,即可在全速运行时动态地观察有关变量值的变化。选中该项,将会使程序模拟执行的速度变慢。
选择菜单“View/Disassembly Window”可以打开反汇编窗口,如图1-29所示。
反汇编窗口
该窗口可以显示反汇编后的代码、源程序和相应反汇编代码的混合代码,可以在该窗口进行在线汇编、利用该窗口跟踪已执行的代码、在该窗口按汇编代码的方式单步执行。打开反汇编窗口,单击鼠标右键,出现快捷菜单,如图1-30所示,其中“Mixed Mode”是以混合方式显示,“Assembly Mode”是以反汇编码方式显示。
程序调试中常使用设置断点然后全速执行的方式,在断点处可以获得各变量值,但却无法知道程序在断点前究竟执行了哪些代码,而这往往是需要了解的。为此,Keil Vision2提供了跟踪功能,在运行程序之前打开调试工具条上的运行跟踪代码开关,然后全速运行程序。当程序停止运行后,单击查看跟踪代码按钮,自动切换到反汇编窗口,其中前面标有“-”号的行就是中断以前执行的代码,可以按窗口边的上卷按钮向上翻查看代码执行记录。
Keil Vision2提供了2个串行观察窗口,用于PC机与模拟的51单片机窗口通信。从模拟的51单片机的CPU串口输出的数据,将在这个串行窗口中显示,而在串口中输入的字符,将被输入到模拟的51单片机的CPU串口中,利用这一点,可以在没有外部硬件的情况下模拟51单片机CPU的UART。这是一种高级调试技巧,本书不再做详细介绍。
C51基础知识
C51控制语句
C51语言中,有相关的控制语句,用以实现选择结构与循环结构。
选择控制语句:if语句和switch-case语句。
循环控制语句:for语句、while语句和do…while语句。
转移控制语句:break语句、continue语句和goto语句。
1.选择控制语句
在C51语言中选择结构主要是利用if语句和switch-case语句来实现的。
(1)if语句的3种常用形式。
C51语言中分支结构主要是应用if语句来实现的,if语句是对给定条件进行判断,然后决定执行某个分支。if语句包括if语句、if-else语句、else-if语句3种形式。
if(表达式)语句
含义:如果表达式的值为真,则执行其后的语句;否则不执行该语句后面的语句。
if-else语句
if(表达式)
        语句1;
        语句2;
含义:如表达式的值为真,则执行语句1;否则执行语句2。
else-if语句
if(表达式1)
        语句1;
else if(表达式2)
        语句2;
else if(表达式3)
        语句3;
else if(表达式m)
        语句m;
else(表达式m + 1);
含义:依次判断各个表达式的值,如某个值为真时,则执行其对应的语句,然后跳出else-if结构。如果所有的表达式的值均为假,则执行语句m + 1,然后执行后续程序。
【实例6】if语句实例:
void main()
{ int a,b,c,
printf("\n please input three number:");
scanf("%d%d%d ",&a,&b,&c);
if(a&b&&a&c)
printf("min=%d\n",a );
else if(b&a&&b&c)
printf("min=%d\n",b);
else if(c&a&&c&c)
printf("min=%d\n",c);
printf("There at least two numbers are equal\n");
(2)switch-case语句。
在C51语言中提供了直接处理多分支的方法,如switch-case语句。
switch-case语句
switch-case语句的一般形式:
switch(表达式){
  case常量表达式1:语句1;
  case常量表达式2:语句2;
  case常量表达式n:语句n;
  default
:语句n + 1;
含义:首先计算表达式的值,然后逐个与每一个case后的常量表达式值进行比较。当表达式的值与某个常量表达式的值相等时,就执行该case后的语句组,然后不再进行判断,继续执行后面所有的语句。如表达式的值与所有case后的常量表达式均不相同时,则执行default后的语句组。
【实例7】switch-case语句实例:
void main()
{ printf("input one number:");
scanf("%d",& num);
switch(num)
case 1: printf("num =%d\n", num);
case 2: printf("num =%d\n", num);
case 3: printf("num =%d\n", num);
case 4: printf("num =%d\n", num);
default: printf("The number is out of the range\n", num);
2.循环控制语句
在C51语言中循环结构主要是利用for语句、while语句和do-while语句来实现的。
(1)for语句。
在C语言的循环语句中,for语句使用最为灵活。它常用于循环次数已知的循环控制,也可以灵活用于循环次数不确定的而只给出循环结束条件的情况。
for语句的一般形式:
for(表达式1;表达式2;表达式3)语句;
通常在循环开始时用来给循环变量赋初值,一般是赋值表达式。也允许在for语句外给循环变量赋初值,此时可以省略该表达式。
通常是循环条件,一般为关系表达式或逻辑表达式。只要这个条件是满足的,循环就得继续下去。表达式2一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要其值非零,就执行循环体。
通常是循环增量,用来修改循环变量的值,一般是赋值语句。表达式1和表达式3可以是逗号表达式,即每个表达式都可由多个表达式组成。
含义:求解计算表达式1(循环变量初值)的值;求解表达式2(循环条件)的值,若值为真(非0)则执行循环体一次,否则循环结束,执行for语句下面的语句;执行构成循环体的程序语句;计算表达式3(循环增量表达式)的值,转回求解表达式2;循环结束,执行for语句下面的语句。
【实例8】for语句实例:
void main()
for(int a=10;n&0;a --)
printf("%d",a);
(2)while语句。
while语句的一般形式:
while(表达式)语句
含义:先判断表达式,后执行语句。
【实例9】while语句实例:
void main()
{ int i=0;
while(i&=10)
(3)do…while语句。
do…while语句一般形式:
do 循环体语句
while(表达式);
含义:先执行语句,后判断表达式。
【实例10】do…while语句实例:
void main()
while(i&=10);
3.转移控制语句
break语句、continue语句和goto语句都是限定转向语句,改变程序的正常流向,但是它们不允许用户自己指定转向,而是按程序事先规定的原则向某一点转移。
(1)break语句。
当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行后面的语句。
break语句的一般形式为:
语句 break;
(2)continue语句。
continue语句只能用在循环体中。其一般格式是:
continue;
含义:continue语句作用是结束本次循环,即跳过循环体重下面尚未执行的语句,转入下一次循环条件的判断与执行。
(3)goto语句。
goto语句也称为无条件转移语句,其一般形式如下:
语句标号;
含义:goto语句的语义是改变程序流向,转去执行语句标号所标识的语句。
程序设计中C51程序由一个主函数和若干个函数组成,主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次,所以有经验的开发人员将一些常用的功能模块编写成函数,放在函数库中以供调用,以减少重复程序段的工作量。
1.函数的划分
函数从形式上划分,分为无参数函数和有参数函数及空函数。
(1)无参函数的定义形式
类型标识符
(2)有参函数的定义
类型标识符
函数名(形式参数列表)
(3)空函数
类型说明符 函数名()
2.函数参数和函数的返回值
函数之间的参数传递,由函数调用时主调函数的实际参数与被调用函数的形式参数之间进行数据传递来实现。
(1)形式参数和实际参数。
形式参数:定义函数时,函数名后面括号中的变量名称为“形式参数”,简称“形参”。
实际参数:调用函数时,函数名后面括号中的表达式称为“实际参数”,简称“实参”。
(2)函数的返回值。
通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。
3.函数的调用
C51语言中被调用的函数必须是已经存在的函数,可以是库函数,也可以是用户自定义的函数。在确定函数存在的情况下用户可以通过以下方法来使用函数。
(1)函数调用的一般形式。
函数名(实参列表)
对于有参数型的函数,若包含多个实际参数时,则用逗号隔开各参数。其中实参与形参的个数应相等,且类型一致,并按顺序对应的进行数据传递。如果调用的是无参函数,可省去“实参列表”项,但括号不能省。
(2)函数调用的方式。
C51语言中可以通过以下3种方式实现函数调用。
① 函数作为一个语句调用,不要求函数带返回值,只要求函数完成一定的功能操作。
【实例11】语句形式调用实例:
void main()
{ int i=0; while(i&=10)
i++; … …
/*函数调用*/
② 将函数结果作为表达式的一个运算对象,要求函数带回一个确定的值以参加表达式的运算。
【实例12】表达式形式调用实例:
void main()
{ int a,b,i=0; while(i&=10)
i++; … …
i=4*Sum(a,b);
/*函数调用*/
③ 将函数作为另一个函数的参数进行调用。
【实例13】以函数的参数形式调用实例:
void main()
{ int a,b,c,i=0; while(i&=10)
i++; … …
i= max(c,Sum(a,b));
/*函数调用*/
(3)调用函数的声明和函数原型。
在对一个函数进行调用时不仅需要其已经存在,还必须在调用前在主调函数中对被调用的函数进行声明,如调用的是库函数应在文件开头用#include命令将调用的有关库函数的信息“包含”到本文件中。
【实例14】函数的声明实例:
void main()
{ int max(int x,int y);
/*函数的声明*/
int a,b,c,i=0; while(i&=10)
i++; … …
i= max(c,Sum(a,b));
/*函数调用*/
函数原型的一般形式如下所示。
函数名(参数类型1,参数类型2……)
函数名(参数类型1
参数名1,参数类型2
参数名2……)
其中第1种形式是基本的形式,在声明函数时给出参数类型。也可以如第2种形式所示,在函数原型中加上参数名。
(4)函数的嵌套调用。
在C51中函数的定义都是相互独立的,但允在调用时许嵌对函数进行嵌套调用。即在调用一个函数的过程中,允许调用另一个函数,如实例13所示。
(5)函数的递归调用。
在C51中调用函数时,直接或间接地调用该函数本身,即称为函数的递归调用。但递归调用过程中应避免无终止地自身调用。
【实例15】函数递归调用的简单实例:
void fun()
{ int a=1, result,i;
for(i=0;i&10;)
result = fun();
/*函数调用*/
C51数组和指针
1.C51数组
所谓数组就是指具有相同数据类型的变量集,并拥有共同的名字。其可以是一维的,也可以是多维的。
(1)一维数组
一维数组的说明格式:
变量名[长度];
(2)多维数组
多维数组的一般说明格式:
数组名[第n维长度] [第n-1维长度]…[第1维长度];
【实例16】数组的实例:
void main()
{ char num[3] [3]={{'','#',''},{'#','','#'},{'','#',''}}; /*定义多维数组*/
int i=0,j=0;
for(;i&3;i++)
for(;j&3;j++)
printf("%c",num[i][j]);
printf("/n");
2.C51指针
(1)指针变量的定义。
在C51语言中,对变量的访问形式之一,就是先求出变量的地址,然后再通过地址对它进行访问,这就是这里所要论述的指针及其指针变量。变量的指针,实际上指变量的地址。
指针变量的一般定义:
类型标识符
其中标识符是指针变量的名字,标识符前加了个“*”号,表示该变量是指针变量,而最前面的“类型标识符”表示该指针变量所指向的变量的类型。一个指针变量只能指向同一种类型的变量,也就是说,不能定义一个指针变量,既能指向一个整型变量又能指向一个双精度变量。
(2)指针变量的引用。
在指针变量中只能存放地址,因此,在使用中不要将一个整数赋给一个指针变量。
(3)指针的运算。
指针允许的运算方式有指针在一定条件下进行比较,指针和整数进行加、减运算,两个指针变量在一定条件下进行减法运算等多种。
【实例17】指针的实例:
void main()
{ int a=3,*p;
/*将变量a的地址赋值给指针变量p*/
printf("%d,%d",a,*p);
/*输出二者的数值进行对比*/
【实例18】数组与指针实例:
void main()
{ int i=3,num[3]={1,2,3},*p;
/*将数组num[]的地址赋值给指针变量p*/
result =max(p,3);
/*函数调用,计算数组的最大值*/
1.4 【实例19】P1口控制直流电动机实例
利用P1口,编制程序输出一串脉冲,经放大后驱动小电动机,改变输出脉冲的电平及持续时间,达到使电动机正转、反转、加速、减速、停转之目的。
1.实例概述
可以通过74HC244输入开关量数据来控制小直流电动机的转动,实现正转4种转速,反转4种转速及停转。电路及连线如图1-31所示。
图1-31中P1.0连接74HC244的2A2。两个输出通过两个74HC32连接直流电动机电源。小直流电动机原理是:转动方向是由电压来控制的,电压为正则正转,电压为负则负转。转速大小则是由输出脉冲的占空比来决定的,正向占空比越大则转速越快,反向转则占空比越小转速越快,如图1-32所示。
实例电路及连线
小直流电动机转动原理
2.程序框图及代码
在编写代码前,最好先把程序流程图画出来,这样可以使得编写的代码更加简洁有效。实例程序的流程图如图1-33所示。
实例程序框图
程序代码如下:
sfr p1=0x90;
sbit p10=p1^0;
sbit p11=p1^1;
void main ()
int j=100;
for (i=0; i&100; i++)
for (j=0; j&50; j++)
for (j=0; j&10; j++)
for (i=0; i&100; i++)
for (j=0; j&10; j++)
for (j=0; j&50; j++)
for (i=0; i&100; i++)
for (j=0; j&50; j++)
for (j=0; j&10; j++)
for (i=0; i&100; i++)
for (j=0;j&10;j++)
for (j=0; j&50; j++)
Cx51源程序是一个ASCII文件,可以用任何标准的ASCII文本编辑器来编写,例如记事本、写字板等。
C源程序的书写格式自由度较高,灵活性很强,有较大的任意性。其要点如下。
一般情况下,每个语句占用一行。
不同结构层次的语句,从不同的起始位置开始,即在同一结构层次中的语句,缩进同样的字数。
表示结构层次的大括号通常写在该结构语句第一个字母的下方,与结构化语句对齐,并占用一行。
存储器的扩展
输入/输出及显示技术
实用电子制作
传感控制技术
智能仪表与测试技术
电气传动及控制技术
单片机数据处理
单片机通信技术
单片机实现信号与算法
单片机的总线与网络技术
典型器件及应用技术
综合应用实例
8051的指令列表
PS/2键盘键值和符号对照表

我要回帖

更多关于 单片机求最小值c程序 的文章

 

随机推荐