【蓝桥杯】单片机学习(3) 您所在的位置:网站首页 定时中断流程图 【蓝桥杯】单片机学习(3)

【蓝桥杯】单片机学习(3)

2024-07-03 19:09| 来源: 网络整理| 查看: 265

数码管+定时+中断 一、定时器1、定时器基础知识2、定时器的寄存器(TCON&TMOD)3、定时器的应用 二、中断1、中断的概念2、51单片机内与中断控制有关的寄存器3、中断的响应条件及应用 三、数码管1、数码管的原理介绍2、数码管的真值表(code关键字介绍)3、数码管的静态显示(1)以普中科技的开发板为例(共阴极数码管)(2)以CT107D开发板为例(共阳级数码管) 4、数码管的动态显示(1)原理分析(2)数码管动态扫描的一般步骤。(3)例程(普中·共阴)(4)例程(CT107D·共阳)

一、定时器 1、定时器基础知识

实现定时/计数,有3种主要方法:软件延时、数字电路硬件定时和可编程定时/计数器。

软件定时:让机器执行一个程序段,这个程序段本身没有具体的目的,通过挑选适当的指令和设置合适的循坏次数来实现软件延时,由于执行每条指令都需要时间,执行这个程序段所需要的时间就是延时时间。常见的指令有for循环,通过改过循环次数来改变延时的时间。缺点:软件延时占用CPU,降低CPU的利用率。

数字电路硬件定时:采用小规模集成电路器件,外接定时部件(电阻和电容)。通过改变电阻和电容的值来改变定时范围。缺点:硬件电路连接好之后,不方便修改。

可编程定时/计数器:硬件定时,同时可以通过软件来确定和改变它的定时值,通过初始化编程,能够满足各种定时和计数需求,也是应用较多的一种方式。

时钟周期,即时钟源频率频率(晶振)分之一,一个机器周期为12个时钟周期。机器周期就是定时器的计数周期,在我们设定好初值之后,每经过一个机器周期,定时器自动加1,加到一定数值之后就会溢出。对于8位的定时器,加到255后再加1溢出;对于16位的定时器,加到65535后再加1溢出。

定时器既可以工作在定时方式也可以工作在计数方式。这两种方式本质都是对脉冲进行计数,不过所计脉冲的来源不同。常用的是定时方式,(以T0为例)每过一个机器周期,计数器的初值加1,直至计满预设的个数,TH0和TL0回零,溢出中断标志位TF0置1,产生溢出中断。当我们设定了定时器的工作方式并启动后,定时器就按照规定的方式工作,不占用CPU的操作时间,此时CPU可以执行其他其他程序,除非定时器溢出,才会中断CPU正在执行的程序(类似于人在工作或者睡觉的时候,手表依然滴滴滴滴在走,到了设定的时间,闹钟会响)。

2、定时器的寄存器(TCON&TMOD)

标准的51单片机内,常用的定时器有T0和T1。TH0和TL0分别用于存储定时器T0定时初值的高八位和低八位;TH1和TL1用于存储定时器T1定时初值的高八位和低八位。

定时器控制寄存器——TCON(定时器控制只用高四位) 位76543210符号TF1TR1TF0TR0IE1IT1IE0IT0

TF1:T1溢出中断请求标志。T1有溢出中断请求,TF1硬件置 1;T1无溢出中断请求,TF1 =0。有两种清零方式,软件清零和进入定时器中断时硬件清零。

TR1:T1运行控制位。TR1=1,启动T1工作;TR1=0,停止T1工作。 TF0:T0溢出中断请求标志。T1有溢出中断请求,TF0硬件置1;T0无溢出中断请求,TF0 =0。有两种清零方式,软件清零和进入定时器中断时硬件清零。 TR0:T0运行控制位。TR0=1,启动T1工作;TR0=0,停止T0工作。

注:硬件置1或清零是指符合条件后,单片机自动完成;软件置1或清零是指需要通过编写程序实现。

定时器模式寄存器——TMOD 位76543210符号GATE(T1)C/T(T1)M1(T1)M0(T1)GATE(T0)C/T(T0)M1(T0)M0(T0)

