51单片机逆向学习实战教程(电子设计与嵌入式开发实践丛书)
上QQ阅读APP看书,第一时间看更新

第1部分 从项目起步,学习单片机

第1章 单片机的前世今生

学习,从来就是一件严肃的事情!关于单片机的入门方法,有人习惯研究datasheet,把单片机的寄存器一个一个看一遍,然后再去写代码,设计电路;有人建议买开发板,在一个规划好的平台上进行学习。

而编者更喜欢在实战中入门与学习,为什么?当我们学习走路的时候,不需要知道脚面与地面成多少角度,不需要知道左右脚要用多少力,只是去模仿别人就行了。亚里士多德曾经说过,一切学习都是从模仿开始的!

1.1 老生常谈单片机

1.1.1 你好,单片机

到底什么是单片机?根据百度百科的定义,单片机(microcontroller)是一种集成电路芯片,采用超大规模集成电路技术把具有数据处理能力的中央处理器(CPU)、随机存储器(RAM)、只读存储器(ROM)、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。

说实话,编者不是很喜欢这个定义,因为对于一个新手来说,这个定义貌似给不了他想要的东西,反而带来了更多的疑问。例如,什么是RAM,什么是ROM,什么是I/O,什么是定时器/计数器等。对于一个新人来说,这些问题估计他想破头也想不出来。

换个说法,单片机是一种芯片,可以通过对其编写程序来控制它进行工作。其中,ROM用来存储编写的程序;RAM用来提供程序执行和运算所需的空间;I/O就是芯片上的引脚,通过编程可以控制I/O输出不同的电平信号;定时器/计数器可以实现定时和计数的功能。把这些功能(高级单片机还有其他功能)集成到一块芯片上,这就是单片机。图1.1就是一个单片机的框架结构。

图1.1 单片机的框架结构

举个例子,小明要参加一场数学考试,需要准备什么?草稿纸、笔、手表,同时要背诵大量的计算公式等。在这个过程中,计算公式就是程序,小明要按照公式的规则去计算,才能得出正确的结果;大脑是ROM,用于存储公式;草稿纸是RAM,当处理问题的时候,那些处理的流程和中间结果都要在草稿纸上体现出来;小明的手是I/O口,用于输出计算得到的结果;手表是计时器,当一道题花费时间太多的时候,就要放弃,进行下一道题。

这样一来,对单片机的理解是不是深入了很多?

在编者刚接触电子的时候,对单片机有一个误解,觉得所有的芯片都是单片机,或者都是可编程的。例如编者小的时候拆解自己家里的电子设备,看到每一个引脚多的芯片,都以为是单片机,现在想想,还是挺单纯的。那么单片机在一个电路里到底充当什么角色呢?通过一个原理图来说明,如图1.2所示,这是一个MP3的解决方案。

图1.2 MP3的解决方案

这是一个基于Atmega_32+VS1003B+SD卡+LCD的MP3的解决方案。在图中, Atmega_32是ATMEL公司的单片机,SD卡(Secure Digital Memory Card)即常用的半导体闪存卡,VS1003B是VLSI公司生成的一款内置DSP核心、具有音频编解码功能的集成电路,LCD为液晶屏。

在这个系统中,电源电路为整套设备供电,需要播放的歌曲存储在SD卡中。播放歌曲时,单片机(Atmega_32)从SD卡中读取歌曲的数据。关于歌曲的属性方面的信息,例如作者、歌曲名、时长,显示在液晶屏上面;关于歌曲的音频方面的数据,传送到集成电路VS1003B里面,经过解码,转换为旋律,只要插上耳机,即可听到美妙的音乐。

在这个过程中,单片机实现的是数据的读取、运输以及简单的分析、处理的功能。最终音频数据的解码通过芯片VS1003B实现,歌曲信息的显示通过液晶屏来实现,都是借助外部电路。打个比方,单片机就好像变形金刚的大脑,给它装上一个躯体,再输入相应的程序,就可以实现想要的功能。而这些躯体有的是不具备可编程能力的,只能被动地接收一些指令或数据。

1.1.2 为什么学习51单片机

一说起51单片机,最先想到的型号是什么?8051,8031,还有89C51,89S51,89C52,它们之间究竟是什么关系?

MCS-51其实是美国Intel公司(是的,就是大名鼎鼎的英特尔)生产的一系列单片机的总称,这一系列单片机包括很多品种,例如8031、8051、8751、8032、8052、8752等,其中8051是最早、最典型的产品,该系列的其他单片机都是在8051的基础上进行功能的增、减、改变而得来的,所以人们习惯于用8051来称呼MCS-51这一系列单片机,或者直接说51单片机。8031是前些年在我国流行的单片机,它和8051相比最大的特点是没有程序存储空间。后来Intel公司将MCS-51的内核技术转让给了很多其他公司,所以市面上出现了很多以8051为核心的单片机。各家公司根据自身的技术实力对单片机的功能进行了一些优化,以满足不同的需求,但是整体架构不会变。

