在keil下开发lpc176x

更新时间:2024-01-16 23:06:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一、创建工作项目

第一步,建立工作目录:

这一步完全按照个人的使用习惯,比如我会在文件夹中建立五个子目录,分别是usr,用来放置上层的程序文件;cm3,用来存放内核与底层设备文件;driver,用来放置模块驱动文件;obj,用来放置编译的中间文件和生成的二进制文件,如*.axf文件;lst,用来放置编译的列表文件。

cm3 driver 项目文件夹 usr lst

cm3中的文件有:core_cm3.c, core_cm3.h, LPC17xx.h, system_LPC17xx.c, system_LPC17xx.h, type.h和startup_LPC17xx.s。其中startup_LPC17xx.s可由keil自动生成,其它的文件可从NXP的官方网站中下载。lst和obj的文件夹中的文件由keil自动生成。 第二步,建立项目:

obj

将项目文件放到项目文件夹中就可以了,接着会让你选择CPU的型号:

接下来会出现

是否生成启动文件,选是,会生成startup_LPC17xx.s,我将其放入了cm3文件夹中。

接下来就是建立项目虚拟文件夹,并将内核文件等已有的文件加入项目中

最后我们的目录是:

然后我们建立主函数入口程序:

建立一个最简单的主函数,然后另存到真实目录usr中,然后加载到虚拟目录usr中

完成后为:

第三步,设定各项参数:

其中在Output和Listing中,分别把目录设为Obj和lst,具体可见教程中,我们主要说C/C++、Debug和Utilities的选项。

其中,Define中可以填写需要预定义的宏,Optimization中的Level 0(-O0)表示优化参数,Level后面的数字越大,表示优化程度越高,但是优化程度的提高可能导致Debug的失败,

因此我们一般选择0,等到程序全部测试成功后再用高优化参数进行编译。

Simulator表示使用虚拟仿真技术,也就是Keil自带的ARM虚拟机来进行仿真,一般我们使用时会选中下面的Limit Speed to Real-Time,使虚拟机的时钟和实际的时间保持一致。而选中右面的部分左上角的单选按钮后,使用仿真器在实际的目标板上进行调试,仿真器有很多种,注意要选对你所用的仿真器,不然没有办法进行调试。我们选择的是CooCox Debuger,这是我们根据开源仿真器ColinkEx自制的仿真器。在Run to main前面的多选框中打勾,这是使每次目标板重启是程序指针从main中开始。

如果我们使用硬件仿真调试,接下来我们的工作是配置仿真器,按Settings会出现设置对话框,不同的仿真器的界面是不同的。在Debug选项中,确定仿真器的名称、连接方式和下载速率。然后在Flash Download中添加嵌入式芯片Flash的种类。

这样,项目最基本的设置完成了,下一步开始编写程序,在这之前不妨编译一次看看。

得到编译结果:

没有错误,也没有警告。这样,我们引用的那些头文件就可以看到了:

下面来介绍这几个文件:startup _LPC17xx.s是汇编语言的文件,它根据ARM本身型号不同来设定一些最基本的参数,比如中断的名称和中断矢量就是在这里定义的。core_cm3.c和core_cm3.h是内核文件,里面主要是__ASM类型的函数,也就是嵌入到c语言中的汇编语言函数,它们主要对ARM进行底层的操作,我们一般不会用到;system_LPC17xx.c和system_LPC17xx.h是时钟初始化文件,它的作用是定义时钟的运行方式,在这个文件中一共有两个函数:SystemInit(),用来初始化时钟,在我们对ARM操作之前必须执行这个函数(或者运行由程序员自己编写的时钟初始化函数);另一个函数为SystemClockUpdate(),它可以在程序运行过程中改变时钟参数;type.h是关于数据类型的定义,它主要来定义那些标准c语言中本来没有的数据类型,比如bool型;lpc17xx.h是这里面最重要的一个文件,我们编程主要依靠的文件就是它,它的作用是将所有寄存器的地址映射到容易识别的字符上,便于我们操作。

二、GPIO的使用

下面是关于GPIO的使用,也是ARM系列使用的基础。对于ARM,它的功能比8051系列单片机强大很多,也灵活很多,这造成了使用起来比8051系列要复杂很多。

ARM的嵌入式芯片使用起来,有着和c语言很相似的特点——先声明,后使用。ARM的各个功能模块都是由寄存器组成的,我们使用ARM,本质上就是对它的各种寄存器进行操作,我们使用哪个模块,首先在确定它的性质的寄存器中写入数据,然后再对其进行操作。