GATE:门控信号。GATE=0, TRx=1时,可启动定时器工作;GATE=1,除TRx=1外,还需INTx= 1才可启动定时器工作。

C /T:定时/计数器选择控制位。置1为计数器,置0为定时器。

M1M0:定时器的工作模式选择位。 定时器工作模式选择位 定时器初值的计算:(设定时时间为T) ①方式0:13位定时器。T=(2^13-T0初值)* 12 / fosc TH0 = (2^13-T * fosc/12) / 32 TL0 = (2^13-T * fosc/12) / 32; ②方式1:16位定时器。T=(2^16-T0初值)* 12 / fosc TH0 = (2^16-T * fosc/12) /256, TL0 = (2^16-T * fosc/12) / 256; ③方式2:8位自动重载定时器。T=(2^8-T0初值)* 12 / fosc TH0 = TL0 = T=(2^8-T0初值)* 12 / fosc

3、定时器的应用

定时器应用可以按照以下四个步骤: ①设置特殊功能寄存器TMOD,配置好工作模式。 ②设置计数寄存器THO和TL0的初值。 ③设置TCON,通过TRO置1来让定时器开始计数。 ④判断TCON寄存器的TF0位,监测定时器溢出情况。

二、中断 1、中断的概念 中断的发生:CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理。中断响应和中断服务:CPU暂时中断当前的工作,转去处理事件B中断返回:CPU将事件B处理完成后,再回到原来事件A被中断的地方继续处理事件A。

以上整个过程即为中断。8XX51有5个中断源,3个在片内,2个在片外(如下图)。它们在程序存储器中有固定的中断入口地址,当CPU响应中断时,硬件自动形成这些地址,由此进入中断服务程序;5个中断源有两级中断优先级,可形成中断嵌套。 51单片机中断源 使用定时器时一般也会用到中断,但要注意定时器和中断不是一个概念,定时器是单片机模块的一个资源,而中断只是单片机的一种中断机制。

2、51单片机内与中断控制有关的寄存器 中断控制寄存器——IE 位76543210符号EA…ET 2ESET1EX1ET0EX0

IE寄存器的各位对应相应的中断源,如果允许该中断源中断,则该位置1,禁止中断则该位为0。其中EA为中断总控开关,是CPU是否响应中断的前提。ES为串行口中断允许位,ET2为定时器T2中断允许位,ET1为定时器T1中断允许位,ET0为定时器T0中断允许位,EX0为外部中断INT0允许位,EX1为外部中断INT1允许位。

定时器控制寄存器——TCON(低四位) 位76543210符号TF1TR1TF0TR0IE1IT1IE0IT0

IE1:外部中断1(INT1)运行控制位。IE1=1.启动INT1控制; IE1=0,停止INT1控制。 IT1:外部中断1(INT1)触发方式控制位。IT1=1,下降沿触发;IT1=0,低电平触发。 IE0:外部中断0(INT0)运行控制位。IE0=1.启动INT1控制; IE0=0,停止INT1控制。 IT0:外部中断0(INT0)触发方式控制位。IT0=1,下降沿触发;IT0=0,低电平触发。

中断优先级管理寄存器——IP 位76543210符号……PT2PSPT1PX1PT0PX0

当某几个中断源同时发出中断请求时,由内部查询确定优先级,查询的顺序为:(INT0的优先级最高) INT0——T0——INT1——T1——串行口 ——T2

中断查询序列如下: 中断查询序列

3、中断的响应条件及应用

响应条件:

中断源有中断请求此中断源的中断允许位为1总中断打开(允许),即EA=1

中断的应用:

void timer() interrupt n { }

注:timer()为函数名,自己随意取;interrupt为关键字,不能更改,n为中断函数序列编号。

三、数码管 1、数码管的原理介绍

数码管的原理图如图3-1,本质就是把8段LED小灯组合在一起。 数码管原理图 数码管可以分为共阴极和共阳极,内部结构如下图3-2所示:  共阴极数码管,即把8只LED灯的阴极连接在一起,由阳极来控制单个小灯的亮灭(1亮0灭);同理,共阳数码管就是阳极连接在一起,通过阴极来控制小灯的亮灭(1灭0亮)。

