十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
一下来自我的空间
为企业提供成都做网站、成都网站制作、网站优化、成都全网营销、竞价托管、品牌运营等营销获客服务。创新互联建站拥有网络营销运营团队,以丰富的互联网营销经验助力企业精准获客,真正落地解决中小企业营销获客难题,做到“让获客更简单”。自创立至今,成功用技术实力解决了企业“网站建设、网络品牌塑造、网络营销”三大难题,同时降低了营销成本,提高了有效客户转化率,获得了众多企业客户的高度认可!
注意要设定选项,不然中断向量表不位于地址0出,也就无法进入中断例程,具体设定方法是:Options for Target'???'-Linker-选中"Use Memory Layout from Target Dialog"
//*****************************************************************************************
//非向量外部中断C例程
//P0.16做键盘输入,P0.18做LED输出
#includeLPC2103.H
#define LED 118
void __irq WaiBuZhongDuan(void) // 注意要加“__irq”,告诉编译器,
{ //这是中断例程
if((IOSETLED)==0) IOSET=LED;
else IOCLR=LED; //将P0.0取反
EXTINT=0X01; //清除中断标志,写1清0
VICVectAddr=0; //清0,通知VIC中断结束
}
int main(void)
{
PINSEL1=0X1; //P0.16选为外部中断0引脚输入
IODIR=LED; //P0.18作为LED输出
EXTMODE=0X01; //边沿触发
VICDefVectAddr=(int)WaiBuZhongDuan; //填入中断例程的地址
VICIntEnable=114; //使能EINT0中断
while(1) ;
}
//*****************************************************************************************
PROTEUS仿真见下:
硬件仿真:
补充说明:程序中没有区分IRQ或FIQ,因为VICIntSelect默认为0即所有中断源都是IRQ。
如果中断不能进入,查看一下CPSR中的I位,如果是1,说明CPSR中断标志禁止中断,所以要将I清0,解决办法是利用一个软件中断,进入管理模式,将SPSR的I清0,返回前将SPSR复制到CPSR中。具体做法有待以后解决。本来是想用内嵌汇编的,但是考虑到用户模式不能对CPSR修改。或者修改一下启动代码。
VICDefVectAddr是非向量IRQ的中断例程地址(与此相似的16个向量IRQ的中断例程地址VICVectAddr0~15),中断触发后,VICDefVectAddr(同样,如果是向量IRQ,相应的VICDefVectAddr0~15)中的值自动进入VICVectAddr,所以PC指向VICVectAddr后就进入相应的中断例程。
那么PC为什么会指向VICVectAddr呢?与C51相似的是,ARM的IRQ触发后,PC会跳到0x00000018地址处,查看Startup里的异常向量表,在地址0x00000018处有这样一条指令: LDR PC, [PC, #-0x0FF0],计算一下 0x00000018+8-0x0FF0=0xFFFFF030,(+8是因为三级流水线),0xFFFFF030就是VICVectAddr的地址。
观察一下异常向量表,和C51的中断向量表比较一下,是不是有相似之处:
ARM:
Vectors LDR PC, Reset_Addr ;0x00000000复位
LDR PC, Undef_Addr ;0x00000004未定义异常
LDR PC, SWI_Addr ;0x00000008软件中断
LDR PC, PAbt_Addr ;0x0000000C预取指中止
LDR PC, DAbt_Addr ;0x00000010数据中止
NOP ;0x00000014保留
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ;0x00000018中断
LDR PC, FIQ_Addr ;0x0000001C快速中断
C51:
ORG 0003H
SJMP INT0
ORG 000BH
SJMP TIME0
ORG 0013H
SJMP INT1
ORG 001BH
SJMP TIME1
ORG 0023H
SJMP SERIAL
VICIntEnable=114是因为外部中断0的编号为14。
“__irq”如果不写,编译器无法正常处理此中断例程,经测试,如果没有,中断例程不能返回正常,具体原因:若不加“__irq”,编译器把此程序看作普通子程序,返回指令是BX RL,若加“__irq”,编译器把此程序看作中断例程,返回指令是SUBS PC,R14,#4,这才是中断返回的正确指令。
EXTINT是外部中断的中断标志位,写1才能清0,写0无效,硬件仿真证明:如果不清0,中断例程将无限循环。顺便说一句:PROTEUS的虚拟仿真结果和事实(硬件仿真)有差异,比如对EXTINT、EXTMODE,VICVectAddr=0没有真实表现,KEIL的软件仿真效果和事实符合的很好。
经测定:如果没有VICVectAddr=0;这一句代码,程序将不会第二次进入中断例程。
......................抱歉,之前没看到用中断,现在在程序上稍作修改
P3口为控制口(中断int0——p3.2),P1口为输出口,p2口提供高电平,LED为共阳极,程序如下:
#include reg51.h
#define uchar unsigned char
#define uint unsigned int
sbit k1=P2^0;
sbit k2=P2^1;
sbit k3=P2^2;
sbit LED_1=P1^0;
sbit LED_2=P1^1;
sbit LED_3=P1^2;
void relay(uint ms)
{
uint i,j;
for(i=ms;i0;i--)
for(j=110;j0;j--);
}
void main()
{
while(1)
{
EA=1;
ET0=1;
while(P3^2==0)
{
if(k1==0)
{
LED_1=0;
relay(100);
}
if(k2==0)
{
LED_2=0;
relay(100);
}
if(k3==0)
{
LED_3=0;
relay(100);
}
}
}
程序完毕!
下面是电路图:
中断大概是这样的。。。如果有点错误不要怪我。。。我以前作过鼠标中断的东西。。现在有些想不起来了。。。所以。。。呵呵呵。。。
当程序运行到中断条件的时候,会向CPU发信号改变优先级(原先运行的东西会放进哪个特定的地方的,作保存),以发出中断的那段程序作为最高优先,执行完成后再由执行另外的。。。建议你去看看汇编。。。哈哈哈。。。我没学过的。。。
C中实现中断是用了一个函数:geninterrupt(...)
这个“...”是个16进制的数字,是中断号,像鼠标中断号就是0x33
还要用到类似汇编里寄存器模样的变量:如_AX,_BX,_CX,_DX...不同的值功能不同。。。哎呀,我都忘完了。。。建议去查下geninterrupt()的用法就OK了。。。
驻留程序
通俗点讲
就是
程序运行完了,
还要保留
临时数据
和
运行状态,
等下一次
调用时
继续
执行
和普通程序的
区别:
普通程序(如一个
子函数)
调用完了
,
临时数据
就
不需要了,
分配的
内存
空间
就
回收了,
而
驻留程序
是
要保留这些的
驻留
程序
主要
用于
中断函数
,
非中断函数
也
有应用,较少。分别举个例子:
1)用于
中断:
假设
一个
用
定时器
做的
时钟函数,定时器
设置为
1s一个中断。
main()
{
显示
时间
hour,min,sec;
//
循环
刷屏显示
}
中断函数
{
sec++;
if(sec=60)
{
sec=0;
min++;
}
if(min=60)
{
min=0;
hour++;
}
if(hour=24)
{
hour=0;
}
}
这时候
就能看出,
中断程序
在
运行完的
时候
不能
把
3个
变量
清空,
因为
下次
中断
还要用到
上次的
值,
这个程序
要
一直
驻留
内存;
2)再来个
普通
函数的
假设
做了一个程序
,程序中
有一个
函数aa,而
函数
aa
我只能
让它执行
3次就得
关闭程序(这个
用在
密码
验证上)
aa()
{
密码验证次数n+1
返回n
和
验证结果
}
那这个
aa函数
在
密码
验证
阶段
就要
常驻
内存
首先你要写中断函数
然后在主程序中像调用子函数一样调用就可以了
举个例子吧
#define uchar unsigned char
#define uchar unsigned char
sbit D1=P1^0;
uchar aa;
void init()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
void main()
{
init();
while(1)
{
if(aa==20)
{
D1=~D1;
aa=0;
}
}
}
void T0time()interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
aa++;
}