其中89C51与89C52这几年在我国非常流行,两者的主要区别在于89C51有两个定时器/计数器,它的程序存储空间是4KB;89C52有三个定时器/计数器,它的程序存储空间是8KB。

因此51单片机是上述这几种单片机型号的统称,而在旧型号不断被淘汰的今天,51主要用来特指89C51或89C52这两种型号。

为什么选择学习51单片机,原因有以下几点。

第一,学习资料丰富,无论是书籍、视频、源码还是开发板,51的学习资料太全了。想看书,图书馆里有好多种供你选择——讲汇编语言的,讲C语言的,讲寄存器的;想看视频,优酷、土豆视频网上有,各个大学的老师还有一些MCU爱好者自己录制的学习视频;或者买一套开发板,也会送相应的配套视频;源码,就更不用提了,电子工程世界、电子发烧友网站等提供了大量的源码供你学习;开发板,上某宝一搜,铺天盖地。所以,学51单片机的时候,千万不要担心资料不够多,因为它的资料是最多的!

第二,遇到问题的时候求助方便。因为学习51单片机的人多,所以,当你学习的时候遇到解决不了的问题时,可以轻易地找到解决的方案。为什么?因为你遇到的90%的问题,别人已经遇到并且解决了,所以当你向别人求助的时候,很轻易就能得到答案。

例如,用51单片机设计一款产品,它能够把运行过程中产生的重要数据存储到AT24C01里面。用过的人都知道,这个芯片是IIC接口的,正常来说,需要单片机有相应的硬件接口,然后配置一下相应的寄存器就行了。但是在51单片机里面是没有IIC接口的,那就需要用普通的I/O引脚来模拟IIC总线的运行时序,进行数据的读写。

如果是没做过模拟的人,第一次自己写肯定很头疼。但是你有没有想过,中国有这么多工程师学习51单片机,他们是不是早就遇到了你遇到的问题?他们是不是已经把问题解决了?如果你能够想明白这一点,再去学习单片机,就会事半功倍了!只要在百度中输入“51单片机模拟IIC总线”,如图1.3所示,就能得到你想要的答案。

图1.3 51单片机模拟IIC总线搜索结果

第三,也是最重要的一点,学习51单片机是学习其他单片机的一个桥梁!51单片机从配置上说算是低端单片机了,但正是由于功能低端,学习方便,反而是入门的良好选择。通过51单片机入门以后,再去学习任意一款单片机,都会有一种水到渠成的感觉。

单片机从IC结构上说,有哈佛结构和冯·诺依曼结构的分别;从指令集复杂程度上区分,会有复杂指令集和精简指令集的区别;从运算的数据长度区分,会有8位单片机、16位单片机和32位单片机的分别。但是在应用上,单片机就是单片机,没有太多花哨的说法,会用才是硬道理!

1.1.3 常见的单片机类型

8051单片机最早由Intel公司推出,一经面世就受到了无数电子工程师的热爱。然后在20世纪80年代,Intel公司将MCS-51的内核技术转让给了各大芯片厂家,于是市面上出现了带有各个厂家标志的51单片机:ATMEL、STC、WINBOND、飞利浦等。那么市面上到底有多少种单片机呢?这个还真不好说,就编者经常看到的而言有以下几种:

(1)AVR单片机,1997年由ATMEL公司设计并推广开来的一款高性能、低成本、精简指令集的8位单片机。关于AVR的名字还很有意思,因为它是由ATMEL公司挪威设计中心的A先生与V先生基于精简指令集(RISC)设计出来的一款单片机,所以以AVR命名。

(2)MSP430单片机。提到430,所有人脑子里都会反映出一个词:超低功耗!现在编者还记得一本430书籍的封面上使用水果电池给单片机供电,段码液晶显示时间。现在想想,也是醉了!虽然它和AVR单片机都是精简指令集,且推出时间相差只有一年,但是MSP430和AVR相比最大的区别在于它是16位单片机。同时由于它的超低功耗性能,在仪器仪表上的应用比较广泛。

(3)STM32单片机,由意法半导体公司推出的近几年最火的32位单片机,没有之一!它具有高性能、低成本、低功耗的专为嵌入式应用设计的ARM Cortex-M内核,一流的外设,超高的运算速度。有人说它有着单片机的外表,ARM的内心!很多人学完51单片机以后,直接去学STM32,这也体现了它的火热程度。

(4)PIC单片机,由美国Microchip公司推出的精简指令集单片机,功耗低,驱动能力强,可以和51单片机一样进行I/O的位定义。在汉化这方面PIC做得非常好,因为很多型号的PIC单片机在它的官网上能找到中文的datasheet。很多时候,可能产品质量、价格都差不多,但是服务做到了,竞争力自然就凸显出来了。

