LPC2103–GPIO

转自Ming’s World

LPC2103–GPIO
七月 4th 2009 in 侃侃技术

开始搞ARM7了,虽说本来很早就准备玩ARM,手头这个LPC2103的板子还是08年2月份买的……一直到最近学校那什么无聊实习在用ARM,好吧,我其实突击还是很可以的……
芯片上手第一件事干嘛!?看基本的电路,芯片的引脚链接,既然手头已经有现成开发板,那么省得自己做电路了。学芯片,首当其冲的当然是GPIO喽!~
啥是GPIO?通用输入/输出~是完全可控的引脚,就像51中没有硬件SPI和IIC就得靠GPIO模拟出来。
NXP的ARM7有几组GPIO的控制寄存器,对于我手头的LPC2103,32个GPIO正好4字节,也就是控制寄存器基本都是一个DWORD(unsigned long)类型的。

首先来说说PINSEL0和PINSEL1。因为这个芯片很多引脚是复用的,自然多个功能不可能同时使用,所以就需要选择引脚功能,用的就是这两个寄存器,具体细节就不说了,自己看Datasheet吧…LPC2103中PINSEL0管PIN0.0-PIN0.15,PINSEL1管PIN0.16-PIN0.31。值的设定基本是00–GPIO,01–第一复用功能,02–第二复用功能03–第三复用功能。这两个寄存器的复位值都是0×00000000,也就是所有引脚复位都是做GPIO用的。

再下来是GPIO的控制寄存器了。
IOPIN 管脚值寄存器。可以用来读取当前的管脚值,赋值也可以控制管脚输出。
IOSET 用来管脚置位的寄存器。写0无效,写1管脚置高电平。
IOCLR 用来管脚清除的寄存器。写0无效,写1管脚置低电平。
IODIR 管脚方向控制寄存器。0对应输入,1对应输出。复位值:0×00000000(所有管脚复位为输入)

IOSET和IOCLR是组合起来用的,也可以直接用IOPIN来控制引脚。其实和51以及AVR比起来,这个控制还是很随意的,对于51连方向寄存器都没,AVR的话只有一个类似IOPIN的寄存器。还是人家ARM好啊……

另外对于GPIO还有一组功能相同的寄存器,叫快速GPIO寄存器(Fast GPIO),速度比慢速的快大约3.5倍。
寄存器有FIODIR/FIOMASK/FIOPIN/FIOSET/FIOCLR,这个除了多的那个FIOMASK寄存器,其他功能与上面相同
FIOMASK 快速GPIO管脚屏蔽寄存器,对快速IO管脚的任何操作只有在对该寄存器对应位激活(写0)时有效

下面给出一些示例代码:

1.第一个实例是令两个LED交替闪烁,用的是IOSET和IOCLR实现的

#include <LPC2103.H>
 
#define uint unsigned int
#define uchar unsigned char
 
#define	LED1	(1<<17)//define LED1 port 
#define	LED2	(1<<18)//define LED2 port
 
void MyDelay(uint tm);
 
int main(){
	PINSEL0=0x00000000;//link all port to GPIO
	PINSEL1=0x00000000;
	IODIR=LED1|LED2;//set LED1 & LED2 port to be output
	while(1){			
		IOCLR=LED1;//set LED1 port low
		IOSET=LED2;//set LED2 port high
		MyDelay(100);	
		IOCLR=LED2;//set LED2 port low	
		IOSET=LED1;//set LED1 port high
		MyDelay(100);
	}
}
 
void MyDelay(uint tm){//delay function
	uint i,j,k;
	for(i=0;i<tm;i++)
		for(j=0;j<1000;j++)
			for(k=0;k<100;k++)
				;	
}

2.第二个实例是从5向按钮(类似手机导航键那种按钮)读取按键来进行不同的闪烁。控制端口输出使用的IOPIN寄存器。

#include <LPC2103.H>
 
#define uint unsigned int
#define uchar unsigned char
 
#define	LED1	(1<<17)//define LED1 port 
#define	LED2	(1<<18)//define LED2 port
 
