51单片机——中断系统、外部中断、定时器中断、串口通信C语言入门编程

  • Post author:
  • Post category:其他



目录


中断系统:


外部中断:


1.外部中断0、1:当触发时,LED状态取反


定时器中断:


1.定时器0、1:LED以1S为周期闪烁


串口通信:


1.串口中断:通过串口发送什么数据给单片机,单片机再通过串口发送回来



中断系统:



当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU

暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,

继续原来的工作,这样的过程称为中断。当几个中断源同时向 CPU请求中断,

CPU总是先响应优先级别最高的中断请求。

当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。STC89C5X 系列单片机提供了8个中断请求源,它们分别是:外部中断0(INT0)、外部中断1(INT1)、外部中断2(INT2)、外部中断3(INT3)、定时器0中断、定时器1中断、定时器2中断、串口(UART)中断。(需要查看手册确定具体中断)

所有的中断都具有四个中断优先级

(基本型只有两个)。每一个中断的优先级别均可用软件设置。


1.低优先级中断可被高优先级中断所中断,反之不能。

2.任何一种中断(不管是高级还是低级),一旦得到响应,不会再被他的同级中断所中断。

void Int0_Routine() interrupt 0
void Timer0_Routine() interrupt 1
void Int1_Routine() interrupt 2
void Timer1_Routine() interrupt 3
void UART_Routine() interrupt 4
void Timer2_Routine() interrupt 5
void Int2_Routine() interrupt 6
void Int3_Routine() interrupt 7


外部中断:



STC89C5X系列单片机提供了4个外部中断:外部中断0(INT0)、外部中断1(INT1)、外部中断2(INT2)、外部中断3(INT3)。

INT0 对应的是 P3_2 口的附加功能,INT1 对应的是 P3_3 口的附加功能。


1.外部中断0、1:

当触发时,LED状态取反

外部中断0函数

#include <REGX52.H>

void Int0_Init(void)
{
    IT0=1;//下降沿触发
    IE0=0;//中断请求标志位 触发后硬件置零
    EX0=1;//打开中断允许位
    EA=1;//打开总中断
    PX0=0;//设置优先级
}
/*中断函数模板
void Int0_Routine(void) interrupt 0
{
    
}
*/

外部中断1函数

#include <REGX52.H>

void Int1_Init(void)
{
    IT1=1;//下降沿触发
    IE1=0;//中断请求标志位 触发后硬件置零
    EX1=1;//打开中断允许位
    EA=1;//打开总中断
    PX1=0;//设置优先级
}
/*中断函数模板
void Int1_Routine(void) interrupt 2
{
    
}
*/

主函数

#include <REGX52.H>

void main()
{
    Int0_Init();
    Int1_Init();
    while(1)
    {
        
    }
}

void Int0_Routine() interrupt 0
{
    P2_0=~P2_0;
}

void Int1_Routine() interrupt 2
{
    P2_1=~P2_1;
}


定时器中断:

51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器。定时器/计数器和单片机的

CPU是相互独立的

。定时器/计数器工作的过程是自动完成的,不需要CPU的参与。51单片机中的定时器/计数器是根据机器内部的时钟或者是外部的脉冲信 号对寄存器中的数据加1。有了定时器/计数器之后,可以增加单片机的效率,一些简单的重复加1的工作可以交给定时器/计数器处理。CPU转而处理一些复杂的事情。同时可以实现精确定时作用。

振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)。

状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称S周期或时钟周期。

机器周期:1个机器周期含6个状态周期,12个振荡周期。

指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。

例如:外接晶振为12MHz时,51单片机相关周期的具体值为:振荡周期=1/12us; 状态周期=1/6us; 机器周期=1us; 指令周期=1~4us。

STC89C5X单片机内有两个可编程的定时/计数器T0、T1和一个特殊功能定 时器T2。定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。它随着计数器的输入脉冲进行自加1,也就是每来一 个脉冲,计数器就自动加1,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时 /计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到; 如果工作于计数模式,则表示计数值已满。可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。

我们希望每次进入中断函数时,i保存的是上次累加值,使用了static关键字,就可以让变量i实现这种功能,即不会每次进入中断函数后被初始化为0。假如去掉static关键 字,那么变量 i 就是一个局部变量,每次进入中断函数后,变量i初始值都是0, 也就是说它的值永远也不会递增到1000,从而实现不了1s定时。可以这样理解,

使用了static关键字就相当于将i变成了一个全局变量功能。


1.定时器0、1:

LED以1S为周期闪烁

定时器0函数

#include <REGX52.H>

void Timer0Init(void)		//1毫秒@11.0592MHz
{
    TMOD &= 0xF0;		//设置定时器模式
    TMOD |= 0x01;		//设置定时器模式
    TL0 = 0x66;		//设置定时初始值
    TH0 = 0xFC;		//设置定时初始值
    TF0 = 0;		//清除TF0标志
    TR0 = 1;		//定时器0开始计时
    ET0=1;
    EA=1;
    PT0=0;
}

/*中断函数模板
void Timer0_Routine() interrupt 1
{
    static unsigned int t0count;
    TL0 = 0x66;		//设置定时初始值
    TH0 = 0xFC;		//设置定时初始值
    t0count++;
    if(t0count>=1000)
    {
        	
        t0count=0;
    }
}
*/

定时器1函数

#include <REGX52.H>