(5)Freescale单片机,也就是飞思卡尔单片机。它种类齐全,从8位单片机到32位单片机,各个系列几乎都覆盖到了。它有多种通信模块接口:IIC、SPI、CAN、LIN、SCI等,可以根据需求进行配置和价格的选型。从每年一次由飞思卡尔冠名的大学生智能车竞赛就能看出该类型的单片机覆盖范围有多广。而且它凭借超强的抗干扰能力在汽车电子中占有很高的市场份额。

上述几种单片机都是市面上比较常见的类型,除此以外,还有很多,这里不再一一说明。如果大家对这些单片机感兴趣,在学完51单片机以后,可以选择其中一款进行学习。

1.2 因材施教,因物施法

记得高中的时候上微机课,因为计算机数量有限,所有班级都是先上理论课,等排上实操课了,再去机房上课。那个时候,老师经常讲的内容就是Word的菜单里有哪些内容,然后在黑板上把菜单栏画出来,完全用话来解释什么是对话框,什么是菜单。当时听得云里雾里,但是当上实操课的时候,操作了几下就全都懂了。现在回想起来,那种授课方式真的是浪费时间。那么学习单片机该用什么方法呢?

1.2.1 通过Proteus仿真学习单片机

先说一下Proteus是什么。Proteus是英国Lab Center Electronics公司设计的一款EDA(Electronic Design Automation)仿真软件,具有原理图设计、单片机程序仿真、外围电路仿真等强大的功能,它的处理器平台支持8086、51、AVR、DSP、MSP430、HC11、PIC、ARM7和Cortex-M3/M0等。

它的虚拟器件库包含超过27000种的电子元件,像那些电阻、电容、LED之类的东西完全不在话下。更重要的是,它自带很多虚拟仿真器:虚拟串口、SPI、IIC、逻辑分析仪、频率计、示波器,这些器件在实际的电路设计中起到的作用是非常重要的。

该软件在实际应用中是如何协助电子爱好者开展设计的呢?以原理和代码的验证为目的,就个人经验而言,分为以下几步:

(1)原理图设计。根据项目所需的功能要求,选定该项目所需的硬件,包括MCU和外围器件。在Proteus中找到相应器件,进行摆放和各个元件之间的导线连接。

(2)源代码编写。功能的实现除了硬件的支持,少不了程序的帮助。

(3)验证及修改。将写好的程序进行编译,一般是生成hex文件,然后把hex文件导入Proteus中调用的单片机上,使程序运行,观察输出是否符合要求。

一般来说,一段程序从开始编写到最后确定版本会修改很多次(那种点亮LED的小程序除外)。也就是说,上述的步骤(2)和(3)会重复多次,甚至功能要求有变动时,步骤(1)也会重复进行。

那么Proteus的优势就很明显了,要知道,在实际工作中,进行原理验证是很麻烦的一件事,需要购买元器件、在洞洞板(也称万能电路板、万用板或实验板)或者样板上焊接、下载、调试。如果焊接有失误,还要进行故障排查。也就是说,需要大量的人力和物力。然而有了Proteus,大部分工序都可以省了,只需要动动鼠标和键盘,所有的器件都能够听从你的安排,仿真结果一目了然,进行修改也不会有多麻烦。

那么,通过该软件进行单片机的入门学习是不是很好呢?不见得!再看一下上面的步骤:原理图设计,源代码编写,验证及修改。这些步骤针对的都是已经学会单片机的人,他们知道89C52有多少个I/O,所以知道可以外接多少设备;他们知道89C52有多大的ROM,所以知道源代码最多能写多少;他们知道单片机和外围电路如何匹配,所以知道原理图该如何设计。但是新人呢?他们貌似什么都不知道。

是的,通过学习可以掌握Proteus的大部分功能,但是学到最后,可能很多人都不知道真实的单片机长什么样子,电阻长什么样子,电容长什么样子。就好像很多人玩反恐精英CS这个游戏一样,在游戏里面很厉害,在现实生活中也能这么厉害吗?

因此编者建议:新人少碰Protues。什么时候接触?当你已经基本掌握了单片机的应用,想要在某个项目中验证原理和程序的可行性的时候,它会是你的利器。

1.2.2 通过开发板学习单片机

在网上买一块开发板,然后根据配套视频,输入相应的代码,然后编译、下载,这种方式是当前比较流行的学习方式。编者也买了很多块开发板,有51的,有430的,有AVR的,有STM32的,通过这种方式也掌握了很多知识。那么这种方式是否是学习单片机的最佳方式呢?

老实说,买现成的开发板固然方便,但是硬件电路都是已经设计好的。虽然厂商会提供开发板的原理图,但是缺少了手动搭建的过程,难免会对硬件原理的理解不是很深刻。例如,为什么LED要下拉驱动,上拉可不可以?为什么要用锁存器驱动数码管,三极管行不行?多按键扫描一定要排成矩阵的形式吗,别的样式行不行?驱动蜂鸣器多是PNP三极管,NPN为什么用得少?