#define KEY0	(1<<24)//define KEY0 port	(SELECT)
#define KEY1	(1<<11)//define KEY1 port	(UP) 
#define KEY2	(1<<10)//define KEY2 port	(DOWN) 
#define KEY3	(1<<23)//define KEY3 port	(LEFT)
#define KEY4	(1<<12)//define KEY4 port	(RIGHT)
 
void MyDelay(uint tm);
 
int main(){
	IODIR=LED1|LED2;//set LED1 & LED2 port to be output
	IOPIN=0xFFFFFFFF;//set output port high
	while(1){
		if((IOPIN & KEY0)==0x00){//SELECT press
			IOPIN=0;
			MyDelay(100);	
			IOPIN=LED1|LED2;//LEDs off
		}
		else if((IOPIN & KEY1)==0x00){//UP press
			IOPIN=LED1;//LED1 on
			MyDelay(100);	  
			IOPIN=LED1|LED2;//LEDs off
		} 
		else if((IOPIN & KEY2)==0x00){//DOWN press
			IOPIN=LED2;//LED2 on
			MyDelay(100);	  
			IOPIN=LED1|LED2;//LEDs off
		}
		else if((IOPIN & KEY3)==0x00){//LEFT press
			IOPIN=LED1;//LED1 on
			MyDelay(100);	  
			IOPIN=LED1|LED2;//LEDs off
			MyDelay(100);
			IOPIN=LED1;//LED1 on
			MyDelay(100);	  	  
			IOPIN=LED1|LED2;//LEDs off
		}
		else if((IOPIN & KEY4)==0x00){//RIGHT press
			IOPIN=LED2;//LED2 on 
			MyDelay(100);	  	  
			IOPIN=LED1|LED2;//LEDs off
			MyDelay(100);
			IOPIN=LED2;//LED2 on
			MyDelay(100);	  	  
			IOPIN=LED1|LED2;//LEDs off
		}
	}
}
 
void MyDelay(uint tm){//delay function
	uint i,j,k;
	for(i=0;i<tm;i++)
		for(j=0;j<1000;j++)
			for(k=0;k<100;k++)
				;	
}

3.第三个实例是快速GPIO的示例,注意一点是—-要让GPIO工作在快速GPIO需要设置SCS寄存器为1!!!然后对快速GPIO寄存器操作才有效。程序功能与示例1略有不同,示例里面还演示了FIOMASK寄存器,屏蔽了LED2,所以只有LED1在闪烁。

#include <LPC2103.H>
 
#define uint unsigned int
#define uchar unsigned char
 
#define	LED1	(1<<17)//define LED1 port 
#define	LED2	(1<<18)//define LED2 port
 
void MyDelay(uint tm);
 
int main(){
	SCS=1;
	FIODIR=LED1|LED2;//set LED1 & LED2 port to be output
	while(1){
		FIOMASK=~(LED1);
		FIOCLR=LED1;//set LED1 port low
		FIOSET=LED2;//set LED2 port high -- No use
		MyDelay(100);	
		FIOCLR=LED2;//set LED2 port low	
		FIOSET=LED1;//set LED1 port high -- No use
		MyDelay(100);
	}
}
 
void MyDelay(uint tm){//delay function
	uint i,j,k;
	for(i=0;i<tm;i++)
		for(j=0;j<1000;j++)
			for(k=0;k<100;k++)
				;	
}

No Comments

关于51的程序下载

可能很多人平时在PC上写程序,就知道编译出来一个EXE文件,然后双击运行就OK。关于硬件的开发过程还不很了解。其实学校有些硬件方面的实验已经有给出硬件开发的流程了。
一般是在PC上写好程序,编译出HEX文件(或者BIN文件),然后下载到目标芯片,加电运行即可。

写程序和运行我在最早的那个文章里已经说了,关于下载,这里再详细说一下。

首先是下载线的引脚定义,一般都是用一个10针的座子,其引脚定义如下:
ISP

连接好下载电路以后就可以用下载软件进行下载。成本比较低的是并口的下载线几块钱就能打造一个,但是因为本本没并口,我自己平时都是用USBasp来进行51和AVR的程序下载。
下载的软件我自己用的是AVR fighter,不过这个只支持USBasp下载线,另外有一个不错的下载软件叫PROGISP,支持的下载线比较多。
PROGISP的网站:
http://www.zhifengsoft.com/
网站上也有并口下载线的电路图,可以照着DIY一个并口下载线。

