(重修改的版本)搞了个单片机3:数码管(静态部分)、中断程序、定时器。(蓝桥杯单片机速成)(零基础!超详细!小白速成!教你跑遍单片机例程!)

对不起大家,之前这个我看错文件,现在没问题了,我还上传了验证的视频。
这边,开讲之前,我们插入几个知识点

在这里插入图片描述
单片机只有在启动的时候,才检测要不要下载程序,所以,这就是冷启动的意义。

——————————————————————————————————————————————————————————————————————————————————————————————————————

数码管静态显示

在这里插入图片描述
在这里插入图片描述
这是共阳的数码管,共阳和共阴根据我单片机系列文章的第一个文章中有详细说明。
数码管的显示分为静态显示和动态显示,我今天先说静态显示,动态显示下一节说。静态显示可保持显示。

下面我们来研究电路图

在这里插入图片描述
这个是我连的电路图,其中会有重复的寄存器,表示是同一个东西,只是为了方便观看而已。
下面我们来一步一步拆解这个电路图。
在这里插入图片描述
位选控制让哪一位亮,段选控制让哪一节数码管亮。
我们先来看位选
在这里插入图片描述
我们可以看到是P0口控制位选,我们接着往下看
在这里插入图片描述
然后我们又发现,想要控制位,必须先打开锁存器,然后我们顺藤摸瓜,熟悉的一幕又出现了,和LED、蜂鸣器一样的场景。最终都是由P27-P25端口控制的。

下面我们再来看段选
在这里插入图片描述
我们发现,段选也是由P0口控制的
再接着往下看
在这里插入图片描述
最终也是由P2控制的,所以段和位的控制原理基本一样。
—————————————————————— 电路图研究到此为止 ————————————————————
接下来,我们就要想办法写程序了,我们先控制一个位的数码管,代码如下:
我们先控制位选
首先,我们要打开Y6口,我们要对比真值表来:
在这里插入图片描述
在这里插入图片描述P2口的其他位置并不需要操作,所以我们其他位都是1。P27-P20就是1101 1111。我们首先要将P2口的高三位初始化,并或上“位”的控制信号。
在这里插入图片描述
在这里插入图片描述
这个结果就是我们刚刚分析的结果。
下面,代码上:

#include <STC15F2K60S2.H>
void main(void)
{
		P2 = ((P2&0x1f)|0xc0);
}

接下来,我先让第一个位的数码管亮
分析如图:
在这里插入图片描述
代码上:

#include <STC15F2K60S2.H>
void main(void)
{
		P2 = ((P2&0x1f)|0xc0);
		P0 = 0x01;
		P2 &= 0x1f;
}

再接下来,我们要控制段选了!
我们要打开Y7口
在这里插入图片描述
我们要找到真值表中对应的P27-P25的值
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
上代码:

#include <STC15F2K60S2.H>
void main(void)
{
		P2 = ((P2&0x1f)|0xc0);
		P0 = 0x01;
		P2 &= 0x1f;
	
		P2 = ((P2&0x1f)|0xe0);
	
		P2 &= 0x1f;
}

我打算先亮个0
在这里插入图片描述
上代码:

#include <STC15F2K60S2.H>
void main(void)
{
		P2 = ((P2&0x1f)|0xc0);
		P0 = 0x01;
		P2 &= 0x1f;
	
		P2 = ((P2&0x1f)|0xe0);
		P0 = 0xc0;
		P2 &= 0x1f;	
}

来吧!!!展示!!!!
在这里插入图片描述
好,简单的控制完成了,这里我需要强调一点,其实位和段要给的值是不一样的,位要给高(1),段要给低(0)。
下面,我总结了数字和字母的码,以方便调用。
在这里插入图片描述

上代码验证:
代码中的cbuzz和delay 函数,都是我上节课说过的,如果有不明白的,往上节课回顾。

#include <STC15F2K60S2.H>
unsigned int code list[]={0xc0,0xf9,0x24,0x30,
0x19,0x12,0x02,0xf8,
0x00,0x10,0x08,0x00或者0x03,
0x46,0xc0或者0x21,0x06,0x0e};
unsigned int i = 0;
sbit BUZZ = P0^6;

void cbuzz(unsigned int c)
{
		P2 = ((P2&0x1f)|0xA0);
		BUZZ = c;
		P2 &= 0x1f;
}
void delay(unsigned int k)
{
		unsigned int v = 0;
		unsigned int j = 0;
		for(v=700;v>0;v--)
		{
				for(j=0;j<k;j++)
			{
					;
			}
		}
}

void main(void)
{
		cbuzz(0);
		P2 = ((P2&0x1f)|0xc0);
		P0 = 0xff;
		P2 &= 0x1f;
		
		while(1)
		{
				for(i=0;i<16;i++)
				{
						P2 = ((P2&0x1f)|0xe0);
						P0 = list[i];
						P2 &= 0x1f;	
						delay(500);
				}
		}
}

来吧!!!!展示!
在这里插入图片描述视频点击这里观看

中断程序