如果是通过开发板学习的朋友,上面的问题估计不是很好回答。单片机的学习不只是写代码、编译、下载,还会有单片机外围电路的设计。要熟悉LED如何跟电阻匹配才能正常点亮;要了解数码管如何设计驱动电路最省成本,不伤害单片机性能。如果购买开发板进行学习,相当于在一定程度上抛开了电路设计的内容,只学习程序的编写,对于外部元器件为什么这样放置只能知其然不知其所以然。甚至在应用到特殊环境时,一些在实验室工作正常的电路有可能无法正常工作。

这里,编者并不是说开发板没有用,当你已经掌握单片机常用外围电路,想要学习高级单片机的内核时,开发板会非常有帮助。入门阶段,还是多动手为好。

1.2.3 逆向学习

什么是逆向学习?先了解一下正向学习,就是按照学校里的学习步骤,先了解一项事务的概况,然后了解该事务运行的基本规则、专有名词等,逐步深入地学习、研究。举个例子,中国的孩子学习英语都是首先学26个英文字母;然后是音标——元音、辅音;然后背单词,还要区分动词、名词、系动词、形容词、副词;然后熟悉语法;最后可能会要求背诵课文。

美国的小朋友是如何学习英文的?估计不会有哪位妈妈整天对着自己一两岁的孩子说:这个是动词,你要记住!那个语法比较特殊,你要理解!每个孩子都是从牙牙学语开始的,他(她)不会管什么语法,什么词性,别人怎么说,他(她)就怎么学,首先是爸爸、妈妈,然后是吃、拿、爷爷、奶奶等。其实,无论是中国孩子还是美国孩子,他(她)们学习母语的过程都是逆向学习的过程,在这个过程里摒弃了大部分的语法、规则,一切都以实用为主,先用后学,用到什么就学习什么,这就是逆向学习。

因此,在这本书里,希望大家跟随编者一起动手搭建电路,以制作出一个小产品为目标,从点亮一个LED开始,边做边学。遇到难点或者不懂的地方,有针对性地深入了解,当你把整个流程都走一遍之后,51单片机基本上就入门了。

说了这么多,那么到底用什么学习呢?编者想了又想,决定用51最小系统板+洞洞板(或面包板)+零散的元器件等进行教学。

什么是51最小系统板?还记得1.1节讲到的51开发板吗?开发板上有很多已经连接好的硬件电路,最小系统上没有这些硬件,它配备单片机、时钟电路、复位电路、下载线接口、电源接口、电源开关和电源指示灯,同时,把单片机的I/O口使用排针全部引出来,这样的一款板子叫做最小系统板,如图1.4所示。因为它简洁,不啰嗦,越来越受到电子爱好者的推崇。高端学习板的设计也是越来越倾向这种风格。最小系统板对于使用者来说非常方便。

图1.4 最小系统板

为什么选它?理想状态下,最好的学习方式自然是让初学者从搭建一个最小系统开始学习,但是那样的话,需要初学者自己去选购、焊接元器件。焊接周期可能要几个小时,如果焊接过程中出现问题,修改、调试会花费更多的时间,初学者的热情很快就会被磨灭,这是编者不想看到的。而51最小系统板恰好解决了这个问题,它给了初学者一个完美的起步的平台,在这个平台上,你可以快速开始学习,验证你的程序。

注意:如果自己购买的话,每家的最小系统板样式可能多少会有一些不同,但是差别不大,因为整体架构都是一样的。

1.3 软件入门基础

1.3.1 汇编语言与C语言的那些事

说到编程语言,免不了要把汇编语言与C语言放在一起比较。

什么是汇编语言?它是计算机语言的一种,属于低级的计算机语言。说它低级,并不是因为它功能低级,而是有两个原因,一是因为它出现在计算机发展的早期,二是拿它和C语言作比较,它属于低级语言。同时因为它低级,所以很难被一般人掌握,需要一定的硬件基础和计算机原理方面的知识。

什么是C语言?它是国际上广泛流行的计算机高级语言。它的祖先是BCPL语言, 1967年BCPL语言诞生,1970年它被改进为B语言,1972—1973年,美国贝尔实验室在B语言的基础上设计出了C语言。它是如此美好,可以作为系统设计语言,编写工作系统应用程序,也可以作为应用程序设计语言,编写不依赖计算机硬件的应用程序。因此,它的应用范围非常广泛。

学习单片机到底是用汇编语言好还是C语言好?其实,社会早已给出了答案。最简单的验证方法是,打开招聘网站,输入“单片机”这个关键字,看看每一家公司对这个职业的技能要求,相信只要不是特别奇葩的公司,都会要求你用C语言。

图1.5是某招聘网上随意点开的两家公司的招聘信息,一家的任职要求是了解汇编语言,熟练使用C语言,另一家只提到了C语言,没有提到汇编语言。

图1.5 招聘网站搜索结果