AVR fighter界面
AVR_fighter

PROGISP界面
PROGISP

软件的使用也都比较简单,一般都会先选择芯片型号,然后检测芯片,再下载,最后校验,程序就烧写到芯片中了。

No Comments

51单片机的串口编程

首先得明白,串口是什么!?嗯,大家学过通信都应该知道的了,我就不多说废话了。一般台机后面都有的那种9针的,本本的话,就得要USB转串口的线了,我个人比较推荐PL2303HX去DIY转换线,物美价廉!~
对于硬件电路一般使用的MAX232芯片来转换51的TTL电平到串口的232电平,其硬件连接如下:
注:对于MAX232选取电容为1uf,而对于MAX232A则选取电容为0.1uf
RS232
硬件电路连接好以后还需要一个PC的串口工具来与单片机通信,这类软件网上很多,自己随便找个下吧!~
我自己也用VB的COMM控件写过一个串口调试工具,有兴趣的可以向我索取源码。

对于串口首先应该明白串口是基于字节收发数据的,收发的数据会放到一个叫SBUF的寄存器(对于用C写来说)。如果设定了串口中断则可以在中断程序中处理,否则得用查询的方式来检测是否接受到数据或者数据已经发出,下面给出一个查询方式的代码(我自己一直这么用的),51单片机的串口发送需要占用一个Timer,使用的是Timer1来产生固定比特率。我自己在程序中用宏预定义了一些常用的波特率,可以参考Uart.c。另外,对于串口最好用11.0592M的晶振,可以产生多种无误差的比特率。

Uart.h

/******************************************************************************
使用注意事项:
1.在UART.c内设定所使用的晶振和串口波特率
2.在程序开始应当先进行串口初始化工作
******************************************************************************/
#ifndef	_UART_H_
#define	_UART_H_
 
#include "at89x52.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define nop _nop_()
 
//**************注释不需要的函数**************//
#define _HAVE_INIT_UART
#define _HAVE_SENDSTR_UART
#define _HAVE_SENDBYTE_UART
#define _HAVE_RECIVEBYTE_UART
//********************************************//
 
#ifdef _HAVE_INIT_UART
void InitUART();
#endif //end of _HAVE_INIT_UART
#ifdef _HAVE_SENDSTR_UART
void SendStrUART(char * Str);
#endif //end of _HAVE_SENDSTR_UART
#ifdef _HAVE_SENDBYTE_UART
void SendByteUART(uchar Data);
#endif //end of _HAVE_SENDBYTE_UART
#ifdef _HAVE_RECIVEBYTE_UART
uchar ReciveByteUART();
#endif //end of _HAVE_RECIVEBYTE_UART
 
#endif //end of _UART_H_

Uart.c

#include "uart.h"
 
//**********晶振设定(仅可选择一个)**********//
//#define CRYSTAL_6M
#define CRYSTAL_110592
//#define CRYSTAL_12M
 
//**********波特率设定(仅可选择一个)**********//
//#define RATE62500
//#define RATE19200
#define RATE9600
//#define RATE4800
//#define RATE2400
//#define RATE1200
 
#ifdef _HAVE_INIT_UART
void InitUART(){
    TMOD=(TMOD&amp;0x0F)|0x20;//Timer0模式不变,Timer1为8位自动加载(For UART)
    #if defined(CRYSTAL_110592)
        #if defined(RATE19200)
            TL1=0xFD;
            TH1=0xFD;
            PCON=0x80;
        #elif defined(RATE9600)
            TL1=0xFD;
            TH1=0xFD;
            PCON=0x00;
        #elif defined(RATE4800)
            TL1=0xFA;
            TH1=0xFA;
            PCON=0x00;
        #elif defined(RATE2400)
            TL1=0xF4;
            TH1=0xF4;
            PCON=0x00;
        #elif defined(RATE1200)
            TL1=0xE8;
            TH1=0xE8;
            PCON=0x00;
        #else
            #error Unknow Rate
        #endif
    #elif defined(CRYSTAL_12M)
        #if defined(RATE62500)
            TL1=0xFF;
            TH1=0xFF;
            PCON=0x80;
        #elif defined(RATE4800)//可能产生误码
            TL1=0xF3;
            TH1=0xF3;
            PCON=0x80;
        #elif defined(RATE2400)
            TL1=0xE6;
            TH1=0xE6;
            PCON=0x80;
        #elif defined(RATE1200)
            TL1=0xE6;
            TH1=0xE6;
            PCON=0x00;
        #else
            #error Unknow Rate
        #endif
    #elif defined(CRYSTAL_6M)
        #if defined(RATE2400)
            TL1=0xF3;
            TH1=0xF3;
            PCON=0x80;
        #elif defined(RATE1200)
            TL1=0xF3;
            TH1=0xF3;
            PCON=0x00;
        #else
            #error Unknow Rate
        #endif
    #else
        #error Unknow Crystal
    #endif
    SCON=0x58;
    TR1=1;
}
#endif //end of _HAVE_INIT_UART
 
