LPC2103–GPIO
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++) ; }
关于51的程序下载
可能很多人平时在PC上写程序,就知道编译出来一个EXE文件,然后双击运行就OK。关于硬件的开发过程还不很了解。其实学校有些硬件方面的实验已经有给出硬件开发的流程了。
一般是在PC上写好程序,编译出HEX文件(或者BIN文件),然后下载到目标芯片,加电运行即可。
写程序和运行我在最早的那个文章里已经说了,关于下载,这里再详细说一下。
首先是下载线的引脚定义,一般都是用一个10针的座子,其引脚定义如下:

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

PROGISP界面

软件的使用也都比较简单,一般都会先选择芯片型号,然后检测芯片,再下载,最后校验,程序就烧写到芯片中了。
51单片机的串口编程
首先得明白,串口是什么!?嗯,大家学过通信都应该知道的了,我就不多说废话了。一般台机后面都有的那种9针的,本本的话,就得要USB转串口的线了,我个人比较推荐PL2303HX去DIY转换线,物美价廉!~
对于硬件电路一般使用的MAX232芯片来转换51的TTL电平到串口的232电平,其硬件连接如下:
注:对于MAX232选取电容为1uf,而对于MAX232A则选取电容为0.1uf

硬件电路连接好以后还需要一个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&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()); } }
下来的话,拿个串口工具测试吧!~:)
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久没找到问题出在哪……- -|||)

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<tm;i++){ for(j=0;j<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
平时我自己用的都是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<tm;i++) for(j=0;j<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
基本数论算法-最大公约数和最小公倍数
基本数论算法-最大公约数和最小公倍数
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)求出。
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,你可以发现网站的速度有明显的提升。
添加你的自定义头像
这里使用了WordPress自带的Gravatar Logo头像,你只需要到如下网站按你在本站注册的E-mail地址注册一个账户,然后在那个站点上传自己的Image就可以了。
Hope you enjoy here!~