首先,编者当年学单片机是从汇编语言开始的,但是使用了一个月后,老师就建议我们转向了C语言。用我老师的话说,使用汇编语言,只是为了更好地理解单片机的底层架构,实际做项目还是要使用C语言。而且在那一个月里,我们确实被汇编语言折腾得很惨。

其次,汇编语言的缺点在哪里?移植性太差!就这一点就足够了!开始工作后,你会发现工作中可能会用到多种单片机,例如有的时候用MSP430单片机,有的时候用PIC单片机。如果使用的是汇编语言,麻烦来了,因为这两款单片机都有自己的汇编指令,几乎是完全不一样的。假设用PIC单片机实现了一款液晶屏的驱动和应用,想在MSP430单片机上实现同样控制的时候,之前做的努力白费,依然需要从头开始写相关的控制程序。但如果是使用C语言,那就不一样了,驱动层的程序肯定需要重写,但是应用层的程序几乎不需要做变动,拿来就能用,而且几乎所有的单片机编译器都支持C语言。

最后,优胜劣汰。市场大环境已经决定了这一点,可能老项目维护会继续使用汇编语言,前提是老项目就是用汇编做的。但是大部分公司做新项目都是用C语言,用汇编语言的比较少。像编者工作的第一家公司,他的老项目是用汇编语言做的,进去以后也仅仅是修补之前的缺陷。而且有的同事担心后续的维护工作不好进行,已经开始进行程序的重写了,就是说重新写一套C语言的代码,替换之前的汇编语言的程序。编者看了他写的一部分程序,代码简洁、易读,相比汇编语言,维护起来太容易了。

比较尴尬的一点就是,一些学校依然在使用汇编语言作为单片机的编程语言。可能是因为对这个行业的了解程度还处于十几年前,也可能是懒得更新教程,导致学生花费大量的时间去学习一些今后几乎用不到的编程语言,这是非常可惜的一件事。

1.3.2 C语言入门五式

“工欲善其事,必先利其器。”讲了那么多的理论,从现在开始讲点实用的。虽然单片机的入门门槛很低,但是有些东西是必然要掌握的。先从C语言的5个常用语句开始。

(1)i=1;赋值语句。

(2)if…else条件语句。

(3)for循环语句。

(4)while循环语句。

(5)switch…case多分支选择语句。

第一说赋值语句。从小学学习1+1=2开始,“=”这个符号就一直陪伴着我们,它的含义也一直没变过。但是,到了C语言这里就全然不同了。在C语言中“=”的意义是赋值,顾名思义,把一个值赋予变量或者其他的量。赋值语句是把“=”右边的那个值或者说一个数赋给“=”左边的变量。例如,a的值为20,经过如下语句,a变成了多少?

        a = 1;

经过上面的语句后,a现在的值是1。

再如,a的值为20, b的值为2,经过如下语句,a变成了多少?

        a= b;

经过上面的语句后,a现在的值是2。有没有觉得神奇而又简单?

第二是if…else条件语句。学过初中英语的人都知道,if的意思是如果,else的意思是否则。这个语句也很好理解:如果if后面的括号里的条件是真的,那么执行if后面的语句,否则执行else后面的语句,就是说if和else后面的语句只能执行一种。

例如,a的值为1,经过如下语句,b变成了多少?

        if(a==1)                           //判断a是否等于1
            b=1;
        else
            b=0;

刚刚知道“=”在C语言中是赋值的意思,又出来一个“==”,什么情况?不要慌,还记得“=”原来的意思吗?不错,就是等于。所以,在表达式a==1中进行的是一个判断:如果a等于1成立,那么执行if后面的语句;如果a等于1不成立,则执行else后面的指令。所以,执行完上面的指令,b等于1。

第三,for循环语句。它进行的也是一个判断,为什么说它是循环语句?因为只要括号内的条件满足,它会一直执行下去。例如:

        for(i=0 ; i<10; i=i+1)               //当i小于10的时候,a等于1
        {
            a=1;
        }
        a=0; //当i大于或等于 10的时候,a等于0

在上述代码中,先解读一下for(i=0; i=i+1; i<10)这个语句,它的执行过程如下:

(1)把整数0赋值给变量i。

(2)在i等于0的情况下,判断i<10是否正确。0<10当然正确,然后执行大括号里面的指令a=1; ,然后执行第(3)步。

(3)执行i=i+1。在这里,i等于0,0加1等于1,然后把1赋值给i,所以得到的结果就是i等于1。

(4)跳回到第(2)步继续进行判断。此时i等于1, i<10依然正确,继续执行大括号里面的指令,然后执行第(3)步。依次循环,一直到i等于10,此时i<10不成立,不执行大括号里面的指令,跳出循环,执行第(5)步。

(5)循环结束,执行for语句下面的指令,也就是a=0;执行完了之后,a的值又变成了0。

以上就是for语句的工作流程。如果你觉得简单,说明你悟性很高;如果觉得有点难也没有关系,在后面的实战里可以边用边学。