注解:
线段就是程序执行的进程,左图是一般中断,右图是嵌套中断,单片机的嵌套能力有限,但嵌入式的单片机嵌套能力强一些。
断点:发生中断响应的点。
在这里插入图片描述
还有一点,中断服务程序没有返回值。
在这里插入图片描述
这是官方展示的我们这块板子上的中断以及它们的中断触发方式。

我们还需要知道一个知识点是,正在响应的中断只能被更高级的中断打断。
对于中断系统,我画了我们目前需要控制的部分,省略的部分,我们待会结合定时器来说,现在,我们只需要知道,中断系统的部分组成和它的连接情况就行了,下面我们来看一下我画的图:
在这里插入图片描述

红色部分就是我们需要控制的部分,这个系统我只画了左边中断源的4个部分,也就是红色椭圆圈出来的部分,这个也是重点部分。
所以,我们现在大概知道了,我们需要控制4个部分。
要想响应中断,那我们首先要保证中断源有中断请求;
然后我们有的需要选择中断的响应方式;
其次中断源的中断允许位为1,也就是使能中断;
最终我们要保证总中断的打开。

那么 接下来,我们要知道中断的书写格式
在这里插入图片描述
这时候同学们就有疑问了,中断顺序是什么?
可以参考官方给的这张图片,还有我的注释。官方的名称更让人一目了然是什么中断。
在这里插入图片描述
好,目前上面这些就是这块板子的中断服务程序。
那么我们插入一个定时器的用法 来检验中断服务程序。

定时器

我们的定时方式有很多种:
①单片机内置的定时装置
②软件定时,也就是我们之前说过的delay
③外接元器件定时
④拓展芯片定时

一、接下来我们先来研究定时器的结构:

定时器就是+1的16位的两个寄存器组成,一个是高8位,一个是低8位,这里的高低是地址高低。
下面我们再介绍2个寄存器
TCON
在这里插入图片描述
简而言之,就是控制定时器的启动和停止还有设置溢出标志。但溢出标志是系统自动控制的,我们可以不关注这个。
TR0是控制T0的控制允许位,GATE=0,TR0=1,就允许T0开始计时;TR0=0,禁止T0计数。
TR1同理。
TMOD:
在这里插入图片描述
在这里插入图片描述
下面,我画了一张图,来辅助大家理解,颜色比较浅的线条意思就是他们相关联的意思。
在这里插入图片描述

定时器/计数器0有4种工作方式:
模式0(16位定时器/计数器(自动重装)),【00】
模式1(16位定时器/计数器模式(不可重装)),【01】
模式2(8位自动重装模式),【10】
模式3(不可屏蔽中断的16位自动重装定时器)。【11】
定时器/计数器1除模式3外,其他工作模式与定时器/计数器0相同,T1在模式3时无效,停止计数。
工作方式由TMOD的M1、M0控制。
GATE=1 时,允许由外部输入INTi控制定时器1,INTo控制定时器0,这样可实现脉宽测量。GATE = 0,而且TR0、TR1为1,就可以启动定时器工作。

二、定时器的工作原理

就是对内部机器周期的计数。
1个机器周期=12个时钟周期
时钟周期就是振荡周期,就是一个脉冲的时间,就是频率的倒数。

当计数器全满时,再输入一个脉冲,就会回零。且定时器的溢出会使TF0、TF1置一,向系统发出中断请求。

我们的这个板子计数的数字+1的效果有2种方式:
在这里插入图片描述
12T模式下:
在这里插入图片描述
假如当做12MHZ的板子,那么一个机器周期就是1微秒
那么我们最多可以加到65535,也就是65535微秒,也就是65毫秒左右。
6T模式下:
在这里插入图片描述

三、设置固定的定时时间

用65535来计时,显然是十分麻烦的,所以,我们就暂定计数一个50毫秒,最为一个溢出的时间,溢出会导致中断发生。
那么我们怎样才能确保是50毫秒的时候溢出呢?
这个时候,我们知道**“方式1”**的计数值=2^16-计数初值,那么这个问题就可以解决了,我们只需要使初值=(65535-50000),这样,以后+1的次数就是50000次了,也就是固定的50毫秒了。这种方式比我们之前设置的delay( )函数精准多了。

四、怎么采用方式一(16位计数位数)

这是官方给的16位的模式图:
红色是我圈出来的重要部分,其他的可以不需要太在意。
在这里插入图片描述
设定计时器怎么计时
在这里插入图片描述

我们用低八位来装256以内的数字,每满256,就向高八位进1。
那么高八位可以最大可以装65536个数。
如果全部装满后,又送了一个脉冲,那就会溢出,然后 TF0就会自动置一,就会向CPU发出中断请求。
但是我们需要50毫秒,所以,我们需要给2个寄存器初值,使其可以实现只+50000次。
首先,我们要知道,我们需要给计时器一个初值是15535,但一个计时器,分为2个寄存器,那么,我们需要把这个初值分配给2个寄存器。

因为我们高八位是每次低八位溢出才会+1的,所以,高八位的数字实质上是256的倍数
所以我们在高八位的初值赋予
TH0 =(65535-50000)/256
这样得到的数字和高八位定义的数字的实际表示的大小才是等价的。