我们打开lpc17xx.h文件,可以看到lpc17xx的寄存器结构,为了集中注意力我们只说GPIO相关的部分,我们来看结构体LPC_GPIO_TypeDef,它定义了每个GPIO端口的寄存器对应的结构体,它根据ARM中GPIO寄存器的地址来定义的结构体(比如次结构体中的uint32_t RESERVED0[3]; 是为了和寄存器的地址一一对应),结构体中的成员的作用为: 联合体FIODIR,用来定义端口中每个引脚数据传输的方向,例如: LPC_GPIO_TypeDef* P1; //定义GPIO结构体指针P1

P1->FIODIR = 0x000000FF; //此结构体中,低8位引脚为写,其它引脚为读 联合体FIOMASK,用来定义端口中的引脚是否被屏蔽(只取0值),例如:

P1->FIOMASK = 0x00000001; //此结构体中,0引脚被屏蔽——即不可用 联合体FIOPIN,用来存放端口中每个引脚的数值,例如:

P1->FIOPIN = 0x00000003; //给寄存器的0、1两位写入1(因为屏蔽第0位无法输出),执行后此寄存器的值为0x00000002

a = P1->FIOPIN; //将P1数据寄存器中的数值写入变量a中 联合体FIOSET,输出模式下改变寄存器的引脚电平为高电平,例如:

P1->FIOSET = 0x0000003F; //令低6位引脚置1(因为屏蔽第0位无法输出),执行后此寄存器的值为0x0000003E。

联合体FIOCLR,输出模式下改变寄存器的引脚电平为低电平。

至于为什么P1后面要用“->”而不是“.”请查询任意一本C语言的书籍。

当我们在程序中写入main.c中:

编译无错后,进行调试(Debug),在调试过程中,因为我们用到的资源都是片上设备,因此用软件仿真即可(还能省硬件)。我们打开片上设备显示窗口(无论是软件还是硬件仿真

都可以通过这个菜单来观察设备运行情况)。

最后进行步进调试,我们就能得到我们预计的结果了。

其中有一句话:P1 = LPC_GPIO0; 是没有讲过的,这句话的意义很大,前面我们说结构体LPC_GPIO_TypeDef很重要,它里面的成员结构与内存中相应寄存器的地址相对应,但是我只说了一半,了解C语言的同学应该知道,他只是一个表示变量的数据结构,如果不定义变量,就没有实际的作用。于是我定义了一个P1的变量,P1是表示LPC_GPIO_TypeDef结构体的指针,即P1是一个长整形值,里面存放着具有LPC_GPIO_TypeDef结构的地址。但是地址的值是多少必须我们为它设定,这就是头文件lpc17xx.h后半部分的意义了,它的后半部分主要定义了一些宏定义,对应着寄存器的地址,其中有这样一句话:

#define LPC_GPIO0 ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE ) 它将宏定义LPC_GPIO0定义为另一个宏定义LPC_GPIO0_BASE,不过将其类型强制转换为LPC_GPIO_TypeDef结构体的指针。而LPC_GPIO0_BASE的值可参考:

#define LPC_GPIO0_BASE (LPC_GPIO_BASE + 0x00000)

这句话将LPC_GPIO0_BASE的值定义为LPC_GPIO_BASE的值加上偏移量0,LPC_GPIO _BASE的含义可参考:

#define LPC_GPIO_BASE (0x2009C000UL)

其中0x2009C000UL就是GPIO寄存器的一个基准地址。可以说,所有的操作都是基于这种方式的,看懂了lpc17xx.h就可以实现lpc系列的CPU90%以上的功能。

此外,lpc17xx中,每个引脚除了通用的输入输出功能外,还有其它功能以及输入输出模式,通过改变结构体LPC_PINCON_TypeDef的值来实现。

在LPC_PINCON_TypeDef中,有三类成员, PINSEL、PINMODE和PINMODE_OD。其中PINSEL来声明引脚的功能,在lpc17xx中,一个引脚最多有4种功能,用二进制数值表示就是:00、01、10和11,占两位2进制数,因此端口0对应两个32位二进制变量:PINSEL0和PINSEL1。每个引脚的电气性质由PINMODE来定义,同样对应4种特性:上拉、中继、浮空和下拉,占两位2进制数,也对应两个32位二进制变量。最后一种成员PINMODE_OD表示引脚是否为开漏模式,1为开漏模式,0为正常模式(有些功能时需要,比如I2C通信时)。

直接操作寄存器相对比较麻烦,因此我们一般的方法是先写出一套操作寄存器的函数库,然后利用函数库对GPIO进行操作。我的GPIO函数库为lpc_GPIO.c和lpc_GPIO.h 文件,它们可以对GPIO进行更方便的控制。虽然我编写的程序能够实现GPIO的功能,但是相对比较罗嗦,希望能够进一步精简。

