ARM设计实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录
一,实验目的
二,实验软件, 硬件
三,实验题目及要求(设计要求)
四,软件时钟设计总体方案
五,软件时钟的电路原理图
六,程序流程图及C程序(软件部分)七,Proteus仿真图(硬件部分)
一实验目的。
1,应用所学的ARM知识设计一个实时时钟
掌握LPC2106中断处理, RTC的使用。
二实验软件, 硬件。
软件:proteus6.9仿真软件, ARM开发环境ADS.
硬件: WINDOW 2000/XP PC机一台。
三实验题目及要求(设计要求)。
题目: 带报警功能并且可以调节时间的实时时钟。
要求: 1, 实时时间可通过按键选择调节。
2, 可以通过按键设定报警时间。
3, 当达到报警时间时, 蜂鸣器响一下, LED灯点亮。
4, 报警时间和实时时间通过液晶模块LCD1602显示
四软件时钟设计总体方案
本实验是基于LPC2106ARM处理器而设计的实时时钟, 综合性较强, 涉及到RTC外部中断, 引脚的GPIO功能, C语言编程等知识。
首先要定义P0口为基本I\O功能, 然后通过引脚功能选择寄存器PINSEL0及PINSEL1定义输入输出外部中断口所在的位, 另外还要对外部中断进行初始化, 其中有规定他们的优先级, 中断触发方式, 中断地址分配, 本实验采用液晶模块LCD1602同时显示实时时间和报警时间, 同样要对他们进行初始化, 包括检查总线忙与闲, 传送地址, 传送数据及显示函数的编程、
1,LPC2106微控制器自带有一个实时时钟RTC带日历和时钟功能, 要使用它也要进行一下的基本操作:
2,设置RTC基准时钟分频器
3,初始化RTC的时钟值如, YEAR,MONTH,HOUR等
4,启动RTC即CCR的CLKEN位职位
5,读取完整时间寄存器值或等待中断。
陈述完以上的模块初始化后, 下面简要说明一下程序的流程
先调用以上各个模块的初始化函数lcd_int(),RTCint()
然后开启RTC时钟, 并调用LCD显示函数SendTimetRtc(),如果没用中断发
生就判断实时时间是否与以设定的报警时间相同, 如果相同就马上接通蜂鸣器报警并且点亮LED灯。
假如有中断发生, 在无效状态下, 马上给中断标志寄存器EXTINT对应位, 然后写1清零, 然后转到中断服务程序。
本实验设定7种系统状态
正常运行: 0态
设定RTC的
HOUR 1态
SEC 2态
MIN 3态
ALHOUR 4态
ALSEC 5态
ALMIN 6态
电路中通过三个按钮开关与三个中断eint的输入端相连, 对应也有eint0,eint1,eint3三个中断服务程序, 当eint2 端按下时, 就转到eint2中断服务程序, 它的功能就是设定系统当前所取的状态, 也就是所选择实时时钟和报警时间的时, 分, 秒, 按一下, 状态就自增一, eint0,eint1的中断服务程序都是调节时间不同的是一个以加1调节, 一个以减2调节。
按下一次就加一次时间值, 但具体是对HOUR,SEL,MIN,ALHOUR,ALMIN,ALSEL中的哪一个调节那还得看eint2触发下系统所处的状态所以只有在eint2发生的基础上eint0,eint1发生才有意义。
在判断状态是我灵活的使用了C语言开关语句——switch,可以优化程序使程序看起来更紧凑, 一目了然。
五软件时钟的电路原理图
六程序流程图及C程序(软件部分)#include "config.h"
#define rs (1<<8)
#define rw (1<<9)
#define en (1<<10)
#define busy (1<<7)
#define FPCLK 2764800L
uint8 change;
uint8 txt[]={"ALM: "};
uint8 MESSAGE[]={"RTC: "};
/**********************************外部中断*************************************/
void __irq eint0(void) //向量中断开始,说明有外部中断
{
switch(change)
{
case
1:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;ALSEC++;if(ALSEC>59)ALS EC=0;break;}
case
2:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;ALMIN++;if(ALMIN>59)AL MIN=0;break;}
case
3:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;ALHOUR++;if(ALHOUR>23 )ALHOUR=0;break;}
case
4:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;SEC++;if(SEC>23)SEC=0;bre ak;}
case
5:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;MIN++;if(MIN>23)MIN=0;br eak;}
case
6:{ while(EXTINT&(1<<0))EXTINT=1<<0;VICVectAddr=0;HOUR++;if(HOUR>23)HOU R=0;break;}
}
}
void __irq eint1(void) //向量中断开始,说明有外部中断
{
switch(change)
{
case
1:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;ALSEC--;if(ALSEC==0XFF) ALSEC=59;break;}
case
2:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;ALMIN--;if(ALMIN==0XFF) ALMIN=59;break;}
case
3:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;ALHOUR--;if(ALHOUR==0 XFF)ALHOUR=23;break;}
case
4:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;SEC--;if(SEC==0XFF)SEC=5 9;break;}
case
5:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;MIN--;if(MIN==0XFF)MIN=
59;break;}
case
6:{ while(EXTINT&(1<<1))EXTINT=1<<1;VICVectAddr=0;HOUR--;if(HOUR==0XFF)H OUR=23;break;}
}
}
void __irq eint2(void) //向量中断开始,说明有外部中断
{
change++;
if(change>6)
change=0;
while(EXTINT&(1<<2))//等待extint[2]变成1
EXTINT=1<<2; //往extint[1]写1清除中断
VICVectAddr=0; //向量中断结束
}
/****************************LCD**************************************/
/************************************************************************** **
* 名称: WrOp()
* 功能: 写函数
*************************************************************************** */
void ChkBusy()
{
IODIR=0x700; //设置P0.8~P0.10为输出
while(1)
{
IOCLR=rs; //命令选择
IOSET=rw; //写操作
IOSET=en; //使能有效
if(!(IOPIN & busy))break;
IOCLR=en; //使能无效
}
IODIR=0x7ff; //设置P0.0~P0.10为输出
}
/************************************************************************** **
* 名称: WrOp()
* 功能: 写命令函数
***************************************************************************
void WrOp(uint8 dat)
{
ChkBusy(); //判忙
IOCLR=rs; //全部清零,命令选择
IOCLR=rw; //写选择
IOCLR=0xff; //先清零
IOSET=dat; //再送数
IOSET=en; //使能有效
IOCLR=en; //使能无效
}
/************************************************************************** **
* 名称: WrDat()
* 功能: 写数据函数
*************************************************************************** */
void WrDat(uint8 dat)
{
ChkBusy(); //判忙
IOSET=rs; //数据选择
IOCLR=rw; //写选择
IOCLR=0xff; //先清零
IOSET=dat; //再送数
IOSET=en; //使能有效
IOCLR=en; //使能无效
}
/************************************************************************** **
* 名称: lcd_init()
* 功能: lcd初始化函数
*************************************************************************** */
void lcd_init(void)
{
WrOp(0x38); //设置16*2显示, 5*7点阵
WrOp(0x06); //读/写后地址加一, 光标加一
WrOp(0x0c); //开显示, 不显示光标, 光标不闪烁
}
void DisText(uint8 addr,uint8 *p)
{
WrOp(addr); //调用写命令函数
while(*p !='\0')WrDat(*(p++));
}
/******************************************************
//函数名称: void lcd_string( uchar *p, uchar flag )
//函数功能: 1602LCD显示函数
//参数功能: *p -- 显示数据首地址;
// flag -- 显示行数
******************************************************/
void lcd_string( uint8 *p, uint8 flag )
{
if( flag == 1 )
{
DisText(0x80,p); //指定显示地址,第一行显示
}
if( flag == 2 )
{
DisText(0xc0,p); //指定显示地址,第二行显示
}
}
/*****************************RTC**********************************/
void RTCIni(void)
{ PREINT=FPCLK/32768-1; //设置预分频器
PREFRAC=FPCLK-(FPCLK/32768)*32768;
YEAR=2005; //初始化年
MONTH=6; //初始化月
DOM=10; //初始化日
HOUR=8;
MIN=30;
SEC=0;
ALHOUR=8;
ALMIN=50;
ALSEC=37;
AMR=0xf8;
CIIR=0x01; //设置秒值的增量产生一次中断
CCR=0x01; //启动RTC
}
/************************************************************************** *****
*名称: SendTimeRtc()
*功能: 读取RTC的时间值, 并将读出的时分秒值由lcd1602显示,显示报警时间
*************************************************************************** ****/
void SendTimeRtc(void)
{
MESSAGE[4]=HOUR/10+'0'; //时的值
MESSAGE[5]=HOUR%10+'0';
MESSAGE[6]=':';
MESSAGE[7]=MIN/10+'0'; //取得分的值
MESSAGE[8]=MIN%10+'0';
MESSAGE[9]=':';
MESSAGE[10]=SEC/10+'0'; //取得秒的值
MESSAGE[11]=SEC%10+'0';
lcd_string(MESSAGE,1);
txt[4]=ALHOUR/10+'0'; //时的报警值
txt[5]=ALHOUR%10+'0';
txt[6]=':';
txt[7]=ALMIN/10+'0'; //分的报警值
txt[8]=ALMIN%10+'0';
txt[9]=':';
txt[10]=ALSEC/10+'0'; //秒的报警值
txt[11]=ALSEC%10+'0';
lcd_string(txt,2);
}
void DelayNS(uint32 dly)
{ uint32 i;
for(; dly>0; dly--)
for(i=0; i<500; i++);
}
/*****************************************************************
*******************************主函数**************************************/
int main()
{
lcd_init(); //LCD初始化
RTCIni(); //RTC初始化
PINSEL0=PINSEL0|0XA0000000; //选择外部中断1, 2
PINSEL1=PINSEL1|0X00000001; //选择外部中断0
//EXTPOLAR=0X00; //低电平或下降沿
//EXTMODE=0X07; //下降沿
VICIntSelect=0; //Eint0,Eint1,Eint 为普通中断
VICIntEnable=0x0001c000; //允许Eint0,Eint1,Eint中断
VICVectCntl0=0x0000002e; //外部中断0的优先级为0
VICVectCntl1=0x0000002f; //外部中断1的优先级为1
VICVectCntl2=0x00000030; //外部中断3的优先级为2
VICVectAddr0=(int)eint0; //给向量地址0赋初值
VICVectAddr1=(int)eint1; //给向量地址1赋初值
VICVectAddr2=(int)eint2; //给向量地址2赋初值
EXTINT=0x07; //Eint0,eint1,eint 中断状态为清除, 等待中断在把这3位置1
while(1)
{
while((ILR&0x01)==0); //等待RTC增量中断标志位
SendTimeRtc();
if((ALSEC==SEC)&&(ALMIN==MIN)&&(ALHOUR==HOUR))
{
IODIR=0xffff;
IOSET=0x1800;
//IOCLR=(IOCLR|(3<<11));
DelayNS(8000);
//CCR=0x00;
//while(1);
}
ILR=0x01;
}
}
七 proteus仿真图(硬件部分)
灯一个PNP三极管, 一个极性电容。
微处理器芯片PLC2106一片, 液晶显示器LCD1602一片。