#ifdef _HAVE_SENDSTR_UART
void SendStrUART(char * Str){
    while(*Str){//还有字节要发送"\0"为字符串终止
        SBUF=*Str;//设定要发送的字节
        while(TI==0)//等待发送
            nop;
        TI=0;//发送完成置回TI
        Str++;//发送下一个字节
    }
}
#endif //end of _HAVE_SENDSTR_UART
 
#ifdef _HAVE_SENDBYTE_UART
void SendByteUART(uchar Data){
    SBUF=Data;//设定要发送的字节
    while(TI==0)//等待发送
        nop;
    TI=0;//发送完成置回TI
}
#endif //end of _HAVE_SENDBYTE_UART
 
#ifdef _HAVE_RECIVEBYTE_UART
uchar ReciveByteUART(){
    uchar tmp;
    while(RI==0)//等待接受到数据
        nop;
    tmp=SBUF;//保存接受数据
    RI=0;//接收完成置回RI
    return tmp;
}
#endif //end of _HAVE_RECIVEBYTE_UART

在主程序里面引用Uart.h,就可以使用那几个接受和发送的函数了,下面再给一个实例程序,实现接收一个字节把该字节发送出去

main.c

#include "at89x52.h"
#include "intrins.h"
#include "Uart.h"
 
#define uchar unsigned char
#define uint unsigned int
#define nop _nop_()
 
void main(){
    while(1){
        SendByteUART(ReciveByteUART());
    }
}

下来的话,拿个串口工具测试吧!~:)

3 Comments

51单片机的最小系统

鉴于最近一些同学实习在做单片机,我就提供一些基本的资料吧……

平时我自己用的都是Atmel的单片机AT89S52/AT89S51,其实也有AT89C52/AT89C51,S系列支持ISP在线下载,C系列就比S少了串行ISP方式下载,其他一样,89X51的EEPROM是4K,而89X52的EEPROM是8K其他的都一样。

以AT89S52为例给一个最小系统的电路,这个最小系统指的是单片机能工作所需最少的元件电路,其中VCC接5v电源(Datasheet说供电范围为4.0v–5.5v)。GND接地。XTAL1、XTAL2接晶振,同时都要连一个33pF的电容(12M晶振的情况下…芯片手册建议为C1, C2 = 30 pF ± 10 pF for Crystals)。51单片机复位为高电平有效,所以复位电路如图,在按下按钮后RST被拉高,单片机复位。另外,要51单片机能工作,EA要接到VCC(最早我自己做电路就是没接这个,找了N久没找到问题出在哪……- -|||)

1

OK,有了这个最小系统,下来就可以开始弄程序进去了,不过首先说明,程序需要下载器去下载,我自己感觉比较好的是USBasp,因为现在的本本都没串口或者并口,这个低成本USB编程器还是很不错,而且价格便宜(主要是AVR烧写用,不过一些编程器也支持51)。另外USBasp可以自己DIY。我就弄了个自己的…..

2

USBasp官网:http://www.fischl.de/usbasp/