第四,while循环语句。for语句是循环语句,while语句也是循环语句,主要的区别在于for语句的表达式多一些。while语句的一般形式如下:

        while(表达式)
        {
            语句
        }

只要表达式成立,while语句会一直执行下去。例如,a的值为1,执行以下语句:

        while(a<100)
        {
            a=a+1;
        }

在上述指令中,解读一下while(a<100)这个语句,它的执行过程如下:

(1)判断a<100是否成立,因为当前条件下a的值为1,所以a<100肯定成立。

(2)执行a=a+1; ,因为当前条件下a的值为1,1加1等于2。

(3)跳回步骤(1),此时a的值为2,所以a<100肯定成立。如此循环,一直到a的值为100。此时a<100不成立,跳出循环,执行while语句后面的语句。

以上即为while语句的执行过程。在实际应用中,你会发现它的用途非常广,使用方法也非常简单。

第五,switch…case多分支选择语句。其实if语句也是分支选择语句,只不过它只有两个分支,而switch语句里面可以有很多分支。它的一般形式如下:

        switch(表达式)
        {
            case 常量 1:语句 1
            case 常量2:语句2
            …
            case 常量n:语句n
            default:    语句n+1
        }

它的执行方式也很简单,先计算括号里面的表达式,用计算出的值和每一个case后面的常量进行比较,如果相等,那么执行后面的语句。在这个过程中,它只能或者跟一个case后面的常量相等,然后执行后面的语句,或者都不相等,执行default后面的语句,不会出现执行两个case后面的语句的情况。例如a的值为3,如下所示,执行完之后b等于多少?

        switch(a)
        {
            case 1:b=a+1; break;
            case 2:b=a+2; break;
            case 3:b=a+3; break;
            case 4:b=a+4; break;
            default:b=a; break;
        }

在上述指令中,switch语句执行的流程如下:

(1)判断括号内的值是多少,通过已知条件,可知a的值为3。

(2)将a与case后面的值进行比较。a与1进行比较,不相等。

(3)a与2进行比较,不相等。

(4)a与3进行比较,相等。执行其后面的语句b=a+3; , a的值为3,3加3等于6,所以b的值为6。然后执行break语句,该语句可以使程序跳出switch的结构。

注意:每个case语句后面都要跟一个break,用来跳出switch的结构。

switch语句的使用量相比前面几个略少,但是依旧是最常用的几个语句之一。学习的时候可以把它和if语句放在一起,便于理解和区分。

以上就是单片机C语言中最常用的5个语句。编者尽量把它们写得简单一些,以免大家理解上有困难。而且,本书的目的是让大家入门,并不是成为C语言的高手,所以内容上尽量精简。如果学完本书,真的激发了你的学习热情,可以买一本谭浩强老师的《C程序设计》,在那本书中,读者会学到很多高大上的技能。现在还是跟编者快快乐乐地玩单片机吧!

1.3.3 加减乘除

本节内容相对简单很多,因为大部分都是借用数学运算中的符号和方法,只需要把赋值的理念结合一下就可以了。C语言中的常用运算符号如表1.1所示。

表1.1 常用运算符号

估计大家看到这里长长地出了一口气,原来C语言的加减乘除运算这么简单,跟数学里面的差不多嘛。但是,可能多少还是会有疑问。

:等等,9除以4为什么等于2?应该是2.25啊!

:因为存储结果的a为整型变量,简单理解,就是它只能进行整数的存储,小数点后面的数全都丢弃。

:无符号整型变量是什么意思?听起来很神秘啊!

:这个在后面实战的时候会讲给你,现在只要知道就好。

一般来说,在C语言的计算过程中,加法和减法用得多一些,乘法和除法因为受到运算速度的限制而用得少,或者用移位的方式来实现相应的结果。

1.3.4 数制三变

什么是数制?用一组固定的数字和一套统一的规则来表示数字的方法,就叫做数制。

:什么!没听懂?好吧,举个例子,从0开始,一个一个的数字往上写,1、2、3一直到9,下一个数字是多少?

路人甲:当然是“10”啊!

:Good boy!不错,这就是数制的一种:十进制,逢十进一!小学的时候老师有没有讲过?

路人甲:这么一说,好像有点印象。那你今天讲的“数制三变”是啥意思?

:意思是说,在写程序的时候,不光要用到十进制,还有两种常用的数制:二进制和十六进制!这三种数制是C语言编程的时候较为常用的,啥?八进制?那个用得不多,暂时不用考虑。

路人甲:好麻烦地说,不学了,我还是安静地做一个美男子吧!

其实数制是非常简单的。二进制,顾名思义,逢二进一;十六进制,逢十六进一。所有的秘密都在表1.2中一览无余!

表1.2 十进制、二进制与十六进制换算

怎么样,看到这个表格后,对这3种数制直接的关系是不是更了解了?十进制的数字5就是二进制的数字101,十进制的数字7就是二进制的数字111……十进制的数字5对应的二进制数101和十进制的数字101一模一样,这让人怎么区分?