2、数码管的真值表(code关键字介绍)

将数码管的8个段当成8个LED小灯来控制,即a、b、c、d. e、f、g、dp- -共8个LED小灯。以图3-1,如果点亮b和c这两个LED小灯,也就是数码管的b段和c段,其他的所有的段都熄灭的话,就可以让数码管显示出一个数字1,以共阳极数码管为例,二进制数字为0b11111001,十六进制为0xF9。同理可得其他数字多对应的数码管的真值,如下:

共阳极数码管的真值表: 字符01234567数值0XC00XF90XA40XB00X990X920X820XF8字符89ABCDEF数值0X800X900X880X830XC60XA10X860X8E unsigned char code LEDchar[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f}; //共阳极数码管从0到F的真值 共阴极数码管的真值表 字符01234567数值0X3F0X060X5B0X4F0X660X6D0X7D0X07字符89ABCDEF数值0X7F0X6F0X770X7C0X390X5E0X790X71 unsigned char code LEDchar[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //共阴极数码管从0到F的真值 code关键字:C51单片机中,使用关键字unsigned char或者 unsigned int定义的变量都是放在单片机的RAM中,这些变量的值可以通过程序改变。而在定义时使用code修饰的变量是存储到存储空间FLASH里的,这样可以大大的节省的RAM的空间,但是这些变量的值在程序中不可以修改,所以我们在定义一些程序中不需要修改的变量时,可以使用code关键字,例如上面提到的数码管的真值的定义:unsigned char code LEDchar[]={}; 3、数码管的静态显示 (1)以普中科技的开发板为例(共阴极数码管)

原理图如下: 普科技开发版原理图(部分)代码功能:一位数码管静态显示0到F,数字(字母)切换时间为1秒。

//数码管静态显示,0到F #include sbit LSA = P2^2; sbit LSB = P2^3; sbit LSC = P2^4; typedef unsigned char u8; unsigned char code LEDchar[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //共阴极数码管从0到F的真值 void TimeInit(); //定时器初始化函数 void main() { u8 cnt = 0; //记录T0中断次数 u8 sec =0; //记录经过的秒数 LSA = 0; //数码管的位选 LSB = 0; LSC = 0; TimeInit(); //定时器初始化 while(1) { if(TF0 == 1) //判断T0是否溢出 { TF0 = 0; //T0溢出后,清楚中断标志 TH0 = (65536-2*110592/12)/256; //0xB8,定时20ms 0.02秒*11059200 TL0 = (65536-2*110592/12)%256; //0x00 cnt++; if(cnt>=50) //判断是否达到50次,即一秒钟 { cnt = 0; //清零 P0 = LEDchar[sec]; //当前秒数对应的真值表中的真值送到P0口 sec++; //秒数记录加1 if(sec>=16) //秒数达到0x0F后,重新从0开始 { sec = 0; } } } } } void TimeInit() { TMOD = (TMOD & 0xf0)|0x01; //设置定时器工作在模式1 TH0 = (65536-2*110592/12)/256; //0xB8,定时20ms TL0 = (65536-2*110592/12)%256; //0x00 TR0 = 1; //允许定时器T0工作 } (2)以CT107D开发板为例(共阳级数码管)

CT107D开发板是蓝桥比赛用开发板,原理图如下: CT107原理图(部分)代码如下:

