搜索
bottom↓
回复: 475

从单片机基础到程序框架(连载)

  [复制链接]

出0入0汤圆

发表于 2016-1-17 11:30:34 | 显示全部楼层 |阅读模式
本帖最后由 吴坚鸿 于 2016-1-17 11:32 编辑

前言:


      大家好,我叫吴坚鸿,以前一直想写两本书,一本讲单片机入门基础,一本讲单片机程序框架。现在发现,单片机基础和程序框架并没有明显的分水岭,基础中有框架,框架中有基础,应该合二为一,读起来才会连贯舒畅。所以我决定中止当前已写到55节的《从业十年,教你单片机入门基础》连载帖,新开此连载帖。
      再提一下我2014年写的《从业将近十年,手把手教你单片机程序框架》,一方面受到很多网友的好评,另一方面也有一些热心网友提出了宝贵的意见,我今天看来,确实还有一些可待改进的地方。本来计划在2017年重写《……单片机程序框架》那个老帖,现在看来不用那么折腾了,只要把《……单片机程序框架》的内容也整合到此新帖里就可以了,这样对我也比较省事。我的时间计划是,先花4年时间写一个初稿,然后再花2年时间重写一次,最后再花1年时间整理成书,整个过程大概7年时间左右,今年是2016年,估计到2023年左右《从单片机基础到程序框架》的新书就可以出版了。
      感谢各位朋友的支持。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-1-17 11:42:16 | 显示全部楼层
2023年...热情还在吗?

出0入42汤圆

发表于 2016-1-17 11:45:58 | 显示全部楼层
天下武功为快不破。

出0入0汤圆

发表于 2016-1-17 12:00:47 | 显示全部楼层
喜欢楼主的文章,支持!

出0入0汤圆

发表于 2016-1-17 12:15:34 | 显示全部楼层
又见吴老师,哈哈,计划做的很详细啊,都到2017了,佩服您的耐心和毅力,可以花好几年时间来写书,谢谢知识传播

出0入0汤圆

发表于 2016-1-17 13:07:43 | 显示全部楼层
然后再花2年时间重写一次,最后再花1年时间整理成书,整个过程大概7年时间左右  这么久。。。

出0入0汤圆

发表于 2016-1-17 14:19:31 | 显示全部楼层
支持一下。

出0入0汤圆

发表于 2016-1-17 14:53:44 来自手机 | 显示全部楼层
顶一下   

出0入0汤圆

发表于 2016-1-17 15:49:52 | 显示全部楼层
支持一下鸿哥,学到不少东西

出0入0汤圆

发表于 2016-1-17 16:57:09 | 显示全部楼层
7年。。。

出0入0汤圆

发表于 2016-1-17 17:23:43 | 显示全部楼层
   十年磨一剑,铁杵磨成针。

出0入0汤圆

发表于 2016-1-17 17:35:58 | 显示全部楼层
2023年,如果我那时还搞电子一定买楼主的书

出0入0汤圆

发表于 2016-1-17 17:38:58 | 显示全部楼层
甚是佩服楼主的毅力与坚持,支持你

出20入0汤圆

发表于 2016-1-17 17:43:47 | 显示全部楼层
  时间拉的太长了,不知道能不能坚持下来。

出425入0汤圆

发表于 2016-1-17 18:41:40 | 显示全部楼层
时间太长了。我认为多投入精力,把时间缩短。把它做成挣钱的模式,把投入收回。

出0入0汤圆

发表于 2016-1-17 20:23:16 | 显示全部楼层
如果真到2023出版了,我一定买,不是为技术 ,而是为情怀

出0入0汤圆

发表于 2016-1-17 20:33:43 | 显示全部楼层
到2023年    最后真的就是情怀了

出0入0汤圆

发表于 2016-1-17 20:43:41 | 显示全部楼层
mark,等待更新

出0入0汤圆

发表于 2016-1-17 20:50:50 | 显示全部楼层
用7年专注写一本书,支持你 不容易

出0入0汤圆

发表于 2016-1-17 20:53:51 | 显示全部楼层
谢谢老师的知识传播

出0入0汤圆

发表于 2016-1-17 21:15:47 | 显示全部楼层
做这件事不是为了利益 可以说是奉献    认真去做一件自己觉得有意义的事 并坚持把它做好

吴老师 求真务实的精神值得我们每个人去学习

如果各行各业 都有 吴老师这样的人  我们国家能不强大么

真心的佩服吴老师

出0入0汤圆

发表于 2016-1-17 21:30:31 | 显示全部楼层
上次的贴还没看完

出0入0汤圆

发表于 2016-1-17 21:52:08 | 显示全部楼层
谢谢吴老师,支持你。

出0入0汤圆

发表于 2016-1-17 22:26:30 | 显示全部楼层
支持楼主锲而不舍的精神

出0入0汤圆

发表于 2016-1-17 23:04:36 | 显示全部楼层
不错。              

出0入0汤圆

 楼主| 发表于 2016-1-18 11:49:15 | 显示全部楼层
第一节:我是中国最幸福的单片机工程师。


       熟悉我的人都知道,我在深圳过着隐居般的生活。别人工作时,我可能在睡觉,在打乒乓球,在看电影,在写连载帖,在洗脚按摩(正规那种)。别人睡觉时,我可能还在工作偶尔还会通宵。状态好时我就工作,状态差时我就休息,平均下来,一个星期的工作时间大概三四天,每天三四个小时。我今年32岁,这辈子要跟哪个女人过、要在哪个城市定居、要做一件什么事都已经定了,工作能带给我乐趣,工作时间又相对自由,感觉又回到了童年我已经很知足了。
       我06年毕业,09年就出来做自由职业者,在深圳以接单片机项目谋生,期间有两件事是我比较自豪的,一件是发明了液晶万能测试仪申请了国家发明专利,另外一件是辅助朱兆祺成立了一家新公司,后来我功成身退了。我现在有自己的机器人技术有限公司,做数控机器人系统,运动卡,三轴五轴联动之类的产品。公司的ARM单片机编程,DSP编程,FPGA编程,电路板设计,上位机软件都是我一个人在做。我只专心做技术,而市场,生产,行政,资金,财务,采购通通不用我分心去管,有我另外的合伙人雷总去打理。我常跟雷总开玩笑说,我就是大明星只管唱歌拍电影那些技术层面的事,他就是我的经纪人负责公司具体运作经营,所以我常感恩我能过上自由生活自由创作的日子,是因为有雷总的关照。
       光有经济保障还是不够的,人最重要的是要找到自己的归宿自己的位置。我最爱看老子,庄子,孔子,王阳明的圣人书,王阳明说人人皆可成为圣人,所以我一直在追求圣人之道,我渴望成为圣人,无忧,无惑,无惧。圣人之道有真三不朽之说,立功,立言,立德。在立功层面,我这一辈子的定位就是做技术,我想做超级宇宙技术大牛,特别牛的那种牛,然后以我的技术协助雷总把我们的机器人公司做大做强。在立言层面,在不涉及我公司商业机密的前提下,我的天命和归宿就是做单片机技术分享,写一辈子源源不断的技术分享连载帖,然后写一本《从单片机基础到程序框架》的书,帮助更多单片机初学者,出书可以满足我在立言方面的追求。在立德层面,我平时信因果,在生活中多传播正能量。
       我有自知之明,我的天命就是传播单片机技术。人最宝贵的东西是生命,生命属于人只有一次,人的一生应当这样度过:当他回首往事的时候,他不因虚度年华而悔恨,也不应碌碌无为而羞愧。在他临死的时候,他能够这样说:我的整个生命和全部精力,都献给了世界上最壮丽的事业——为传播单片机技术而奋斗。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-1-18 12:04:12 | 显示全部楼层
吴坚鸿 发表于 2016-1-18 11:49
第一节:我是中国最幸福的单片机工程师。

支持坚哥,我可是你的粉,一直在跟着的帖。

出0入0汤圆

