在写之前我先说一下为什么写这篇文章,其实主要是出于这么一些考虑:
1、一个人力量有限,资源有限,了解到的东西就更加有限,现代社会讲究团队协作,SO......希望以此为契机,大家能参与其中,将这些内容不断完善
2、开源软件,开源硬件,开源教程,其实这方面早有先河,但是更多的是单人收集的,单人写,而本文章希望是集大众力量写文章服务于大众
3、这里面主要从基础单片机开始,然后是模块化编程,编程规范,从零开始构造单片机操作系统这些方面跟大家一起分享,其实还有很多非常优秀的编程思想,像状态机,PID算法等等,大家都可以一一添加进去
4、基础篇主要参考《爱上单片机》--杜洋、《电子设计从零开始》; 模块化主要参考uCOS作者《嵌入式系统构件》,然后结合个人的一些经验; 编程规范参考华为的规范文档,单片机系统参考《51时间系统》、实时系统uCos及阿莫电子论坛、正点原子论坛
5、个人学习技术性东西的原则:
先入门,有一个整体感知(也就是学习一些基础性的东西)->实践,发现问题,解决问题->再次学习基础性东西->由易到难做一些有挑战性的工程
说明:由于本人了解的东西有限,文章是2016年写的,这里面如果有什么错误的地方,误导到家的地方,希望大家在看了本教程之后,大家多多参与,提出宝贵的意见。本篇主要以思路,方法与编程思想为主,层层深入,将复杂的问题,深奥的东西进行剖析,以便于大家更好的吸收、理解这些东西,至于怎么去用编程软件,下载等我会给出已经讲得很详细的教程。
时间仓促,内容难免措辞不当,恳请大家不吝赐教。
第一篇 、51单片机基础篇
我们先来看下下图的一个对比
人与单片机对比图
首先说一说我个人对单片机的理解,如果把我们人类的大脑比作MCU里面的核心CPU的话,那么人的手脚就相当于外设中的基本输入输出端口(Input and Output),人的耳朵相当于MCU的通信输入,嘴巴相当于通信输出,这里只是做一个比较简单的比喻。单片机是一个人为的给它安排事情去做的这么一个单片型微型计算机,其实我们非常熟悉电脑,电脑有内存,显卡,声卡等。单片机也有类似的这些东西,比如说有些功能强一点单片机内部自带AD转换模块、USB控制器、CAN总线控制器,为什么单片机只有这么些低端的东西呢?我们我们可以成本和需求方面考虑下,如果说在单片机里面集成个声卡你用的上么,集成个USB控制器大部分情况你又用的上么,还有这么一个东西集成在里面需不需要额外的成本。其实讲到这里,大家可以去了解下你们常用的手机,里面那块主芯片,市面上现在主要是联发科与高通,其余的就是三星的,还有我们国家华为的,手机厂商在发布新产品时,经常提到什么GPS,蓝牙,什么全网通(GSM/TDSCDMA/WCDMA/LTE)等等,基本上是宣传芯片的功能,并不是手机的功能,这也就是想告诉大家,手机上的那块主芯片也是单片机,只不过它的功能更强大一点,集成的东西更多一点;把这些问题想清楚了,然后我们就得到描述单片机常用的一句话:
其实我们从自面上也可以理解一下,单片机:就是单独的一个芯片的机器,大家试想一下,一个芯片的机器,那么这个芯片里面应该需要些什么呢??都可以大胆的去想。还有一个就是大家经常聊起的嵌入式,首先发表一下个人的看法,在我看来只要是上面带了单片机的,不论大小,不论功能强弱,都可以称为嵌入式,但是往往我们谈的更多的就是功能强大型的,能跑LINUX的.....个人觉得这是一个误区。
说到这里说点题外话,经常有人说232,485,CAN总线接口,但是跟很多人交流发现很多人没有把通信协议与这些物理接口区分清楚,我在这里用一个简单的比喻来跟大家说明下,上面我们所说的232,485,CAN总线都是物理接口,也就是我们每个人都有一个嘴巴、鼻子、耳朵一样,中国人有这些,美国人也有这些,同样非洲人也有这些东西(肢体残缺的不算),但是我们中国人主要用汉语交流,美国人主要用英语交流,德国用德语等等,我们要想顺利的与外国人沟通,那我们只能说他们的母语,这就是协议,像典型的协议在单片机中有很多,工业控制里面的modbus,openbus,卡车上面有SAEJ1939,然后在互联网领域里面我们众所周知的TCP/IP协议等等,modbus可以存在于232上,同样也可以通过485接口通信,CAN总线接口也行,是独立于物理接口的,是为了解决特定问题而诞生的。大家有空可以去看下计算机整个诞生的历史,关于这方面的书籍非常多,包括很多优秀的算法的诞生,软件的诞生,都是为了解决特定问题而出现的。学习单片机我们始终要明白,单片机的诞生也是为了方便人类生活的,说道这里我又不得不提一下计算机的语言,其实我们学过一点计算机的人都晓得,最初的计算机编程直接是二进制,但是慢慢的这些计算机科学家发现他们每天做的这些事情很多是重复的,并且二进制对于其它人来说非常难懂,然后就出现了汇编语言,也就是我们熟悉的A语言,A语言是接近计算机底层的,我们要用计算机的思考方式去编程,这时期的计算机也就只能少部分人能玩,总有一些“不安分”的计算机科学家在想办法解决这些问题,然后就出现了Basic语言,也就是B语言,B语言就有一点接近人的思考方式了,本人只是了解了一些基本的汇编语言,Basic语言不是太了解,我就不多说了,以免误导大家。后面有出现了C语言,接本上接近人的思考方式,我们也称这些语言是高级语言,之所以高级,是因为符合人类的思考方式,人类是高级动物嘛......这两年学习C++与JAVA语言的人非常多,也非常热,我只学习了一点点的C++语言,我用的最多是C语言,为什么没去学习C++ OR JAVA语言,如果认真去了解这些语言我们会发现,C++与JAVA乃至后面的D、E、F等语言都是越来越接近人的思考方式的,语言本身只是一个工具,真正核心的东西是思想,编程思想,就像我们解决一个问题有不同的方法,我们肯定会选择简单易行的方法,我给大家举个例子:我们从小都玩过俄罗斯方块,俄罗斯方块用汇编语言可以实现,用C语言也可以实现,同样用C++ JAVA也可以实现,但是它的核心算法却都是一样的,这一点大家可以去证实。C++的核心思想是面向对象,什么是面向对象我没有深入的去学习,只是了解了一些。但是我可以告诉大家一些东西,或许大家对语言本身会有一些感悟。假设我们去驾驶一辆汽车,我想大家所关心的应该是怎么去把它开动,以自动档为例,我们只要晓得怎么挂档,松手刹,踩刹车,打方向盘的基本操作就行了;大家可以想象一下如果我们去驾驶一辆汽车,在驾驶的过程中,我们关心这些问题,发动机怎么运行,里面的电路怎么工作,我踩刹车,哪个刹车钳在工作,我打方向盘的时候关注电子助力转向在怎么工作,在细化一点,发动的几个缸在工作,曲轴在转动等等。我想大家开车一定会非常辛苦。其实在这里汽车本身就是一个对象,对象里面的东西我们就不需要关注太多,我们只要关心我们要使用到的东西就可以了,对于汽车本身,发动机是一个对象,电子设备也是一个对象,我们驾驶汽车,操作这些东西,只需关注我们要用到的接口就行了。再近一点,我们看下我么学校的管理模式,整个学校是属于校长管理,但是校长并不是一对一的对我们进行管理,而是一级一级的往下通知,至于下面的细节他不会太多的去关心。就像我们要找别人帮忙一样,如果我们还关心别人用什么方法给我解决问题,我想别人一定非常反感,明白这一点我们对于我们以后学习这方面选择什么语言非常有帮助。其实不单单语言方面有这种面向对象、模块化思想,在电路设计当中这种模块化思想也体现的淋漓尽致,在这里我们一典型的工业PLC为例:PLC里面基本上带有哪些功能模块呢?有电源模块、AD转换模块、DA转换模块、开关量检测模块、控制继电器输出模块,通信模块有CAN、RS232、RS485、以太网接口。明白电路这方面的功能,对于基本电路检修非常有利。
STC89系列(摘自官方数据手册)
联发科MT6795功能描述(摘自联发科官网)
骁龙820描述(摘自高通官网)
一、如何学习单片机
发表一下个人的观点:书要看,但是不要过多的看,把它作为一个知识的补充,我们读了这么多年的书,其实只有在自己静下心来看书的时候效率才最高。
首先,我们不能像以往学习其他课程一样,又是背,又是拿笔计算,学什么寄存器,从那难懂的汇编语言入手....我直接告诉大家,这样是达不到效果的,反而会丧失学习单片机的兴趣。那该如何去学呢,我们要充分利用自己的兴趣去学,去“玩”单片机,而不是被它所“玩”,在此过程中切记浮躁,不要跟着自己的情绪走,想学就学一下,不想学就不学,要持之以恒。
①刚开始可以对照着别人的代码抄写,但是后期只能借鉴别人的,不要一味的CTRL+C,CTRL+V,我晓得大家这两个东西用的很熟,多借鉴别人的编程方法,用自己的思路去写;
②不要蜻蜓点水,得过且过,细微之处体现实力;
③把时髦的技术挂在嘴边,不如把过时的技术记在心里;
④经典的书时不时的去重新看一遍,多看国外的书;
⑤网上的资源要多利用,但是不要瞎逛,要有目的;
⑥单片机十天是学不会的,只能入门,要打持久战;
⑦思想很重要,方法很重要!!
二、学习的一个基本流程
1、了解单片机是个什么东西,主要出现在那些领域,弄清自己为什么要学?
2、基本开发软件安装,代码下载(Keil是最基本的);
3、跟着教程从零开始建立第一个工程,一次不会多试几次:跟着教程把代码一个一个的敲上去,然后编译,出现错误不要立马询问他人,先自行尝试去解决,实在搞不懂再去问别人,当控制了LED的亮灭工作后,就要去分析一下这个LED到底是怎么点亮的,里面相应的代码又是怎么回事,都要去了解一遍;
4、到了这个阶段,就可以学习单片机的其他东西,对照着代码一个一个字母的抄,不要觉得繁琐,没抄完一个功能,正确无误后,先做好备份,然后再去修改,看是否与你的预期相符,抄着抄着你就有感觉了,有了感觉就可以尝试着不参考别人的程序自己从零去建立自己想要实现的功能,从最简单的开始,哪怕是点亮一颗LED灯,这个很重要!!!;
5、当把单片机的基本功能都学完后,就可以以工程的形式进一步学习了;用单片机实现一个电子钟,用单片机控制一辆小车.....在做这种工程的过程中我们会发现很多问题,解决很多问题,这样我们就上升了一个层次了;
6、编程规范,本来想将编程规范放在最前面,考虑到可能会让大家丧失学习单片机的热情。这阶段就要看人家写的代码,为什么看上去那么舒服,并且很容易阅读,函数一看就知道它用来干嘛......从规范着手,编写能重复利用,便于维护的代码;
7、工程也做了,规范也有了,是不是有点感觉单片机不怎么好玩了?其实还有大把的东西需要你了解,随着工程一个比一个大,我们就要从全局开始思考这些问题了。要对一个复杂的工程分成一个个的模块,比如说在电子钟工程里,我们可以尝试着把它分为按键模块,显示模块,时钟模块......
Keil:软件不要汉化,英语没有那么可怕,它本身也自带了说明书,遇到有些问题可以去看它
(二维码自动识别)
Pretous:个人建议只用来做一些功能性的检验,像算法类型的,切不可在实际硬件中用其作为真实参考
Notepade++
Notepade++:平时查看,编写代码非常方便
Notepad++软件截面
三、了解51单片的的基本东西及C语言
单片机:硬件设施,躯壳首先要了解基本的51单片机知识,实验室一般以国产宏晶公司的STC89C52RC为例,要知道怎么给单片机供电,有哪些基本的I/O口,I/O口的基本内部结构,串口登(这些东西只做基本了解,不需要刻意去记住,在后续的练习过程中,大家会慢慢记住的);
C语言:灵魂对于学习单片机C语言,个人建议刚开始可以直接跟着抄写代码就行了,至于为什么是那样写的不必纠结太多,练习一段时间后再去看那些单片机的C语言书籍,这样大家更深刻些。
四、Keil软件的安装以及怎么用ISP软件下载
① Keil软件怎么安装,以及怎么破解,基本的设置,怎么使用,大家网上去搜索,如果这一点都做不到,不要说你会用电脑(关于使用这一块了解就行,后面在写代码的过程中会反反复复的用到的,不必刻意去记)
keil软件图标
keil软件界面截图
② 程序烧写ISP(ISP--In System Programming是在线编程的意思)软件可直接从宏晶公司官www.stcmcu.com下载STC-ISP,这里面也有很多值得参考的东西,有事没事可以去看看,也可以百度,怎么安装USB转串口的驱动(USB转串口常用芯片:CP2102,PL2303,CH341),它的功能也就是将我们编写好的代码下载到我们的单片机当中,怎么从ISP软件中找相应单片机的型号进行代码的下载
STC单片机烧写软件图标
ISP烧写截图
烧写步骤:
(1)、在烧写前先断开单片机的电源(注意)
(2)、首先选中单片机的型号,根据自己用的单片机选定,我这里是STC89C52RC
(3)、打开要烧写的文件:如LED.HEX
(4)、选择当前有效的串口
(5)、点击下载按钮。
(6)、接通单片机的电源
关于下载我总结了一下,如果要重复下载的话,最好装个那种自锁的开关,然后每次去点击下载,直接按开关
③将别人验证成功简单功能(etc:LED灯闪烁)HEX文件下载进单片机以便验证自己的思路是否正确
五、点亮一颗LED灯
LED灯实物(摘自爱上单片机)
LED灯其实我们平时到处都可以看到,不同的LED灯的驱动电压有区别,这个我就不多说了,百度上一大堆,大家只要记住一点LED灯的那个限流电阻的值是怎么来的就行了,比如说红色LED灯的驱动电压是3V,电源是5V,一般的驱动电流大约10mA就足够了 R = (5V-3V)/10mA*1000 = 200Ω,我这只是举个例子,其他的大家都可以根据数据手册,或者某宝卖家提供的参数进行电阻的计算。
硬件部分
如图所示D1连接在P0.0端口,我们为什么要采用这种方式连接呢?可不可以将LED灯反向呢?对于这个问题我给出的回答是,有些可以,有些不可以。为什么是这样呢?
这个我们就要了解STC89C52RC这款单片机的GPIO内部的基本结构了,在本实验中所使用的端口为P0口,内部为开漏输出,什么是开漏输出?度娘.....因为在这个教程中我只教大家学习单片机知识,其它的不过多的说,以免牵扯太多,大家消化不了。P1~P3口是准双向上拉,这款单片机(5V)I/O口的驱动能力的灌电流20mA;弱上拉时,拉电流能力是200uA,设置成强推挽时,拉电流能力也可达20mA。
灌电流:即MCU被动输入电流。
拉电流:即MCU主动输出电流。
那下图就不用多解释了.....
点亮一颗LED灯实验原理图
代码:
/************ (C) COPYRIGHT 2016 wllis **************
*
* 文件名: LED.C
* 描 述:点亮一颗LED
* 作 者: wllis
* 日 期: 2016/01/15
* ****************************************************/
#include typedef unsigned char UINT8; typedef unsigned int UINT16; sbit LED = P0^0; /* * 函数名:void DelayMS( UINT16 n ) * 描 述:延时 * 输 入:UINT16 * 输 出:无 */ void DelayMS( UINT16 n ) { UINT8 a; while(--n) { for( a=114; a>0; a--); } } /* * 函数名:void main() * 描 述:主函数 * 输 入:无 * 输 出:无 */ void main() { P0 = 0XFF; // 将P0端口全部初始化为高电平 while(1) { LED = 1; // LED灭 DelayMS(500); // 延时500毫秒 LED = 0; // LED亮 DelayMS(500); // 延时500毫秒 } } /********************end of file ***********************/ 代码分析: 首先我们看下我们要点亮的LED怎么实现,先在代码中定义[图片上传失败sbit LED0 = P0^0;也就是P0口的最低位,这句代码大家可能是初次接触,不怎么好懂,sbit是Keil开发环境中的关键字,是直接用来进行位定义的,它的用法大家参考我后面给出的书籍。这么P0又是怎么来的呢?我们来看下REG52.H这个头文件 REG52.H头文件 在里面是不是看到有关于P0的定义,再看下那个英文单词BYTE Registers字节寄存器,一个字节是多少位?八位。sfr又是怎么回事呢?它的全称是Special Function Register这个是Keil软件规定的用来定义特殊寄存器的,这是规定,大家也没必要了解为什么了,感兴趣的话自行去了解。然后再来看下P0后面的0X80是什么意思?,这个其实就是P0端口的地址,讲到这里大家可能又会问,地址又是怎么回事?这个问题我给大家打个比方,比如说你到宾馆去住宿,你上服务台那边花钱开了一间房,服务员告诉你的房间在112号,这个112号也就是宾馆房间的一个地址,有了这个地址你就可以在你的房间自由进出了,看电视,睡觉等等。如果说没有地址那岂不是乱了套了,大家到处乱走,很容易走错别人的房间。单片机也是如此,有了这个地址我们就可以对它里面的东西进行操作,变换高低电平,读取高低电平,这个地址是怎么来的,从单片机的数据手册上可以找到,这个就不要问为什么了,当初造这块单片机的时候就早已经固定好了。 特殊功能寄存器映像(摘自STC80C52RC数据手册) 大家看下最下面的80h是不是有个P0 .....,功能越强大的单片机,它的寄存器就越多,以至于它们的数据手册写了厚厚的一本书,像STM32、S3C2410大家可以去找它们的数据手册看看。再来看看当中的延时函数,如果我们把它进行拆解,外面一个500次的循环,内部一个114次的循环,500*114我的天呐,500多万次的减法,不停的对其中的数进行减法运算,一直到运算条件不成立为止,也就是CPU每运行一个指令都要花费一点时间,将这些时间全部加起来达到我们需要时间。说道这里,大家是不是感觉太TM浪费了,一个小小的延时,这么占用MCU的资源,以至于如果还有其他的东西需要运行的话都有困难,那有没有别的方法可以将这种方式的延时资源占用释放出来呢?答案肯定是有的,只要大家坚持往下看就会学到自己想学的东西.... 流水灯实验原理图 代码1: /************ (C) COPYRIGHT 2016 wllis ************** * * 文件名: Flow_LED.C * 描 述:LED流水灯实验 * 作 者: wllis * 日 期: 2016/01/21 * ****************************************************/ #include typedef unsigned char UINT8; typedef unsigned int UINT16; /* * 函数名:void DelayMS( UINT16 n ) * 描 述:简单的延时 * 输 入:UINT16 * 输 出:无 */ void DelayMS( UINT16 n ) { UINT8 a; while(--n) { for( a=114; a>0; a--); } } /* * 函数名:void main() * 描 述:主函数 * 输 入:无 * 输 出:无 */ void main() { UINT8 i = 0; P0 = 0XFF; // 将P0端口全部初始化为高电平 0XFF化为二进制为 1111 1111 while(1) { for( i=0; i<8; i++ ) { P0 = 0XFE; // 1111 1110 DelayMS(100); // 延时100毫秒 P0 = 0XFD; // 1111 1101 DelayMS(100); // 延时100毫秒 P0 = 0XFB; // 1111 1011 DelayMS(100); // 延时100毫秒 P0 = 0XF7; // 1111 0111 DelayMS(100); // 延时100毫秒 P0 = 0XEF; // 1110 1111 DelayMS(100); // 延时100毫秒
六、流水灯实验
相关文章