Autoleaders控制组-------蓝桥笔记(二)

本文详细介绍了51单片机中的中断系统、定时器功能、PWM的应用以及串行通信,包括中断初始化、服务函数的编写,以及如何利用定时器实现波特率控制和串口通信。
摘要由CSDN通过智能技术生成

蓝桥笔记(二)

1.中断系统

中断系统可以实现:在设备请求服务或程序需要处理某些事件时,立即切换到相应的中断服务程序,并且当中断服务程序执行完后,返回主函数,恢复原工作状态继续执行。有了中断系统就可以使程序执行更加高效。
形象的来说,中断系统就像在办公室上班一样,本来在做手里的事情,突然电话响了,你就停下手中的事情,接电话,接完电话,再回到手中的事情。手中的事情就是主函数,电话响了就是中断,打电话的时候就是执行中断服务函数,打完电话再回到手中的事情就是恢复主函数运行状态。
使用中断系统需要两个函数,一个是初始化函数,用来允许中断的产生与作用,另一个是中断服务函数,用来在中断后执行一系列操作。有了中断,那么执行时会以【主函数】----->中断产生---->【中断服务函数】---->【主函数】的路线运行。

1.1中断初始化函数

要初始化,首先我们需要了解与中断相关的寄存器。与中断相关的一共有四个寄存器(均可以位寻址),IE寄存器IP寄存器TCON寄存器SCON寄存器。其中IE相当于中断的开关,IP用来规定中断优先级,TCONSCON则与中断标志和启动有关。
IE寄存器:

EAESET1EX1ET0EX0
总开关串口定时器1外部中断1定时器0外部中断0
0:禁止中断1:允许中断

IP寄存器:

PT2PSPT1PX1PT0PX0
定时器2串口定时器1外部中断1定时器0外部中断0
0:低优先级1:高优先级

TCON寄存器:

TF1TR1TF0TR0IE1IT1IE0IT0

TF1:定时/计数器T1中断请求标志位(0:无中断请求,1:有中断请求)。
TR1:定时/计数器T1启动位(0:停止定时/计数器,1:启动定时/计数器)。
TF0:定时/计数器T0中断请求标志位(0:无中断请求,1:有中断请求)。
TR0:定时/计数器T0启动位(0:停止定时/计数器,1:启动定时/计数器)。
IE1:外部中断1请求标志位。
IT1:外部中断1触发方式控制位(0:低电平触发,1:下降沿触发)。
IE0:外部中断0请求标志位。
IT0:外部中断0触发方式控制位(0:低电平触发,1:下降沿触发)。

SCON寄存器:

T1R1

T1:串行接口发送信息完成标志位,发送完成后为1(需要软件手动清除为0)。
R1:串行接口接收信息完成标志位,接收完成后为1(需要软件手动清除为0)。

了解了这四个寄存器之后,我们就可以开始初始化了,初始化内容根据所需要的中断源来决定,如果需要的是外部中断0,就要把总开关EA打开,再把外部中断0的开关EX0打开,把外部中断标志IE清零,选择外部中断触发方式。具体操作如下:

void init_timer0()
{
	IE0=0;
	IT0=0;
	EA=1;
	EX0=1;
}

这就是外部中断0的初始化函数了。

1.2中断服务函数

当中断源产生以后,会执行中断服务函数,编写一个中断服务函数,需要注意函数格式:

void 函数名() interrupt 中断号

中断服务函数没有返回值,也不能带参数,而且需要在中断服务函数后面加上interrupt作为中断服务函数的标志,而中断号则是标志和区分此服务函数为哪一个中断源服务的。

中断号对应的中断源
0外部中断0 (INT0)
1定时/计数器T0
2外部中断1 (INT1)
3定时/计数器T1
4串口中断

下面是一个例子:

void service() interrupt 0
{
	tt=1;
}

当然,在工作的时候接到电话,谁都不希望被打扰太久,所以中断服务函数里面做的事情越少越好,这样才能尽快回到主函数里。中断一次之后,需要再初始化一次后才可以让中断再次起作用。

2.定时/计数器

定时/计数器一般会与中断系统组合起来,定时器可以用来定时,形象地说,定时器是一个闹钟,时间到了就会响,即发出中断请求,进入中断服务函数。计数器可以用来记录非周期性外部输入信号的次数,当记录数达到要求的时候,也会发出中断请求,进入中断服务函数。
本质上来讲,定时器和计数器都是计数器,不同点在于,定时器是在初始值的基础上,每过单位时间就会加一,当加到某个设定值时就会触发产生中断请求。而计数器则是每接收一次信号就加一,也是到当加到某个设定值时就会触发产生中断请求。
你可以把这个定时器想象成是一个水壶,里面的水会随着时间而均匀地增加,等啥时候水要溢出来了,就会产生一个脉冲,相当于闹钟。 想要设定不同的时间,可以设定初始水位的高低,如果想要定时久一点,就让水位低一些,反过来像定时短一点,就让初始水位高一些,至于如果想要定一个比较长的时间,大致操作就是当水满了之后把水倒掉,重新计时,这样反复操作就可以延长的定时了,而计数器原理类似。

