s3c2440有130个I/O口,GPA,GPB...GPJ通过设置寄存器来确定其功能。
GPxCON寄存器:
选择引脚的功能,GPBCON-GPJCON每两位控制一根引脚: 00表示输入,01表示输出,10表示特殊功能,11保留不用。
GPACON特殊,每一位控制一根引脚,共23根,某位为0时,为输出引脚,当某位1时,相应引脚为地址线或用于地址控制, 此时GPADTA无用。
一般的,GPACON设为全1,以便访问外部存储器件。
GPxDAT寄存器:
当引脚为输入时,读其对应位可知电平状态是高还是低。
当引脚为输出时, 写寄存器对应位则引脚输出高电平或低电平。
GPxUP寄存器:
某位为1时,相应引脚无内部上拉电阻,为0时,相应引脚使用内部上拉电阻 。
这里只讨论GPIO口的使用,其余的做成子函数,直接调用,可暂时不深究。
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
/* 延迟函数*/
void delay(U32 count)
{
U32 i,j;
for(i=count;i>0;i--)
{
for(j=0;j<10000;j++);
}
}
int Main(int argc,char **argv) //main函数
{
U8 key;
U32 mpll_val=0;
mpll_val = (92<<12)|(1<<4)|(1);
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //设置主时钟频率405MHZ
ChangeClockDivider(key, 12); //设置时钟驱动频率的函数
MMU_DisableICache(); //对内存管理单元MMU的设置
MMU_DisableDCache();
//呵呵,第一次 看到Arm是不是很晕,先不管他以上是我照搬过来的。
//以下是GPB配制寄存器和数据寄存器
rGPBCON=0x155555; //控制GPBCON全部为01,即输出
while(1)
{
/*rGPBDAT = (0x0e<<5); //00001110左移5位,LED1亮
delay(120);
rGPBDAT = (0x0d<<5); //00001101左移5位,LED2亮
delay(120);
rGPBDAT = (0x0b<<5); //00001011左移5位,LED3亮
delay(120);
rGPBDAT = (0x07<<5); //00000111左移5位,LED4亮
delay(120);*/
//从LED1到LED4依次亮
rGPBDAT=(0x0e<<5);
delay(120);
rGPBDAT<<=1;
delay(120);
rGPBDAT<<=1;
delay(120);
rGPBDAT<<=1;
//从LED4到LED1依次亮
rGPBDAT=0x0e0;
delay(120);
rGPBDAT>>=1;
delay(120);
rGPBDAT>>=1;
delay(120);
rGPBDAT>>=1;
delay(120);
//两边灯往中间亮
rGPBDAT=0x0c0;
delay(120);
rGPBDAT=0x120;
delay(120);
//全亮全灭两次
rGPBDAT=0x0;
delay(60);
rGPBDAT=0x1e0;
delay(60);
rGPBDAT=0x0;
delay(60);
rGPBDAT=0x1e0;
delay(60);
//蜂鸣器响
rGPBDAT=0x0f;
delay(120);
}
}
以上是我编写的例子,以下是摘自互联网
===========性感的分隔线============
KEY+LED测试
/*
LED IO控制,数据,上拉寄存器
*/
#define GPBCON (*(volatile unsigned *)0x56000010)
#define GPBDAT (*(volatile unsigned *)0x56000014)
#define GPBUP (*(volatile unsigned *)0x56000018)
/*
KEY IO控制,数据,上拉寄存器
*/
#define GPGCON (*(volatile unsigned *)0x56000060)
#define GPGDAT (*(volatile unsigned *)0x56000064)
#define GPGUP (*(volatile unsigned *)0x56000068)
寄存器地址,可参考2440的datasheet
/*
LED1-4对应的GPB5,GPB6,GPB7,GPB8
*/
#define GPB5_out (1<<(5*2)) //LED1
#define GPB6_out (1<<(6*2)) //LED2
#define GPB7_out (1<<(7*2)) //LED3
#define GPB8_out (1<<(8*2)) //LED4
LED,将十进制1左移多少位,对着datasheet从高位向底位自己手写一次,就明白了,刚开始我也不明白为什么用这样方式。
K1-K6对应GPG0,GPG3,GPG5,GPG6,GPG7,GPG11
*/
#define GPG7_in ~(3<<(7*2)) //key5
#define GPG6_in ~(3<<(6*2)) //key4
#define GPG5_in ~(3<<(5*2)) //key3
#define GPG3_in ~(3<<(3*2)) //key2
#define GPG0_in ~(3<<(0*2)) //key1
{
/*用作读取KEY状态值*/
unsigned long dwDat=0;
/*LED1~LED4对应的4根引脚设为输出*/
GPBCON=GPB5_out | GPB6_out | GPB7_out | GPB8_out; //将输出的引脚在配置寄存器中设为01
/*KEY1-KEY6对应的6根引脚设为输入*/
GPGCON=GPG11_in & GPG7_in & GPG6_in & GPG5_in & GPG3_in & GPG0_in;//讲输入的引脚在配置寄存器中设为00
/*关闭KEY和LED的引脚上拉*/
GPBUP=0xFFFFFFFF;
GPGUP=0xFFFFFFFF;
while(1)
{
GPBDAT=0xFFFFFFFF;
dwDat=GPGDAT; //读取KEY引脚状态
if(dwDat & (1<<11)) //key6是否按下 按下时,电压拉入地,为低电平,状态0
{
GPBDAT |=(1<<5); //熄灭LED1
}else{
GPBDAT &=~(1<<5); //点亮LED1
}
if(dwDat & (1<<7)) //判断KEY5是否按下
{
GPBDAT |=(1<<6); //熄灭LED2
}else{
GPBDAT &=~(1<<6); //点亮LED2
}
if(dwDat & (1<<6)) //key4
{
GPBDAT |=(1<<7);
}else{
GPBDAT &=~(1<<7);
}
if(dwDat & (1<<5)) //key3
{
GPBDAT |=(1<<8);
}else{
GPBDAT &=~(1<<8);
}
if(dwDat & (1<<3)) //key2
{
GPBDAT |=(1<<5) | (1<<6);
}else{
GPBDAT &=~((1<<5) | (1<<6));
}
if(dwDat & (1<<0)) //key1
{
GPBDAT |=(1<<7) | (1<<8);
}else{
GPBDAT &= ~((1<<7) | (1<<8));
}
}
return 0;
}