下面再给一个简单的示例程序,平时我写的代码都是C的,开发环境为Keil uVision2。建立工程的时候Project–New Project,然后选择芯片型号,选择Atmel–AT89S52,然后建立工程,在建立一个c文件,名字随便,里面必须有main函数,并将该文件添加到工程里,下面这个示例用上面的最小系统,再加上一个LED来实现LED闪烁。添加电路如下(用单片机吸取电流,因为单片机的电流驱动能力比较弱……不过51其实驱动LED还是可以的)

3

代码如下:

#include "at89x52.h"
 
#include "intrins.h"
 
#define uchar unsigned char
 
#define uint unsigned int
 
#define nop _nop_()
 
sbit LED = P0^0;//设定LED引脚
 
void MyDelay(uint tm);//延迟函数
 
void main(){
 
    while(1){
 
        LED=!LED;//LED引脚置反
 
        MyDelay(1000);//延迟1s多...
 
    }
 
}
 
void MyDelay(uint tm){//延迟函数
 
    uint i,j;
 
    for(i=0;i<tm;i++){
 
        for(j=0;j<1000;j++){
 
            nop;//空语句
 
        }
 
    }
 
}

编译的时候需要在Project–Option里面,Output分栏里面把Create HEX File项勾选(才能产生烧录用的HEX文件),编译,然后得到输出HEX文件,再用烧写软件和编程器烧入芯片,加电运行吧~:)

4

硬件这东东还是得多动手,看再多书不做东西出来其实还是不会,有时间自己买把廉价烙铁,加入电子DIY行列吧~下面是我最早自己的51板子,把所有引脚都引了出来,然后加了个MAX232芯片给串口,加了些LED和开关,还有个EEPROM和模拟比较器。

51Broad(1)

最后给出AT89S51和AT89S52的芯片手册下载地址:

AT89S51 Datasheet:http://www.atmel.com/dyn/resources/prod_documents/doc2487.pdf

AT89S52 Datasheet:http://www.atmel.com/dyn/resources/prod_documents/doc1919.pdf

鉴于最近一些同学实习在做单片机,我就提供一些基本的资料吧……

平时我自己用的都是Atmel的单片机AT89S52/AT89S51,其实也有AT89C52/AT89C51,S系列支持ISP在线下载

,C系列就比S少了串行ISP方式下载,其他一样,89X51的EEPROM是4K,而89X52的EEPROM是8K其他的都一样

以AT89S52为例给一个最小系统的电路,这个最小系统指的是单片机能工作所需最少的元件电路,其中VCC接

5v电源(Datasheet说供电范围为4.0v–5.5v)。GND接地。XTAL1、XTAL2接晶振,同时都要连一个33pF的电容

(12M晶振的情况下…芯片手册建议为C1, C2 = 30 pF ± 10 pF for Crystals)。51单片机复位为高电平有

效,所以复位电路如图,在按下按钮后RST被拉高,单片机复位。另外,要51单片机能工作,EA要接到VCC(

最早我自己做电路就是没接这个,找了N久没找到问题出在哪……- -|||)

OK,有了这个最小系统,下来就可以开始弄程序进去了,不过首先说明,程序需要下载器去下载,我自己感

觉比较好的是USBasp,因为现在的本本都没串口或者并口,这个低成本USB编程器还是很不错,而且价格便

宜(主要是AVR烧写用,不过一些编程器也支持51)。另外USBasp可以自己DIY。我就弄了个自己的…..

USBasp官网:http://www.fischl.de/usbasp/

下面再给一个简单的示例程序,平时我写的代码都是C的,开发环境为Keil uVision2。建立工程的时候

Project–New Project,然后选择芯片型号,选择Atmel–AT89S52,然后建立工程,在建立一个c文件,名

字随便,里面必须有main函数,并将该文件添加到工程里,下面这个示例用上面的最小系统,再加上一个

LED来实现LED闪烁。添加电路如下(用单片机吸取电流,因为单片机的电流驱动能力比较弱……不过51其

实驱动LED还是可以的)

代码如下:

#include "at89x52.h"
 
#include "intrins.h"
 
#define uchar unsigned char
 
#define uint unsigned int
 
#define nop _nop_()
 
sbit LED = P0^0;//设定LED引脚
 
void MyDelay(uint tm);//延迟函数
 
void main(){
 
while(1){
 
LED=!LED;//LED引脚置反
 
MyDelay(1000);//延迟1s多...
 
}
 
}
 