2.1与定时/计数器相关的寄存器

与定时/计数器相关的寄存器有两个16位寄存器TCON寄存器TMOD寄存器
16位寄存器:
两个16位寄存器分别是 定时/计数器T0定时/计数器T1,每个十六位寄存器是由两个八位寄存器组成,低的八位是TLx,高的八位是THx(x为编号),最大记录数是65535,也就是说当记录数达到最大值时,再加一就产生溢出。而加一的频率是由单片机的晶振频率来决定的,假设计数脉冲为10Hz,那么相当于每一秒寄存器就会加10,如果我们要定时3秒,就要让寄存器初始值为65505,这样三秒过后,就会溢出产生脉冲。
也就是说,我们需要在定时/计数前给TLxTHx设定初始值以达到定时的目的。

TCON寄存器(中断中有提到):

TF1TR1TF0TR0----------------

TF1:定时/计数器T1中断请求标志位(0:无中断请求,1:有中断请求)。
TR1:定时/计数器T1启动位(0:停止定时/计数器,1:启动定时/计数器)。
TF0:定时/计数器T0中断请求标志位(0:无中断请求,1:有中断请求)。
TR0:定时/计数器T0启动位(0:停止定时/计数器,1:启动定时/计数器)。

注意TCON可以位寻址,但TMOD不能。

TMOD(模式控制):

GATEC/TM1M0GATEC/TM1M0

(左侧为高位,右侧为低位)
高四位用于定义 定时/计数器T1的模式 ,低四位用于定义 定时/计数器T0 的模式。
GATE(门系统):
当GATE=0,由TR0/TR1启动定时器。
当GATE=1,由外部中断INT0/INT1启动定时器。
C/T(计数/定时):
高电平计数,低电平定时。
M1,M0用于设定寄存器工作模式:

M1M0工作模式
0013位定时/计数模式
0116位定时/计数模式
10自动重装八位定时/计数模式
11T0分为独立的两个八位定时器,T1停用

若无自动重装,每次都需要手动重新赋初始值。

2.2定时/计数器初始化与服务函数

要想启动定时/计数器,需要一个初始化函数,设置定时器的参数然后再写一个中断服务函数,用来执行定时结束后的事情:

void init()
{
	EA=1;
	ET0=1;
	TMOD=0x01;
	TH0=0x00;
	TL0=0x00;
	TF0=0;
	TR0=1;
}

然后写一个主函数和中断服务函数:

unsigned char f=10,i=0;
void main()
{
	init();
	while(1)
	{
		if(i==1)
		{
			nixie(1,1);
		}
		nixie(2,4);
	}
}
void ieee() interrupt 1
{
	//TH0=0x00;
	//TL0=0x00;  若无自动重装需要手动重装
	f--;
	if(f==0)
	{
		i=1;
	}
}   

这里我们让它计时完就让参数f减一,如此就实现了延长定时的功能。

3.PWM(脉宽调制)

脉宽调制是利用微处理器的数字输出,来对模拟电路进行控制的一种非常有效的技术,通过对一系列脉冲的宽度进行调制,来等效的获得所需要的波形,即通过改变导通时间占总时间的比例,也就是占空比,达到调整电压和频率的目的。
在51单片机中需要利用定时器来实现调制脉宽的功能。调制脉宽有什么作用呢?它可以实现对LED灯光亮度的控制,实现电机功率的控制等等。拿LED的亮度控制举例,我们能控制LED灯的亮度,是因为我们控制了LED的工作时间,比如我希望它亮度为50%,只需要在每秒钟里有一半的时间都是熄灭状态,一半的时间是亮起的状态就可以实现。也就是说,我们需要利用定时器控制LED亮起和熄灭的频率,虽然LED不停在闪,但由于亮灭频率比较高,我们肉眼是无法观察到灯在闪的,只能观察到亮度暗了一些。
现在举个例子,我们用定时器设置灯的信号频率为100Hz,相当于把一秒拆分成了100份,每一份我们都只让其中的一半时间让灯亮起,另一半熄灭,这样就达成了亮度为50%的目的。让我们来实际操作一下:

void Timer0Init(void)	
{
	EA=1;
	ET0=1;	
	TMOD=0x01;	
	TL0 = 0x66;		
	TH0 = 0xFC;		
	TF0 = 0;		
	TR0 = 1;		
}
unsigned char con
void main()
{
	if(con<50)
	{
		light();
	}
	else
	{
		unlight();
	}
}
void service() interrupt 1
{
	con++;	
	if(con==100)
	{
		con=0;
	}
}