//数码管静态显示,0到F #include typedef unsigned char u8; unsigned char code LEDchar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e, 0xbf,0x7f}; //共阳极数码管从0到F的真值 void TimeInit(); //定时器初始化函数 void HC138(u8 channel); //138译码器通道选择函数 void ShowSMG_Bit(u8 date,u8 pos); //数码管显示函数 void main() { u8 cnt = 0; //记录T0中断次数 u8 sec =0; //记录经过的秒数 TimeInit(); //定时器初始化 while(1) { if(TF0 == 1) //判断T0是否溢出 { TF0 = 0; //T0溢出后,清楚中断标志 TH0 = (65536-2*110592/12)/256; //重新加载初值 TL0 = (65536-2*110592/12)%256; cnt++; if(cnt>=50) //判断是否达到50次,即一秒钟 { cnt = 0; //清零 ShowSMG_Bit(LEDchar[sec],7); //数码管显示对应的秒数 sec++; //秒数记录加1 if(sec>=16) //秒数达到0x0F后,重新从0开始 { sec = 0; } } } } } void HC138(u8 channel) { switch(channel) { case 4: P2 = (P2&0x1f)|0x80; //选择Y4对应模块(LED小灯) ,运算结果为P2高三位为100 break; case 5: P2 = (P2&0x1f)|0xa0; //选择Y5对应模块(蜂鸣器),运算结果为P2高三位为101 break; case 6: P2 = (P2&0x1f)|0xc0; //选择Y6对应模块(数码管的位选),运算结果为P2高三位为110 break; case 7: P2 = (P2&0x1f)|0xe0; //选择Y7对应模块(数码管的段选),运算结果为P2高三位为111 break; } } void ShowSMG_Bit(u8 date,u8 pos) { HC138(6); //Y6模块工作,数码管进行位选 P0 = 0x010x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; //共阴极数码管从0到9的真值 u8 LedBuff[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //数码管显示缓冲区,初值0xFF确保启动时都不亮 u8 flags = 1; //1秒定时标志 void TimeInit(); //定时器中断初始化函数 int main() { u8 sec = 0, minutes = 0, hours = 0, days = 0; //定义记录秒,分,时,天的变量 TimeInit(); //定时器中断初始化 while(1) { if(flags == 1) //判断1秒定时标志 { flags = 0; //标志位清零 sec++; //秒加1 if(sec == 60) //判断秒变量到达60秒 { sec = 0; //清0零 minutes++; //分钟位加1 } if(minutes == 60) //判断达到60分 { minutes = 0; //清零 hours++; //小时位加1 } if(hours == 24) //判断达到24小时 { hours =0; //清零 days++; //天数加1 } LedBuff[0]= LedChar[sec%10]; //秒的低位 LedBuff[1]= LedChar[sec/10%10]; //秒的高位 LedBuff[2]= LedChar[minutes%10]; //分钟的低位 LedBuff[3]= LedChar[minutes/10%10]; //分钟的高位 LedBuff[4]= LedChar[hours%10]; //小时的低位 LedBuff[5]= LedChar[hours/10%10]; //小时的高位 LedBuff[6]= LedChar[days%10]; //天数的低位 LedBuff[7]= LedChar[days/10%10]; //天数的高位 } } } void TimeInit() { EA = 1; //打开中断总开关 ET0 = 1; //打开T0中断开关 TMOD = (TMOD & 0xf0)|0x01; //设置定时器工作在模式1 TH0 = (65536-1*11059/12)/256; //0xFC,定时1ms 0.001秒*11059200 TL0 = (65536-1*11059/12)%256; //0x67 TR0 = 1; //允许定时器T0工作 } void InterruptTimer0() interrupt 1 { static u8 i = 0; //动态扫描的索引 static u16 cnt = 0; //用来记录中断次数,设置的中断定时为1ms,中断1000次即一秒钟 TH0 = (65536-1*11059/12)/256; //重新加载初值 TL0 = (65536-1*11059/12)%256; cnt++; //中断次数计数值加1 if(cnt>=1000) //中断次数达到1000次即为1秒 { cnt = 0; //清零,重新记录中断次数 flags = 1; //设置1秒定时标志位1 } P0 = 0xff; //消隐 switch(i) //根据动态索引i的值进行位选,依次点亮八个数码管 { case 0 :LSA = 0; LSB = 0; LSC = 0;i++; P0 = LedBuff[0];break; case 1 :LSA = 1; LSB = 0; LSC = 0;i++; P0 = LedBuff[1];break; case 2 :LSA = 0; LSB = 1; LSC = 0;i++; P0 = LedBuff[2];break; case 3 :LSA = 1; LSB = 1; LSC = 0;i++; P0 = LedBuff[3];break; case 4 :LSA = 0; LSB = 0; LSC = 1;i++; P0 = LedBuff[4];break; case 5 :LSA = 1; LSB = 0; LSC = 1;i++; P0 = LedBuff[5];break; case 6 :LSA = 0; LSB = 1; LSC = 1;i++; P0 = LedBuff[6];break; case 7 :LSA = 1; LSB = 1; LSC = 1;i=0; P0 = LedBuff[7];break; default:break; } } (4)例程(CT107D·共阳)