void MyDelay(uint tm){//延迟函数
 
uint i,j;
 
for(i=0;i&lt;tm;i++)
 
for(j=0;j&lt;1000;j++){
 
nop;//空语句
 
}
 
}

编译的时候需要在Project–Option里面,Output分栏里面把Create HEX File项勾选(才能产生烧录用的

HEX文件),编译,然后得到输出HEX文件,再用烧写软件和编程器烧入芯片,加电运行吧~:)

硬件这东东还是得多动手,看再多书不做东西出来其实还是不会,有时间自己买把廉价烙铁,加入电子DIY

行列吧~下面是我最早自己的51板子,把所有引脚都引了出来,然后加了个MAX232芯片给串口,加了些LED

和开关,还有个EEPROM和模拟比较器。

最后给出AT89S51和AT89S52的芯片手册下载地址:

AT89S51 Datasheet:http://www.atmel.com/dyn/resources/prod_documents/doc2487.pdf

AT89S52 Datasheet:http://www.atmel.com/dyn/resources/prod_documents/doc1919.pdf

No Comments

基本数论算法-最大公约数和最小公倍数

转自Windforce’s Cabin

基本数论算法-最大公约数和最小公倍数

by zzhang on 六.26, 2009, under 算法

在数论相关的算法中,求最大公约书(Greatest Common divisor,简称gcd)和最小公倍数(lowest common multiple,简称lcm)是很基础的算法,其中最大公约数又是最最基础的算法,因为对任意两个数a、b,有lcm(a,b) = a*b/gcd(a,b)。
求解最大公约数的算法有很多种,其中最简单的就是穷举法,对任意m,n我们知道,其最大公约数一定大于等于1,小于等于min(m,n),因此,我们从min(m,n)到2枚举,如果找到结果,返回结果,否则返回1,其代码如下所示:
int gcd(int m,int n)
{
int t=m<n?m:n;
while(t>1){
if(!((m%t)|(n%(t–)))) return t+1;
}
return 1;
}

这种算法的效率是十分低下的,很容易可以得出,其时间复杂度为O(min(m,n))。
在实际应用中,更常用的是欧几里得算法,欧几里得算法给予以下原理:
gcd(m,n)=gcd(n,m%n),
该性质可以容易的证明。利用改性质,我们可以设计一个迭代的算法,其代码如下
int gcd(int m,int n)
{
while(n!=0){
int t;
t = m%n;
m = n;
n = t;
}
return m;
}

对于最小公倍数,可以直接利用lcm(m,n)=m*n/gcd(m,n)求出。

, , ,

No Comments

ubuntu8.04,lighttpd环境上ZendOptimzer的安装

转自Windforce’s Carbin
ubuntu8.04,lighttpd环境上ZendOptimzer的安装
by zzhang on 六.25, 2009, under 网络, 软件

在装好php和lighttpd后,我们有了一个可以php的开发、运行环境,但是他的运行速度还很不理想,尤其是笔者的VPS仅有128M内存,因此,不得不限制php-cgi并发进程数,为了提高php的响应速度,我已经安装了eaccelerator,为了进一步提升机器的潜能,我决定装上大名鼎鼎的ZendOptimzer。

通过Google,我找到了一些关于ZendOptimzer安装的How-to,但是这些教程大多适用于apache环境,而关于lighttpd的文章也有一些小错误。我们需要注意的是,lighttpd的php运行方式为fastcgi,其php.ini保存在/etc/php5/cgi/下,在安装ZendOptimzer时我们只需要指定php.ini所在的目录为php.ini即可安装,而不需要向其他文章写的那样还要改动lighttpd的配置文件,之后,我们一路next,安装完成后重新启动lighttpd,你可以发现网站的速度有明显的提升。

, , ,

1 Comment

添加你的自定义头像

这里使用了WordPress自带的Gravatar Logo头像,你只需要到如下网站按你在本站注册的E-mail地址注册一个账户,然后在那个站点上传自己的Image就可以了。

http://en.gravatar.com/

Hope you enjoy here!~

2 Comments

Start Here…

这个站弄来玩玩…Hey!~WordPress!~

4 Comments