总的来说,PWM是一种技术,而且很常用,虽然一些新的单片机其实已经将这个给融合进定时器里了,但我们还是需要加以理解和练习。

4.串行通信

串行通信就是将一串数据一位一位地顺序发送或者接收。串口通信有SPI,IIC,UART等种类,UART是最常用的。串口通信有单工,半双工,全双工三种制式,串口通信的方式主要有两种:同步和异步。

单工:要么只能发送,要么只能接收。
半双工:既可以发送信息,也可以接收,但两者不能同时进行。
全双工:同时可以进行的接收和发送信息。
同步:两个设备连接着一条线用来确定时间,或者使用同一个时钟,以达到收发信息同步的目的。
异步:两个设备约定一个相同的速率来收发信息,会有误差,但也可以正常收发信息。

这里需要提到一个概念叫做波特率,就是每秒接收或者发送信息的位数。
为了保证收发信息准确,发送信息会有起始位,停止位,有的还会有校验位。
在51单片机里,串口通信一共有四个模式,其中模式1和模式3的波特率是可以改变的,这取决于定时器,一般会使用定时器1的工作模式2(8位自动重装模式)来产生波特率,在这个模式下,TH1作为自动重装寄存器,而TL1作为脉冲计数寄存器,当计数器达到最大计数值溢出时,TH1的值会自动装到TL1中。

在12M或者11.0592M的晶振的情况下,要产生9600的波特率时,若SMOD=0时,参数位0xfd;SMOD=1时,参数为0xfa。

4.1与串口有关的寄存器

两个缓冲寄存器SBUF:
这两个SBUF,一个是发送寄存器,一个是接收寄存器,用来发送信息或者接受信息。它们在物理结构上是完全独立的两个寄存器,字节寻址,但两者拥有完全相同的地址。
当往SBUF写入值的时候,是往发送寄存器里写入东西,而当读取SBUF的值时,是读出接收寄存器的东西。所以是靠做左值运算还是右值运算来区分SBUF的。

SCON串口控制寄存器:

SM0SM1SM2RENTB8RB8TIRI

TIRI:
数据发送完成,TI标志位值会被置1,而接收数据完成,RI标志位值会置1。这两个标志位都需要手动软件清零。
TB8RB8:
分别是发送数据和接收数据的第八位。用于奇偶校验。
REN:
当REN=1时允许接受数据。REN=0时,禁止接收数据。
SM0SM1
控制工作模式:

SM0,SM1工作模式
00同步移位寄存器(波特率:fosc/12)
018位可变波特率的UART
109位UART(波特率:fosc/32或者fosc/64)
119位可变波特率的UART

SM2置0即可。
串行通信一般使用异步八位UART并且允许接收数据模式,所以令SCON=0X50即可。

辅助寄存器AUXR(0x8e)
这个寄存器没法直接使用,需要自己定义一下。其实不管这个寄存器也没有关系,如果要用,直接赋值为0x00即可。

B7B6B5B4B3B2B1

B7:定时器0的速度控制位
为0:12分频。为1:不分频。
B6:定时器1的速度控制位
为0:12分频。为1:不分频。
B5:串口1模式0的通信速度设置
为0:12分频。为1:2分频。
B4:定时器2运行控制位
为0:不可运行。为1:允许运行。
B3:定时器2作定时/计数器控制位
为0:作定时器。为1:作计数器。
B2:定时器2的速度控制位
为0:12分频。为1:不分频。
B1:内部/外部RAM存取控制位
为0:允许使用扩展RAM。为1:不允许。
B0:串口1选则定时器1/2控制位
为0:选择定时器1为串口1的波特率发生器。
为1:选择定时器2为串口1的波特率发生器。

4.2串口中断的初始化函数和中断服务函数

首先写一个初始化函数:

sfr AUXR=0x8e;
void init()
{
	AUXR =0x00;
	TMOD=0x20;  //八位自动重装模式
	TL1=0xfd; //波特率9600
	TH1=0xfd;
	TR1=1;
	SM0=1;SM1=0;REN=1;//SCON=0x50
	EA=1;//总开关
	ES=1;//串口中断开关
	TI=0;//清除标志
	RI=0;
}

初始化不仅要打开串口的中断,还需要打开定时器1,用定时器1来产生波特率。
然后我们可以单独写一个用于发送信息的函数:

void send(unsigned char mes)
{
	SBUF=mes;
	while(TI==0);
	TI=0;//手动清除标志
}

再写一个用于接收信息的中断服务函数:

void service() interrupt 4
{
	if(RI==1)
	{
		dat=SBUF;
		RI=0;//手动清除标志
	}
}

这样就可以在主函数里随意调用来接收和发送信息的函数了,但在调试的时候要注意一下在STC-ISP上打开串口,设置相同的波特率后才能正常的收发信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值