STC15F2K60S2/中断详细讲解
STC15F2K60S2中断程序详细讲解
T0中断
/****************************************************************/
/****************************2019.11.15**************************/
/********************吉林大学无线电爱好者协会********************/
/**************************单片机基础培训************************/
/************************Creat by Devilaboy**********************/
/****************************************************************/
/****************************************************************/
/*************************头文件+宏定义区************************/
#include <STC15FXXXX.H>
#define key1 P33
#define key2 P32
#define led1 P00
#define led2 P01
#define led3 P02
#define led4 P03
#define led5 P04
#define led6 P05
#define led7 P06
#define led8 P07
#define uchar unsigned char
/****************************函数声明*************************/
void breath();
void Timer0Init(void) ;
void delayus(unsigned int a);
/***************************主函数*****************************/
void main()
{
Timer0Init();
breath();
}
/****************************中断函数*************************/
void Timer0Init(void) //(我们的T0用的是16位自动重装定时器模式)
{
TMOD=0x00;// 16位自动重装
TL0 =( 65536-50000)%256;//低位装入 (对于晶振为12MHz的片子来说,65536-50000,意思是实现程序的50ms定时,因为一次指令周期是1us,这里执行了50000个指令周期才溢出)
TH0 = (65536-50000)/256;//高位装入
EA=1; //打开全局中断
ET0=1; //打开定时器1中断
//TF0 = 0;//中断溢出清零,对于TMOD=0x00模式来说,该操作由系统自动完成
TR0 = 1;//开启定时器0
}
uchar a=0;
void TIME0() interrupt 1 //定义定时器0中断函数
{
a=a++;
if (a==20)//执行20次循环,即定时器中断效果显现设定为非常准确的1s
{
led2=~led2;led4=~led4;led6=~led6;led8=~led8;
a=0;
}
}
/************breath***********/
void breath()//设计一个模拟PWM波控制的呼吸灯程序,大家可以自己想一下为什么会有这种效果
{
int b=0,c=1600;
// while(1)
// {
for(b=1;b<c;b++)//大家可以试下让b=0,看一看灯会有什么效果,并想一想这是为什么
{
led1=0;led3=0;led5=0;led7=0;
delayus(b);
led1=1;led3=1;led5=1;led7=1;
delayus(c-b);
}
for(b=1500;b>0;b--)
{
led1=0;led3=0;led5=0;led7=0;
delayus(b);
led1=1;led3=1;led5=1;led7=1;
delayus(c-b);
}
// }
}
void delayus(unsigned int a) //@12.000MHz
{
while(--a);
}
一、上面程序涉及到的几个相关寄存器
1、TCON(可位寻址)
这里我们内部中断常用到的就是TF0/1 、TR0/1
可位寻址的意思就是,我们不用写整个寄存器的名字来设置这个寄存器,我们直接写寄存器中的某一位的名字就可以来设置了。
2、TMOD(不可位寻址)
在这里,我们主要设置
1、定时器的工作模式
2、是内部中断触发还是外部中断触发
其中我们常用的工作模式是
模式0:16位自动重装(在用内部时钟中断的时候常用)
模式2:8位自动重装(在设置波特率的时候常用,在我的另一篇介绍有关串口中断的文章中深有体现,附上文章链接 https://blog.csdn.net/Star19180325/article/details/103396806)
3、IE(中断允许寄存器)/IP(中断优先级设置寄存器)(可位寻址)
这里我们常用到的有
EA:开启全局中断
ET0/1:打开定时器0或者定时器1的中断
二、定时器0的介绍
设置一个定时器中断的大致过程就是
1、配置寄存器工作方式
三、中断级别以及中断程序的大致写法介绍
中断源 | 默认中断级别 | 序号(C语言用) | 入口地址(汇编语言用) |
---|---|---|---|
INT0,外部中断0 | 最高 | 0 | 0003H |
T0,定时器/计数器0中断 | 第2 | 1 | 000BH |
INT1,外部中断1 | 第3 | 2 | 0013H |
T1,定时器 /计数器1中断 | 第4 | 3 | 001BH |
TI/RI,串行口中断 | 第5 | 4 | 0023H |
T2,定时器/计数器2中断 | 最低 | 5 | 002BH |
单片机在使用中断功能时候,通常需要设置两个与中断有关的寄存器
IE:中断允许寄存器
IP:中断优先级寄存器
具体的使用方法在上面的技术文档截图中已经介绍过了,在这里不再赘述。
void TIME0() interrupt 1 //定义定时器0中断函数
{
a=a++;
if (a==20)//执行20次循环,即定时器中断效果显现设定为非常准确的1s
{
led2=~led2;led4=~led4;led6=~led6;led8=~led8;
a=0;
}
}
这里我们看到,是定时器0的中断程序的写法
普适格式如下
void 函数名() interrupt 中断号 using 工作组
{
中断服务程序//(中断程序里面的东西最好能迅速的执行,不要有延时什么的,否则会影响正常程序的执行)
}
这里需要注意几点
- 中断程序不能有任何的返回值,所以函数定义的时候一定是void
- 函数名的名字可以随便起,但是一定要方便辨认,不要和已有的函数名冲突
- 中断函数里面应该不能带任何的参数,所以函数名后面的()里面是空的,或者写void
- 中断序号指的是单片机那几个中断源的序号,具体的请看上面的那个表;这个序号非常重要,是编译器识别不同中断的唯一符号,因此在写中断服务的时候一定一定一定要写好,写正确。
- using 工作组:是指这个中断函数使用单片机内存4组工作寄存器中的哪一组,对于KEIL,编译器在变异的时候会自动分配工作组,所以这个通常我们会直接忽略
四、附上其他的程序
T0+T1中断
/****************************************************************/
/****************************2019.11.15**************************/
/********************吉林大学无线电爱好者协会********************/
/**************************单片机基础培训************************/
/************************Creat by Devilaboy**********************/
/****************************************************************/
/****************************************************************/
/*************************头文件+宏定义区************************/
#include <STC15FXXXX.H>
#define key1 P33
#define key2 P32
#define led1 P00
#define led2 P01
#define led3 P02
#define led4 P03
#define led5 P04
#define led6 P05
#define led7 P06
#define led8 P07
#define uchar unsigned char
/****************************函数声明*************************/
void breath();
void Timer01Init(void) ;
void delayus(unsigned int a);
/****************************主函数*****************************/
void main()
{
while(1)
{
Timer01Init();
breath();
}
}
/****************************中断函数*************************/
void Timer01Init(void)
{
TMOD=0x00;
TL0 =( 65536-50000)%256;
TH0 = (65536-50000)/256;
TL1 =( 65536-50000)%256;
TH1 = (65536-50000)/256;
EA=1;
ET0=1;
ET1=1;
//TF0 = 0;//中断溢出清零,对于方式0来说,由系统自动清零
TR0 = 1;
TR1 = 1;
}
uchar a=0,b=0;
void TIME0() interrupt 1
{
a=a++;
if (a==20)
{
led5=~led5;led6=~led6;
a=0;
}
}
void TIME1() interrupt 3
{
b=b++;
if (b==10)
{
led7=~led7;led8=~led8;
b=0;
}
}
/************breath***********/
void breath()
{
int b=0,c=1600;
// while(1)
// {
for(b=1;b<c;b++)
{
led1=0;led2=0;led3=0;led4=0;
delayus(b);
led1=1;led2=1;led3=1;led4=1;
delayus(c-b);
}
for(b=1500;b>0;b--)
{
led1=0;led2=0;led3=0;led4=0;
delayus(b);
led1=1;led2=1;led3=1;led4=1;
delayus(c-b);
}
// }
}
void delayus(unsigned int a) //@12.000MHz
{
while(--a);
}
未闻花名0926: 你好,这个怎么实现级联
立志控制全栈: 请问怎么添加啊? 可以讲讲嘛?
huangfang8161: 这个电路可以考虑增加一些东西,使它具有过流/输出短路保护功能
2401_85647329: 用LCD12864显示该怎么修改
somebodyunsimple: 谢谢博主的分享,但是你的后级电路中,有一个稳压二极管虽然可以保护Pmos管,但是在缓启动完成之后,也会对电路发挥稳压作用,会对后级电路产生较大的噪声纹波。同时与MOS并联的两个电容也会在缓启动之前进行储能放电,影响到缓启动的效果