void Timer1Init(void)		//1毫秒@11.0592MHz
{
    TMOD &= 0x0F;		//设置定时器模式
    TMOD |= 0x10;		//设置定时器模式
    TL1 = 0x66;		//设置定时初始值
    TH1 = 0xFC;		//设置定时初始值
    TF1 = 0;		//清除TF1标志
    TR1 = 1;		//定时器1开始计时
    ET1=1;
    EA=1;
    PT1=0;
}

/*中断函数模板
void Timer1_Routine() interrupt 3
{
    static unsigned int t1count;
    TL1 = 0x66;		//设置定时初始值
    TH1 = 0xFC;		//设置定时初始值
    t1count++;
    if(t1count>=1000)
    {
        	
        t1count=0;
    }
}
*/

主函数

#include <REGX52.H>
#include "timer0.h"
#include "timer1.h"

void main()
{
    Timer0Init();
    Timer1Init();
    while(1)
    {
        
    }
}

void Timer0_Routine() interrupt 1
{
    static unsigned int t0count;
    TL0 = 0x66;		//设置定时初始值
    TH0 = 0xFC;		//设置定时初始值
    t0count++;
    if(t0count>=1000)
    {
        P2_0=~P2_0;
        t0count=0;
    }
}

void Timer1_Routine() interrupt 3
{
    static unsigned int t1count;
    TL1 = 0x66;		//设置定时初始值
    TH1 = 0xFC;		//设置定时初始值
    t1count++;
    if(t1count>=1000)
    {
        P2_1=~P2_1;
        t1count=0;
    }
}


串口通信:



通信的方式可以分为多种,按照数据传送方式可分为串行通信和并行通信。按照通信的数据同步方式,可分为异同通信和同步通信。按照数据的传输方向又可分为单工、半双工和全双工通信。

串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。串行通信的特点:传输线少,长距离传送时成本低,且可以利用电话网等现 成的设备,但数据的传送控制比并行通信复杂。

并行通信通常是将数据字节的各位用多条数据线同时进行传送,通常是8位、16位、32位等数据一起传输。并行通信的特点:控制简单、传输速度快;由于传输线较多,长距离传送时成本高且接收方的各位同时接收存在困难,抗干扰能力差。

异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接 收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。 异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时 间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不 一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为“ 位间隔”的整数倍。异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位用于起止位,各帧之间还有间隔,因此传输效率不高。

同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同 步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符 间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步 可以通过两种方法实现。

单工是指数据传输仅能沿一个方向,不能实现反向传输。

半双工是指数据传输可以沿两个方向,但需要分时进行。

全双工是指数据可以同时进行双向传输。

衡量通信性能的一个非常重要的参数就是通信速率,通常以比特率(Bitrate)来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为10位×240个/秒 = 2400bps后面会遇到一个“波特率”的概念,它表示每秒钟传输了多少个码元。而码元是通信信号调制的概念,通信中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。如常见的通信传输中,用0V表示数字0,5V表示数字1,那么一个码元可以表示两种状态0和1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致;如果在通信传输中,有0V、2V、4V以及6V分别表示二进制数00、01、10、11,那么每个码元可以表示四 种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。由于很多常见的通信中一个码元都是表示两种状态, 所以我们常常直接以波特率来表示比特率。

串口通信(Serial Communication),是指外设和计算机间通过数据信号线、 地线等按位进行传输数据的一种通信方式,属于串行通信方式。串口是一种接口 标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。串口数据收发线要交叉连接,

计算机的TXD要对应单片机的RXD,计算机的RXD要对应单片机的TXD并且共GND。

RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。 “96”表示的是通信波特率为 9600。串口通信中通常使用的是异步串口通信,即没有时钟线,所以两个设备要通信,必须要保持一致的波特率,当然,波特率常用值还有4800、115200等。

“N”表示的是无校验位,由于串口通信相对更容易受到外部干扰导致传输 数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。

“8”表示的是数据位数为8位,其数据格式在前面介绍异步通信中已讲过。 当然数据位数还可以为 5、6、7位长度。

“1”表示的是1位停止位,串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑0的数据位表示,而数据包的停 止信号可由0.5、1、1.5 或2个逻辑1的数据位表示,只要双方约定一致即可。




1.串口中断:

通过串口发送什么数据给单片机,单片机再通过串口发送回来

串口函数

#include <REGX52.H>

void UartInit(void)		//4800bps@11.0592MHz
{
    PCON &= 0x7F;		//波特率不倍速
    SCON = 0x50;		//8位数据,可变波特率
    TMOD &= 0x0F;		//设置定时器模式
    TMOD |= 0x20;		//设置定时器模式
    TL1 = 0xFA;		//设置定时初始值
    TH1 = 0xFA;		//设置定时重载值
    ET1 = 0;		//禁止定时器%d中断
    TR1 = 1;		//定时器1开始计时
    ES=1;
    EA=1;
    PS=0;
}

void UART_SendByte(unsigned char Byte)
{
    SBUF=Byte;
    while(!TI);//等待TI=1
    TI=0;
}

/*串口中断模板
void UART_Routine() interrupt 4
{
    if(RI)
    {
        	
        RI=0;
    }
}
*/

主函数

#include <REGX52.H>
#include "UART.h"

void main()
{
    UartInit();
    while(1)
    {
		
    }
}

void UART_Routine() interrupt 4
{
    if(RI)
    {
        UART_SendByte(SBUF);
        RI=0;
    }
}



版权声明:本文为m0_69169562原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。