STC15W104支持的中断,不明白外部中断是什么意思,外部中断有什么很重要的作用吗
一,中断请求源
外部中断的触发方式
主要是检测电平的上升沿和下降沿来触发中断。
外部中断0:支持上升沿和下降沿两种触发方式
外部中断2,3,4:只支持下降沿触发
检测中断是否发生通过检测中断标志位,是 否允许中断发生设置中断控制
二,中断相关寄存器
寄存器配置
//中断特殊功能寄存器
sfr IE = 0xA8; //0000,0000 中断控制寄存器
sbit EA = IE^7;
sbit ELVD = IE^6;
sbit EADC = IE^5;
sbit ES = IE^4;
sbit ET1 = IE^3;
sbit EX1 = IE^2;
sbit ET0 = IE^1;
sbit EX0 = IE^0;
sfr IP = 0xB8; //0000,0000 中断优先级寄存器
sbit PPCA = IP^7;
sbit PLVD = IP^6;
sbit PADC = IP^5;
sbit PS = IP^4;
sbit PT1 = IP^3;
sbit PX1 = IP^2;
sbit PT0 = IP^1;
sbit PX0 = IP^0;
sfr IE2 = 0xAF; //0000,0000 中断控制寄存器2
sfr IP2 = 0xB5; //xxxx,xx00 中断优先级寄存器2
sfr INT_CLKO = 0x8F; //0000,0000 外部中断与时钟输出控制寄存器
中断允许寄存器 IE IE2 INT_CLKO
开启中断第一步找到中断源对应的控制位并开启
第二步开启中断总控制位 EA=1;
中断优先控制寄存器IP IP2
传统8051单片机 所有中断源可以申请:高优先级和低优先级 可以实现两级中断嵌套
任何一种中断不会被他同级的中断所中断
测试代码
#include "STC15WXX.H"
sbit LED1 = P3^1;
sbit LED2 = P3^0;
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
// _nop_();
// _nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//-----------------------------------------------
//中断服务程序 关门动作
void exint2() interrupt 10 //INT2中断入口
{
LED1 = 1;
Delay500ms();
Delay500ms();
Delay500ms();
}
中断服务程序 开门关门,两个中断同时触发
//void exint3() interrupt 11 //INT3中断入口
//{
// LED1 = 0;
// LED2 = 1;
//
INT_CLKO &= 0xDF; //若需要手动清除中断标志,可先关闭中断,此时系统会自动清除内部的中断标志
INT_CLKO |= 0x20; //然后再开中断即可
//}
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
LED1 = 0;
INT_CLKO |= 0x10; //(EX2 = 1)使能INT2中断
EA = 1;
while (1)
{
LED1 = 0;
}
}
额,采雷区了,不能在中断函数使用延时函数,这个需要优化,可是原因是什么
而且我已经猜到肯定使用定时器代替,但是这两者的区别是什么
在delay的这段时间,CPU处于死等的状态,这会导致中断处理的整体时间拉长,若还有其他低优先级的中断,会延误其他中断的处理,导致反应不够灵敏。但是使用定时器就不一样,在定时器计数的这段时间里,不会影响CPU去执行其他的事情,然后根据优先级去处理不同的中断。
优化方案一定时器
#include "STC15WXX.H"
sbit LED1 = P3^1;
sbit LED2 = P3^0;
//-----------------------------------------------
//中断服务程序 关门动作
void exint2() interrupt 10 //INT2中断入口
{
LED1 = 1;
//100ms后关闭LED1,额最大计数单位就是ms,
TH0 = 0x4C;
TL0 = 0x00;
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
LED1 = 0;
}
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
LED1 = 0;
INT_CLKO |= 0x10; //(EX2 = 1)使能INT2中断
EA = 1;
AUXR &= 0x7f; //定时器0为12T模式
TMOD = 0x00; //设置定时器为模式0(16位自动重装载)
while (1);
}
优化方案二标志位
我倒是有个问题,为什么低功耗的产品的I/O状态需要中断来检测,如果使用中断检测的话,我倒是能理解使用两个I/O口
#include "STC15WXX.H"
sbit LED1 = P3^1;
sbit LED2 = P3^0;
sbit Door_GUAN = P3^4;
sbit Door_KAI = P3^5;
unsigned int door_flag; //1=开门 1亮 2=关门 2亮 0=无变化
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
//-----------------------------------------------
//中断服务程序 关门动作
void exint2() interrupt 10 //INT2中断入口
{
door_flag = 2;
}
//中断服务程序
void exint3() interrupt 11 //INT3中断入口
{
door_flag = 1;
}
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
LED1 = 0;
door_flag=0;
INT_CLKO |= 0x10; //(EX2 = 1)使能INT2中断
INT_CLKO |= 0x20;
EA = 1;
while (1)
{
if(door_flag == 1) //door_flag=1时,说明已经检测到下降沿的低电平端,接下来就是消抖
{
door_flag = 0;
Delay1ms();
if( Door_GUAN == 0)
{
LED1 = 1;
LED2 = 0;
}
}
else if( door_flag == 2)
{
door_flag = 0;
Delay1ms();
if( Door_KAI == 0)
{
LED1 = 0;
LED2 = 1;
}
}
}
}
三,电池低压检测电路
分析完电路后,为什么通过外部检测电路来检测I/O口的变化,而不是直接读取I/O口,由原理图可知由外部中断INT1检测
检测代码
经检测电池电压6v左右才算低压,既然给予这个临界线,表示变量还有一个的状过渡状态
高电平:严格意义上是 VCC (2.2V以上)
低电平: 严格意义上是 GND (0.8V以下)
#include "STC15WXX.H"
sbit LED1 = P3^1;
unsigned int vlot_low; // 0 表示电池未低压 2表示低压 1表示检测低压的状态
//未低压I/O端口为高电平,低压为低电平
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//-----------------------------------------
//中断服务程序
void exint1() interrupt 2 //INT1中断入口
{
vlot_low = 1;
}
//-----------------------------------------------
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
IT1 = 1; //设置INT1的中断类型 (1:仅下降沿 0:上升沿和下降沿)
EX1 = 1; //使能INT1中断
EA = 1;
while (1)
{
if(vlot_low == 1)
{
Delay1ms();
if(P33 == 0)
{
vlot_low = 2;
}
}
if(vlot_low == 2)
{
LED1 = 1;
Delay500ms();
LED1 = 0;
Delay500ms();
}
}
}
那么这样的话,为什么不直接读取I/O口的状态