不用担心,当然有办法区分!以赋值为例,把一个同样大小的数字的十进制、二进制、十六进制数分别赋给一个变量a,语句如下:

        a = 10; //十进制
        a = 0B1010; //二进制
        a = 0xA; //十六进制

通过在二进制数和十进制数前面添加符号的方式,可以轻易区分这3种数制的区别。如果想把一个十进制数换算成二进制数或者十六进制数,该怎么换算?可以使用Windows自带的计算器,它有一项非常方便的功能,就是数制转换,例如编者使用的是Win7系统,打开以后如图1.6所示,选择“查看”→“程序员”菜单命令,界面如图1.7所示,数制默认为十进制。

图1.6 计算器初始页面和计算器类型选择页面

图1.7 十进制、十六进制和二进制的相互转换

在该界面下输入10,然后选择“十六进制”单选按钮,看看数字变成了多少?转换二进制也是一样,通过这种方式可以实现这3种数制的任意切换。更多功能不作介绍,大家可以自己去摸索!

1.3.5 与或反

1.3.3节讲到了关系运算符加减乘除,本节主要介绍逻辑运算符。在单片机的C语言中,主要有3种逻辑运算:与操作(&)、或操作(|)、取反操作(~)。这3种运算都是进行位运算。在逻辑运算中,0代表假,非0代表真。例如,0是假,1是真,3是真,254也是真。

首先说与操作,与表示两个值作比较时,如果都为真,那么结果为真,只要有一方为假,那么结果为假。它的运算符是“&”,有的时候用一个符号&,有的时候用两个符号 &&,有什么区别?

例如,a=0B10101111, b=0B11000011, a&b的意思是让a的每一位和b进行与操作,称为“按位与”,运算过程如图1.8所示,得到的结果是0B10000011。

图1.8 与操作运算

如果是a&&b,是对整个数值进行判断。a 的值是0B10101111,非零;b 的值是0B11000011,非零。两个真值相与,结果为1。

然后是或操作,它的运算符是“|”,表示两个值按位进行比较,只要有一方是1,那么那一位得到的结果就是1。例如,依然是a=0B10101111, b=0B11000011, a|b的运算过程如图1.9所示,得到的结果是0B11101111。

图1.9 或操作运算

如果是a||b,也是对整个数值进行判断,只要有其中一方非零,那么结果就是1。

最后是取反操作,它的运算符是“~”,听名字就知道,它是进行取反操作。和与、或操作不同,取反的操作对象只有一个,即把被操作数按照二进制的格式展开,逐位取反。例如, a=0B10101111,取反之后再次把值赋给a:

        a = ~a;

运算过程如图1.10所示,得到的结果是0B01010000,可以发现,结果的每一位都和原先的值相反。

图1.10 取反操作运算

1.3.6 常用数据类型与大小

前面曾经提到过,89C51单片机程序存储空间为4KB,这个KB到底是什么?它是描述计算机数据大小的一种单位。在计算机中,要处理的数据有大有小,它们是怎么分类的?又是怎么存放的?

先说B,它是byte的缩写,中文意思是字节,在C语言中是存储空间的基本计量单位,通常是一个8位的二进制数。2的8次方等于256,因此一个字节可以表示256个数。

再看K。在常用的计量单位中,k表示千的意思,例如1km=1000m,1kg=1000g。在C语言中略有不同,1KB=1024B, K也就是2的十次方。

而无论是B还是KB,都是描述单位或者大小的,而真正起到分类作用的是各种各样的数据类型。什么是数据类型?数据的格式通常称为数据类型。标准的C语言的数据类型可分为基本数据类型和组合数据类型,组合数据类型由基本数据类型构造而成。另外,C51中还有专门针对MCS-51单片机的特殊功能寄存器型和位类型。表1.3为Keil C51编译器能够识别的基本数据类型。

表1.3 数据类型

在51单片机中较为常用的是sbit、unsigned char和unsigned int。这些数据类型到底怎么用?后面的章节会详细说明。除了常用的几个数据类型外,这个表格不需要大家背下来,只要用的时候查一下就行。

1.4 单片机资料准备

51单片机入门要准备的资料很简单,手上有一本芯片的datasheet就行了。为什么不提教科书?那里面说的貌似还没有datasheet详细。本书里选中的芯片型号是STC89C52RC,接下来要先找到它的datasheet。

1.4.1 找到datasheet

很多人习惯一上来就百度“STC89C52RC datasheet”,并不是说这样不好,而是思路有些问题。百度是一个几乎什么都有的地方,什么都有就意味着你什么都能找到,但是同时也意味着你找到的可能不是真的。关于查找资料的方法后面会有专门的章节解释,这里只说如何找官方的datasheet。

第一步,STC89C52RC的生产厂家是STC公司,那么需要先找到STC公司的官网。百度搜索“STC单片机官网”或者“STC官网”,得到的结果如图1.11所示。

图1.11 STC单片机官网