以CT107D开发板为例(共阳极数码管),原理图如下: CT107D开发板原理图(部分)功能同上,代码如下:

#include typedef unsigned char u8; typedef unsigned int u16; u8 LedChar[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳极数码管从0到9的真值 u8 LedBuff[] = {0xFF, 0xFF, 0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //数码管显示缓冲区,初值0xFF确保启动时都不亮 u8 flags = 1; //1秒定时标志 void TimeInit(); //定时器中断初始化函数 void HC138(u8 channel); //138译码器通道选择函数 void ShowSMG_Bit(u8 date,u8 pos); //数码管显示函数 int main() { u8 sec = 0, minutes = 0, hours = 0, days = 0; //定义记录秒,分,时,天的变量 TimeInit(); //定时器中断初始化 while(1) { if(flags == 1) //判断1秒定时标志 { flags = 0; //标志位清零 sec++; //秒加1 if(sec == 60) //判断秒变量到达60秒 { sec = 0; //清0零 minutes++; //分钟位加1 } if(minutes == 60) //判断达到60分 { minutes = 0; //清零 hours++; //小时位加1 } if(hours == 24) //判断达到24小时 { hours = 0; //清零 days++; //天数加1 } LedBuff[0]= LedChar[sec%10]; //秒的低位 LedBuff[1]= LedChar[sec/10%10]; //秒的高位 LedBuff[2]= LedChar[minutes%10]; //分钟的低位 LedBuff[3]= LedChar[minutes/10%10]; //分钟的高位 LedBuff[4]= LedChar[hours%10]; //小时的低位 LedBuff[5]= LedChar[hours/10%10]; //小时的高位 LedBuff[6]= LedChar[days%10]; //天数的低位 LedBuff[7]= LedChar[days/10%10]; //天数的高位 } } } void TimeInit() { EA = 1; //打开中断总开关 ET0 = 1; //打开T0中断开关 TMOD = (TMOD & 0xf0)|0x01; //设置定时器工作在模式1 TH0 = (65536-1*11059/12)/256; //0xFC,定时1ms 0.001秒*11059200 TL0 = (65536-1*11059/12)%256; //0x67 TR0 = 1; //允许定时器T0工作 } void HC138(u8 channel) { switch(channel) { case 4: P2 = (P2&0x1f)|0x80; //选择Y4对应模块(LED小灯) ,运算结果为P2高三位为100 break; case 5: P2 = (P2&0x1f)|0xa0; //选择Y5对应模块(蜂鸣器),运算结果为P2高三位为101 break; case 6: P2 = (P2&0x1f)|0xc0; //选择Y6对应模块(数码管的位选),运算结果为P2高三位为110 break; case 7: P2 = (P2&0x1f)|0xe0; //选择Y7对应模块(数码管的段选),运算结果为P2高三位为111 break; } } void ShowSMG_Bit(u8 date,u8 pos) { HC138(6); //Y6模块工作,数码管进行位选 P0 = 0x01 cnt = 0; //清零,重新记录中断次数 flags = 1; //设置1秒定时标志位1 } P0 = 0xff; //消隐 switch(i) //根据动态索引i的值进行位选,依次点亮八个数码管 { case 0 : i++; ShowSMG_Bit(LedBuff[0],7); break; //最右边一位数码管(com8)对应P0^7口 case 1 : i++; ShowSMG_Bit(LedBuff[1],6); break; case 2 : i++; ShowSMG_Bit(LedBuff[2],5); break; case 3 : i++; ShowSMG_Bit(LedBuff[3],4); break; case 4 : i++; ShowSMG_Bit(LedBuff[4],3); break; case 5 : i++; ShowSMG_Bit(LedBuff[5],2); break; case 6 : i++; ShowSMG_Bit(LedBuff[6],1); break; case 7 : i=0; ShowSMG_Bit(LedBuff[7],0); break; default:break; } }

前一篇: 单片机学习(2)——点亮LED小灯

下一篇: 单片机学习(4)——点阵LED



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有