第一部分罗嗦与废话(必看)我写这个,再次申明:这不是教程,至少不是教科书式的教程。只是自己学习的一个过程,准确说是我个人学习的一个思维方式,学习顺序。可能我后面的写的有些乱,又有些天马行空,不过这真正是反映我学习的一个先后过程。说实话,入门真的很痛苦,那种徘徊再门外而不得要领的感觉真的很痛苦,论坛上大多数教程啊例子什么的都是ADS的,刚看时那个郁闷啊,特别是对于学单片机用惯KEIL的人来说哦,还要再去学ADS,真是。。。所以我下面说的一些包括例子,都是基于keil的,为的是我们能够像学习51单片机一样学习ARM。刚开始也是什么都不懂,在论坛上下了好多ARM的教程。也逐个浏览下了,就我个人认为,比较好的两本书,也是我自己整个浏览完(注意,是浏览)的两本。一本是“《ARM嵌入式基础教程》配套讲义”,这个是PPT文档,我没有找到完整的原书。这个教程我从头到尾看了一次,不过看完还是脑袋糊糊的。在这里,我也请大家对它不要钻研,糊糊的看完即可(要看完),大致知道ARM是什么意思,知道ARM是有一个内核的,ARM公司开发内核(什么ARM7,ARM9,AR1M1就是内核不同),然后交给其他公司添加其他外围设备,所以导致ARM有衍生出很多种类;然后知道ARM都几种操作模式,什么用户模式,系统模式等等(我到现在也叫不全),至于具体什么时候用,干什么用,不用管,用的时候再看;还有就是知道ARM分为ARM指令集及Thumb指令,这个是汇编的,暂且搁搁吧,哎,本来我也是想向51一样先学汇编再学C的,不过看来看去,还是不知道汇编从何下手;然后看到PPT里一直有个什么启动代码的,什么意思?8懂,留着,到后面就知道了。。不过要写出来,,,有难度。。然后。。。自己看看,反正看完脑袋还是浆糊就对了,你都搞懂了,我想下面的你也不用看了,你是天才。。。。。。。说说我当初用keil学ARM的开端。刚开始不知道keilC51原来和KEILforarm是两个东西,从论坛上下了例子后,直接keil编译,失败ing。。后来下了个keilforarm的,想自己建个工程呢,楞是找不到LPCXX在哪里,找到Philips,下面只写着seeNXP——就是这个就搞了好久,把keilC51,KIELFORARM反复装来装去,然后又下了别的版本的keilforarm,还是搞不定,再网上找了几个keilarm的教程,就是看不不到怎么教人找到LPCXX栏目的―――后来,光是这个就搞了两个多星期,没头绪。于是下了个ADS,看教程,发现。。。不会用。没法,又转会keil,一个偶然的以外,被我发现创建时左边有个NXP的栏目,于是点开,往下拉,天啊,上帝啊,终于看到LPC叉叉了。所以这就告诫我们,英文理解能力一定要好。。。(汗!!)然后问题又来了,看了ADS的例子(下了一个基于PROTEUS的ARM虚拟开发技术,是ADS的),我晕,文件好多啊,什么main.c,target.c,starup.c,lpcxx.c,….然后又看keil的,我靠,又是一堆文件―――说实话,对初学者来说,看见这些文件就怕,干嘛搞那么多啊,我××××无语。。。。。哪些是可以放在一个文件里的?还是必须要分成几个文件的?还是分成的几个文件必须那样命名的?还是这些文件是必须的,哪些是不必要的?哪些是系统的,哪些自己写的,哪些是可以更改的?还是。。。真是彻底被这些乱七八糟的例子打败了。。。。想我当初学单片机,就建立一个工程,一个程序文件,写两句:SETBP1.0,END,OK。装上那个dpj.dll(平凡老师的,大家不陌生吧),效果就出来的,多么简单干脆,哪像这ARM这么繁琐啊,真的烦。。。。为了研究这个问题,我反复实验,一个一个的改,删,得出结论:除了starup这个文件是必须要的(当然还要一个程序文件),其他都可以删,通通删(lpcxx。H是自动生成)。..然后说说我看的另一本书,也是我现在还在看的一本书(电子档的)“深入浅出ARM7(上,下)”,这是本好书,建议大家开始写程序看这个。前面的就像看我说的第一本一样,浏览,纯粹的浏览,,有个印象即可;有不懂的地方,以后后面写程序时可以再回过头来研究,带着问题学习――――这是最好的;否则都不明白对后面的学习有什么帮助,看了也白看,没理解,转眼就忘了。。我这里说的,像学C51一样学ARM,只是给大家一个入门的路,只能说入门,更高深的偶也8懂。至于到“会”的程度,我记得曾经学VC时有句话说的好“什么叫会VC,会建个工程,能弹出个‘HelloWorld’就叫会VC了?”所以这里也说“不是会点亮个LED就叫会ARM的!!”至于“精通”,当今21世纪,呵呵,谁敢言“精通”二字?那么“入门者”和“高手”有什么区别呢?借用当初学单片机时平凡老师的话,“入门者和高手的区别,看到FEH这个16进制数,入门者只有看到8个LED,7个灭,1个亮,然后才能回过头把FEH这个数和LED7灭1亮联想起来;而高手一看到FEH,脑海里自然就想到8个LED,7亮1灭(大致是这个意思,忘了,,!)”―――最后一句正文,我这个应当是大多数正常人的思维模式了,不敢说让大家成为高手,不过入个门应该不是什么难事。如果最后还没有入门的人,只能说我的思维方式不适合你。一种要么你是牛B的天才,另一种。。。不说了,自己明白。。。。。。好了,废话就说到这里了,脑袋又糊了,打游戏去。。。。王谷成于2008年12月8日星期一农历戊子鼠年冬月十一晚第二部分像学51一样学ARM■一些说明:本文所述的以及附带的keil-protues仿真例子,我都一一重新运行了的,能够protues仿真,然后基本上逐条逐句都有详尽的注释。例子以及注释主要参考了论坛下的“基于PROTEUS的ARM虚拟开发技术”(光盘)和“深入浅出ARM7(上,下)”,不过不是像“基于××”样完全照抄“深入××”,其中有我自己的理解,有些地方有疑问的我都标出了,哪位如果后来解决了可以发到论坛共享下。。。我使用的keilforarm版本是mdk3.22a,protues版本是protues7.2sp6(自己装第三方库).如果有人仿真不能的话,估计可能是软件版本的问题。大家可以网上搜搜自己下载。1:开始-创建工程+点亮一个LED还是从最简单的开始,点亮一个LED。◆打开keilu3(mdk3.22a),进入时如下图:◆然后选择project(工程)-NewuVisionProject(新工程),起一个工程名,保存。◆然后进入如下界面◆下拉滚条,找到NXP(foundedbyPhilips),展开,下拉滚条,选择自己所用的ARM型号(我下面的都是LPC2131的)◆确定后弹出一个对话框如下,问你是否要加载启动代码,选择是,这里必须要加载启动代码(不像51,加启动代码A51反而出错)◆然后就是和keilC51一样了,建立一个程序文件,加载到工程里。然后写程序,编译,链接。要生成HEX代码的话,要在target里设置,如下图:好了,开始点亮一个LED使用的是LPC2131,点亮LED2.程序如下(后续省略,建附带的例子文件):#includeLPC213X.Hintmain(){PINSEL0=0X00000000;//P0口配置为GPIO功能IODIR0=0XFFFFFFFF;//P0口为输出状态IOSET0=0XFFFFFFFF;//P0口置高电平,所有LED关闭IOCLR0=0X00000002;//P0.1置低电平,点亮第二个LED}//这里(19行)必须空出一行,否则KEIL编译会警告具体的可以看keil-protues的例子。在这里,#includeLPC213X.H表示是包含一个LPC213X.H的文件这个文件在...keil\ARM\INC\Philips目录下,里面有一些关于寄存器地址的定义,至于到底是如何定义的,先不管他,反正知道用C语言写,都要包含这个文件就是了。然后是PINSEL0=0X00000000这句,表示把P0口用作GPIO功能。在ARM里,每一个端口可能有很多功能,什么GPIO,串口,IIC,SPI等等等等,而要让每个端口工作在什么功能下,就要靠PINSEL0或PINSEL1这两个寄存器来选择了,GPIO-GeneralPurposeInputOutput,通用输入输出,就是指那些可以通过软件把输入输出设置为高低电平1,0之类的端口,类似与C51中的P0,P1,P2等口。在ARM里,各端口的默认功能是GPIO,所以这一句PINSEL0=0X00000000可以不要。IOSET0=0XFFFFFFFF;IOCLR0=0X00000002;IOSET0,IOCLR0是P0口设置高低电平的两个寄存器,只有当选择GPIO功能时才有效。IOSET0,IOCLR0为1时,相应的端口才输出高或低电平,注意,不是IOCLR0=0输出低电平,IOSET0,IOCLR0为0时,也就是说对IOSET0,IOSET1赋值(写)0是无效的。最后一点,貌似是mdk的BUG?就是C程序写完后,要空一行,注意,这行必须是空的,不能有任何字,注释的也不行,否则keil编译会有警告,可以看看附带的例子,删掉空行试试。2:按键识别,点亮一个LED具体程序见我的附带实例。前面的都一样,设置GPIO功能,输入输出等。刚开始P0.0口置高电平,LED是灭的。然后while语句不停的循环,检查是否有按键按下。IOPIN0这个寄存器是一个读/写的状态寄存器,可以反映当前I/O口状态,将它与0X400(010000000000)相与,检查第【11】位(其他位“相与”后恒为0),即按键接的P0.10口。当按下键时,P0.10为低电平,执行if语句后面的一句,将P0.0变为低电平,LED点亮。这里有一个问题,用if语句查询按键时,如果将IOPIN0&0X400得出的值赋给另一个变量,例如我程序中的temp,然后检测temp是否为0,结果protues仿真时会出错:不会判断if语句,而是跳过if语句,直接点亮LED。这里不知道为什么,是程序的问题,还是protues仿真的问题呢?3:按键控制LED闪烁具体程序见我的附带实例。基本上是在前一个实验的基础上增加闪烁效果,不停的使P0.0口高/低电平切换。这里有两种方法:一是循环灯亮-延时-灯灭-延时;二是使用取反,检测P0.0口电平,为高-则变低,为低-则变高。4:多按键控制LED闪烁具体程序见我的附带四个按键控制4个LED,按下相应按键时,LED闪烁。这个算法不是很好,我用的是一个一个检查,并且只能依次1-2-3-4,按键时才会被识别。加入LED1闪烁,按下K3时,则不会被识别。5:流水灯具体程序见我的附带跟51单片机的原理一样的。这里有2中方法,一是我写的先定义一个数组,然后在程序中直接调用该数组即可;另一种是用指针的方式,使灯亮的顺序递增。本例首先查询按键,有键按下时,灯开始从上到下流动。6:串口通信_查询方式具体程序见我的附带例子关于串口的工作原理,这里就不赘述了,可以参考周立功的那本书或随便找个单片机的书,都一样。这里说一下一个问题,周立功的书上说,在系统默认情况下,也就是上电复位时,系统频率Fcclk=外部晶振频率Fosc,VPB频率Fpclk=Fcclk/4,按照这样,如果在程序开头不进行分频设置,也就是采用系统默认的频率,计算出当串口波特率=9600时的除数锁存寄存器U0DLM/U0DLL的值,由公式得出(外部晶振11.0592MHz):U0DLM,U0DLL=(11059200÷4)/(16×9600)=18=0X0012则:U0DLM=0X00,U0DLL=0X12按照这个值写入程序里,并在protues里设置通信波特率为9600(如下图),结果仿真时无任何反映。说明,程序的波特率和protues设置的波特率不一致。然而,当按照默认系统频率Fcclk=5×Fosc计算U0DLM和U0DLL时(波特率为9600),protues仿真却能够正常通信。不知道是我那个环节弄错了,还是周立功的书上搞错了。。。这里有个问题?怎么接收字符