单片机攻略4——中断和串口

一、中断

首先要明白什么是中断程序

书上说:中断程序是一种特殊的程序运行方式,中断向量是这个中断程序运行的入口,一个中断程序包括中断请求,中断响应,中断关闭三步走。定义很严谨,用我的理解来讲中断其实可以类比我们日常生活中的“随时响应”

比如说:目前正在努力学习(主函数执行其任务),突然肚子咕咕叫起来(中断请求),肚子叫是随时都有可能发生的,也有可能是每次饭后隔3个小时又饿了,反正就是在满足肚子饿了的条件下才会叫(中断开关和条件),提醒我们要进食了(中断响应)。吃完饭后我们回去继续学习(中断返回)。

从程序的角度来看,一旦打开中断开关,中断就会开始判断条件,满足条件之后执行中断里面的程序内容。理清楚先后顺序对于理解后面的大规模程序非常重要。


二、中断几种类型

在C51/C52中有3大类中断服务:定时器计数器(简称定计,计数最小单位为1次,计时单位为1us)、串口通信(串口)、功率控制

六个中断控制寄存器。TCON是控制定时器的启停,溢出和中断情况、SCON串口控制、PCON功率控制、中断允许IE、中断优先级IP、TMOD定计控制端口。其中:TCON、IE最好位寻址,其余的最好还是字节寻址。

控制这几个口直接采用字节寻址的方式比如:TMOD=0x01代表设置定时器T0工作于方式1。

位寻址那就是直接 TR0=1;ET0=1; //对TCON的TR0位直接控制置1,ET0=1打开定时器0的开关

注意:C52/51的P3端口就是不同中断的控制口(见前几篇文章的C51引脚配图)。

2.1 TCON和TMOD

细节看这个(9条消息) 51单片机---IE寄存器,TCON寄存器,TMOD寄存器_IMET-的博客-CSDN博客_ie寄存器

——1.TMOD的Gate位一般用来测量时序长度,所以大部分时间不用,赋0。

——2.写程序时:一般先开启TMOD,设置好计数值TH和TL,选择TCON和IE要打开的开关,最后一个EA开启总中断即可完成。

——3.计数值的设置问题:1.用STC-ISP提供的功能计算   2.TH=(当前选择的工作方式的计数/计时最大值 - 目标计数/计时值)/256     TL = (当前选择的工作方式的计数/计时最大值 - 目标计数/计时值)% 256。写程序时,除了方式2,计数值的设置需要在初始化和中断函数两个地方都写上。

——4.TCON中的TF:定计计数满溢出TF变成1,使用中断会自动清零,比较方便。但是要是用查询的方式(也就是自己写的函数)完成定时器计数器任务就需要人工清零。

——5.四种计数方式的对比:

方式0:13位定时计数方式,最大计数值为2^13=8192,定时8192个机器周期。此方式已经不再用了,是为了和以前的单片机兼容,初学者不用掌握。
方式1:16位定时计数方式,最大计数值为2^16=65536,定时65536个机器周期。此方式可实现最大的定时时间和最大计数次数。是最常用方式之一。
方式2:8位自动重装计数方式,最大计数值为2^8=256,定时256个机器周期。此方式工作时定时或计数到了不用重装初值,而且TH和TL设置的数据大小一样。另外在串口通讯时常用此方式。是最常用方式。
方式3:特殊工作方式。将定时器0分成两个8位功能不全的定时计数器,要占用T1部分功能。也不常用。

main(){
TMOD = 0X01; 
TH0 = (65535 - 50000) / 256; //计时50000us,50ms
TL0 = (65535 - 50000) % 256; 
EA = 1; //总中断
 ET0 = 1; //T0定计中断
 TR0 = 1; //开始工作
while(1);
}

2.2 SCON

数据传输:对于数据的发送,我们都是把数据转换成一串串的字节。比如发送“HelloWorld”,计算机会先对其采用ASCALL编码(不同的编码方式),比如变成:0xb3(H),0x23(e),0x43(e),0xf6(l),0x7d(l)...发送一个字节最后再组装。而衡量发送字节的快慢这是波特率。

波特率:单位时间内(一般1s)发送的二进制数据位数。例如9600b/s,每秒发9600位,算成字节就是9600/8=1200个字节。

SCON的产生和定计T1密切相关,有一个SCON对应的定计方式选择和初值选择表,可以直接参考。也可以使用波特率计算器,我放上来,不要积分。

(9条消息) 51波特率初值设定计算器-嵌入式文档类资源-CSDN文库

细节参考这个博主的文章。 

(9条消息) TMOD、SCON、PCON寄存器的配置_逸凌Time的博客-CSDN博客_scon寄存器

——1.每个串口的工作方式发送的帧不同,直接影响TB8和RB8。方式0:扩展并行IO口;方式1:双机通信;方式2:双机和多机通信;方式3:同上。

——2.实际使用起来,用定计T1方式2;且发送数据用查询方式,接收数据用中断方式。如下:

#include "reg52.h"			 //接收数据程序

sbit led=P0^0;   //将单片机的P0.0端口定义为led

void UsartInit()        //串口初始化函数,新手可以直接写在main函数里,熟悉再模块化
{
	SCON=0X50;			//设置为工作方式1
	TMOD=0X20;			//设置计数器工作方式2
	PCON=0X80;			//波特率加倍
	TH1=0XF4;				//计数器初始值设置,注意波特率是4800的
	TL1=0XF4;
	ES=1;						//打开接收中断
	EA=1;						//打开总中断
	TR1=1;					//打开计数器
}

void main()
{	
	UsartInit();  //	串口初始化
	while(1);		
}

void Usart() interrupt 4	//进入中断服务函数
{
	char receiveData;

	receiveData=SBUF;//出去接收到的数据,此时SBUF存放接收数据
	RI = 0;//清除接收中断标志位
	if(receiveData=='1') 
	{
		led=1;			 //接收1时,打开LED灯
	}
	if(receiveData=='0') 
	{
		led=0;			 //接收0时,关闭LED灯
	}
    SBUF=receiveData;
	while(!TI);			 //等待发送数据完成
	TI=0;						 //清除发送完成标志位
}

发送数据用查询方法: 

#include 
//发送数据查询方式 
void delay(unsigned char x)
{
  int i,j;
  for(i=0;i

同时收发程序:

#include 
sbit LED1 = P1^0;
sbit LED2 = P1^1;
unsigned char UART_buff;
bit New_rec = 0;
bit Send_ed = 1;

void delay(unsigned char x)
{
  int i,j;
  for(i=0;i

2.3 中断的使用方法概括

void nameoffunction() interrupt n using m
{}

中断函数必须void;name就是中断函数的名字;interrupt 是关键字不能少,后面的n是中断号;using m是用几号工作寄存器。

中断号:n=0:INT0外部中断0控制号;n=1:定计T0中断控制口;n=2:外部中断INT1控制;n=3:T1定计控制口;n=4:串口中断控制口;【n=5:T2定计控制口,T2定时计数器其C51/52单片机都没有】

工作寄存器:将工作寄存器内容保存到堆栈中,中断函数返回前进行恢复。m=0~3,有四个,不能混用,可以省略不指定,程序会自动分配。

你可能感兴趣的:(单片机开发原理,单片机,嵌入式,51单片机)