发表于 2016-1-18 12:26:59 | 显示全部楼层
  期待大作`!

出0入0汤圆

发表于 2016-1-18 13:06:15 来自手机 | 显示全部楼层
鸿哥的框架连载看过一遍了,个别重新移到STM32里验证过,受益匪浅。

出0入8汤圆

发表于 2016-1-18 13:13:27 来自手机 | 显示全部楼层
顶,准备以后就按你这个来

出0入0汤圆

发表于 2016-1-18 13:14:51 | 显示全部楼层

出0入0汤圆

发表于 2016-1-18 20:13:12 来自手机 | 显示全部楼层
鸿鹄之志

出0入0汤圆

发表于 2016-1-18 20:44:31 | 显示全部楼层
感谢,现在用的就是楼主的程序 编写方式,很好,很强大。

出0入0汤圆

发表于 2016-1-18 21:48:46 | 显示全部楼层
感觉您把自己的工作经验,经历,看问题的方式,分享出来,会更有价值。

出0入0汤圆

发表于 2016-1-18 22:08:53 | 显示全部楼层
期待坚哥的佳作!

出0入0汤圆

发表于 2016-1-18 22:34:18 | 显示全部楼层
看了《从业十年,教你单片机入门基础》的帖子,受益匪浅,收获良多。单片机高手有很多,但是能像鸿哥这样,毫无保留的把实战经验都传授给大家,实在是太少了。强力支持鸿哥,期待大作早日完成!

出0入0汤圆

发表于 2016-1-18 22:37:44 | 显示全部楼层
  我觉得坚鸿大哥是咱们做技术人员的榜样,觉得现在的人做技术动机不纯了,不单单是为了做技术而做技术。

出0入0汤圆

发表于 2016-1-19 20:07:38 | 显示全部楼层
支持楼主,十年磨一剑,如果老师出版  我还在从事技术的话  我也买一本书

出0入0汤圆

发表于 2016-1-22 22:24:02 | 显示全部楼层
期待中

出0入0汤圆

发表于 2016-1-22 22:35:36 | 显示全部楼层
支持楼主

出0入0汤圆

发表于 2016-1-23 05:52:50 来自手机 | 显示全部楼层
支持坚鸿

出0入36汤圆

发表于 2016-1-23 08:54:07 | 显示全部楼层
支持 做技术不浮躁

出0入0汤圆

发表于 2016-1-23 10:23:29 | 显示全部楼层

出0入0汤圆

发表于 2016-1-23 18:52:57 | 显示全部楼层
若能坚持7年,完成一本书,必定能完爆一大片出书者,让更多后学者受益。毅力可嘉!!!
7年,我替楼主担忧啊。。。。。
有的老师不愿意轻易写书,是怕自己的辛苦之作被人轻视,比如西安交大的杨老师(你好,放大器)------这样的书确实好书。

出书的话 我就预定一本。。。。

出0入0汤圆

 楼主| 发表于 2016-1-26 13:53:02 | 显示全部楼层
第二节:初学者的疑惑。


【2.1   单片机应用的核心技术是什么?】

        单片机应用的核心技术是什么?是按键,数码管,流水灯,串口。是它们的程序框架。按键和数码管是输入是人机界面,把它们的程序框架研究透了,以后做彩屏或者更花销的显示界面,程序框架也可以通用。流水灯是应用程序是APP,把它的程序框架研究透了,以后控制飞机大炮的程序框架也是一样。串口是通讯是接口,把它的程序框架研究透了,以后搞SPI,CAN,USB等通讯项目时,上层的程序框架也可以通用。如果某天你突然腰酸背痛可能是缺钙了,如果某天你第一次做项目时突然发现无从下手,你缺的可能是程序框架。

【2.2   研发汽车还是驾驶汽车?】

         研发汽车还是驾驶汽车?研究单片机还是驾驭单片机?我建议把学单片机当作考驾照,是学“用”的技术,而不是研究单片机本身。

【2.3   学哪种单片机更有前途?】

         对于51单片机,PIC,AVR,stm32,初学者学哪种更有前途?既然是考驾照,用桑塔纳还是用宝马车都不重要,驾驶技术是通用的。单片机只要会一种其它的就触类旁通了。

【2.4   单片机神奇的工作原理是什么?】

        单片机神奇的工作原理是什么?初学者不用纠结这个问题,这不是我们学习的方向。考驾照只要大概知道汽车是由四个轮,发动机,制动系统,离合器,方向盘等部分构成就够了,再深入的细节不用纠结。学单片机只要大概知道单片机内部由运算器,寄存器,IO口,复位电路,晶振电路等部分组成就够了,再深入的不用纠结。说实话,我本人做单片机开发有很多年了,但是我对单片机的工作原理也很模糊,就像人为什么能通过大脑来灵活控制双手,对于我仍然是一个迷。有这样的疑惑时咋办?我建议用“游戏规则”这个概念去应付它。游戏规则是不需要解释的,只要遵守就可以了。在应用的技术领域,把暂时不解的东西当作游戏规则来解读和遵守是我常用的思维方式。

【2.5   很难记住繁杂的寄存器?】

       很难记住繁杂的寄存器?寄存器不用死记硬背,只要知道它大概的操作流程,有哪几类就够了。配置寄存器时,可参考别人已经配置好的代码,这些代码都很容易通过网络或者书本获得。也可以查找芯片数据手册,有很多单片机厂家会给出各个功能的代码范例。


【2.6   C语言很难学?】

      C语言很难学?暂时不用学指针,暂时不用学结构体,暂时不用学多文件编程,暂时不用学链表,暂时不用学宏定义,暂时不用学文件操作,暂时不用学所有的数据类型。只要会:
      5条指令语句switch语句,if else语句,while语句,for语句,=赋值语句。
      7个运算符+,-,*,/,|,&,!。
      4个逻辑关系符||,&&,!=,==.
      3个数据类型unsigned char, unsigned int, unsigned long。
      3个进制相互转化,二进制,十六进制,十进制。
      1个void函数。
      1个一维数组code(或const) unsigned char array[]。
      只要会上述一些知识点,应付任何一种逻辑功能的单片机软件都足够了。
      我在学校时只学了汇编程序,出来工作后才知道用C语言也能开发单片机,一开始只用常见的几条语句就把项目做出来了,没有用到printf这类繁琐格式的语句,第一次感觉C语言原来是那么容易那么简单,我是到后来才陆陆续续用到C语言其他的高级功能。

【2.7   汇编语言很难学怎么办?】

       汇编语言很难学怎么办?这方面我要向中国很多工科大专院校提个建议,对于初学者,一开始就学汇编语言确实难学,不如先学C语言,学会了C语言再学汇编,这样理解起来就容易多了。也可以把C语言列入必修课,汇编语言列入选修课,因为实际工作中也是C语言为主。

【2.8   很难记住各种繁杂的通信协议?】

        很难记住繁杂的各种通信协议?IIC,SPI,232,CAN,USB等等。不用记那么多,你只要理解串行和并行通讯方式的基本原理就可以了,剩下的只是不同的协议而已,工作时再根据需要去看看相关资料就可以上手。不管世上有多少种通讯协议,物理世界上只有这两种通讯方式。

【2.9   很难写出短小精悍的程序?】

        很难写出短小精悍的程序?初学者不用纠结于此。很多项目开发,程序容量不是刻意追求的目标,多一点少一点没关系,不会是寸土寸金的事情,现在大容量的单片机品种也非常多,反而更值得关注的是程序的运行效率,可读性和可修改性。当然,一些成本敏感的消费类电子不在此讨论范围,这类项目往往对程序容量也要求很苛刻。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-1-26 14:35:23 | 显示全部楼层
支持楼主的分享!!

出0入0汤圆

发表于 2016-1-28 17:38:15 | 显示全部楼层
支持楼主的上课!

出0入0汤圆

 楼主| 发表于 2016-1-31 21:21:43 | 显示全部楼层
第三节:单片机最重要的一个特性。


【3.1   单片机的“一”。】

                                     图3.1

    “道生一,一生二,二生三,三生万物。”《道德经》认为,世间万物,缤纷多彩,都源自一个东西,这个“一”的东西就是“道”。电子世界也存在“一”,这个“一”繁衍出手机,电脑,电视机,机器人等丰富多彩的电子世界,这个“一”就是单片机最重要的一个特性:“程序下载进内存后,单片机既可以通过管脚识别外部输入的高低电平信号,也可以通过管脚对外部输出不同时间长度的高低电平。”这句话有5个关键词“程序,内存,管脚,电平,时间。”下面我详细解读每个关键词的含义,涉及到某些专用名词如果不理解也没关系,主要是让大家有个感性的认识就足矣。

【3.2   程序。】

    单片机程序有3种:C程序,汇编程序,机器程序。能下载进单片机的只有机器程序,C程序和汇编程序都不能直接下载进单片机,所以C程序和汇编程序都要经过编译软件翻译成机器程序后,才能下载进单片机。程序是语言,语言是用来交流,交流就必须存在两个对象,对象分别是程序员和单片机。程序员是人所以用C或者汇编语言,单片机是机器所以用机器语言,人和机是不同的世界,两者交流就需要一个翻译家,翻译家就是编译软件,俗称编译器,它能把C语言或者汇编语言翻译成单片机能识别的机器语言。机器语言就是0101的代码,一般以十六进制的形式呈现。
    理论上,程序员也可以抛开C和汇编语言,直接用机器语言做项目。我读书时老师让我们做实验就是这么整。那时我还不知有烧录器,老师让我们先用汇编语言写好程序,然后自己充当编译器,对照汇编语言和机器语言的指令表,人工把汇编语言翻译成十六进制的机器语言,最后把机器语言按字节一个一个的输入到特定的实验设备来观察现象。现在回想起来,老师当时的初衷是让我们了解编程语言的本质。
    既然可以直接用机器语言做项目,为什么还要C语言或者汇编语言?在C语言或者汇编语言没有诞生前,程序员就是通过在纸带上打孔来代表01的机器语言,此时相当于结绳记事的原始阶段。后来人类发明了汇编语言,通过英语单词来表示01机器语言特定的指令语句,此时开始诞生了汇编语言的编译器相当于进入象形文字的阶段。再到后来人类又发明了C语言,通过数学符号和英语单词来表达自己的逻辑,诞生了C语言的编译器相当于进入了汉字白话文阶段,从此程序员写出来的C程序就非常方便移植,编辑,阅读,传播,继承。现在单片机开发的主流是C语言,我本人出来工作后就没有用过汇编做项目开发。C语言是必修课,汇编语言是选修课;C语言是白话文简单易懂,汇编语言是文言文繁琐难读。当然汇编也有它的应用场合,汇编的翻译效率高,往往是一句汇编语言对应一句机器语言,而一句C语言有可能对应几句机器语言,这样C程序的代码效率在很大程度上取决于编译器的水平,编译器能不能帮你翻译出高效的机器语言对于我们来说往往像黑盒子,不像汇编语言那么可控制。所以很多嵌入式系统某段要求简洁高效的源代码往往用汇编来写,也有少数一些很便宜的单片机不提供C编译器,只能用汇编语言开发。要不要学汇编,最好根据个人的工作需求来决定。

【3.3   内存。】

    单片机就像MP3,程序代码就像歌曲,把不同的歌曲下载到MP3里就可以听到不同的音乐,把不同的程序下载到单片机里,单片机就能做不同的事。能装程序的单片机必然有内存,内存由ROM和RAM组成,ROM和RAM都能装东西,但各有不同。
    ROM的优点是存储的东西断电后不会丢失,缺点是存储的东西上电后不能更改,想要改变ROM的内容除非重新下载程序,而且下载次数有限制,FLASH的ROM最大次数通常是10万次,而OTP的ROM只能下载1次,所以平时上电工作时ROM存储的东西是不能更改的,某些具有IAP功能的高级单片机不在此讨论范围内。而RAM恰好反过来,RAM的优点是存储的东西上电后可以随时被单片机更改,更改次数没有限制,缺点是存储的东西断电后会丢失,没有记忆功能。
    ROM和RAM各有特点,单片机从中各取所长。ROM用来存储不可更改的指令代码和常量数据,ROM的容量往往相当于代码的容量。RAM用来存储可以被更改的变量数据,RAM的容量往往相当于全局变量和局部变量的容量。不管是用C语言还是汇编,所写的程序代码就自然包含了指令代码、常量数据、全局变量、局部变量,那么谁在幕后帮我们进行分类存储,谁把一个程序代码的一分为二让它们在ROM和RAM里各就各位?是编译器软件和下载器(烧录器),编译器除了把C语言翻译成机器语言之外,还帮我们分好了类,分配好了存储的地址和位置,下载器(烧录器)再根据这些信息把程序存储到内存中,这些工作一般不用程序员干预,它们自动完成。

【3.4   管脚。】

    管脚是单片机与外部电路进行能量和信息交互的桥梁。有电源,复位,晶振和IO口这4类管脚。   
    第一类电源管脚。是给单片机内部电路供电的接口。单片机有两种常用的供电电压,一般是3.3V或者5V,有的单片机两种电压都兼容。
    第二类复位管脚。单片机上电后需要外部电路给它一个瞬间高电平或者低电平的复位信号,才能启动工作。复位电路通常是由电容和电阻组成的充电电路来实现,也有一些系统是用专门的复位芯片来实现。
    第三类晶振管脚。任何单片机想要工作必须要有晶振。单片机执行程序指令是按一个节拍一个节拍来执行的。这个节拍的时间就是由晶振产生,所以把晶振比喻成单片机的心脏是非常恰当的。现在也有很多单片机直接把晶振集成到内部,这类单片机不用外接晶振也可以。
    第四类IO口管脚。这是跟我们编写程序关联最密切的管脚。前面提到的电源,复位,晶振这3种管脚是为了让单片机能工作,俗称单片机工作的三要素。而单片机工作的具体内容就是通过IO口管脚来体现的。比如,IO口能识别按健的输入,也能输出驱动继电器工作的开关信号,也能跟外围器件进行通信。

【3.5   电平。】

    电平就是电压的两种状态,低或者高,低相当于程序里的0,高相当于程序里的1。单片机IO口管脚检测到的电压低于或等于0.8V时是低电平,程序里读取到的是0数字。单片机IO口管脚检测到的电压高于或等于2.4V时是高电平,程序里读取到的是1数字。必须注意的是,IO口输入的最大电压不能超过单片机的供电电压。单片机输出的低电平是0V,单片机输出的高电平等于它的供电电压值,往往是3.3V或者5V。

【3.6   时间。】

    时间是单片机程序必不可少的元素。跟外围芯片通信的时序节拍需要时间,驱动发光二极管闪烁需要时间,工控自动化的某些延时需要时间。单片机的时间来源自两方面。第一方面源自指令的周期时间。单片机是根据节拍来执行程序指令的,每执行一条指令都要消耗一点时间,只要让程序执行的指令数量越多,产生的时间就越长,通过调整所执行指令的数量就可以得到所需的时间长度。第二方面源自单片机内部自带的定时器。假如设置定时器每20毫秒产生一次中断,现在要获取10秒钟的时间,只需在程序里统记500次定时中断就可以了,因为1秒等于1000毫秒。指令和定时器这两者的时间最后都来源于晶振。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-2-2 10:47:32 | 显示全部楼层
支持坚哥,我可是你的粉,一直在跟着的帖。
头像被屏蔽

出0入0汤圆

发表于 2016-2-3 15:41:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2016-2-3 21:58:19 | 显示全部楼层
提前祝鸿哥春节快乐

出0入0汤圆

发表于 2016-2-4 16:54:03 来自手机 | 显示全部楼层
必须要顶

出0入296汤圆

发表于 2016-2-5 08:18:14 来自手机 | 显示全部楼层
这个必须要顶!!!

出0入0汤圆

发表于 2016-2-9 22:40:13 | 显示全部楼层
祝新年快乐!
期待楼主的好文章.

出0入0汤圆

发表于 2016-2-10 07:54:16 来自手机 | 显示全部楼层
支持!新年快乐!期待!

出0入0汤圆

发表于 2016-2-10 09:11:33 | 显示全部楼层
关注此贴。

出0入0汤圆

 楼主| 发表于 2016-2-11 11:14:17 | 显示全部楼层
第四节 : 平台软件和编译器软件的简介。


【4.1   平台软件和编译器软件的各自分工。】

        C语言写在哪?谁来把C语言翻译成单片机可以识别的机器语言?这就是平台软件和编译器软件的分工。平台软件负责编辑C语言,编译软件负责把C语言翻译成单片机可以识别的机器语言。

【4.2   每一种单片机的平台软件和编译器软件不一定是唯一的。】

        C语言在单片机的应用也是最近这些年发展起来的,早期做单片机的原厂更关注芯片硬件本身,配套的C语言开发软件方面涉入不深,他们往往只管把单片机芯片生产出来后,给大伙提供一个汇编语言的编译器软件就草率了事,所以给了很多第三方商家做平台软件和C编译器的机会,后来单片机原厂也乐意支持和配合这些第三方开发软件的厂商,也有一些单片机原厂直接收购这类第三方软件公司。因此,不同厂家的单片机,它所用的平台和编译器软件可能都不一样。即使是同样一个厂家的单片机,它也有可能存在多种不同的第三方平台软件和编译器软件,每一种单片机所用的平台软件和编译器不一定是唯一的。比如stm8单片机可以用 STVD软件平台,也可以IAR平台。stm32单片机可以用keil平台,也可以用IAR平台。

【4.3  平台软件和编译器软件的宿主与寄生关系。】

        平台软件选定了之后,所用的编译器软件也可能存在多种选择,并不是一种平台软件就绑定一种编译器软件。生物学的比喻,平台软件是宿主,编译器软件是寄生在平台软件里的。一个平台软件可以嵌入多种不同的编译器软件,平台软件和编译器软件存在一对多的关系。比如,PIC单片机的平台软件是MPLAB,8位PIC单片机是PICC编译器,12位PIC单片机是PIC18编译器,16位PIC单片机是C30编译器。而且MPLAB平台软件与上述各种编译器软件都要单独一个一个分开来安装,最后运行MPLAB平台软件,在里面操作某个菜单设置选项,把各种C编译器软件跟MPLAB平台软件关联起来。

【4.4  51单片机的平台软件和编译器软件。】

        我后面的讲解,51单片机的平台软件用keil2,编译器软件用C51。单片机程序开发需要用到这两种软件,但在项目开发的时候,只要跟平台软件打交道就可以了,因为编译器软件是当做一种独立配件嵌入到平台软件里,统一接受平台软件的控制。我在用PIC的8位单片机时,需要安装一次MPLAB平台软件,也需要独立再安装一次PICC编译器软件,然后运行MPLAB平台软件,在里面操作某个菜单设置选项,把PICC编译器跟MPLAB平台软件关联起来,也就是我所说的把PICC编译器嵌入到MPLAB平台软件里,统一接受平台软件的控制,但我平常写代码时只需要跟MPLAB平台软件打交道就可以了。我早期在做51单片机开发时,也是需要把keil平台软件和C51软件分开安装,然后再把它们关联起来,但是现在从keil2版本开始,在安装keil平台软件时就已经默认把C51安装好了,并且自动把C51嵌入到了keil平台软件。我现在用keil2这个版本的平台软件,只需要安装一次keil2平台软件就可以了,不需要像早期那样再单独安装C51编译器。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-2-11 20:59:52 | 显示全部楼层
春节都不忘更新,春节快乐,鸿哥!

出0入0汤圆

发表于 2016-2-11 21:21:42 | 显示全部楼层
非常支持!感谢LZ

出0入0汤圆

发表于 2016-2-12 20:55:49 来自手机 | 显示全部楼层
吴坚鸿 发表于 2016-1-18 11:49
第一节:我是中国最幸福的单片机工程师。



楼主,你好!我是在校学生,学的通信。对单片机非常感兴趣,以后打算以此为生,但不知从何做起,希望不吝赐教!

出0入0汤圆

发表于 2016-2-12 21:41:08 来自手机 | 显示全部楼层
已经看了楼主上面的帖子,收获很多!感谢楼主,持续关注!!

出0入0汤圆

发表于 2016-2-13 09:51:27 | 显示全部楼层
我只是业余爱好者。看了楼主的帖子,多任务的难题总算解决了。

出0入4汤圆

发表于 2016-2-13 10:20:24 来自手机 | 显示全部楼层
这才是高手。必须顶。

出0入0汤圆

发表于 2016-2-16 21:53:45 | 显示全部楼层
谢谢楼主分享,已收藏,从你这边学到了很多编程技巧

出0入0汤圆

发表于 2016-2-17 18:49:58 | 显示全部楼层
继续跟进。向群主致敬!

出0入0汤圆

发表于 2016-2-17 23:37:52 | 显示全部楼层
鞭辟入里,高手的讲解总是通俗易懂

出0入0汤圆

 楼主| 发表于 2016-2-19 16:59:53 | 显示全部楼层
本帖最后由 吴坚鸿 于 2016-2-20 10:02 编辑

第五节:用keil2软件关闭,新建,打开一个工程的操作流程。


【5.1   本教程选择keil2软件版本的原因。】

        Keil软件目前有Keil2,Keil4,Keil5等版本。本教程之所以选用keil2版本,是因为keil2版本比较单纯,它本身内置了C51编译器,并且只适用于51单片机不能适用于stm32这类单片机。而Keil4,Keil5等版本不仅可以适用于51单片机的,还可以适用于ARM类的单片机,它们有C51编译器和MDK-ARM编译器两种选择,在同一个keil4或者keil5版本里,C51和MDK-ARM两者往往只能二选一,MDK-ARM编译器是针对stm32这类单片机,如果你电脑上用了MDK-ARM编译器想再切换到C51编译器就很麻烦了往往不兼容,为了电脑上既能用C51编译器,又能兼容MDK-ARM编译器,我的电脑上是同时安装了C51编译器的keil2和MDK-ARM编译器的keil4,一台电脑同时安装keil2和keil4不会冲突,能兼容的。

【5.2   如何在不用关闭keil2软件的前提下又能关闭当前被打开的工程?】

       要关闭当前工程,最简单的方法是直接点击keil2软件右上角的“X”直接把keil2软件也一起关了,这种方法不在讨论范围,现在要介绍的是如何在不关闭keil2软件的前提下又能关闭当前被打开的工程。


     
                        图5.2.1            
        
      第一步:启动keil2软件。
      双击桌面”keil uVision2”的图标启动keil2软件。

----------------------------------步骤之间的分割线----------------------------------------

     
                        图5.2.2      

       第二步:关闭被打开的已有工程。
       启动keil2软件后,假设发现此软件默认打开了一个之前已经存在的工程。关闭已有工程的操作是这样子的:点击上面”Project”选项,在弹出的下拉菜单中选择“Close Project”即可。这时keil2软件处于“空”的状态,没有打开任何工程了。
   

【5.3   keil2如何新建一个工程?】

      
                         图5.3.1  

       第一步:新建一个工程文件夹。
       在电脑D盘目录下新建一个文件夹,取名为“stc89c52rc”。

  1.       补充说明:
  2.     (1)文件夹的命名以及后面涉及到的工程文件名统统都不要用中文,请全部用英文,数字,或者下划线这些字符。即使keil软件支持中文名,我建议也不要用中文名,因为在单片机这个行业,有一些单片机厂家提供的平台软件,某些版本是不支持中文名的,所以大家从一开始就养成这个习惯,以后可以避免遇到一些不必要的麻烦。
  3.     (2)新建的文件夹请直接放在某盘的根目录下,而不要放到某个已有文件夹的目录下。一方面是因为已有的文件名目录往往带有中文单词,另外一方面是有一些单片机厂家的平台软件不支持嵌入层次太深的文件目录,所以大家从一开始就养成这个习惯,以后可以避免遇到一些不必要的麻烦。
复制代码


----------------------------------步骤之间的分割线----------------------------------------

       第二步:启动keil2软件。
       双击桌面”keil uVision2”的图标启动keil2软件。

----------------------------------步骤之间的分割线----------------------------------------

      第三步:关闭默认被打开的已有工程。
      启动keil2软件后,如果发现此软件默认打开了一个之前已经存在的工程,请先关闭此工程让keil2软件处于“空”的状态,如果没有发现此软件默认打开已有工程,这一步可以忽略跳过。关闭已有工程的操作是这样子的:点击上面”Project”选项,在弹出的下拉菜单中选择“Close Project”即可。这时keil2软件处于“空”的状态,没有打开任何工程了。

----------------------------------步骤之间的分割线----------------------------------------


     
                               图5.3.4.1  


     
                               图5.3.4.2  



                               图5.3.4.3  


      
                               图5.3.4.4  

       第四步:利用工具向导新建一个工程。
       点击上面”Project”选项,在弹出的下拉菜单中选择“New Project...”,在弹出的对话框中,选择保存的目录是刚才第一步新建的文件夹“stc89c52rc”,同时输入跟文件夹名称一样的工程文件名“stc89c52rc”,然后单击“保存”按键(一个新工程模板就建成了),单击“保存”按键后此时会弹出一个选择单片机型号的对话框,单击”Atmel”这个厂家前面的“+”号,在展开的下拉选项中选中“AT89C52”这个型号,然后点击“确定”,此时会弹出一个英文询问框,大概意思是“是否要复制STARTUP.A51这个文件到工程里?”我们单击“否”即可。

  1.       补充说明:
  2.      (1)以上新建的保存文件名应该跟我们第一步在D盘新建的文件夹名称一致,确保都是“stc89c52rc”,因为有一些单片机厂家的平台软件是有这个要求的,所以大家养成这个习惯,以后可以避免遇到一些不必要的麻烦。
  3.      (2)上面之所以选择Atmel厂家的AT89C52单片机,是因为本教程选用的单片机STC89C52RC跟AT89C52是兼容的。
  4.      (3)在弹出的英文询问框,大致意思是“是否要复制STARTUP.A51这个文件到工程里?”,那么STARTUP.A51这个文件有什么含义?STARTUP.A51是一个启动程序文件,在单片机进入.c程序执行main函数之前,先去执行这个启动程序,这个启动程序是专门用来初始化RAM和设置堆栈等,如果我们选“否”不添加这个启动程序,编译器也会自动加入一段我们不能更改的默认启动程序。如果选“是”,那么这个文件就会出现在我们工程里,我们可以根据需要对它进行更改。但是大多数的情况下,我们都不会去更改此文件,所以无论你选“是”还是“否”,只要你不更改START.A51文件,对我们来说都是一样的。因此我本人一般情况下都是选“否”。
复制代码


----------------------------------步骤之间的分割线----------------------------------------

   
                        图5.3.5.1  


   
                       图5.3.5.2  

   
                        图5.3.5.3  

       第五步:新建一个.c源文件。
       点击上面”File”选项,在弹出的下拉菜单中选择“New...”,会看到弹出来一个名字为”Text1”的文件。再一次点击上面”File”选项,在弹出的下拉菜单中选择“Save”,会弹出一个保存的对话框,此时还是选择保存在第一步新建的文件夹目录下,并且把“Text1”文件名更改为“stc89c52rc.c”(注意后缀是.c扩展名),单击“保存”。
   
  1.        补充说明:
  2.       (1)此时你如果打开D目录下“stc89c52rc”的文件夹,你会发现此文件夹有一个“stc89c52rc.c”的文件,这个文件就是在这一步被新建添加进来的,但是此文件“stc89c52rc.c”目前跟整个工程还没有关联,还需要在接下来的第六步那里进行关联操作。
  3.       (2)上面新建添加的文件,它的文件名必须是带.c这个扩展名,表示此文件是C文件格式,这一个很重要不要搞错了。往后我们所写的C语言程序代码就是写在此C格式的文件里。此文件也俗称C源文件。
复制代码

   
----------------------------------步骤之间的分割线----------------------------------------
     


                                   图5.3.6.1  


   
                                   图5.3.6.2  



     
                                   图5.3.6.3  

       第六步:把刚才新建的.c源文件添加到工程里,跟当前工程关联起来。
       点击左边竖着的选项框里面的”Target 1”前面的“+”号,在展开的下拉菜单下看到“Source  Group 1”。右键单击“Source  Group 1”选项,在下拉菜单中选择“Add Files to Group ‘Source  Group 1’”选项,弹出一个文件选择对话框,单击选中刚才新建的.c源文件,然后单击一次“Add”按钮,此时虽然对话框没有关闭,但是已经悄悄地把.c源文件添加到工程里了(这个地方keil的用户体验设计得不够好,容易让人误解还没有把文件添加进来),这时再点击一次“Close”按钮先把此对话框关闭,然后发现左边的“Source Group 1”前面多了一个”+”号,单击此”+”号展开,发现下面的文件恰好是刚才新添加进去的.c源文件“stc89c52rc.c”。

  1.       补充说明:
  2.      (1)在刚才的操作中,我本人觉得keil软件有一个地方的用户体验做得不够好,容易引起误解。就是在弹出一个文件选择对话框时,先单击选中刚才新建的.c源文件,此时单击一次“Add”按钮,已经相当于把.c文件添加进工程了,但是此时keil软件并没有自动关闭对话框,这样很容易让初学者误以为.c源文件还没有被添加进去。
复制代码

   
   ----------------------------------步骤之间的分割线----------------------------------------
   

                                           图5.3.7  

       第七步:至此,可以正常的编辑C语言代码了。
       双击打开左边Target1里面Source Group1下刚刚被添加进工程的“stc89c52rc.c”源文件,就可以在此“stc89c52rc.c”文件下输入C语言代码了,请把以下范例代码复制进去,然后再一次点击”File”选项,在弹出的下拉菜单中选择“Save”保存。此时,新建一个工程的步骤已经完成。供复制的范例代码如下:

  1. #include "REG52.H"
  2. void delay_long(unsigned int uiDelayLong); //延时函数
  3. sbit led_dr=P3^5;  
  4. void main()  
  5. {
  6.    while(1)
  7.    {
  8.        led_dr=1;  //LED亮
  9.        delay_long(100);    //延时50000个空指令的时间
  10.        led_dr=0;  //LED灭
  11.        delay_long(100);    //延时50000个空指令的时间
  12.    }
  13. }
  14. void delay_long(unsigned int uiDelayLong) //延时函数
  15. {
  16.    unsigned int i;
  17.    unsigned int j;
  18.    for(i=0;i<uiDelayLong;i++)
  19.    {
  20.       for(j=0;j<500;j++);  //内嵌循环的空指令数量
  21.    }
  22. }
复制代码

------------------此处为分割线,上面的是代码的结束,下面的是补充说明的开始------------------

     
  1. 补充说明:
  2.      (1)可能有些朋友不是用keil2版本,如果他们是用keil4的版本,当把代码复制到keil4时,如果中文注释出现乱码怎么办?解决办法是这样的:点击keil4软件的左上角"Edit",在下拉菜单中选最后一项“Configuration”,在弹出的对话框中把Encoding的选项改成“Chinese GB2312(Simplified)”.然后删除所有C代码,重新复制一次代码进去就恢复正常了。当然,我们用keil2版本不会遇到这个问题,况且keil2版本的"Edit"下拉菜单也没有“Configuration”这个选项,所以keil2和keil4还是有一些差别的。
复制代码


【5.4   keil2如何打开一个现有的工程?】

        第一步:启动keil2软件。
        双击桌面”keil uVision2”的图标启动keil2软件。

----------------------------------步骤之间的分割线----------------------------------------

        第二步:关闭默认被打开的已有工程。
        启动keil2软件后,如果发现此软件默认打开了一个之前已经存在的工程,请先关闭此工程让keil2软件处于“空”的状态,如果没有发现此软件默认打开已有工程,这一步可以忽略跳过。关闭已有工程的操作是这样子的:点击上面”Project”选项,在弹出的下拉菜单中选择“Close Project”即可。这时keil2软件处于“空”的状态,没有打开任何工程了。

----------------------------------步骤之间的分割线----------------------------------------

      
                                      图5.4.3.1



      
                                      图5.4.3.2

       第三步:打开一个现成的工程。
       点击上面”Project”选项,在弹出的下拉菜单中选择“Open Project”,在弹出的文件对话框中,找到需要被打开工程文件夹(本例程是D盘下的“stc89c52rc”文件夹),在此文件夹目录下单击选中“stc89c52rc.Uv2”这个工程文件名,然后点击“打开”,就可以打开一个现有的工程文件了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2016-2-28 12:03:15 | 显示全部楼层
本帖最后由 吴坚鸿 于 2016-2-28 12:06 编辑

第六节:把.c源代码编译成.hex机器码的操作流程。


【6.1   详细步骤。】

      第一步:启动keil2软件。
      双击桌面”keil uVision2”的图标启动keil2软件。

----------------------------------步骤之间的分割线----------------------------------------

        第二步:关闭默认被打开的已有工程。
     启动keil2软件后,如果发现此软件默认打开了一个之前已经存在的工程,请先关闭此工程让keil2软件处于“空”的状态,如果没有发现此软件默认打开已有工程,这一步可以忽略跳过。关闭已有工程的操作是这样子的:点击上面”Project”选项,在弹出的下拉菜单中选择“Close Project”即可。这时keil2软件处于“空”的状态,没有打开任何工程了。

----------------------------------步骤之间的分割线----------------------------------------

         第三步:打开一个现成的工程。
      点击上面”Project”选项,在弹出的下拉菜单中选择“Open Project”,在弹出的文件对话框中,找到需要被打开工程文件夹(本例程是上一节在D盘下建的“stc89c52rc”文件夹),在此文件夹目录下单击选中“stc89c52rc.Uv2”这个工程文件名,然后点击“打开”,就可以打开一个现有的工程文件了。

----------------------------------步骤之间的分割线----------------------------------------

         
                                 图6.1.4.1

         
                                 图6.1.4.2

         第四步:设置编译环境让keil2软件允许产生.hex格式的机器码文件。
      鼠标右键点击选中左边选项框里面的”Target 1”选项,在右键下拉菜单中选择“  Options for Target‘Target 1’ ”选项,弹出一个编译环境设置对话框,左键单击上面子菜单切换到“Output”窗口下,把“Create Hex File”勾选上。点击“确定”。

  
  1.   补充说明:
  2.     (1)这个选项很重要,必须把“Create Hex File”选项勾上,否则后续的操作不能在工程文件夹的目录里生成.Hex的机器码文件。对于一个文件夹的工程模板,只需要设置一次就可以保存起来了,下次开电脑重新打开此工程模板时不需要再设置,这些被设置的参数都是能掉电保存起来的。

复制代码

----------------------------------步骤之间的分割线----------------------------------------


         
                                 图6.1.5.1

         第五步:启动编译。
      在确保stc89c52rc.c源文件里面有C语言源代码的情况下(如果没有,请先复制上一节的例程源代码),点击上面”Project”选项,在弹出的下拉菜单中点击“Rebuild all target files”编译命令,编译器开始编译工作。

----------------------------------步骤之间的分割线----------------------------------------

        
                                 图6.1.6.1

         第六步:在”Output Window”窗口下观察编译结果。
      可以在最下方的”Output Window”窗口下观察到编译的过程提示。”Output Window”窗口默认出现在源代码区的最下方,如果没有发现”Output Window”窗口,请把鼠标的光标移动到最下方的滑动条下边,当它呈现移动光标的形状时,按住左键往上拖动就可以看到“Output Window”窗口了。当“Output Window”窗口最后一行显示“"stc89c52rc" - 0 Error(s), 0 Warning(s).”等信息时,表示翻译工程结束了。其中0 Error(s)代表编译成功,没有任何错误。0 Warning(s)代表没有任何警告。

     
  1. 补充说明:
  2.      (1)只要有一个错误Error产生,就说明编译不通过。如果没有任何错误Error产生,但是有几个警告Warning产生,在这种情况下很多时候都不影响程序的正常运行,只有少数情况下是会影响代码的正常运行的,因此我本人建议哪怕是一个警告,大家也不要放过它,也要找到产生这个警告的原因。

复制代码
   

     
                                 图6.1.6.2
  1.   (2)查找错误的时候,只需要双击错误提示error那行内容,光标就会自动跳到源代码错误的附近,方便大家寻找语法错误。

复制代码


     ----------------------------------步骤之间的分割线----------------------------------------

     
        
                                 图6.1.7.1

        第七步:编译后生成.hex机器码文件的目录位置。
     以上编译成功后,只要打开电脑D盘的stc89c52rc文件夹,就可以找到.hex扩展名的机器码文件,这个文件就是我们要下载到单片机的机器码文件。

     

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-1 13:52:49 | 显示全部楼层
支持  期待大作

出0入0汤圆

 楼主| 发表于 2016-3-6 14:15:47 | 显示全部楼层
第七节:坚鸿51学习板的版权和品牌无偿捐赠给全社会。




       因为我热爱写单片机技术贴并以此为终身追求,所以在我退出朱兆祺的公司团队时,朱总主动把“朱兆祺51单片机学习板”的版权和品牌免费转让给了我,并且鼓励我继续坚持去分享去帮助更多初学者。我接过朱总的51学习板后,觉得此学习板还有一些地方要改进,比如用了太多的74HC595作为中间IO口扩展的芯片,硬件电路板太复杂不利于初学者入门学习,成本太高对于在校学生也是一种负担,也不利于技术的传播,为了使本教程《从单片机基础到程序框架》具有更广泛的通用性,我对原朱兆祺51学习板的原理图做了大量的修改和简化,并冠以新的名称“坚鸿51学习板”,此学习板几乎就是最简单的单片机核心电路板,几乎目前市场上所有厂家的51单片机学习板都能兼容它(只是有一些引脚定义不一样),初学者也可以根据此原理图快速自制学习板。我以硬件电路如此简单的坚鸿51学习板作为本教程的硬件平台,目的就是为了使本教程不局限于特定厂家的学习板,在别的厂家学习板上,本教程的源代码只需要更改一下引脚定义就可以跨硬件平台来学习,极大的方便初学者。
       为了使《从单片机基础到程序框架》此教程具有更广泛的通用性,我今天还做了一个重要的决定,我决定把此教程配套的“坚鸿51学习板”的版权和品牌无偿捐赠给全社会,今后任何其他学习板的公司厂家或者个人生产坚鸿51学习板我都不追究版权责任。同时,此教程电子档的版权(但是禁止用于印刷出版)也无偿给全社会免费使用,任何学习板开发板厂家都可以免费使用和传播此电子档教程,但是仅限于电子档的版权,我个人最后保留此教程的印刷出版权。
       我当前还没有生产销售坚鸿51学习板,我计划等4年后此教程的初稿写完了,也就是在2020年3月1日左右才会生产一批学习板放淘宝上,现在有需要的朋友请自己根据此原理图来焊接学习板,也可以买其它厂家类似的51学习板来学习,也欢迎更多学习板厂家去生产坚鸿51学习板,一起促进中国单片机技术的普及和推广。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-6 16:18:06 来自手机 | 显示全部楼层
收益很多,谢谢鸿哥。

出0入0汤圆

发表于 2016-3-6 17:03:10 来自手机 | 显示全部楼层
先收藏了

出0入0汤圆

发表于 2016-3-6 17:46:03 | 显示全部楼层
十年磨一剑啊,大作

出0入0汤圆

发表于 2016-3-6 22:26:26 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2016-3-6 22:40:25 | 显示全部楼层
好贴,顶起来,慢慢感觉写单片机程序也要注意架构了,效率,思路

出0入0汤圆

 楼主| 发表于 2016-3-12 18:17:57 | 显示全部楼层
本帖最后由 吴坚鸿 于 2016-3-12 18:23 编辑

第八节:把.hex机器码程序烧录到单片机的操作流程。





【8.1   烧录程序的本质。】

       “烧录”是比较专业的说法,很多初学者第一次听这词还以为跟火有关,莫名其妙的“烧录”是啥意思?烧录其实就是下载,烧录程序就是下载程序。下载好理解了吧,下载电影,下载歌曲,让播放器去播放。此处的下载程序跟下载歌曲的“下载”完全是一回事。有人会问,下载歌曲到手机,手机是成品,下载程序到单片机,单片机也是成品?新买回来的单片机不是一张白纸的电子元件吗?其实,新买回来的单片机就是一个成品,它不是白纸,它内部已经嵌入了一段系统程序,这个系统程序就像你刚买回来的手机就帮你预装了安卓系统一样,只是它的用户存储区是空白的。比如手机,你往这个存储区里存电影就可以看电影,存音乐就可以听音乐。比如单片机,你往这个存储区存不同的程序就可以让单片机做不同的事。而预装在新单片机内部的系统程序就是专门负责跟外部接口通讯,同时负责把hex格式的程序代码存放在单片机内部正确的位置,这个就是烧录程序(下载程序)的本质。这样一比喻,所以.hex格式的烧录文件跟.MP3格式的音乐文件在存储本质上是一样的。
        再回顾总结一下,烧录程序的本质是:把单片机当做一个存储器,每一条程序指令都对应一个唯一的存储地址,把这些指令以字节为单位一条条存储到指定的存储地址中,这就是烧录程序的本质。对于STC89C52RC单片机,在下载程序时需要上位机软件和一根USB转串口线。上位机软件负责把.hex格式的机器码文件打开,机器码文件里面记录着每条程序指令所对应的地址信息,下载过程时,上位机软件根据.hex文件记录的指令内容和对应的地址信息,经过USB转串口线,跟单片机的预置系统程序进行串口通讯,从而把.hex记录的信息传输到单片机内部的flash存储器中,实现了程序的烧录下载。

【8.2   烧录程序所需的工具和软件。】

      (1)装有XP或者WIN7系统的电脑一台。
       其它更高系统的我还没测试过,应该问题也不大。



     
                                  图8.2.2

      (2)带9针串口、1颗LED灯、电源拨动开关、能5V电源供电的stc89c52rc单片机核心板一块。
        单片机的学习离不开硬件平台的编程练习,本教程用的是坚鸿51学习板,此学习板的原理图在第七节已经分享到附件资料里。大家也可以根据原理图自己焊接一块学习板来学习,或者用其它厂家带有串口的单片机学习板来学习。
        串口是用来单片机跟电脑通讯的接口,是STC89C52RC单片机下载程序的通道。LED灯用来观察单片机是否正常运行程序。电源拨动开关方便烧录程序时提供所需的断电和上电的操作。本单片机系统是5V供电。


     
                                  图8.2.3

      (3)主控芯片是CH340的USB转RS232串口线一条。
       我之所以推荐主控芯片是CH340的USB转RS232串口线,因为CH340的下载线在烧录程序时很稳定可靠。这款USB转串口线可以在淘宝购买到。


     
                                  图8.2.4

     (4)5V供电的USB电源线一条。
      此USB线可以从电脑的USB口取电,也可以从输出5V的手机充电器处取电。但是我建议大家用输出5V的手机充电器来供电,因为很多电脑的USB口供电干扰比较大,会影响程序烧录。


   
                                  图8.2.5

     (5)主控芯片是CH340的USB转RS232串口线驱动安装程序。
      此驱动程序USB转RS232串口线的厂家通常都会提供,但是建议用我在附件资料里推荐给大家的驱动程序,毕竟这个程序经过我本人验证测试过。


   
                                  图8.2.6

     (6)烧录程序和串口助手功能都具备的“stc-isp-15xx-v6.85I”上位机软件。
       这是宏晶单片机官方免费提供的上位机软件,可以在宏晶单片机的官网上下载获取。这款软件有很多功能,除了有下载程序和串口助手的功能外,还可以用来配置自动生成所需的初始化代码。当然,本教程后面主要是用到此软件的下载程序和串口助手这两个功能。所以大家所选的软件版本必须是v6.85I版本或者以上的版本,因为早些年有一些版本只有烧录功能但是没有串口助手的功能。

【8.3   把.hex文件烧录到单片机的操作流程。】

       前面第6节内容已经教大家把一个驱动LED灯闪烁的C源代码编译成.hex文件的操作流程,同时在D盘的“stc89c52rc”文件夹里已经生成了一个“stc89c52rc.hex”的机器码文件,现在就要教大家如何烧录此文件到单片机内。此程序的功能是让单片机驱动一颗LED灯闪烁。



     
                     图8.3.1.1

        
                                图8.3.1.2

        
                                图8.3.1.3

       第一步:安装USB转串口驱动程序。
       上位机“stc-isp-15xx-v6.85I”烧录软件就是安装在电脑端的用户软件,电脑跟单片机进行通讯,需要一根USB转串口线,欲使USB转串口线正常工作,必须预先安装USB转串口的驱动程序。具体的操作是这样的:在本连载贴附件资料处下载“USB转串口的驱动程序CH340.zip”文件压缩包,解压后打开此文件夹,找到“SETUP.EXE”这个安装应用程序,双击启动,在弹出的界面中,单击“安装”按钮即可完成驱动程序的安装。

----------------------------------步骤之间的分割线----------------------------------------

      
                               图8.3.2.1

      
                               图8.3.2.2

      
                               图8.3.2.3

      
                               图8.3.2.4

        第二步:硬件线路连接,同时记录串口号。
        把USB转串口线插入电脑USB口,此时USB转串口线的另外一端连接51学习板的9针串口。同时,电源线一端用输出的5V手机充电器USB端口供电,电源线另一端连接51学习板的USB供电端口,此时可以通过51学习板的电源拨动开关来控制断电和上电。然后是查找串口号,方法是:以电脑WIN7系统为例,右击桌面“计算机”,单击选择下拉菜单的“管理”选项,在弹出的窗口中,点击“设备管理器”选项切换到对应的设置窗口,双击“端口(COM和LPT)”选项,在展开的下拉选项中,会看到“USB-SERTAL CH340(COM3)”,这个COM3就是我们要记住的串口号,记住此串口号,后面的步骤要用到。你们的串口号不一定是COM3,请以你们电脑显示的串口号为准。

----------------------------------步骤之间的分割线----------------------------------------


      
                                 图8.3.3

       第三步:打开上位机用户软件“stc-isp-15xx-v6.85I.exe”。
       这个软件可以在宏晶单片机的官网下载获取,获取到的软件压缩包只需解压后就可以使用,不用安装,
直接双击打开“stc-isp-15xx-v6.85I.exe”,此时会弹出“温馨提示”的窗口,我们按“确定”就可以进入到真正的工作界面了。

----------------------------------步骤之间的分割线----------------------------------------


      
                                  图8.3.4

       第四步:选择单片机型号。
       在“单片机型号”的下拉菜单中选择“STC89C/LE52RC”这个型号。如果中途弹出推荐选用其它型号的窗口,可以忽略它,我们用来学习只要认准“STC89C/LE52RC”这个型号就可以了。

----------------------------------步骤之间的分割线----------------------------------------

       第五步:设置串口号。
       点击“串口号”右侧的选项,在“串口号”的下拉菜单中,选择跟前面第二步所记录一样的串口号COM3(你们的串口号不一定是COM3,请根据你们的电脑实际显示情况来选择)。


----------------------------------步骤之间的分割线----------------------------------------

        第六步:设置最低波特率和最高波特率。
       “最低波特率”设置为2400,,“最高波特率”设置为9600。波特率如果设置太高,可能会导致烧录(下载)不成功。

----------------------------------步骤之间的分割线----------------------------------------

        第七步:导入.hex格式的机器码文件。
        点击“打开程序文件”的按钮,在弹出的对话框中,选择D盘下“stc89c52rc”文件夹目录下的“stc89c52rc.hex”,双击把“stc89c52rc.hex”导入到上位机用户软件。


----------------------------------步骤之间的分割线----------------------------------------

        
                                   图8.3.8            

        第八步:启动下载。
        点击“下载/编程”的按钮,发现“正在检测目标单片机..”的提示信息,此时需要通过电源波动开关把51学习板重新断电然后再上电才能正常下载,很多人也把这个重新上电的过程称为“冷启动”。之所以要重新断电再上电,是因为单片机内部预置的系统程序只在上电短暂的瞬间才会检查一下是否接收到需要重新烧录程序的指令,如果没有接收到烧录指令,单片机整个话语权就由原来的系统程序转交给我们的用户程序来接管,所以此串口后面的时间就给我们用户程序来使用。因此每次烧录程序时,先启动上位机的下载命令,此时上位机不断发送请求下载的命令给单片机,但是此时单片机并不理会这些指令,因为此时单片机的话语权已经交给了我们的用户程序,此时并不是预置系统程序在掌控,所以除非重新断电然后再上电那一瞬间才会让系统内置程序去检测并且响应此下载命令。另外多说一句,其实不是所有厂家的单片机在烧录程序时都需要“冷启动”,也不是所有单片机都支持串口烧录,各厂家的单片机烧录程序方式会有一些差异,但基本原理是一样的,大同小异。


----------------------------------步骤之间的分割线----------------------------------------

        
                                   图8.3.9

        第九步:“冷启动”后观察是否操作成功的信息。
        执行完前面第九步的“冷启动”后,如果发现有“...操作成功!”的提示信息,就说明程序下载成功了。此时会发现51学习板上面的一颗LED灯不断闪烁,是因为我们的LED灯程序驱动它才开始闪烁的,说明我们的程序在单片机上正常工作了。

       补充说明:
      (1)以后只要每次重新编译了C源代码后,都会生成最新版本的.hex格式文件,所以每次烧录程序时,必须重新返回第七步,重新执行一次导入最新版本.hex格式文件的操作,确保被烧录的程序是最新版本的.hex烧录文件。


【8.4   51学习板下载程序失败时的解决办法。】

      (1)可以先松一下单片机卡座,稍微挪动一下单片机,然后再卡紧单片机。卡座必须卡紧单片机,避免接触不良。
      (2)改变供电电源,很多电脑的USB口供电电源干扰非常大,严重影响下载程序,请把USB电源线插入到手机充电器5V的USB接口,效果显著,明显提高了下载的成功率。
      (3)检查确保所选择的单片机型号是STC89C/LE52RC,如果软件弹出推荐其它型号的单片机窗口,不用管它,我们就选STC89C/LE52RC。
      (4)检查STC-ISP烧写软件是否选择匹配的COM口。
      (5)单片机是靠串口烧录程序进去的,单片机的串口是P3.0,P3.1两根线经过232转换芯片,然后才与USB转串口线连接的。因此,在烧录程序时,请确保P3.0,P3.1两个IO口不能跳线连接到其它外围元器件上。
      (6)点击“下载/编程”后,记得再断电并且重新上电一次。看看是否烧录成功。
      (7)确保最低波特率一直设置为2400,最高波特率为9600。如果还不行再把最高波特率也改成2400试试。
      (8)如果还不行,就退出软件,拔掉USB转串口线,同时断电(必须把整根电源线拔出!),重新插入USB串口线,重新插入电源线开电,重新打开软件。
      (9)如果还不行,学习板先断电(必须把整根电源线拔出!),然后重启一次电脑。
      (10)总之:如果还不行,就按上述步骤多折腾几次。
      (11)最后实在不行,就尝试更换到其它USB口,或者尝试更换到其它电脑上试试。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-15 15:57:54 | 显示全部楼层
收藏=。=

出0入0汤圆

发表于 2016-3-15 17:09:33 | 显示全部楼层
偶尔看到,必成精品。

出0入0汤圆

 楼主| 发表于 2016-3-17 07:32:41 | 显示全部楼层
第九节:我对网友的一封检讨书并致以我真诚的道歉。


      昨晚一夜未眠,因为看到有一些热心网友在批评我,而且他们不是无中生有,他们说的很多都是事实。他们批评的也正是我内心深处最不愿意直视的痛点。但是经过一整夜的反思后,我觉得出来混迟早要还的,躲是躲不过的,只有坦然面对自己过去的不足,才能更好的活在当下和展望未来,所以我决心本着坦白从宽和争取大家尽量原谅的心态,主动交待一下我过去存在的五个问题,并且就这五个问题真诚的向大家道歉。
   (1)狂妄自大,目中无人。我曾自称“大师”,“深圳同龄人中最牛的单片机工程师”,“四大天王之一”等等。现在想起来我当年太无知太幼稚了,太不尊重广大热心网友的感受,我为我当初的言论向大家道歉。
   (2)爱出名爱炒作太高调。我曾经有一段时间在网上写的所有文章都自带“只要记得这篇文章的原创是吴坚鸿”等文字,想炒作之心路人皆知,正如一些热心网友批评我那样,技术圈不是娱乐圈,想靠炒作出名是行不通的,搞技术必须老老实实搞技术,不能浮躁。我现在接受大家这些批评,我也认识到自己过去的错误,向大家道歉。
   (3)我过去很多文章的观点太片面太偏激。以后我决心不再写这类文章,我向大家道歉。
   (4)伪善。我表面上看似很无私分享那么多技术经验,其实我一直都有私心,就是爱出名,这点我以后要改,尽量低调谦虚。虽然做不到完全的无私,但是尽量让更多初学者受益。
   (5)我的技术水平还不够好,还停留在初级阶段,我现在觉得我写的很多东西确实在很多有经验的工程师眼里不值得一提,所以希望广大网友看我的技术帖不要太过迷信我,要有自己的独立判断然后再吸收对自己有价值的技术。说起这点我确实惭愧,我以前以为自己的技术很完美很无懈可击,但是最近这几年来发表了几个技术连载帖后,经过很多热心网友的提醒和点拨,才暴露了我许多的不足,也因此让我涨进了不少知识和技术。比如我是出来工作六年后才懂多文件编程,才懂static关键字的用途,才知Tab快捷键的用法,这些都得益于广大热心网友,我要感恩。正因为认识到我之前写的很多技术帖还有很多改进的空间,所以我才一直没有急着出书,所以今年我才决定重开新帖重写一遍。
    我挺后悔过去在网上发表过的一些欠考虑的言论,现在看到我都会觉得无地自容,但是一旦在互联网上发帖就像泼出去的水难以收回,我虽然曾主动删过自己某些帖,但是觉得删不完,因为有很多帖被转载了,所以我干脆不删帖了,也算留点证据让网友认识我过去不好的一面。即使今后很多网友继续批评我,我也坦然接受大家的批评,然后积极改正自己的错误。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-17 09:26:34 | 显示全部楼层
做事先做人!难得看到一个淡定的人,做人切忌浮躁。支持!

出0入0汤圆

发表于 2016-3-17 16:06:06 | 显示全部楼层
anyway,支持你继续坚持!加油

出0入0汤圆

 楼主| 发表于 2016-3-19 11:20:50 | 显示全部楼层
第十节:程序从哪里开始,要到哪里去?


       程序从哪里开始,要到哪里去?为了让初学者了解C语言程序的执行顺序,我把程序分成三个区域:进入主程序前的区域,主程序的初始化区域,主程序的循环区域。当然,这里三个区的分类暂时没有把中断程序的情况考虑进去,中断程序的内容我会在后面相关的章节中再详细介绍,这里暂时不考虑中断。
       进入主程序前的区域。这是上电后,在单片机执行主程序代码之前就已经完成了的工作。包括头文件的包含,宏定义,内存分配这些工作。这部分的内容可以暂时不用去了解,我会在后面的一些章节中陆续深入讲解。
       主程序的初始化区域。这是上电后,单片机进入主程序后马上就要执行的程序代码,这部分区域的代码有一个特点,大家也必须记住的,就是单片机只执行一次。只要单片机不重启,不复位,那么上电后这部分的代码只被执行一次。
       主程序的循环区域。单片机在主程序中执行完了初始化区域的代码,紧接着就进入这片循环区域的代码。单片机一直在逐行循环执行这些代码,执行到末尾时又返回到循环区域的开始处继续开始新一轮的执行,周而复始,往复循环,这就是上电后单片机的最终归宿,一直处在循环的状态。
       下面我跟大家分析一个程序源代码的三个区域和执行顺序,大家先看中文解释部分的内容,暂时不用理解每行指令的语法,有个整体的认识就可以了。此源代码实现的功能是:上电后,蜂鸣器鸣叫一声就停止(初始化区域),然后看到一个LED灯一直在不停的闪烁(循环区域)。


                                         图10.1


源代码如下:

  1. #include "REG52.H"             //进入主程序前的区域:头文件包含

  2. sbit beep_dr=P3^4;            //进入主程序前的区域:宏定义
  3. sbit led_dr=P1^6;               //进入主程序前的区域:宏定义

  4. unsigned long i;                  //进入主程序前的区域:内存分配

  5. void main()                          //主程序入口,即将进入初始化区域
  6. {
  7.    beep_dr=0;                     //第一步:初始化区域:蜂鸣器开始鸣叫。
  8.    for(i=0;i<6250;i++);       //第二步:初始化区域:延时0.5秒左右。也就是蜂鸣器鸣叫的持续时间。
  9.    beep_dr=1;                     //第三步:初始化区域:蜂鸣器停止鸣叫。
  10.    while(1)                           //执行完上面的初始化区域,即将进入循环区域
  11.    {
  12.        led_dr=0;                    //第四步:循环区域:LED开始点亮。
  13.        for(i=0;i<6250;i++);   //第五步:循环区域:延时0.5秒左右。也就是LED点亮的持续时间。
  14.        led_dr=1;                    //第六步:循环区域:LED开始熄灭。
  15.        for(i=0;i<6250;i++);   //第七步:循环区域:延时0.5秒左右。也就是LED熄灭的持续时间。
  16.    }                                      //执行完上面第七步后,单片机又马上返回到上面第四步继续往下执行。
  17. }
复制代码

      上述代码执行顺序分析:
      单片机进入主程序后,从第一步到第三步是属于初始化区域,只被执行一次。然后进入循环区域,从第四步执行到第七步,执行完第七步之后,马上又返回上面第四步继续循环往下执行,单片机一直处于第四步到第七步的往复循环中。可以很清晰的看到,上面的main和while(1)关键词就是三个区域的边界分割线。   
      经过以上的分析,可以看出这三个区域的大概分布如下:

  1. //...进入主程序前的区域
  2. void main()               
  3. {
  4.    //...初始化区域
  5.    while(1)                     
  6.    {
  7.        //...循环区域
  8.    }
  9. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-20 23:45:21 来自手机 | 显示全部楼层
程序框架对我帮助很大谢谢鸿哥。

出0入0汤圆

发表于 2016-3-21 01:01:25 来自手机 | 显示全部楼层
确实适合从0开始的新手

出0入0汤圆

发表于 2016-3-25 22:05:42 | 显示全部楼层
支持一下,吴坚鸿的之前的文章看过,说实在的适合初学者,若跟产品的代码比或者跟公司的代码比,还是有差距的。

出0入0汤圆

发表于 2016-3-25 22:20:33 | 显示全部楼层
mark收集整理一下

出0入76汤圆

发表于 2016-3-25 22:43:50 | 显示全部楼层
很基础很朴实,感觉不错, 支持

出0入0汤圆

 楼主| 发表于 2016-3-27 23:41:31 | 显示全部楼层
本帖最后由 吴坚鸿 于 2016-3-28 09:58 编辑

第十一节:一个在单片机上练习C语言的模板程序。




【11.1   一套完整的模板源代码。】

       先给大家附上一套完整的模板源代码,后面章节练习C语言的模板程序就直接复制此完整的源代码,此源代码适合的单片机型号是STC89C52RC,晶振是11.0592MHz,串口波特率是9600,初学者只需修改代码里从“C语言学习区域的开始”到“C语言学习区域的结束”的区域,其它部分不要更改。可复制的源代码请到网上论坛原贴处复制或者下载,搜索本教程名字就可以找到原贴出处。一套完整的模板源代码如下:

  1. #include "REG52.H"
  2. void View(unsigned long u32ViewData);
  3. void to_BufferData(unsigned long u32Data,unsigned char *pu8Buffer,unsigned char u8Type);
  4. void SendString(unsigned char *pu8String);   

  5. /*---C语言学习区域的开始。-----------------------------------------------*/

  6. void main() //主函数
  7. {
  8.    unsigned char a; //定义一个变量a。
  9.    unsigned int  b; //定义一个变量b。
  10.    unsigned long c; //定义一个变量c。
  11.    a=100;          //给变量a赋值。
  12.    b=10000;        //给变量b赋值。
  13.    c=1000000000;   //给变量c赋值。
  14.    View(a);   //在电脑串口端查看第1个数a。
  15.    View(b);   //在电脑串口端查看第2个数b。
  16.    View(c);   //在电脑串口端查看第3个数c。
  17.    while(1)  
  18.    {
  19.    }
  20. }

  21. /*---C语言学习区域的结束。-----------------------------------------------*/

  22. void View(unsigned long u32ViewData)
  23. {
  24.     static unsigned char Su8ViewBuffer[43];
  25.             code unsigned char Cu8_0D_0A[]={0x0d,0x0a,0x00};
  26.            code unsigned char Cu8Start[]={"开始..."};
  27.     static unsigned char Su8FirstFlag=0;
  28.     static unsigned int Su16FirstDelay;
  29.     if(0==Su8FirstFlag)
  30.             {
  31.            Su8FirstFlag=1;
  32.            for(Su16FirstDelay=0;Su16FirstDelay<10000;Su16FirstDelay++);
  33.            SendString(Cu8Start);  
  34.            SendString(Cu8_0D_0A);  
  35.            SendString(Cu8_0D_0A);  
  36.    }
  37.     to_BufferData(u32ViewData,Su8ViewBuffer,1);
  38.           SendString(Su8ViewBuffer);  
  39.     to_BufferData(u32ViewData,Su8ViewBuffer,2);
  40.          SendString(Su8ViewBuffer);  
  41.     to_BufferData(u32ViewData,Su8ViewBuffer,3);
  42.          SendString(Su8ViewBuffer);  
  43.     to_BufferData(u32ViewData,Su8ViewBuffer,4);
  44.             SendString(Su8ViewBuffer);  
  45.            SendString(Cu8_0D_0A);  
  46. }
  47. void to_BufferData(unsigned long u32Data,unsigned char *pu8Buffer,unsigned char u8Type)
  48. {
  49.          code unsigned char Cu8Array1[]="第N个数";
  50.          code unsigned char Cu8Array2[]="十进制:";
  51.             code unsigned char Cu8Array3[]="十六进制:";
  52.          code unsigned char Cu8Array4[]="二进制:";
  53.     static unsigned char Su8SerialNumber=1;
  54.     static unsigned int  Su16BufferCnt;
  55.     static unsigned int  Su16TempCnt;
  56.     static unsigned int  Su16TempSet;
  57.     static unsigned long Su32Temp1;
  58.     static unsigned long Su32Temp2;
  59.     static unsigned long Su32Temp3;
  60.     static unsigned char Su8ViewFlag;
  61.     if(1==u8Type)
  62.           {
  63.         for(Su16BufferCnt=0;Su16BufferCnt<7;Su16BufferCnt++)
  64.                 {
  65.                    pu8Buffer[Su16BufferCnt]=Cu8Array1[Su16BufferCnt];
  66.               }
  67.                 pu8Buffer[2]=Su8SerialNumber+'0';
  68.                pu8Buffer[Su16BufferCnt]=0x0d;
  69.                pu8Buffer[Su16BufferCnt+1]=0x0a;
  70.                 pu8Buffer[Su16BufferCnt+2]=0;
  71.              Su8SerialNumber++;
  72.                 return;
  73.            }
  74.     else if(2==u8Type)
  75.             {
  76.                 for(Su16BufferCnt=0;Su16BufferCnt<7;Su16BufferCnt++)
  77.                 {
  78.                        pu8Buffer[Su16BufferCnt]=Cu8Array2[Su16BufferCnt];
  79.                 }
  80.                Su32Temp1=1000000000;
  81.                    Su32Temp2=10;
  82.                    Su16TempSet=10;
  83.           }
  84.     else if(3==u8Type)
  85.          {
  86.                 for(Su16BufferCnt=0;Su16BufferCnt<9;Su16BufferCnt++)
  87.                 {
  88.                        pu8Buffer[Su16BufferCnt]=Cu8Array3[Su16BufferCnt];
  89.                 }
  90.                 Su32Temp1=0x10000000;
  91.                     Su32Temp2=0x00000010;
  92.                     Su16TempSet=8;        
  93.     }
  94.     else
  95.     {
  96.                 for(Su16BufferCnt=0;Su16BufferCnt<7;Su16BufferCnt++)
  97.                 {
  98.                        pu8Buffer[Su16BufferCnt]=Cu8Array4[Su16BufferCnt];
  99.                 }
  100.                 Su32Temp1=0x80000000;
  101.                     Su32Temp2=0x00000002;
  102.                     Su16TempSet=32;        
  103.            }
  104.     Su8ViewFlag=0;
  105.     for(Su16TempCnt=0;Su16TempCnt<Su16TempSet;Su16TempCnt++)
  106.     {
  107.        Su32Temp3=u32Data/Su32Temp1%Su32Temp2;
  108.                if(Su32Temp3<10)
  109.                {
  110.                  pu8Buffer[Su16BufferCnt]=Su32Temp3+'0';
  111.                }
  112.                else
  113.                {
  114.                  pu8Buffer[Su16BufferCnt]=Su32Temp3-10+'A';
  115.                }
  116.                if(0==u32Data)
  117.                {
  118.                        Su16BufferCnt++;
  119.                        break;
  120.                }
  121.                else if(0==Su8ViewFlag)
  122.                {
  123.                    if('0'!=pu8Buffer[Su16BufferCnt])
  124.                 {
  125.                Su8ViewFlag=1;
  126.                                Su16BufferCnt++;
  127.            }
  128.                }
  129.                else
  130.                {
  131.                    Su16BufferCnt++;
  132.                }

  133.        Su32Temp1=Su32Temp1/Su32Temp2;
  134.     }
  135.     pu8Buffer[Su16BufferCnt]=0x0d;
  136.     pu8Buffer[Su16BufferCnt+1]=0x0a;
  137.     pu8Buffer[Su16BufferCnt+2]=0;
  138. }
  139. void SendString(unsigned char *pu8String)   
  140. {
  141.   static unsigned int Su16SendCnt;
  142.   static unsigned int Su16Delay;
  143.   SCON=0x50;
  144.   TMOD=0X21;
  145.   TH1=TL1=256-(11059200L/12/32/9600);  
  146.   TR1=1;
  147.   ES = 0;
  148.   TI = 0;
  149.   for(Su16SendCnt=0;Su16SendCnt<43;Su16SendCnt++)
  150.   {
  151.      if(0==pu8String[Su16SendCnt])
  152.              {
  153.                  break;
  154.              }
  155.              else
  156.              {
  157.         SBUF =pu8String[Su16SendCnt];
  158.         for(Su16Delay=0;Su16Delay<800;Su16Delay++);
  159.                    TI = 0;
  160.              }
  161.   }
  162. }

复制代码

【11.2   模板程序的使用说明。】

   
                                 图11.2.1

       大多数初学者在学习C语言的时候,往往是在电脑端安装上VC平台软件来练习C语言,这种方法只要在代码里调用printf语句,编译后就可以看到被printf语句调用的变量,挺方便的。本教程没有用这种方法,既然本教程的C语言主要针对单片机,所以我想出了另外一种方法,这种方法就是直接在单片机上练习C语言,这样会让初学者体验更深刻。这种方法对硬件平台要求不高,只要51学习板上有一个9针的串口就可以,这个串口既可以用来烧录程序,也可以用来观察代码里的某个变量,只要在代码里调用View函数就可以达到类似VC平台软件下printf语句的效果,View函数可以向串口输出某个变量的十进制,十六进制和二进制,大家只要在电脑端的串口助手软件就可以看到某个变量的这些信息,View函数能查看的变量最大数值范围是4个字节的unsigned long变量,十进制的范围是从0到4294967295,也可以查看unsigned int 和unsigned char的类型变量(数据的进制以及long,int,char等知识点大家目前还没接触到,因此不懂也没关系,当前只要有个大概的认识就可以,暂时不用深入理解,后面章节还会详细介绍)。View函数是我整个模板程序的其中一部分,所以要用这种方法就必须先复制我整个模板程序,初学者练习代码的活动范围仅仅局限于模板程序里的“C语言学习区域”,在此区域里有一个main主函数,main主函数内有一个初始化区域,初学者往往在这个初始化区域里练习C语言就够了,初学者最大的活动范围不能超过从“C语言学习区域的开始”到“C语言学习区域的结束”这个范围,这个范围之外其它部分的代码主要用来实现数据处理和串口发送的功能,大家暂时不用读懂它,直接复制过来就可以了。比如:

  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.    //...初始化区域,也就是主要用来给初学者学习C语言的区域。
  5.    while(1)  
  6.    {

  7.    }

  8. }

  9. /*---C语言学习区域的结束。-----------------------------------------------*/

复制代码


       上述例子中,初学者练习代码只能在从“C语言学习区域的开始”到“C语言学习区域的结束”这个范围,此范围外的代码直接复制过来不要更改。我们再来分析分析下面节选的main函数源代码:

  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.    unsigned char a; //定义一个变量a。
  5.    unsigned int  b; //定义一个变量b。
  6.    unsigned long c; //定义一个变量c。
  7.    a=100;          //给变量a赋值。
  8.    b=10000;        //给变量b赋值。
  9.    c=1000000000;   //给变量c赋值。
  10.    View(a);   //在电脑串口端查看第1个数a。
  11.    View(b);   //在电脑串口端查看第2个数b。
  12.    View(c);   //在电脑串口端查看第3个数c。
  13.    while(1)  
  14.    {
  15.    }
  16. }

  17. /*---C语言学习区域的结束。-----------------------------------------------*/

复制代码


      上述节选的main函数代码里,比如“a=100;          //给变量a赋值。”这行代码,所谓的“赋值”就是“=”这个语句,它表面上像我们平时用的等于号,实际上不是等于号,而是代表“给”的意思,把“=”符号右边的数复制一份给左边的变量,比如“a=100;”就是代表把100这个数值复制一份给变量a,执行这条指令后,a就等于100了。这里的分号“;”代表一条程序指令的结束。 而双斜线“//”是注释语句,双斜线“//”这行后面的文字或字符都是用来注释用的,编译器会忽略双斜线“//”这一行后面的文字或字符,编译器不把注释文字或字符列入源代码,也就是“//”这一行中后面的文字或字符是不占单片机内存的。当然“//”仅仅局限于当前一行代码。上面除了“//”是注释语句外,上面的“/*”和“*/”之间也是注释语句,跟”//”的作用一样,只不过“/*”是注释开始,“*/”是注释结束,它们的范围不局限于一行,而是从“/*”到“*/”的范围,因此可以用于注释连着的多行文字或者字符。
      接着在分析上述代码中最重要的函数,也是本节最核心最重要的函数View(某个变量)。比如“ View(a); ”这行代码,View(a)就是要把变量a的十进制,十六进制和二进制的数值都发送到串口,我们通过USB转串口线让学习板连接上电脑,在电脑串口助手软件上就能看到被View函数调用的变量a的信息。

【11.3   如何在电脑上使用串口助手软件查看被View函数调用的变量?】

      前面章节在讲烧录程序时提到一个叫“stc-isp-15xx-v6.85I”的上位机软件,这个软件除了用来烧录程序,还集成了串口助手软件的功能。所以本节直接共用烧录程序时的USB转串口线和“stc-isp-15xx-v6.85I”软件就可以了,无需额外再购买新的USB转串口线和下载其它串口助手软件,但是如何设置这个“stc-isp-15xx-v6.85I”上位机软件,还是有一些需要特别注意的地方的,现在把这个详细的步骤介绍给大家。

      第一步:设置烧录软件的选项。
      按前面章节介绍烧录程序时所需的步骤,用USB转串口线连接51学习板和电脑,记录COM号,打开“stc-isp-15xx-v6.85I”软件,选择单片机型号,选择对应的串口号(COM号),设置最低波特率和最高波特率,这部分的内容跟烧录程序时的配置步骤是一样的,唯一必须要特别注意的是最高波特率必须选择9600!最低波特率建议选择2400。否则在烧录完程序后,当上位机集成软件自动切换到串口助手软件窗口时,接收区域显示的一些汉字信息可能会出现乱码。

----------------------------------步骤之间的分割线----------------------------------------

      
                                 图11.3.2

      第二步:设置串口助手软件的选项。
      先点击右上方选中“串口助手”选项切换到串口助手的窗口,接收缓冲区选择“文本模式”,串口选择匹配的COM号(跟烧录软件一致的COM号),波特率必须选择9600,勾选上“编程完成后自动打开串口”选项,最后点击“打开串口”按钮使之切换到显示“关闭串口”的文字状态,至此串口助手软件的设置完毕。接下来就是按烧录程序的流程,打开新的HEX程序文件,程序烧录完成后上位机软件会自动切换到串口助手的串口,就可以观察到View函数从单片机上发送过来的某个变量的十进制,十六进制,二进制的信息了。接收缓冲区的窗口比较小,如果收到的信息比较多,只要在上下方向拖动窗口右边的滑块就可以依次看到全部的信息。如果想让单片机重新发送数据,只要让51学习板断电重启就可以重发一次数据,当串口助手的接收区接收的信息太多影响观察时,大家可以点击“清空接收区”的按钮来清屏,然后断电重启让它再重发一次数据。在电脑的串口助手软件里观察到的数据格式大概是什么样子的呢?比如编译完本章节上述完整的模板源代码程序后,会在串口助手软件里看到a,b,c三个变量的信息如下:



  1. 开始...

  2. 第1个数
  3. 十进制:100
  4. 十六进制:64
  5. 二进制:1100100

  6. 第2个数
  7. 十进制:10000
  8. 十六进制:2710
  9. 二进制:10011100010000

  10. 第3个数
  11. 十进制:1000000000
  12. 十六进制:3B9ACA00
  13. 二进制:111011100110101100101000000000

复制代码
     
         多说一句,烧录程序后,当软件自动切换到串口助手软件选项的窗口时,串口助手窗口显示单片机返回的信息,这时有可能第一行的文字“开始...”会丢失或者显示不出来,但是后面其它的关键信息不受影响,我猜测可能是串口助手软件本身的某个环节存在的小bug,跟我们没关系,我们不用深究原因,因为不会影响我们的使用。此时如果让单片机断电重启就可以看到第一行的文字“开始...”。

【11.4   如何利用现有的工程编辑编译新的源代码?】

      本教程后面有很多章节的源代码,是不是每个章节都要重新建一个工程?其实不用。我们只要用一个工程就可以编译编辑本教程所有章节的源代码。方法很简单,就是打开一个现有的工程,用快捷组合键“Ctrl+A”把原工程里面的C源代码全部选中,再按“Backspace”清空原来的代码,然后再复制本教程相关章节的代码粘贴到工程的C文档里,重新编译一次就可以得到对应的Hex格式的烧录文件。用这种方法的时候,建议大家做好每个程序代码的备份。每完成一个项目的小进度,都要及时把源代码存储到电脑硬盘里,电脑硬盘里每个项目对应一个项目文件夹,每个项目文件夹里包含很多不同版本编号的源代码文件,每个源代码文件名都有流水编号,方便识别最新版本的程序,每天下班前都要把最新版本的源代码文件上传到自己的网盘里备份,在互联网时代,把源代码存到自己的网盘,可以随时异地存取,即使遇到电脑故障损坏也不担心数据永久丢失。

【11.5   编辑源代码的5个常用快捷键。】

      介绍一下常用的快捷键,好好利用这5个快捷键,会让你在编辑源代码时效率明显提高。
(1)选中整篇所有的内容:组合键Ctrl+A。
(2)把选中的内容复制到临时剪贴板:组合键Ctrl+C。
(3)把临时剪贴板的内容粘贴到光标开始处:组合键Ctrl+V。
(4)把选中的一行或者几行内容整体往右边移动:单键Tab。每按一次就移动几个空格,很实用。
(5)把选中的一行或者几行内容整体往左边移动:组合键Shift+Tab。每按一次就移动几个空格,很实用。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-3-28 01:02:24 | 显示全部楼层
确实是很基础很基础的内容,LZ的精神值得鼓励

出0入0汤圆

发表于 2016-3-28 12:39:37 | 显示全部楼层
楼主以前写的帖子就拜读,很不错。现在继续关注中。感谢楼主的奉献!

出0入0汤圆

发表于 2016-3-28 18:57:48 | 显示全部楼层
吴坚鸿 发表于 2016-1-18 11:49
第一节:我是中国最幸福的单片机工程师。

楼主的心性是我最为敬佩的!加油!

出0入0汤圆

 楼主| 发表于 2016-4-3 10:49:12 | 显示全部楼层
本帖最后由 吴坚鸿 于 2016-4-4 00:21 编辑

第十二节:变量的定义和赋值,本作品的印刷出版权也无偿捐给全社会。


【12.0   本作品的印刷出版权也无偿捐给全社会。】

      之前我在第七节里曾说过,要把51学习板的版权捐赠给全社会,但是那时我说要保留印刷出版权,今天我干脆决定把本作品本稿件的印刷出版权也无偿捐给全社会,把它变成公共资源,我不保留我的个人版权,任何出版社都可以不经过我的同意直接印刷出版此书,不用给我版税。版权捐赠给全社会的声明如下:
      我决定把本作品本稿件的版权无偿捐给全社会,把它变成公共资源,我不保留我的个人版权,任何出版社都可以不经过我的同意直接印刷出版此书,不用给我版税。本书本连载教程的pdf电子档稿件也无偿捐给全社会,我不保留我个人版权。此书配套的51学习板版权也直接无偿捐给全社会,任何学习板厂家或者个人都可以不经过我的同意直接生产和销售此51学习板,我不追究版权责任。我希望在我有生之年尽我个人的努力为社会为行业为初学者做点小贡献就知足了。
      因为本论坛在发帖24小时之后不能再编辑修改内容,所以不得不借此篇幅声明一下我的新决定。

【12.1   学习C语言的建议和方法。】

       先提一些学C语言的建议和方法,帮大家删繁就简,去掉一些初学者常见的思想包袱。现阶段我们的学习是使用单片机,把单片机当做一个成品,把单片机当做一个忠诚的士兵,学习C语言就是学习如何使用单片机,如何命令单片机,如何让单片机听懂我们的话并且听我们指挥。单片机内部太细节的构造原理暂时不用过多去关注,只要知道跟我们使用相关的几个特征就可以,这样初学者的学习包袱就没有那么重,就可以把重点放在使用上的,而不是好奇于根本原理的死磕到底。学C语言跟学习英语的性质是一样的,都是在学习一门外语,只是C语言比英语的语法要简单很多,非常容易上手,词汇量也没有英语那么多,C语言常用单词才几十个而已。学习任何一门语言的秘诀在于练习,学习C语言的秘诀是多在单片机上练习编程。本教程后面几乎每个章节都有例程,这个例程很重要,初学者即使看懂了,我也强烈建议要把“C语言学习区域”的那部分代码亲自上机敲键盘练习一遍,并且看看实验现象是否如你所愿。

【12.2   变量定义和赋值的感性认识。】

       这些年我用过很多单片机,比如51,PIC,LPC17系列,STM8,STM32等单片机。尽管各类单片机有一些差异,但是在选单片机时有3个参数我们一定会关注的,它们分别是:工作频率,数据存储器RAM,程序存储器ROM。工作频率跟晶振和倍频有关,决定了每条指令所要损耗的时间,从而决定了运算速度。RAM跟代码里所定义变量的数量有关。ROM跟程序代码量的大小有关。程序是什么?程序就是由对象和行为两者构成的。对象就是变量,就是变量的定义,就是RAM,RAM的大小决定了一个程序允许的对象数量。行为就是赋值,判断,跳转,运算等语法,就是ROM,ROM的大小决定了一个程序允许的行为程度。本节的标题是“变量的定义和赋值”,其中“定义”就是对象,“赋值”就是行为。

【12.3   变量的定义。】

       变量的定义。一个程序最大允许有多少个对象,是由RAM的字节数决定的(字节是一种单位,后面章节会讲到)。本教程的编译环境是以AT89C52芯片为准,AT89C52这个单片机有256个字节的RAM,但是并不意味着程序就一定要全部占用这些RAM。程序需要占用多少RAM,完全是根据程序的实际情况来决定,需要多少就申请多少。这里的“对象”就是变量,这里的“申请”就是变量的定义。
       定义变量的关键字。常用有3种容量的变量,每种变量的取值范围不一样。第一种是”unsigned char”变量,取值范围从0到255,占用RAM一个字节,比喻成一房一厅。第二种是”unsigned int”变量,取值范围从0到65535,占用RAM两个字节,比喻成两房一厅。第三种是“unsigned long”变量,取值范围从0到4294967295,占用RAM四个字节,比喻成四房一厅。unsigned char,unsigned int和unsigned long都是定义变量的关键字,所谓关键字也可以看成是某门外语的单词,需要大家记忆的,当然不用死记硬背,只要多上机练习就自然熟记于心,出口成章。多说一句,上述的变量范围是针对本教程所用的单片机,当针对不同的单片机时上述变量的范围可能会有一些小差异,比如在stm32单片机中,unsigned int的字节数就不是两个字节,而是四个字节,这些都是由所选的编译器决定的,大家暂时有个初步了解就可以。
       定义变量的语法格式。定义变量的语法格式由3部分组成:关键字,变量名,分号。比如:
  1.        unsigned char a;
复制代码

       其中unsigned char就是关键字,a就是变量名,分号”;”就是一条语句的结束符号。
       变量名的命名规则。变量名的第一个字符不能是数字,必须是字母或者下划线,字母或者下划线后面可以带数字,一个变量名之间的字符不能带空格,两个独立变量名之间也不能用空格隔开(但是两个独立变量名之间可以用逗号隔开)。变量名不能跟编译器已征用的关键字重名,不能跟函数名重名,这个现象跟古代要求臣民避讳皇帝的名字有点像。哪些名字是合法的,哪些名字是不合法的?现在举一些例子说明:
  1.         unsigned char 3a; //不合法,第一个字符不能是数字。
  2.         unsigned char char; //不合法,char是编译器已征用的关键字。
  3.         unsigned char a b; //不合法,ab是一个变量名,a与b的中间不能有空格。
  4.         unsigned char a,b; //合法,a和b分别是一个独立的变量名,a与b的中间可以用逗号隔开。
  5.         unsigned char a; //合法。
  6.         unsigned char abc; //合法。
  7.         unsigned char _ab; //合法。
  8.         unsigned char _3ab; //合法。
  9.         unsigned char a123; //合法。
  10.         unsigned char a12ced; //合法。
复制代码

        定义变量与RAM的内在关系。当我们定义一个变量时,相当于向单片机申请了一个RAM空间。C编译器会自动为这个变量名分配一个RAM空间,每个字节的RAM空间都有一个固定唯一的地址。把每个字节的RAM空间比喻成房间,这个地址就是房号。地址是纯数字编号,不利于我们记忆,C语言编译器为了降低我们的工作难度,不用我们记每个变量的地址,只需要记住这个变量的名称就可以了。操作某个变量名,就相当于操作某个对应地址的RAM空间。变量名与对应地址RAM空间的映射关系是C编译器暗中悄悄帮我们分配好的。比如:
  1.         unsigned char a;  //a占用一个字节的RAM空间,这个空间的地址由C编译自动分配。
  2.         unsigned char b;  //b占用一个字节的RAM空间,这个空间的地址由C编译自动分配。
  3.         unsigned char c;  //c占用一个字节的RAM空间,这个空间的地址由C编译自动分配。  
复制代码

        上述a,b,c三个变量各自占用一个字节的RAM空间,同时被C编译器分配了3个不同的RAM空间地址。
        变量定义的初始化。变量定义之后,等于被C编译器分配了一个RAM空间,那么这个空间里面存储的数据是什么?如果没有刻意给它初始化,RAM空间里面存储的数据是不太确定的,是默认的。有些场合,需要在给变量分配RAM空间时就给它一个固定的初始值,这就是变量定义的初始化。变量初始化的语法格式由3部分组成:关键字,变量名赋值,分号。比如:
  1.         unsigned char a=9;
复制代码

        其中unsigned char就是关键字。
        其中a=9就是变量名赋值。a从被C编译器分配RAM空间那一刻起,就默认是预存了一个9的数据。
        分号“;”就是一条语句的结束符号。

【12.4   变量的赋值。】

       赋值语句的含义。把右边对象的内容复制一份给左边对象。赋值语句有一个很重要的特性,就是覆盖性,左边对象原来的内容会被右边对象复制过来的新内容所覆盖。比如,左边对象是变量a,假设原来a里面存的数据是3,右边对象是数据6,执行赋值语句后,会把右边的6赋值给了对象a,那么a原来的数据3就被覆盖丢失了,变成了6。
       赋值语句的格式。赋值语句的语法格式由4部分组成:左边对象,关键字,右边对象,分号。比如:
  1.        a=b;
复制代码

       其中a就是左边对象。
       其中“=”就是关键字。写法跟我们平时用的等于号是一样,但是在C语言里不是等于的意思,而是代表赋值的意思,它是代表中文含义的“给”,而不是用于判断的“等于”,跟等于号是两码事(C语言的等于号是“==”,这个后面章节会讲到)。
       其中b就是右边对象。
       其中分号“;”代表一条语句的结束符。
       赋值语句与ROM的关系。赋值语句是行为的一种,所以编译会把赋值这个行为翻译成对应的指令,这些指令在下载程序时最终也是以数据的形式存储在ROM里,指令也是以字节为单位(字节是一种单位,后面章节会讲到)。本教程的编译环境是以AT89C52芯片为准,AT89C52这个单片机有8K的ROM容量,也就是有8192个字节的ROM(8乘以1024等于8192),但是并不意味着程序就一定要全部占用这些ROM。程序需要占用多少ROM,完全是根据程序的行为程度决定,也就是通常所说的你的程序容量有多大,有多少行代码。多说一句,在单片机或者我们常说的计算机领域里,存储容量是以字节为单位,而每K之间的进制不是我们日常所用的1000,而是1024,所以刚才所说的8K不是8000,而是8192,这个是初学者很容易迷惑的地方。刚才提到,赋值语句是行为,凡是程序的行为指令都存储在单片机的ROM区。C编译器会把一条赋值语句翻译成对应的一条或者几条机器码,机器码指令也是以字节为单位的。下载程序的时候,这些机器码就会被下载进单片机的ROM区。比如以下这行赋值语句:
  1.        unsigned char a;
  2.        unsigned char b=3;
  3.        a=b;
复制代码

       经过C编译器编译后会生成以字节为单位的机器码。这些机器码记录着这些信息:变量a的RAM地址,变量b的RAM地址和初始化时的预存数据3,以及把b变量的内容赋值给a变量的这个行为。所有这些信息,不管是“数据”还是“行为”,本质都是以“数据”(或称数字,数码都可以)的形式存储记录的,单位是字节。

【12.5   例程的分析和练习。】

       接下来练习一个程序实例。直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。本章节在“C语言学习区域”练习的代码如下:


  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.        unsigned char a;  //定义的变量a被分配了一个字节的RAM空间,保存的数据是不确定的默认值。
  5.        unsigned char b;   //定义的变量b被分配了一个字节的RAM空间,保存的数据是不确定的默认值。
  6.        unsigned char c;   //定义的变量c被分配了一个字节的RAM空间,保存的数据是不确定的默认值。
  7.        unsigned char d=9; //定义的变量d被分配了一个字节的RAM空间,保存的数据被初始化成9.

  8.        b=3;  //把3赋值给变量b,b由原来不确定的默认数据变成了3。
  9.        c=b;  //把变量b的内容复制一份赋值给左边的变量c,c从不确定的默认值变成了3。
  10.    View(a);   //把第1个数a发送到电脑端的串口助手软件上观察。
  11.    View(b);   //把第2个数b发送到电脑端的串口助手软件上观察。
  12.    View(c);   //把第3个数c发送到电脑端的串口助手软件上观察。
  13.    View(d);   //把第4个数d发送到电脑端的串口助手软件上观察。
  14.    while(1)  
  15.    {
  16.    }
  17. }

  18. /*---C语言学习区域的结束。-----------------------------------------------*/
复制代码



       在电脑串口助手软件上观察到的程序执行现象如下:

  1. 开始...

  2. 第1个数
  3. 十进制:255
  4. 十六进制:FF
  5. 二进制:11111111

  6. 第2个数
  7. 十进制:3
  8. 十六进制:3
  9. 二进制:11

  10. 第3个数
  11. 十进制:3
  12. 十六进制:3
  13. 二进制:11

  14. 第4个数
  15. 十进制:9
  16. 十六进制:9
  17. 二进制:1001
复制代码



分析:
        第1个数a居然是255,这个255从哪来?因为a我们一直没有给它初始值,也没有给它赋值,所以它是不确定的默认值,这个255就是所谓的不确定的默认值,是编译器在定义变量a时分配的,带有不确定的随机性,不同的编译器可能分配的默认值都会存在差异。根据我的经验,unsigned char类型定义的默认值往往是0或者255(255是十六进制的0xff,十六进制的内容后续章节会讲到)。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-4-9 11:51:41 | 显示全部楼层
进来看看,有更新没有

出0入0汤圆

 楼主| 发表于 2016-4-10 10:40:20 | 显示全部楼层
第十三节:赋值语句的覆盖性。


【13.1   什么是赋值语句的覆盖性?】

  1.         a=b;
复制代码

       上述代码,执行完这条赋值语句后,会把右边变量b的数值复制一份给左边变量a,a获得了跟b一样的数值,但是a原来自己的数值却丢失了,为什么会丢失?就是因为被b复制过来的新数据给覆盖了,这就是赋值语句的覆盖性。

【13.2   例程的分析和练习。】

       既然赋值语句有覆盖性的特点,那么如何让两个变量相互交换数值?假设a原来的数据是1,b原来的数据是5,交换数据后,a的数据应该变为5,b的数据应该变为1,怎么做?很多初学者刚看到这么简单的题目,会马上根据日常生活的思路,你把你的东西给我,我把我的东西给你,就两个步骤而已,看似很简单,现在按这个思路编写一段程序看看会出什么问题,代码如下:


  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.        unsigned char a=1;   //定义的变量a被分配了1个字节的RAM空间,保存的数据被初始化成1。
  5.        unsigned char b=5;   //定义的变量b被分配了1个字节的RAM空间,保存的数据被初始化成5。

  6.        b=a; //第一步:为了交换,先把a的数赋值给b。
  7.        a=b; //第二步:为了交换,再把b的数赋值给a。

  8.        View(a);   //把第1个数a发送到电脑端的串口助手软件上观察。
  9.    View(b);   //把第2个数b发送到电脑端的串口助手软件上观察。

  10.    while(1)  
  11.    {
  12.    }
  13. }

  14. /*---C语言学习区域的结束。-----------------------------------------------*/
复制代码



        在电脑串口助手软件上观察到的程序执行现象如下:

  1. 开始...

  2. 第1个数
  3. 十进制:1
  4. 十六进制:1
  5. 二进制:1

  6. 第2个数
  7. 十进制:1
  8. 十六进制:1
  9. 二进制:1
复制代码



分析:        
         第1个数a和第2个数b居然都是1!这不是我们想要的结果。我们要的交换结果是:交换后,a变为5,b变为1。在哪个环节出了问题?把镜头切换到上述代码的“第一步”和“第二步”,由于b的数据在执行完“第一步”后,b自己原来的数据5被覆盖丢失了变成新的数据1,接着执行“第二步”后,此时相当于把 b的新数据1赋值给a,并没有5!所以a和b的数据都是1,不能达到交换后“a为5,b为1”的目的。其实就是赋值语句的覆盖性在作祟。


       上述交换数据的程序宣告失败!怎么办?既然赋值语句具有覆盖性,那么两变量想交换数据,就必须借助第三方变量来寄存,此时只需要多定义一个第三方变量t。正确的代码如下:

  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.        unsigned char a=1;   //定义的变量a被分配了1个字节的RAM空间,保存的数据被初始化成1。
  5.        unsigned char b=5;   //定义的变量b被分配了1个字节的RAM空间,保存的数据被初始化成5。
  6.        unsigned char t;     //定义一个第三方变量t,用来临时寄存数值。

  7.        t=b; //第一步:为了避免b的数据在赋值后被覆盖丢失,先寄存一份在第三方变量t那里。
  8.        b=a; //第二步:把a的数赋值给b,b原来的数据虽然丢失,但是b在t变量那里有备份。
  9.        a=t; //第三步:再把b在t变量里的备份赋值给a。注意,这里不能用b,因b原数据已被覆盖。

  10.        View(a);   //把第1个数a发送到电脑端的串口助手软件上观察。
  11.    View(b);   //把第2个数b发送到电脑端的串口助手软件上观察。

  12.    while(1)  
  13.    {
  14.    }
  15. }

  16. /*---C语言学习区域的结束。-----------------------------------------------*/
复制代码


        在电脑串口助手软件上观察到的程序执行现象如下:

  1. 开始...

  2. 第1个数
  3. 十进制:5
  4. 十六进制:5
  5. 二进制:101

  6. 第2个数
  7. 十进制:1
  8. 十六进制:1
  9. 二进制:1
复制代码



分析:        
        实验结果显示,两变量的数值交换成功。

【13.3   如何在单片机上练习本章节C语言程序?】

        直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-4-10 10:57:10 来自手机 | 显示全部楼层
非常感谢,学到了很多。

出0入0汤圆

发表于 2016-4-11 00:29:18 | 显示全部楼层
《从业将近十年,手把手教你单片机程序框架》写的非常好!通俗易懂,从中学到了很多东西!感谢楼主! 支持!

出0入0汤圆

 楼主| 发表于 2016-4-17 09:39:44 | 显示全部楼层
第十四节:二进制与字节单位,以及常用三种变量的取值范围。


【14.1   为什么要二进制?】

       为什么要二进制?我们日常生活明明是十进制的,为何数字电子领域偏要选择二进制?这是由数字硬件电路决定的。人有十个手指头,人可以直接发出十种不同声音来命名0,1,2,3...9这些数字,人可以直接用眼睛识别出十种不同状态的信息,但是数字底层基础硬件电路要直接处理和识别十种状态却很难,相对来说,处理和识别两种状态就轻松多了,所以选择二进制。比如,一颗LED灯的亮或灭,一个IO口的输出高电平或低电平,识别某一个点的电压是高电平或低电平,只需要三极管等基础元器件就可把硬件处理电路搭建起来,二进制广泛应用在数字电路的存储,通讯和运算等领域,想学好单片机就必须掌握它。

【14.2   二进制如何表示成千上万的大数值?】

       二进制如何表示成千上万的数值?现在用LED灯的亮和灭来跟大家讲解。

     (1)1个LED灯:
  1.       灭   第0种状态
  2.       亮   第1种状态
复制代码

      合计:共2种状态。

    (2)2个LED灯挨着:
  1.       灭灭   第0种状态
  2.       灭亮   第1种状态
  3.       亮灭   第2种状态
  4.       亮亮   第3种状态
复制代码

      合计:共4种状态。

   (3)3个LED灯挨着:
  1.       灭灭灭   第0种状态
  2.       灭灭亮   第1种状态
  3.       灭亮灭   第2种状态
  4.       灭亮亮   第3种状态
  5.       亮灭灭   第4种状态
  6.       亮灭亮   第5种状态
  7.       亮亮灭   第6种状态
  8.       亮亮亮   第7种状态
复制代码

      合计:共8种状态。

   (4)8个LED灯挨着:
  1.       灭灭灭灭灭灭灭灭   第0种状态
  2.       灭灭灭灭灭灭灭亮   第1种状态
  3.       ......                         第N种状态
  4.       亮亮亮亮亮亮亮灭   第254种状态
  5.       亮亮亮亮亮亮亮亮   第255种状态
复制代码

      合计:共256种状态。

    (5)16个LED灯挨着:
  1.       灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭   第0种状态
  2.       灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭亮   第1种状态
  3.       ......                                                     第N种状态
  4.       亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮灭   第65534种状态
  5.       亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮   第65535种状态
复制代码

      合计:共65536种状态。

    (6)32个LED灯挨着:
  1.       灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭   第0种状态
  2.       灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭灭亮   第1种状态
  3.       ......                                                               第N种状态
  4.       亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮灭   第4294967294种状态
  5.       亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮亮   第4294967295种状态
复制代码

      合计:共4294967296种状态。

结论:
       连续挨着的LED灯越多,能表达的数值范围就越大。

【14.3   什么是位?】

       什么是位?以上一个LED灯就代表1位,8个LED灯就代表8位。位的英文名是用bit来表示。一个变量的位数越大就意味着这个变量的取值范围越大。一个单片机的位数越大,就说明这个单片机一次处理的数据范围就越大,意味着运算和处理速度就越快。我们日常所说的8位单片机,32位单片机,就是这个位的概念。为什么32位的单片机比8位单片机的处理和运算能力强,就是这个原因。

【14.4   什么是字节?】

       什么是字节?字节是计算机很重要的一个基本单位,一个字节有8位。8个LED灯挨着能代表多少种状态,就意味着一个字节的数据范围有多大。从上面举的例子中,我们知道8个LED灯挨着,能表示从0到255种状态,所以一个字节的取值范围就是从0到255。

【14.5   三种常用变量的取值范围是什么?】

       前面章节曾提到三种常用的变量:unsigned char,unsigned int ,unsigned long。现在有了二进制和字节的基础知识,就可以跟大家讲讲这三种变量的取值范围,而且很重要,这是我们写单片机程序必备的概念。
       unsigned char的变量占用1个字节RAM,共8位,根据前面LED灯的例子,取值范围是从0到255。
       unsigned int的变量占用2个字节RAM,共16位,根据前面LED灯的例子,取值范围是从0到65535。多说一句,对于51内核的单片机,unsigned int的变量是占用2个字节。如果是在32位的stm32单片机,unsigned int的变量是占用4个字节的,所以不同的单片机不同的编译器是会有一些差异的。
       unsigned long的变量占用4个字节RAM,共32位,根据前面LED灯的例子,取值范围是从0到4294967295。

【14.6   例程练习和分析。】

       现在我们编写一个程序来验证unsigned char,unsigned int,unsigned long的取值范围。
       定义两个unsigned char变量a和b,a赋值255,b赋值256,255和256恰好处于unsigned char的取值边界。
       再定义两个unsigned int变量c和d,c赋值65535,d赋值65536,65535和65536恰好处于unsigned int的取值边界。
       最后定义两个unsigned long变量e和f,e赋值4294967295,f赋值4294967296,4294967295和4294967296恰好处于unsigned long的取值边界。
       程序代码如下:


  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.         unsigned char a;   //定义一个变量a,并且分配了1个字节的RAM空间。
  5.         unsigned char b;   //定义一个变量b,并且分配了1个字节的RAM空间。
  6.         unsigned int c;    //定义一个变量c,并且分配了2个字节的RAM空间。
  7.         unsigned int d;    //定义一个变量d,并且分配了2个字节的RAM空间。
  8.         unsigned long e;   //定义一个变量e,并且分配了4个字节的RAM空间。
  9.         unsigned long f;   //定义一个变量f,并且分配了4个字节的RAM空间。

  10.         a=255;         //把255赋值给变量a,a此时会是什么数?会超范围溢出吗?
  11.         b=256;         //把256赋值给变量b,b此时会是什么数?会超范围溢出吗?
  12.         c=65535;       //把65535赋值给变量c,c此时会是什么数?会超范围溢出吗?
  13.         d=65536;       //把65536赋值给变量d,d此时会是什么数?会超范围溢出吗?
  14.         e=4294967295;  //把4294967295赋值给变量e,e此时会是什么数?会超范围溢出吗?
  15.         f=4294967296;  //把4294967296赋值给变量f,f此时会是什么数?会超范围溢出吗?

  16.         View(a);   //把第1个数a发送到电脑端的串口助手软件上观察。
  17.     View(b);   //把第2个数b发送到电脑端的串口助手软件上观察。
  18.         View(c);   //把第3个数c发送到电脑端的串口助手软件上观察。
  19.     View(d);   //把第4个数d发送到电脑端的串口助手软件上观察。
  20.         View(e);   //把第5个数e发送到电脑端的串口助手软件上观察。
  21.     View(f);   //把第6个数f发送到电脑端的串口助手软件上观察。

  22.     while(1)  
  23.     {
  24.     }
  25. }

  26. /*---C语言学习区域的结束。-----------------------------------------------*/
复制代码


在电脑串口助手软件上观察到的程序执行现象如下:

  1. 开始...

  2. 第1个数
  3. 十进制:255
  4. 十六进制:FF
  5. 二进制:11111111

  6. 第2个数
  7. 十进制:0
  8. 十六进制:0
  9. 二进制:0

  10. 第3个数
  11. 十进制:65535
  12. 十六进制:FFFF
  13. 二进制:1111111111111111

  14. 第4个数
  15. 十进制:0
  16. 十六进制:0
  17. 二进制:0

  18. 第5个数
  19. 十进制:4294967295
  20. 十六进制:FFFFFFFF
  21. 二进制:11111111111111111111111111111111

  22. 第6个数
  23. 十进制:0
  24. 十六进制:0
  25. 二进制:0
复制代码


分析:        
        通过实验结果,我们知道unsigned char变量最大能取值到255,如果非要赋值256就会超出范围溢出后变成了0。unsigned int变量最大能取值到65535,如果非要赋值65536就会超出范围溢出后变成了0。unsigned long变量最大能取值到4294967295,如果非要赋值4294967296就会超出范围溢出后变成了0。

【14.7   如何在单片机上练习本章节C语言程序?】

        直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-4-17 15:02:23 | 显示全部楼层
顶一个!!!

出0入0汤圆

 楼主| 发表于 2016-4-23 10:53:06 | 显示全部楼层
第十五节:二进制与十六进制。


【15.1   十六进制是二进制的缩写。】

       在我的印象中,C51编译器好像并不支持二进制的书写格式,即使它能支持二进制的书写格式,二进制的书写还是有个弊端,就是数字太多太长了,写起来非常费劲不方便,怎么办?解决办法就是用十六进制。十六进制是二进制的缩写,之所以称它为二进制的缩写,是因为它们的转换关系非常简单直观,不需要借助计算器即可相互转换。

【15.2   何谓十六进制?】

       何谓十六进制?欲搞清楚这个问题,还得先从十进制说起。所谓十进制,就是用一位字符可以表示从0到9这十个数字。所谓二进制,就是用一位字符可以表示从0到1这二个数字。所谓十六进制,当然也就是用一位字符可以表示从0到15这十六个数字。但是十六进制马上就会面临一个问题,十六进制的10到15这6个数其实是有两位字符组成的,并不是一位呀?于是C语言用这些字符A,B,C,D,E,F分别替代10,11,12,13,14,15这6个数,10前面的0到9还是跟十进制的字符一致。A,B,C,D,E,F也可以用小写a,b,c,d,e,f来替代,在数值上不区分大小写,比如十六进制的a与A都是表示十进制的10。

【15.3   二进制与十六进制是如何转换的?】

       前面提到了十六进制是二进制的缩写,它们的转换关系非常简单直观,每1位十六进制的字符,对应4位二进制的字符。关系如下:

    十进制       二进制      十六进制
    0            0000        0
    1            0001        1
    2            0010        2
    3            0011        3
    4            0100        4
    5            0101        5
    6            0110        6
    7            0111        7
    8            1000        8
    9            1001        9
    10           1010        A
    11           1011        B
    12           1100        C
    13           1101        D
    14           1110        E
    15           1111        F

       二进制转换成十六进制的时候,如果不是4位的倍数,则最左边高位默认补上0凑合成4位的倍数。比如一个二进制的数101001,可以在左边补上2个0变成00101001,然后把每4位字符转成1个十六进制的字符。左边高4位0010对应十六进制的2,右边低4位1001对应十六进制的9,所以二进制的101001合起来最终转换成十六进制的数是29(实际上正确的写法是0x29,为什么?请继续往下看。)。

【15.4   十六进制数的标准书写格式是什么样子的?】

       十六进制的标准书写格式是什么样子的?实际上,十六进制29并不能直接写成29,否则就跟十进制的写法混淆了。为了把十六进制和十进制的书写格式进行区分,C语言规定凡是十六进制必须加一个数字0和一个字母x作为前缀,也就是十六进制必须以0x作为前缀,所以刚才的十六进制29就应该写成0x29,否则,如果直接写29编译器会认为是十进制的29,而十进制的29转换成十六进制是0x1D(十进制与十六进制之间如何转换在后面章节会讲到),0x29与0x1D可见差别很大的,凡是不加前缀的都会被默认为十进制。 多说一句,在C语言程序里,对于同样一个数值,既可以用十六进制,也可以用十进制,比如:d=0x2C与d=44的含义是一样的,因为十六进制的0x2C和十进制的44最终都会被C51编译器翻译成二进制00101100,是表示同样大小的数值。

【15.5   例程练习和分析。】

       现在我们编写一个程序来观察十六进制和二进制的关系。
       程序代码如下:

  1. /*---C语言学习区域的开始。-----------------------------------------------*/

  2. void main() //主函数
  3. {
  4.         unsigned char a;    //定义一个变量a,并且分配了1个字节的RAM空间。
  5.         unsigned char b;    //定义一个变量b,并且分配了1个字节的RAM空间。
  6.         unsigned char c;    //定义一个变量c,并且分配了1个字节的RAM空间。
  7.         unsigned char d;    //定义一个变量d,并且分配了1个字节的RAM空间。

  8.         a=0x06;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  9.         b=0x0A;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  10.         c=0x0e;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。
  11.         d=0x2C;   //十六进制前记得加0x前缀,超过9部分的字母不分大小写。

  12.         View(a);   //把第1个数a发送到电脑端的串口助手软件上观察。
  13.     View(b);   //把第2个数b发送到电脑端的串口助手软件上观察。
  14.         View(c);   //把第3个数c发送到电脑端的串口助手软件上观察。
  15.     View(d);   //把第4个数d发送到电脑端的串口助手软件上观察。

  16.     while(1)  
  17.     {
  18.     }
  19. }

  20. /*---C语言学习区域的结束。-----------------------------------------------*/
复制代码


       在电脑串口助手软件上观察到的程序执行现象如下:

  1. 开始...

  2. 第1个数
  3. 十进制:6
  4. 十六进制:6
  5. 二进制:110

  6. 第2个数
  7. 十进制:10
  8. 十六进制:A
  9. 二进制:1010

  10. 第3个数
  11. 十进制:14
  12. 十六进制:E
  13. 二进制:1110

  14. 第4个数
  15. 十进制:44
  16. 十六进制:2C
  17. 二进制:101100
复制代码

分析:        
       通过实验结果,我们知道二进制与十六进制的转换关系确实非常清晰简单,所以十六进制也可以看作是二进制的缩写。

【15.6   如何在单片机上练习本章节C语言程序?】

       直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-4-23 11:58:51 | 显示全部楼层
厉害,顶~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 06:08

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表