三、外部中断

lpc17xx的外部中断有两种,一种是单引脚中断,有四个,为P2.10~P2.13,分别占有四个中断源EINT0~EINT3;一种是端口中断,为GPIO0和GPIO2,与P2.13共用中断源EINT3,对于中断的基本设置,例如中断优先级、触发模式和中断标志位等在lpc17xx.h中声明。外部中断特性的寄存器对应的结构体为LPC_SC_TypeDef中的,EXTINT、EXTMODE和EXTPOLAR它们分别来表示中断的标志、模式和极性。我们使用时首先需要写这三个结构体对应的寄存器。

EXTMODE对应中断模式控制寄存器,它的0~3位分别对应中断源0~3的中断触发模式,此位为0时,为电平触发,为1时,为边沿触发。而EXTPOLAR定义中断触发值,也是使用了0~3位,此位为0时,为低电平有效或下降沿触发,为1时,为高电平有效或上升沿触发。

对于单引脚中断,使用的是P2.10~P2.13的第二功能。例如,我们要使用EINT2,上升沿触发,我们的程序写为:

其中我们利用或运算而不是直接赋值的目的是为了不影响其它位的数值。编译成功后进行软件调试:

这是程序运行之后的结果,一目了然。

对于端口中断,与引脚中断不同,并不是改变引脚的功能,而是相当一个复加的功能,当相应的端口寄存器数值变化时,产生中断。这需要对另一个寄存器进行设置,这个寄存器对应的结构体是LPC_GPIOINT_TypeDef。在这个结构体中一共有如下几个成员: IntStatus 总端口中断标志寄存器(只读)

IO0IntStatR 端口0上升沿中断标志寄存器(只读) IO0IntStatF端口0下降沿中断标志寄存器(只读) IO0IntClr 端口0标志清除寄存器(只写) IO0IntEnR 端口0上升沿中断使能(读写) IO0IntEnF 端口0下降沿中断使能(读写)

IO2IntStatR 端口2上升沿中断标志寄存器(只读) IO2IntStatF端口2下降沿中断标志寄存器(只读) IO2IntClr 端口2标志清除寄存器(只写) IO2IntEnR 端口2上升沿中断使能(读写) IO2IntEnF 端口2下降沿中断使能(读写)

当我们想使用端口0的第4引脚做下降沿中断时: LPC_GPIOINT->IO0IntStatF = (0x00000001<<4);

接下来我们来讲中断的过程。当我们设置的中断条件达到后,应该开启中断,即执行中断矢量地址处的程序。在ARM中,中断对应的中断矢量地址程序的名称在startup_LPC17xx.s中定义:

…… DCD EINT0_IRQHandler ; 34: External Interrupt 0 DCD EINT1_IRQHandler ; 35: External Interrupt 1 DCD EINT2_IRQHandler ; 36: External Interrupt 2 DCD EINT3_IRQHandler ; 37: External Interrupt 3

……

用汇编语言写出了中断矢量地址对应程序的名称。我们在程序文件中建立一个名为EINT0_IRQHandler的函数,此函数对应着外部中断0。

在ARM中中断有256个优先级其定义可以参考Cortex-M3手册,我们在这里介绍一个简单的使用方法。由于中断直接由Cortex的内核确定,因此它的优先级控制程序在

core_cm3.h中。在core_cm3.h中,有一个名为NVIC functions的部分,里面都是关于中断控制的程序,NVIC_SetPriorityGrouping(uint32_t)是用来设置中断优先级的,参数越小,优先级越高。NVIC_EnableIRQ(IRQn_Type IRQn)和

NVIC_DisableIRQ(IRQn_Type IRQn)分别用来开启和关闭中断,IRQn表示中断号,关于中断号,在LPC17xx.h中LPC17xx Specific Interrupt Numbers部分给出。

中断开启时,系统就会等待中断触发,当中断触发时,系统会自动调用相应的中断函数,在执行中断函数时,不要忘记清中断标值位。

四、电源及时钟开关

为了降低功耗,并不是所有的片上设备都保持开启,我们可以控制某些设备开启,关闭某些不用的设备以达到降低功耗的目的(其实对于初学者的意义在于,有时我们往往因为没有开启某设备而不能使之运行)。关于控制开关的结构体为LPC_SC_TypeDef,在

LPC17xx_system.c中的SystemInit中已经进行了一般的设置,能够解决大部分常用设备的运行,但是某些设备是默认关闭的(例如以太网),关于详细的功能,可以参考LPC17xx用户手册。

本文来源:https://www.bwwdw.com/article/9bfo.html

Top