又因为,我们在低八位的计数是256以内的数字,所以,我们在低八位的初值赋予
TL0=(65535-50000)%256
这样得到的数字和低八位定义的数字的大小才是等价的。

五、定时器应用举例(16位方式)

1、我们怎么做?
①设定TMOD 来确定工作方式。
②把初值赋给TH0、TL0。
③使能中断。
④设定TCON启动计数。
2、照着上面一步一步来

在这里插入图片描述

TMOD = 0xF0;

因为我们只控制T0那么,我们就不需要控制7-4位。

		TH0 = (65536-50000)/256;
		TL0 = (65536-50000)%256;


在这里插入图片描述
根据我们这个图一步一步来

		EA = 1;
		ET0 = 1;

		TR0 = 1;

现在我们将4个步骤合并到一起

void main(void)
{
		TMOD = 0xf0;
		TH0 = (65536-50000)/256;
		TL0 = (65536-50000)%256;
		EA = 1;
		ET0 = 1;
		TR0 = 1;	
}

定时器和中断都打开了,那么 我们 现在需要配置中断服务程序:
在这里插入图片描述
进入中断的条件是定时器计数溢出,溢出是说明加满了,又加了1,那就会从65536变成0,而我们是想要每次都实现50毫秒的计数时间,这个时候,我们要在它出中断前,给定时器再次赋初值,这样就可以保证,每次溢出后,不会从0开始计数,也不会使计数器变成65毫秒的定时时间,所以,我们在中断服务程序内,需要将T0的两个寄存器再次赋初值:

void time_interrput() interrupt 1
{
		TH0 = (65535-50000)/256;
		TL0 = (65535-50000)%256;
}

我们以后应用的时候,不能对进行中断的次数一无所知,所以,我们需要定义一个计数器,来帮助我们记录中断进行了多少次:

uint count = 0;
void time_interrput() interrupt 1
{		
		TH0 = (65535-50000)/256;
		TL0 = (65535-50000)%256;
		count += 1;
}

现在,我们回想之前,我们定义了一个delay的函数,为了模拟1s的时间,我试值了很多次,也还是有误差,那么,我们现在掌握了定时器的用法,我们现在就可以用定时器实现1s的延时:
在这里插入图片描述
所以,当count加到20 的时候,也就是进入了20次中断程序,也就是1s。
那么我们来结合一下我们之前所学,一股脑的全都投入应用吧!
代码如下:
这里我新增的代码,都是我之前说过的,如果有地方不明白的,可以回顾我单片机系列文章的前两篇。
这个程序我也不用1s来写,我用2s间隔来写,因为我要用到计时器和LED灯还有数码管的静态显示,如果秒数间隔太短,怕看不出来。

#include <STC15F2K60S2.H>
#define uchar unsigned char
#define uint unsigned int	
sbit buzz = P0^6;
uint count = 0;
uint temp = 0xfe;
uint num = 0;
unsigned int code list[]={0xc0,0xf9,0x24,0x30,
0x19,0x12,0x02,0xf8,
0x00,0x10,0x08,0x00,
0x46,0xc0,0x06,0x0e};

void cbuzz(uint c)
{
		P2 = ((P2&=0x1f)|0xA0);
		buzz = c;
		P2 &= 0x1f;
}
void time_interrput() interrupt 1
{		
		TH0 = (65535-50000)/256;
		TL0 = (65535-50000)%256;
		count += 1;
		cbuzz(0);
		P2 =((P2&0x1f)|0x80);
		P0 = temp;
		P2 &= 0x1f;
		if(temp==0x00)
		{
				temp = 0xff;
		}
		temp <<= 1;
		P2 =((P2&0x1f)|0x80);
		P0 = temp;
		P2 &= 0x1f;
}

void main(void)
{
		TMOD = 0xF0;
		TH0 = (65535-50000)/256;
		TL0 = (65535-50000)%256;
		
		TR0 = 1;	
		ET0 = 1;   //accept t0 interrupt
		EA = 1;   //open all interrupt

		P2 = ((P2&0x1f)|0xC0);
		P0 = 0Xff;
		P2 &= (0X1f);
		P2 = ((P2&0x1f)|0xe0);
		P0 = list[num];
		P2 &= (0X1f);
		while(1)
		{
				if(count == 20)
				{
						cbuzz(1);
				}
				if(count == 40)
				{
						cbuzz(0);
						num += 1;
						if(num == 16)
						{
								num = 0;
						}
						P2 = ((P2&0x1f)|0xe0);
						P0 = list[num];
						P2 &= (0X1f);
						count = 0;		
				}
		}
}

来吧!!!!展示!!!!
如果点进去没视频,就是还在审核,你们可以看我上传的时间。
在这里插入图片描述
视频点击这里观看
————————————————————————————————————————————————————————————————————————————————————————————————————————————
这一节我们到此结束,这个目前完结了,我今天晚上(2020年2月11日)看有7个人看了这个文章,我希望这7个人,可以重新看计时器部分,因为我有修改,因为我前天看错文件了,所以计时器的设置出问题了,但我现在已经修改了,并且还上传了视频,希望大家见谅,建议大家都看看我的实验视频。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值