ARM学习笔记--GPIO接口
- 格式:doc
- 大小:273.50 KB
- 文档页数:10
一、GPIO常用模式高阻输入模式、推挽输出模式和开漏输出模式;二、常用IO口模式的分析及讲解a 高阻输入凡是挂在总线上的的寄存器或存储器等设备,他的输出和输入端不仅能呈现0/1状态,还可以呈现高阻态,此时可以理解被隔离,对总线的状态不起任何作用,总线可以做其他工作,三态控制器都有一个控制端,可以认为控制其工作模式。
上述是管脚的情况,其他管脚和上述类似。
输入模式就是一个带有施密特触发输入的三态缓冲器,有很高的输入阻抗。
施密特的作用是能将缓慢变化的或者畸形的输入脉冲波形整形成理想的矩形脉冲信号。
在执行GPIO读操作时,在脉冲Read Pulse的作用下会把管脚Pin的当前电平状态读到内部的总线上。
在不执行读操作时,外部管脚和内部总线互相隔离,互补干扰b 推挽输出模式推挽输出:在功率放大器电路中大量采用推挽放大电路,电路中的三极管够成放大电路,两只三级干交替工作在放大状态,这样把正弦波的两个半周期全部处在放大状态,最后在Pin 的负载上合成一个完整的放大波形。
推挽模式就是“把原来的数据上拉的意思”,通过内部小心好的变化来控制VDD的导通和截止,从而起到小信号控制大信号的作用,也就好像放大了源信号一样。
GPIO管脚在脉冲Write Pulse的作用下,内部数据被锁存在Q/Q'上面,TI和T2构成COMS反相器,在T1和T2低阻抗的情况下实现推挽输出内部电平的功能,但是T1和T2不能同时导通,否则用以烧坏反相器传输门。
在推挽模式下,GPIO还有回读功能,实现该功能的是三态门U2,在执行回读功能时,读到的是管脚的输出锁存状态,而不是Pin的状态,这一点切记。
c 开漏输出模式推挽输出和推挽输出结构一样,只是断开了p-mos管,连接n-mos管。
内不是1的时候,输出低电平,外部引脚直接和GND连接。
内不是0的时候,n-mos管不截止(通常需要外接上拉电阻才能真正以上输出高电平1,这里和mcs51单片机的P0口结构很类似)。
GPIO接口的原理及应用1. GPIO接口简介1.1 GPIO的含义GPIO(General Purpose Input/Output)是通用输入输出的简称,用于连接外部设备与计算机系统进行数据交互。
它是一种灵活的接口,可以根据需要配置为输入或输出模式,并支持不同的电压和信号类型。
1.2 GPIO接口的作用GPIO接口在嵌入式系统中起到了非常重要的作用。
它可以用来控制或接收外部设备的信号,如按钮、LED灯、传感器等,实现与外部世界的交互。
同时,GPIO接口也可以作为计算机系统与其他设备的通信通道,如串口通信、SPI通信等。
1.3 GPIO接口的特点•多功能性:可以配置为输入或输出模式。
•灵活性:可以根据需要进行配置和控制。
•低功耗:相比其他通信接口,GPIO接口通常功耗较低。
•低速度:相较于专用的通信接口,GPIO接口的传输速度较慢。
2. GPIO接口的工作原理2.1 输入模式在输入模式下,GPIO接口通常用于读取外部设备的信号,如按钮的按压状态、传感器的检测结果等。
工作原理如下:1.配置引脚模式:将GPIO接口的相应引脚设置为输入模式。
2.读取信号:读取引脚上的电平状态,判断外部设备的信号。
3.处理信号:根据读取到的信号进行相应的处理,如触发某个事件或改变某个状态。
2.2 输出模式在输出模式下,GPIO接口通常用于控制外部设备的状态,如控制LED灯的亮灭、驱动电机运动等。
工作原理如下:1.配置引脚模式:将GPIO接口的相应引脚设置为输出模式。
2.设置输出值:通过写入高或低电平来控制外部设备的状态。
3.控制设备:根据设置的电平状态,控制外部设备的工作状态。
3. GPIO接口的应用场景3.1 嵌入式系统在嵌入式系统中,GPIO接口被广泛应用于控制和读取外部设备的状态。
一些常见的应用场景包括: - 控制LED灯:通过GPIO接口控制LED灯的亮灭,实现状态指示或显示效果。
- 读取按键状态:将按键连接到GPIO接口,通过读取引脚的电平状态来检测按键的按压情况。
ARM9的裸奔(一)——GPIO的输入与输出S3C2440A有九组IO口,共130个。
每组IO口数目不同,其中A组口只有输出功能。
截图如下:关于对IO口的操作,就主要设计到3个寄存器。
GPXCON(配置),GPXUP(上拉使能),GPXDAT(数据)。
其中GPXCON配置IO寄存器中每两位控制1个IO口。
00表示输入,01表示输出,10表示第三功能,11保留。
对数据寄存器GPXDAT的操作则是相应位写1高电平,写0低电平。
上拉是能寄存器GPXUP则是相应位为1时禁止相应端口的上拉电阻,为0使能。
下面的代码实现了实现按下某个按键时,相应LED亮,松开按键时LED灭。
练习了IO口德输入与输出。
下面是我的原理图跟LED控制和按键控制相关的IO口。
写程序期间有个小插曲。
错把GPF6看成GPG6,直接让我郁闷了会儿,又是想当然做的怪。
看看其它5个口都是G口。
下面是程序代码:[cpp]view plaincopyprint?1.#include <S3C2440.h>2.#include "cfg.h"3.4.#define KEY1 (1<<1)5.#define KEY2 (1<<9)6.#define KEY3 (1<<10)7.#define KEY4 (1<<11)8.9.#define LED1 (1<<5)10.#define LED2 (1<<6)11.#define LED3 (1<<7)12.#define LED4 (1<<8)13.14.#define READ_KEY(x) (GPGDAT & (x))15.#define TURN_ON(x) (GPBDAT &= ~(x))16.#define TURN_OFF_LEDS (GPBDAT |= LED1 | LED2 | LED3 | LED4)17.#define TURN_ON_LEDS (GPBDAT &= ~(LED1 | LED2 | LED3 | LED4))18.19.void Key_led_init(void)20.{21.//LED Init22. GPBCON &= ~((3<<10) | (3<<12) | (3<<14) | (3<<16));23. GPBCON |= (1<<10) | (1<<12) | (1<<14) | (1<<16); //LED_IO configure output24. TURN_OFF_LEDS;25.//KEY Init26. GPGCON &= 0x0;27.}28.29.void Key_scan(void)30.{31.if(READ_KEY(KEY1) == 0)32. TURN_ON(LED1);33.else if(READ_KEY(KEY2) == 0)34. TURN_ON(LED2);35.else if(READ_KEY(KEY3) == 0)36. TURN_ON(LED3);37.else if(READ_KEY(KEY4) == 0)38. TURN_ON(LED4);39.else40. TURN_OFF_LEDS;41.}42.43.int main(void)44.{45. Key_led_init();46.47.while(1)48. {49. Key_scan();50. }51.}其中头文件cfg.h是一个配置文件,现在里面暂时只有一些数据类型的别名。
第1章GPIO1.1 GPIO本节以LPC1100系列Cortex-M0微控制器为例介绍了ARM微控制器的GPIO功能模块,包括如下内容:●GPIO的基本功能和扩展功能以及相关的基本概念、原理、结构;●GPIO功能的相关寄存器及其功能,以及寄存器的操作示例;●GPIO基本操作的部分重要知识点。
1.1.1 GPIO简介GPIO(General purpose Input/Output,通用输入/输出),顾名思义,它是一种用于完成(数字量)输入/输出的常规功能设备,广泛使用于从单片机到ARM微控制器的各种微控制器。
表1.1给出了LPC1100系列Cortex-M0微控制器的GPIO资源。
表1.1 LPC1100系列Cortex-M0微控制器的GPIO资源1.1.2 寄存器汇总LPC1100系列Cortex-M0微控制器的GPIO相关寄存器见表1.2。
表1.2 寄存器汇总★ 请读者注意,在读写GPIO 相关寄存器内的引脚功能位时,须确认该位对应的引脚是否存在。
例如,LPC1111的端口2只有一根引脚PIO2_0,那么读者在访问LPC1111内端口2对应的引脚方向寄存器GPIO2DIR 时,只能访问GPIO2DIR 的位0,访问其它位都是无效的,因为其它位没有对应的可配置引脚(GPIO2DIR 寄存器的位功能描述见图1.1)。
1.1.3 输入/输出功能1. 简介图1.1是ARM 微控制器GPIO 中和输入/输出功能相关部分的功能框图。
由图1.1可知,ARM 微控制器通过输入/输出数据寄存器存储GPIO 引脚上的数据;通过输入/输出接口电路,令输出的电平信号驱动外界设备并使输入的电平信号能够被ARM 微控制器准确识别和处理。
从单片机到ARM 微控制器,在输入/输出的功能上,GPIO 的基本结构和工作原理变化不大,下面对相关寄存器及其操作进行介绍。
图1.1 GPIO 输入/输出2.GPIO引脚的方向配置(1)简介LPC1100系列Cortex-M0微控制器的GPIO引脚在使用前须配置方向以确定是输入引脚还是输出引脚,这一点和标准80C51单片机不同。
固件库中与GPIO有关旳函数重要有:函数名描述GPIO_Init根据GPIO_InitStruct中指定旳参数初始化外设GPIOx寄存器GPIO_ReadInputDataBit读取指定端口管脚旳输入GPIO_ReadInputData读取指定旳GPIO端口输入GPIO_ReadOutputDataBit读取指定端口管脚旳输出GPIO_ReadOutputData读取指定旳GPIO端口输出GPIO_SetBits设置指定旳数据端口位GPIO_ResetBits清除指定旳数据端口位GPIO_WriteBit设置或者清除指定旳数据端口位GPIO_Write向指定GPIO数据端口写入数据1.1函数GPIO_Init函数名GPIO_Init函数原形void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)功能描述根据GPIO_InitStruct中指定旳参数初始化外设GPIOx寄存器输入参数1GPIOx:x可以是A,B,C,D或者E,来选择GPIO外设输入参数2GPIO_InitStruct:指向构造GPIO_InitTypeDef旳指针,包括了外设GPIO旳配置信息参阅Section:GPIO 输出参数无返回值无先决条件无被调用函数无1.1.1:GPIO_TypeDef为一构造体:typedef struct{__IO uint32_t CRL; // 端口配置低寄存器__IO uint32_t CRH;// 端口配置高寄存器__IO uint32_t IDR; // 端口输入数据寄存器__IO uint32_t ODR;__IO uint32_t BSRR;__IO uint32_t BRR;__IO uint32_t LCKR;} GPIO_TypeDef;GPIOx为一宏定义:#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)其中GPIOA_BASE=0x40010800,即PA口旳起始地址,#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)这句语句旳作用就是将GPIOA指定到PA口旳入口地址中,也就是说将PA口旳寄存器组取名为GPIOA。
LED跑马灯实验修改记录版本号. 作者描述修改日期0.1 徐珊First Draft 2011-9-21审核记录姓名职务签字日期标题文档编号版本页文档名 1.0 2 of 16LED跑马灯1.1 实验介绍GPIO即通用可编程输入输出口,在此我们通过GPIO编程实现一个跑马灯的实验。
该跑马灯实验是最简单,也是一般最先开始的一个实验,它可以搭建一个最小的工程项目,之后,所有的实验都可以建立在该项目之上,从而节省了在搭建过程中所消耗的时间和精力。
所有的 GPIO 操作都是以跑马灯为基础进行的。
1.2 实验目标1. 理解GPIO寄存器配置的相关知识2. 灵活运用 GPIO1.3 实验时间60分钟1.4 预备知识熟悉C语言知识,熟练MDK的使用1.5 实验步骤1.创建一个GPIO_1文件夹2.1 新建子文件夹User,用于存放用户源程序2.2 新建子文件夹RVMDK,用于存放去启动代码(STM32F10x.s)2.3 新建子文件夹Project,用户KEIL工程文件2.4 在Project下依次创建Obj和List子文件夹,存放编译过程中产生的中间文件。
标题文档编号版本页文档名 1.0 3 of 16具体如下图所示:4. 新建Keil MDK工程4.1 启动Keil uVision4,点击菜单 New uVision Project,新建一个工程,命名为GPIO标题文档编号版本页文档名 1.0 4 of 164.2 选择CPU类型为 STM32F107VC (这是MDV-STM32-107开发板采用的CPU类型)标题文档编号版本页文档名 1.0 5 of 164.3 当提示是否复制启动代码时,请选择否。
(为了工程目录标准化,稍后添加Keil软件自带的旧版本启动文件)4.4 根据自己的需要修改Target名字。
(名字任意)4.5 为了便于代码管理,在这个Project下创建几个Group (名字可以任意)User : 存放用户自己写的源代码RVMDK : 存放启动文件(汇编文件)标题文档编号版本页文档名 1.0 6 of 16标题文档编号 版本 页文档名1.0 7 of 164.6 创建好Group 后,我们开始依次添加文件。
通用I/O端口控制s3c6410使用通用IO端口进行相关LED的控制。
首先介绍通用IO相关的寄存器和通用IO端口的使用方法,然后详细介绍通用IO端口控制LED电路及相应驱动程序的开发。
通用IO端口概述每一个端口都可以由软件设置来满足各种系统配置和设计需求。
在启动程序之前,必须定义每个引脚用哪个功能。
通用IO口主要寄存器描述1.端口配置器(例如GPACON)端口控制寄存器(GPnCON)可以定义每个引脚的功能(n=A-----Q)2.端口数据寄存器(例如GPADAT)如果端口配置为输入端口,数据可以被写到GPnDAT寄存器对应的位上。
如果端口设置为输入端口,能从GPnDAT寄存器对应的位中读取数据。
3.端口上拉下拉寄存器(例如GPAPUD)端口上拉下拉寄存器控制着每个端口的上拉下拉的使能和禁止。
当对应位为0时,是允许的,为1时,是禁止的。
数字电路有三种状态:高电平、低电平、和高阻状态,有些应用场合不希望出现高阻状态,可以通过上拉电阻或下拉电阻的方式使处于稳定状态。
上拉电阻是用来解决总线驱动能力不足时提供电流的,下拉电阻是用来吸收电流。
4.外部中断控制寄存器(例如EINT0CON0)该寄存器可以配置外部中断请求信号的触发方式为低电平触发,高电平触发,下降沿触发,上升沿触发或者双边沿触发。
有16个EINT引脚能被用作唤醒中断。
典型的I/O口控制寄存器示例如果要控制IO口GPK0----GPK3,那么涉及端口的寄存器有GPKCON,GPKDAT,GPKPUD端口K配置寄存器GPKCON0(部分内容)端口K数据寄存器GPKDAT端口K上拉下拉寄存器GPKPUD通用IO口的两种应用电路 LED与GPIO的电路图示在这种应用中,需要将相应的端口设置为输出口,当输出口为0时,LED亮,当输出口为1时,LED熄灭。
LED旁接的电阻R为限流电阻,用来防止电流过大损坏LED。
为了保护IO引脚,选取阻值可以稍微大些,一般情况下选取0.5-----1k的电阻。
ARM学习笔记--GPIO接口GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
S3C2410共有117个I/O端口,共分为A~H共8组:GPA、GPB、...、GPH。
S3C2440共有130个I/O端口,分为A~J共9组:GPA、GPB、...、GPJ。
可以通过设置寄存器来确定某个引脚用于输入、输出还是其他特殊功能。
比如:可以设置GPH6作为输入、输出、或者用于串口。
1 GPIO硬件介绍1.1 通过寄存器来操作GPIO引脚GPxCON用于选择引脚功能,GPxDAT用于读/写引脚数据;另外,GPxUP用于确定是否使用内部上拉电阻。
x为B、...、H/J,没有GPAUP寄存器。
1.1.1 GPxCON寄存器从寄存器的名字可以看出,它用于配置(Configure)-选择引脚功能。
PORTA与PORTB~PORT H/J在功能选择方面有所不同,GPACON中每一位对应一根引脚(共23根引脚)。
当某位被设为0时,相应引脚为输出引脚,此时我们可以在GPADAT 中相应位写入0或是1让此引脚为低电平或高电平;当某位被设为1时,相应引脚为地址线或用于地址控制,此时GPADAT无用。
一般而言,GPACON通常被设为全1,以便访问外部存储器件。
PORT B~ PORT H/J在寄存器操作方面完全相同。
GPxCON中每两位控制一根引脚:00表示输入、01表示输出、10表示特殊功能、11保留不用。
1.1.2 GPxDAT寄存器GPxDAT用于读/写引脚;当引脚被设为输入时,读此寄存器可知相应引脚的电平状态是高还是低;当引脚被设为输出时,写此寄存器相应位可以令此引脚输出高电平或是低电平。
1.1.3 GPxUP寄存器GPxUP:某位为1时,相应引脚无内部上拉电阻;为0时,相应引脚使用内部上拉电阻。
上拉电阻的作用在于:当GPIO引脚处于第三态(即不是输出高电平,也不是输出低电平,而是呈高阻态,即相当于没接芯片)时,它的电平状态由上拉电阻、下拉电阻确定。
1.2 访问硬件1.2.1 访问单个引脚单个引脚的操作无外乎3种:输出高低电平、检测引脚状态、中断。
对某个引脚的操作一般通过读、写寄存器来完成。
访问这些寄存器是通过软件来读写它们的地址。
比如:S3C2410和S3C2440的GPBCON、GPBDAT 寄存器地址都是0x56000010、0x56000014,可以通过如下的指令让GPB5输出低电平。
#define GPBCON (*volatile unsigned long *)0x56000010) //long=int 4字节;char 1字节;short 2字节#define GPBDAT (*volatile unsigned long *)0x56000014)#define GPB5_out (1<<(582))GPBCON = GPB5_out;GPBDAT &= ~(1<<5);1.2.2 以总线方式访问硬件并非只能通过寄存器才能发出硬件信号,实际上通过访问总线的方式控制硬件更为常见。
如下图所示S3C2410/S3C2440与NOR Flash的连线图,读写操作都是16位为单位。
图中缓冲器的作用是以提搞驱动能力、隔离前后级信号。
NOR Flash(AM29LV800BB)的片选信号使用nGCS0信号,当CPU发出的地址信号处于0x00000000~0x07FFFFFF之间时,nGCS0信号有效(为低电平),于是NOR Flash被选中。
这时,CPU发出的地址信号传到NOR Flash;进行写操作时,nWE信号为低,数据信号从CPU发给NOR Flash;进行读操作时,nWE信号为高,数据信号从NOR Flash发给CPU。
ADDR1~ADDR20 ------------------> >--------------------A0~A19DATA0~DATA15 <-----------------> <------------------->D0~D15nOE ------------------> -------------------->nOEnWE ------------------> -------------------->nWEnGCS0 ------------------> -------------------->nCES3C2410/S3C2440 缓冲器NOR Flash(AM29LV800BB)软件如何发起写操作呢,下面有几个例子的代码进行讲解。
1)地址对齐的16位读操作unsigned short *pwAddr = (unsigned short *)0x2;unsigned short uwVal;uwVal = *pwAddr;上述代码会向NOR Flash发起读操作:CPU发出的读地址为0x2,则地址总线ADDR1~ADDR20、A0~A19的信号都是1、0...、0(CPU的ADDR0 为0,不过ADDR0没有接到NOR Flash上)。
NOR Flash 的地址就是0x1,NOR Flash在稍后的时间里将地址上的16位数据取出,并通过数据总线D0~D15发给CPU。
2)地址位不对齐的16位读操作unsigned short *pwAddr = (unsigned short *)0x1;unsigned short uwVal;uwVal = *pwAddr;由于地址是0x1,不是2对齐的,但是BANK0的位宽被设为16,这将导致异常。
我们可以设置异常处理函数来处理这种情况。
在异常处理函数中,使用0x0、0x2发起两次读操作,然后将两个结果组合起来:使用地址0x0的两字节数据D0、D1;再使用地址0x02读到D2、D3;最后,D1、D2组合成一个16位的数字返回给wVal。
如果没有地址不对齐的异常处理函数,那么上述代码将会出错。
如果某个BANK的位宽被设为n,访问此BANK时,在总线上永远只会看到地址对齐的n位操作。
3)8位读操作unsigned char *pwAddr = (unsigned char *)0x6;unsigned char ucVal;ucVal = *pwAddr;CPU首先使用地址0x6对NOR Flsh发起16位的读操作,得到两个字节的数据,假设为D0、D1;然后将D0取出赋值给变量ucVal。
在读操作期间,地址总线ADDR1~ADDR20、A0~A19的信号都是1、1、0、...、0(CPU的ADDR0为0,不过ADDR0没有接到NOR Flash上)。
CPU会自动丢弃D1。
4)32位读操作unsigned int *pwAddr = (unsigned int *)0x6;unsigned int udwVal;udwVal = *pwAddr;CPU首先使用地址0x6对NOR Flsh发起16位的读操作,得到两个字节的数据,假设为D0、D1;再使用地址0x8发起读操作,得到两字节的数据,假设为D2、D3;最后将这4个数据组合后赋给变量udwVal。
5)16位写操作unsigned short *pwAddr = (unsigned short *)0x6;*pwAddr = 0x1234;由于NOR Flash的特性,使得NOR Flash的写操作比较复杂——比如要先发出特定的地址信号通知NOR Flash准备接收数据,然后才发出数据等。
不过,其总线上的电信号与软件指令的关系与读操作类似,只是数据的传输方向相反。
2、使用软件来访问硬件当个引脚的操作有3种:输出高低电平、检测引脚状态、中断。
对某个引脚的操作一般通过读写寄存器实现首先我们从点亮LED开始,下图选自mini2440原理图,LED1-4分别对应GPB5-8如果要控制这些LED,那么我们首先要把GPBCON寄存器中GPB5-8对应的位设为输出功能,然后写GPBDAT 寄存器的相应位,使这4个引脚输出高低电平一般是低电平有效,即高电平时,对应LED熄灭,低电平时,对应LED点亮访问寄存器的时候,通过S3C2440的数据手册查到GPBCON和GPBDAT寄存器的地址,附数据手册点击下载GPBCON为0x56000010,GPBDAT为0x56000014通过下面的代码让GPB5输出低电平,点亮LED1#define GPBCON (*(volatile unsigned long *) 0x56000010) //volatile修饰符确保每次去内存中读取变量的值,还不是从cache或者寄存器中#define GPBDAT (*(volatile unsigned long *) 0x56000014)#define GPB5_OUT (1<<(5*2)) //两位控制一个引脚,那么GPB5就是GPBCON的[11:10]位,1左移10位,则[11:10]为01,表示GPB5为输出GPBCON = GPB5_OUT;GPBDAT &= ~(1<<5); //1左移5位取反,那么第5位为0,即GPB5输出低电平,点亮LED1二、GPIO操作实例1、使用汇编代码点亮一个LED先看源程序led_on.S.text.global _start_start:LDR R0,=0x56000010 @ R0设为GPBCON寄存器MOV R1,#0x00000400 @ 设置GPB5为输出口, 位[11:10]=0b01STR R1,[R0]LDR R0,=0x56000014 @ R0设为GPBDAT寄存器MOV R1,#0x00000000 @ 此值改为0x00000020,可让LED1熄灭STR R1,[R0] @ GPB5输出0,LED1点亮MAIN_LOOP:B MAIN_LOOP @无限循环再来看程序的Makefileled_on.bin : led_on.Sarm-linux-gcc -g -c -o led_on.o led_on.Sarm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elfarm-linux-objcopy -O binary -S led_on_elf led_on.binclean:rm -f led_on.bin led_on_elf *.oled_on.S生成led_on.bin第一行做汇编第二行做连接,指定代码段起始地址为0x00000000第三行把ELF格式转为二进制格式clean用于清除编译生成的文件2、使用c语言代码点亮LED汇编可读性比C差,我们用C来实现@*************************************************************************** ***@ File:crt0.S@ 功能:通过它转入C程序@*************************************************************************** ***.text.global _start_start:ldr r0, =0x53000000 @ WATCHDOG寄存器地址mov r1, #0x0str r1, [r0] @ 写入0,禁止WATCHDOG,否则CPU会不断重启ldr sp, =1024*4 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K,这4k是steppingstone,后面会介绍@ nand flash中的代码在复位后会移到内部ram中,此ram只有4Kbl main @ 调用C程序中的main函数halt_loop:b halt_loop下面是led_on_c.c#define GPBCON (*(volatile unsigned long *)0x56000010)#define GPBDAT (*(volatile unsigned long *)0x56000014)int main(){GPBCON = 0x00000400; // 设置GPB5为输出口, 位[11:10]=0b01GPBDAT = 0x00000000; // GPB5输出0,LED1点亮return 0;}最后是Makefileled_on_c.bin : crt0.S led_on_c.carm-linux-gcc -g -c -o crt0.o crt0.Sarm-linux-gcc -g -c -o led_on_c.o led_on_c.carm-linux-ld -Ttext 0x0000000 -g crt0.o led_on_c.o -o led_on_c_elfarm-linux-objcopy -O binary -S led_on_c_elf led_on_c.binarm-linux-objdump -D -m arm led_on_c_elf > led_on_c.disclean:rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o分别汇编crt0.S和led_on_c.c连接目标到led_on_c_elf,代码段起始地址位0x00000000转换ELF格式到二进制led_on_c.bin最后转换结果为汇编码方便查看3、测试程序在先前搭建的编译环境中进入代码目录#make得到的bin文件,在win中使用dnw下载到开发板,设置串口波特率,对应端口,8N1,下载地址0x00000000开关拨到nor flash,打开电源,出现菜单以后,选择a然后选择USB PORT-transmit/restore,选择编译好的bin文件然后开关拨到nand启动,效果如下:(设置LED1和LED4亮)4、使用按键来控制LEDK1-K6如上图对应GPG,我们使用K1-K4操作LED1-LED4@*************************************************************************** ***@ File:crt0.S@ 功能:通过它转入C程序@*************************************************************************** ***.text.global _start_start:ldr r0, =0x56000010 @ WATCHDOG寄存器地址mov r1, #0x0str r1, [r0] @ 写入0,禁止WATCHDOG,否则CPU会不断重启ldr sp, =1024*4 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K,这4k是steppingstone,后面会介绍@ nand flash中的代码在复位后会移到内部ram中,此ram只有4Kbl main @ 调用C程序中的main函数halt_loop:b halt_loop下面是key_led.c文件#define GPBCON (*(volatile unsigned long *)0x56000010)#define GPBDAT (*(volatile unsigned long *)0x56000014)#define GPGCON (*(volatile unsigned long *)0x56000060) #define GPGDAT (*(volatile unsigned long *)0x56000064)/** LED1-4对应GPB5、GPB6、GPB7、GPB8*/#define GPB5_out (1<<(5*2))#define GPB6_out (1<<(6*2))#define GPB7_out (1<<(7*2))#define GPB8_out (1<<(8*2))/** K1-K4对应GPG0、GPG3、GPG5、GPG6*/#define GPG7_in ~(3<<(6*2))#define GPG6_in ~(3<<(5*2))#define GPG3_in ~(3<<(3*2))#define GPG0_in ~(3<<(0*2))int main(){unsigned long dwDat;// LED1-LED4对应的4根引脚设为输出GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;// K1-K4对应的2根引脚设为输入GPGCON = GPG0_in & GPG3_in & GPG6_in & GPG7_in ;while(1){//若Kn为0(表示按下),则令LEDn为0(表示点亮)dwDat = GPGDAT; // 读取GPG管脚电平状态if (dwDat & (1<<0)) // K1没有按下GPBDAT |= (1<<5); // LED1熄灭elseGPBDAT &= ~(1<<5); // LED1点亮if (dwDat & (1<<3)) // K2没有按下GPBDAT |= (1<<6); // LED2熄灭elseGPBDAT &= ~(1<<6); // LED2点亮if (dwDat & (1<<5)) // K3没有按下GPBDAT |= (1<<7); // LED3熄灭elseGPBDAT &= ~(1<<7); // LED3点亮if (dwDat & (1<<6)) // K4没有按下GPBDAT |= (1<<8); // LED4熄灭elseGPBDAT &= ~(1<<8); // LED4点亮}return 0;}最后是Makefilekey_led.bin : crt0.S key_led.carm-linux-gcc -g -c -o crt0.o crt0.Sarm-linux-gcc -g -c -o key_led.o key_led.carm-linux-ld -Ttext 0x0000000 -g crt0.o key_led.o -o key_led_elf arm-linux-objcopy -O binary -S key_led_elf key_led.binarm-linux-objdump -D -m arm key_led_elf > key_led.dis clean:rm -f key_led.dis key_led.bin key_led_elf *.o测试效果。