首先感谢爱板网,这个活动很好,受益匪浅,在其中学习到很多东西。 我之前是做MSP430系列的,由于单片机资源的限制,需要用到ARM,所以想要学习ARM,当时准备买块板子,后来偶然的机会发现爱板网有个活动,一看又是很TI的,那个心动啊,呵呵,然后我运气比较好,有机会借过来玩玩,我之前没有接触过ARM,没有什么了解,我写这个帖子,分享我学习的一些经验和在学习ARM过程中遇到的问题,大神级别的可以忽略这个帖子,菜鸟可以看看。有什么错误和不足的地方还望大家指教和纠正,谢谢。 第一章 编译环境和编译器 拿到板子,硬件已经有了,那需要编译器和编译环境,关于ARM的编译器,有很多,主要是IAR,KEIL,当看见有IAR 的时候,那个开心啊,因为之前一直用IAR ,但是这次不想用了,因为不想依赖于一个编译器,所以想尝试其它的,由于这个板子是TI的,所以CCS也是支持的。 关于编译软件下载,我建议到KEIL和IAR的官网下载,因为有些时候在其它地方下载的可能会遇到一些未知的情况,为了避免以后遇到问题,建议到官网下载,这里我以KEIL为例。 http://www.keil.com/arm/mdk.asp 。 下载安装完成之后,需要破解,在这里我提下,在破解的时候需要把FILE Licence Management 中的CID COPY到破解软件中,不然会出现无法破解的情况,网上提到的可能不是很多。
在这里我们用的是Stellaris_LM3S9B96,我们需要下载TI的驱动库,这个需要到TI的官网下载,这里有点麻烦,我申请了两天才收到TI发回来的下载链接,大家需要点耐心。 下载地址http://www.ti.com/tool/sw-lm3s 。 关于一个芯片,我们需要了解它,最好的途径就是它的DATASHEET,下载个它的DATASHEET就行了,建议还是看英文版的,可能中文版的有些时候翻译的不是很准确,可能会造成理解错误。 关于编译环境,keil的配置,在C,C++这个标签中我们需要配置头文件的路径如图:
Inlude paths添加的是头文件的路径这个路径一定要对。 DUG中配置成这样
在use中要选择RUN TO MAIN 我之前没有点击,这样做的后果就是导致程序下载之后跳不到MAIN 函数,左边simulator中是仿真用的,功能还是不错的。右边是硬件仿真。如果是下载到板子中不要选择错。 可能有人遇到程序下载不进去,在Utilities 中设置成这样如图:
这个是板子对应的编译器,选择错程序是下载不进去的。 关于建工程,每个文件需要加Startup.s这个很重要,以及驱动库,每个文件需要包含driverlib.lib这个其实库文件,是头文件转化成的一个库,需要加载(你也可以加载.h.c的文件原理是一样的)。工程建成如下图所示。
备注:关于在RAM和ROM的配置问题,一般情况下先默认设置,在以后需要用的情况下,再做修改。 第二章 初识Stellaris_LM3S9B96——GPIO 大体看下Stellaris_LM3S9B96的芯片资料看下,芯片资源,大体有个了解就行,从下面这个图我们就可以很容易的看出这个芯片内部有什么。
这里我们关注下GPIO口,GPIO代表什么其实是General-Purpose Input/Outputs (GPIOs)的简称,这里我觉得,对于一个缩写还是知道它的英文全称比较好。我这里以GPIO做个简单的说明,很多人不是很关注英文缩写的意思。 LM3S9B96 datasheet中的对GPIO的说明:The GPIO module is composed of nine physical GPIO blocks, each corresponding to an individual GPIO port (Port A, Port B, Port C, Port D, Port E, Port F, Port G, Port H, Port J). The GPIO module supports up to 65 programmable input/output pins, depending on the peripherals being used. 这段英文不复杂,我不翻译了,呵呵。
关于引脚怎么操作,我用CODE 直接解释, 程序说明:LED闪烁。 #include "hw_ints.h" // memmAP的上一级库 #include "hw_memmap.h" //存储单元分配 #include "hw_types.h" // driverlib上一级库 #include "gpio.h" //GPIO函数库 #include "sysctl.h" //系统设置 关于头文件,其实这个怎么说呢,开始时候你不熟悉,先这样写着,然后在以后的程序用,自己慢慢去查,就会明白了,开始的时候没有必要太在意,只要程序不报错,就行,当然你得知道头文件的意思,不然怎么知道添加什么,关于头文件里面是什么可以先不用管。 由于板子上面是GPIOF PIN3 接的是LED,所以,用F.3这个GPIO口。 #define PINS GPIO_PIN_3 void delay(int d); int main(void) { SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);// SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);//使能外设GIOPB GPIOPadConfigSet(GPIO_PORTF_BASE, PINS, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD);//配置管脚驱动,驱动电流2MA其实已足够 GPIODirModeSet(GPIO_PORTF_BASE, PINS, GPIO_DIR_MODE_OUT);//设置管脚输出 while(1) { GPIOPinWrite(GPIO_PORTF_BASE, PINS, PINS);//输出高电平 delay(2000000);//延时 GPIOPinWrite(GPIO_PORTF_BASE, PINS, ~PINS);//输出低电平 delay(2000000);//延时 } } void delay(int d)//延时函数 { for( ; d; --d); } 学习ARM 可能开始的时候不太熟悉,我开始也不太熟悉,主要原因其实是函数库不熟悉,关于函数库,不用每个函数都记得,只需要在你需要用的时候,能找到就行,关于怎么用,在TI 给的API中已经说明了。
下面解释下voidSysCtlClockSet(unsigned long ulConfig) 它是系统时钟设置:参数是ulConfig ulConfig is the required configuration of the device clocking。 SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN| SYSCTL_XTAL_16MHZ 这句话的意思是不分频选择外部时钟作为主时钟频率为16M,为什么这么解释呢? 看SYSCTL_SYSDIV_1的宏定义是什么 #define SYSCTL_SYSDIV_1 0x07800000 // Processor clock is osc/pll /1 现在应该能够明白为什么是时钟不分频了,其实也不需要看宏定义看它怎么写的也能够明白 SYSTEM CONTROL ————SYSTEM DIVIDE 1 其实就是宏定义的全称,系统控制———系统分频1 不就是不分频嘛,其它的我就不多解释了,方法会了其它也就不难了。 关于函数怎么用,请大家查找Stellaris® Peripheral Driver Library中的 SysCtlClockSet的说明,里面说明的很详细,开始的时候只需要了解怎么用。 SysCtlPeripheralEnable,这个函数库比较简单 就是使能端口,对于一个函数的使用,我们看它的名称也能够大体知道是什么意思。System control peripheral enable 其实就是这个函数的缩写,系统使能外部端口。 GPIOPadConfigSet,GPIO PAD configure set 设置哪个引脚输出,驱动电流,模式是什么。
关于输出模式有好几种: #define GPIO_PIN_TYPE_STD 0x00000008 // Push-pull #define GPIO_PIN_TYPE_STD_WPU 0x0000000A // Push-pull with weak pull-up #define GPIO_PIN_TYPE_STD_WPD 0x0000000C // Push-pull with weak pull-down #define GPIO_PIN_TYPE_OD 0x00000009 // Open-drain #define GPIO_PIN_TYPE_OD_WPU 0x0000000B // Open-drain with weak pull-up #define GPIO_PIN_TYPE_OD_WPD 0x0000000D // Open-drain with weak pull-down #define GPIO_PIN_TYPE_ANALOG 0x00000000 // Analog comparator 在头文件中我们看到这个定义,也许你就能明白了,这个还是比较重要的,需要注意下。 GPIODirModeSet :Sets the direction and mode of the specified pin(s) 设置输出方向。 函数定义 void GPIODirModeSet(unsigned long ulPort, unsigned char ucPins, unsigned long ulPinIO) GPIOPinWrite:Writes a value to the specified pin(s). 写值到特定的端口 函数定义 void GPIOPinWrite(unsigned long ulPort, unsigned char ucPins, unsigned char ucVal) 当然其实这些引脚配置还可以用一个函数代替就是GPIOPinTypeGPIOOutput(unsigned long ulPort, unsigned char ucPins),可以代替上面的几个函数,但是这个函数不能配置引脚输出类型,比如驱动电流和推挽输出 加上拉下拉。 这个是为什么呢?我们可以看下这个函数定义什么,在GPIO.C中有对这个函数的定义: void GPIOPinTypeGPIOOutput(unsigned long ulPort, unsigned char ucPins) { ASSERT(GPIOBaseValid(ulPort)); // // Set the pad(s) for standard push-pull operation. // GPIOPadConfigSet(ulPort, ucPins, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); // // Make the pin(s) be outputs. // GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_OUT); } 看完这个函数的定义,你应该明白为什么能够代替上面程序中那些引脚的配置了,因为在这个函数中已经包括的,但是是写死的,你无法更改。 到这里面就基本了解这个程序的框架,然后我们download 程序到板子,就能看到LED 闪烁。 在这里我想特意说下函数库,之前做单片机的,现在转向ARM,开始的时候不是很习惯,其实它就是封装,把你需要用到的功能给你做好了,其实就是这么简单,函数库你用多了,就能够熟悉了。 关于函数库为什么能够实现这个功能,其实还是操作的寄存器,关于这个我以后再用一个帖子来写吧。 最近也比较忙,拿到这个板子拿到手也有段时间了,也没有什么反应,写个学习的心得,其实这个只是个入门,过几天写个 串口 中断 定时器 时钟的帖子上来,说说我在其中遇到的一些好玩的问题。 帖子中有写的不对的,还请指教。有的地方也说的不是很详细,其实学习的方法很重要,我上面说了一些方法,关于一些更深入的,以后再写。 忘了一件事,keil 软件的问题,其实一个软件,拿到手不会用,我开始的时候也不会用,也不用网上找什么教程,可以多看看软件自己自带的HELP 里面说的很详细,怎么使用它怎么建工程调试等等。看完这些,你应该用这个软件很熟悉了,最起码也能称作高手了,一些教程其实也是翻译HELP里面的东西,道理都是一样的。
待续~~~~~~~~~~~~~~~~~~~~~~~~~~
|