如图1.11所示,这是需要的结果,官方网站为www.stcmcu.com。

第二步,打开网站,向下拖动页面,注意网站的右侧。当出现“STC89C51/52/54/58/516系列用户手册”时停下,如图1.12所示,这就是STC89C52的datasheet,也就是用户手册。单击该链接,在弹出的页面中,浏览器会自动保存该用户手册,若保存速度很慢,可使用迅雷或其他下载工具进行保存。

图1.12 数据手册下载位置

到了这一步,就找到了官方发布的关于单片机的datasheet。大家要记住,无论找什么芯片,思路都是先确定该芯片的生产厂家,然后找到厂家的官方网站,最后在网站内查找所需的资料。

直接在百度中搜索不好吗?个人不建议这样做,因为百度就好像一个图书市场,有正规出版发行的图书,也有盗版图书,还有一些自费印制的小册子,什么都可能找到。如果直接搜索,很难保证找到的资料是最新的或者是修改过的。

而datasheet就如同一款芯片的使用说明,如果说明书都出错,就很难知道它怎么用了。

1.4.2 认识STC89C52

图1.13分别是STC89C52的实物图和原理图。

图1.13 STC89C52的实物图、原理图

先看左侧的实物图,前两行字符为89C52RC和40I-PDIP40,这表示什么意思?这里就体现出datasheet的价值了,打开刚下载的datasheet,第19页1.5节为STC89C52系列单片机的命名规则,通过命名规则可以知道:

● 该单片机为8051系列。

● 工作电压为3.8~5.5V。

● 程序存储空间8KB, RAM空间512B。

● 工作频率可达到40MHz。

● 工业级,工作温度为-40~+80℃。

● 封装类型是PDIP。

● 引脚数量是40。

第三行字符为该芯片的生产信息,例如生产日期、批次等。

再看图1.13右侧的原理图,得知它有40个引脚,这些引脚从1~40按照逆时针的顺序从芯片的左上角开始向下,再从右侧从下往上到右上角。为了让用户在焊接或调试的时候快速找到1脚,在1脚和40脚中间放置了一个半圆形的标记。其他类型的芯片也会有相同或类似的标记告诉用户1脚在什么位置。

STC89C52单片机有4组引脚:P0、P1、P2、P3,每一组有8个引脚。这32个I/O可以通过芯片内部的寄存器进行控制。

其余8个引脚如下:

● 9脚为复位引脚RST,可以通过输入高电平来实现芯片的复位。

● 20脚与40脚分别为GND和VCC,接电源的负极和正极,通过这两个引脚给单片机供电。

● 18脚与19脚为时钟引脚,通常外接时钟电路。

● 29脚(PSEN)为外部程序存储器选通引脚,当使用外部程序存储器的时候,该引脚负责输出选通信号。使用内部程序存储器的时候不用理会该引脚。

● 30脚(ALE)输出地址锁存允许信号。上电后该引脚持续输出正脉冲信号,可通过检测信号的方式来判断单片机是否正常运行。

● 31脚(EA)为内外程序存储器选择引脚。当使用内部程序存储器时,该引脚接高电平;使用外部程序存储器时,该引脚接低电平。

除上述功能以外,大部分引脚还有第二功能。这些第二功能有的不常用,只要看一下datasheet有个初步了解即可;有的较复杂,会在后面的章节里讲解。

1.4.3 STC89C52与AT89S52

初学者经常会被几个单片机型号所困扰,例如STC89C51、STC89C52、AT89C51、AT89C52、AT89S51、AT89S52。它们之间到底有什么区别和联系?

先说51与52。51表示单片机的ROM大小为4KB,有两个定时器/计数器;52表示单片机的ROM大小为8KB,有3个定时器/计数器。这是最主要的区别。

那么STC与AT又是什么?它们分别是两家不同的单片机生产厂家:STC单片机(官方网站http://www.stcmcu.com/)与ATMEL单片机(官方网站http://www.atmel.com/)。就像前面说的,Intel公司把内核技术转让给了几个单片机厂家,它们在各自的基础上对单片机进行了一些修改。最明显的区别是,STC89C52的RAM有512B, AT89S52的RAM只有256B。目前来说,市场上入门用的51单片机以这两家为主。

那么AT89C52与AT89S52又有什么区别?它们的主要区别是,AT89C52需要用并行编程器下载程序,编程电压12V; AT89S52支持在线编程,使用P1口的5、6、7引脚,编程电压为5V,当然AT89S52也支持和AT89C52一样的编程方式。由此可见,AT89S52比AT89C52更加便捷。

本书中为什么选取STC89C52作为学习用的单片机呢?这两种单片机价格上差别不大。而在下载线的价格上,ATMEL要比STC的贵两元左右。更主要的是,进行UART口通信时,AT89S52还需要一条单独的串口线以及电平转换电路;而STC的单片机的一条下载线既可以用于程序下载,又可以用于串口通信,一举两得。