深圳建设银行官方网站,微网站和门户网站的区别,wordpress 输出标签id,苏州物联网app开发公司蓝桥杯单片机组备赛指南请查看这篇文章#xff1a;戳此跳转蓝桥杯备赛指南文章
本文章针对蓝桥杯-单片机组比赛开发板所写#xff0c;代码可直接在比赛开发板上使用。
型号#xff1a;国信天长4T开发板#xff08;绿板#xff09;#xff0c;芯片#xff1a;IAP15F2K6…蓝桥杯单片机组备赛指南请查看这篇文章戳此跳转蓝桥杯备赛指南文章
本文章针对蓝桥杯-单片机组比赛开发板所写代码可直接在比赛开发板上使用。
型号国信天长4T开发板绿板芯片IAP15F2K61S2
使用国信天长蓝板也可以完美兼容与绿板几乎无差别 1.编程目的 通过定时/计数器实现数码管的时钟显示显示格式例如“12-13-14”表示12点13分14秒时刻。并通过设置外部中断0当S5按下时计时暂停再次按下时继续计时。
2.定时/计数器原理
2.1 单片机的基本中断系统 比赛用单片机最多允许两层中断的嵌套。即在低级的中断服务函数执行过程中收到了更高级的中断信号而去先执行更高级的中断工作执行完再返回继续执行低级的中断工作低级的中断工作做完再回到最原本的代码继续执行。 本文中我们使用到的外部中断0与定时/计数器中断0本身自带优先级且INT0的优先级已经高于T0因此我们不需要对两个中断的优先级进行单独设置。
比赛用芯片IAP15F2K61S2 涉及的中断共有14个这里介绍常用的5个
中断号中断名中断名解释0INT0外部中断01T0定时/计数器中断02INT1外部中断13T1定时/计数器14TI/RI串口中断5T2定时/计数器中断2
本文聚焦外部中断0与定时/计数器中断0只对INT0和T0进行讲解他们的中断号对应为0和1。比赛用开发板中还有INT2,INT3,INT4,T2共计5个外部中断信号源三个定时/计数器中断信号源其余中断源将在专栏“蓝桥杯-单片机组进阶”中讲解。
2.2 什么是定时/计数器中断 定时/计数器可以想象成一个每隔一定时间就会自动产生一次中断的开关。但它产生中断的时间间隔是固定的由我们来设置。中断产生的感觉可以想象成一个正在接水的水桶当水桶里的水接满溢出时产生中断由此每次产生中断所需要的时间就可以比拟成水桶接满水的时间。那我们如果按照自己的需求让水桶接满水的时间被人为精确控制呢设置初值——即在最开始让水桶里装有一定数量的水最开始水桶里面的水越多水桶就越快溢出产生中断所需要的时间就越短。上述为口语化的理解更本质的解释如下 定时/计数器的核心是16位的加法计数器在8位的51单片机中使用两个8位的寄存器THx和TLx共同组成16位并分别叫做高8位和低8位。当这16位加法计数器计数溢出则产生一次定时/计数器中断。单片机的晶振我们假定是12Mhz单片机会将12Mhz进行12分频后传入加法计数器中即一个机器周期12Mhz/121MhzTcy1us此时我们可以认为在晶振为12Mhz的单片机中没经过1us的时长加法计数器的值加1 。假设我们让16位加法计数器从0开始计数即计数初值为00000 0000 0000 0000 当变成计数值变成1111 1111 1111 1111时在经过1us计数器就会溢出并产生一次定时/计数器中断此时计数值为65535 。此时我们可以认为在初值为016位计数器晶振为12Mhz的单片机中产生一次中断所需要的时间为65535us65.535ms 。当我们需要单片机50ms就产生一次中断时就可以设置初值为15535 65.535ms-50.000ms 。 实际的单片机中为了方便我们的使用晶振频率可能为12Mhz11.05926Mhz同时在定时/计数器不同的工作方式下计数器的位数可能为16位最大值6553513位最大值81918位最大值255因此我们需要根据不同的设置进行不同的计算。相关的计算过程可查看TMOD寄存器设置的部分。 2.3 定时/计数器中断涉及的寄存器 为了简短篇幅下面将寄存器IP、IE、TCON简略说明详细内容可以查看文章戳此跳转
我们着重介绍TMOD寄存器
两级中断允许控制IEinterrupt enable
EA-ET2ESET1EX1ET0EX0 IE中各位的功能如下 EA—中断总开关控制位EA1所有的中断请求开放。 ES—串行口中断允许位。 ET1—定时器/计数器T1溢出中断允许位。 EX1—外部中断1中断允许位。 ET0—定时器/计数器T0的溢出中断允许位。 EX0—外部中断0中断允许位。 该寄存器允许位寻址在编程时如果只用到一个外部中断0和T0则我们只需要设置总开关EA、外部中断0允许位EX0 、T0中断允许为ET0。
两级优先级控制IP(interrupt priority)
--PT2PSPT1PX1PT0PX0 中断优先级寄存器IP各位含义 PS—串行口中断优先级控制位1—高级0—低级。 PT1—T1中断优先级控制位1—高级0—低级。 PX1—外部中断1中断优先级控制位1—高级0—低级。 PT0—T0中断优先级控制位1—高级0—低级。 PX0—外部中断0中断优先级控制位1—高级0—低级。 该寄存器允许位寻址本题中采用默认优先级因此不用管这个寄存器。
特殊功能寄存器TCONtimer controller
TF1TR1TF0TR0IE1IT1IE0IT0 TCON寄存器中与中断系统有关各标志位功能如下 TF1—定时器/计数器T1的溢出中断请求标志位。 TF0—定时器/计数器T0溢出中断请求标志位似。 IE1—外部中断请求1中断请求标志位。 IE0—外部中断请求0中断请求标志位与IE1类似。 IT1—选择外中断1请求方式。0--电平触发方式1--跳沿触发方式。 IT0—选择外中断0请求方式。0--电平触发方式1--跳沿触发方式。 该寄存器允许位寻址在编程时如果只用到一个外部中断0则我们只需要设置IT0从而确定外部中断0的触发方式 。而对于TF0它不需要我们设置只是在程序中我们可以通过查询TF0是否等于1从而判断T0是否溢出。
特殊方式寄存器TMODtimer mode
GATEC/TM1M0GATEC/TM1M0---- 定时器1T1 -------- 定时器0T0 ---- TMOD寄存器中与中断系统有关各标志位功能如下 通过观察可以发现TMOD寄存器左边位与右边位几乎一样只是左边针对定时/计数中断右边针对定时/计数中断。本文中我们使用T0因此我们介绍T0各位的含义T1与T0相同 GATE: 用于控制定时器启动是否受外部中断源的影响 当GATE0时只要用软件使TR0或TR1等于1就可以启动T0或T1定时/计数器工作。 当GATE1时除了用软件使TR0或TR1等于1外还要使外部中断引脚INT0/1为高电平这样定时/计数器才能启动工作。 注意GATE0表示控制定时器启动不受外部中断源的影响 C/T0为定时模式C/T1为计数模式。 M1 M0工作方式选择位两位一起看 M1 M0工作方式工作说明00方式013位定时/计数器最大值819201方式116位定时/计数器最大值6553510方式28位自动重装定时/计数器最大值25511方式3T1分成两个独立的定时/计数器T1停止计数 举例我们在12Mhz的单片机中不设置外部中断触发定时设置T0工作在方式1实现50ms的定时中断。则GATE0C/T0M1 M001 剩下的位全部赋值0则TMOD应该赋值TMOD0000 00010x01 。 该寄存器不可位寻址编程时我们必须对TMOD寄存器进行整体赋值才能正确设置。充分考虑要使用T1或者T0然后进行对应位的设置并转换成BCD码写入代码。
初值寄存器THx TLx 如果是使用T1则初值的高8位寄存器为TH1低8位寄存器为TL1 如果是使用T0则初值的高8位寄存器为TH0低8位寄存器为TL0 如果T1和T0都使用则TH1TL1TH0TL0都需要设置初值 蓝桥杯比赛使用的开发板是12Mhz的刚好对于加法器加1的时长为1us。假如我们设置TMOD寄存器使得定时/计数器工作在方式1最大计数值为65535则最长的中断间隔时长为65535us65.535ms 。如果我们需要的中断间隔时长为50ms即每50ms产生一次中断则我们需要让加法器有一个固定的初值为65.535ms-50.000ms15.535ms。则初值为15535转换成16进制为3caf。高8位为3c需要赋值给THx低8位位af需要赋值给TLx。 但每次转换进制很麻烦因此我们可以通过以下公式快速写出代码 最大值就是工作方式的最大计数值方式1为16位定时/计数器2 ^1665535即最大值为65535 。定时值是我们的定时时长如果是50ms则为50 000us即定时值为50000 。带入式子即可在运行时由单片机自己进行运算方便我们进行代码编写。注意当计算式确定之后还是要手动把计算结果替换进赋值表达式减少单片机资源占用。 3.编程中涉及的中断函数
3.1 定时/计数器初始化函数 目的使用T0产生一个9.216ms的定时/计数中断 该函数中首先是对TMOD进行设置方式一定时中断无需外部中断只是用T0因此为0x01 。然后设定计数初值对TH0TL0进行赋值。EA和ET0是IE寄存器的对应位作用分别为打开总中断打开定时/计数器T0中断。TR0是TCON寄存器的对应位作用为T0开始计数。
3.2 定时/计数器服务函数 中断的服务函数作用是当中断产生时系统暂停当前工作而去执行中断服务函数里面的程序执行完服务函数的程序后再返回继续执行先前的工作。在这个函数中首先我们对初值寄存器TH0和TL0进行赋值因为工作方式1不会自动重装初值只有工作方式28位自动重装方式会自动重新装载初值因此除了方式2以外的所有方式都需要在中断服务函数中重新对THx和TL0重新赋值。然后下面的自增指令是我们自己定义的功能。
4.代码参考
4.1 编程目的代码代码效果
实现数码管的时钟显示显示格式例如“23-20-00”表示23点20分00秒时刻。并通过设置外部中断0当S5按下时计时暂停再次按下时继续计时。
//写一个计时器分-秒-20ms
#include REGX52.h
#include INTRINS.h unsigned char code SMG_duanma [18]{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,0xbf , 0x7f };sbit S5 P3^2;void select_HC573 ( unsigned char channal )
{switch ( channal ){case 4:P2 ( P2 0x1f ) | 0x80;break;case 5:P2 ( P2 0x1f ) | 0xa0;break; case 6:P2 ( P2 0x1f ) | 0xc0;break;case 7:P2 ( P2 0x1f ) | 0xe0;break;}
}void Input_SMG ( unsigned char pos_SMG , unsigned char value_SMG )
{select_HC573 ( 6 );P0 0x01 pos_SMG;select_HC573 ( 7 );P0 value_SMG;
}void Delay ( unsigned char t )
{while ( t-- ){unsigned char i,j;_nop_ ();_nop_ ();i 22;j 128;do {while ( --j );}while ( --i ); }
}//
void Init_timer0_INT0 ()
{//设置T0初始化TMOD 0x01;TH0 ( 65535 - 18433 ) / 256;TL0 ( 65535 - 18433 ) % 256;ET0 1;//设置INT0初始化IT0 1;EX0 1;//打开总中断开关以及启动定时器EA 1;TR0 1;
}unsigned char state_INT0 0;
void Service_INT0 () interrupt 0
{ state_INT01;//注意 这里有按键产生中断的操作但是没有进行消抖处理//但是中断的执行过程会过滤掉部分抖动时间//因此按下S5只要不是很刁钻单片机都会正确响应//正常情况下不推荐在服务函数中写入if语句这里为了使用外部中断无法使用消抖处理因此出此下策if( state_INT0%20 ){TR0 1;}else{TR0 0;}}unsigned char timer0_50ms 0;
void Service_timer0 () interrupt 1
{TH0 ( 65535 - 50000 ) / 256;TL0 ( 65535 - 50000 ) % 256;timer0_50ms ;
}
//unsigned char timer0_s 00;
unsigned char timer0_m 20;
unsigned char timer0_h 23;
void time_SMGrunning ()
{if ( timer0_50ms 20 ){timer0_s ;timer0_50ms 0;if ( timer0_s 60 ){timer0_m ;timer0_s 0;timer0_50ms 0;if ( timer0_m 60 ){ timer0_m 0;timer0_h;} }}Input_SMG ( 7 , SMG_duanma[ timer0_s%10 ] );Delay ( 1 );Input_SMG ( 6 , SMG_duanma[ timer0_s/10 ] );Delay ( 1 );Input_SMG ( 5 , SMG_duanma[16] );Delay ( 1 );Input_SMG ( 4 , SMG_duanma[ timer0_m%10 ] );Delay ( 1 );Input_SMG ( 3 , SMG_duanma[ timer0_m/10 ] );Delay ( 1 );Input_SMG ( 2 , SMG_duanma[16] );Delay ( 1 );Input_SMG ( 1 , SMG_duanma[ timer0_h%10 ] );Delay ( 1 );Input_SMG ( 0 , SMG_duanma[ timer0_h/10 ] );Delay ( 1 );
}void main ()
{Init_timer0_INT0 ();while ( 1 ){time_SMGrunning ();}
}4.2 小蜜蜂课程代码
代码1//使用定时器实现间隔时间闪烁灯光
//使用定时器实现间隔时间闪烁灯光
#include REGX52.h sbit L1 P0^0;
sbit L8 P0^7;
unsigned char code SMG_duanma [18]{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,0xbf , 0x7f };void select_HC573 ( unsigned char channal )
{switch ( channal ){case 4:P2 ( P0 0x1f ) | 0x80;break;case 5:P2 ( P0 0x1f ) | 0xa0;break; case 6:P2 ( P0 0x1f ) | 0xc0;break; case 7:P2 ( P0 0x1f ) | 0xe0;break; }
}void Input_SMG ( unsigned char pos_SMG , unsigned char value_SMG )
{select_HC573 ( 6 );P0 0x01 pos_SMG;select_HC573 ( 7 );P0 value_SMG;}///
void Init_Timer0 ()
{TMOD 0x01;TH0 (65535-9216) / 256;TL0 (65535-9216) % 256;EA 1; TR0 1; ET0 1;
}unsigned char count_timer0;
unsigned char value_SMG0;
void Service_timer0 () interrupt 1
{TH0 (65535-9216) / 256;TL0 (65535-9216) % 256;count_timer0;
}void Time_Led_Timer0 ()
{ if ( count_timer0 100 ){count_timer0 0;value_SMG; Input_SMG ( 0 , SMG_duanma [value_SMG] );}if ( value_SMG 9 ){value_SMG 0;}}//void main ()
{Init_Timer0 ();while ( 1 ){Time_Led_Timer0 ();}
}
代码2//写一个计时器分-秒-20ms
//写一个计时器分-秒-20ms
#include REGX52.h
#include INTRINS.h unsigned char code SMG_duanma [18]{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,0xbf , 0x7f };sbit S5 P3^2;
sbit S4 P3^3;void select_HC573 ( unsigned char channal )
{switch ( channal ){case 4:P2 ( P2 0x1f ) | 0x80;break;case 5:P2 ( P2 0x1f ) | 0xa0;break; case 6:P2 ( P2 0x1f ) | 0xc0;break;case 7:P2 ( P2 0x1f ) | 0xe0;break;}
}void Input_SMG ( unsigned char pos_SMG , unsigned char value_SMG )
{select_HC573 ( 6 );P0 0x01 pos_SMG;select_HC573 ( 7 );P0 value_SMG;
}void Delay ( unsigned char t )
{while ( t-- ){unsigned char i,j;_nop_ ();_nop_ ();i 22;j 128;do {while ( --j );}while ( --i ); }
}//
void Init_timer0 ()
{TMOD 0x01;TH0 ( 65535 - 18433 ) / 256;TL0 ( 65535 - 18433 ) % 256;ET0 1;EA 1;TR0 1;
}unsigned char timer0_20ms 0;
void Service_timer0 () interrupt 1
{TH0 ( 65535 - 18433 ) / 256;TL0 ( 65535 - 18433 ) % 256;timer0_20ms ;
}
//void time_SMGrunning ()
{static unsigned char timer0_s 0;static unsigned char timer0_m 0;if ( timer0_20ms 50 ){timer0_s ;timer0_20ms 0;if ( timer0_s 60 ){timer0_m ;timer0_s 0;timer0_20ms 0;if ( timer0_m 99 ){ timer0_m 0;} }}if ( S5 0 ){Delay ( 3 );if ( S5 0 ){TR0 0;}else ;}else {TR0 1;}if ( S4 0 ){Delay ( 3 );if ( S4 0 ){timer0_20ms 0;timer0_s 0;timer0_m 0;}}Input_SMG ( 7 , SMG_duanma[ timer0_20ms%10 ] );Delay ( 1 );Input_SMG ( 6 , SMG_duanma[ timer0_20ms/10 ] );Delay ( 1 );Input_SMG ( 5 , SMG_duanma[16] );Delay ( 1 );Input_SMG ( 4 , SMG_duanma[ timer0_s%10 ] );Delay ( 1 );Input_SMG ( 3 , SMG_duanma[ timer0_s/10 ] );Delay ( 1 );Input_SMG ( 2 , SMG_duanma[16] );Delay ( 1 );Input_SMG ( 1 , SMG_duanma[ timer0_m%10 ] );Delay ( 1 );Input_SMG ( 0 , SMG_duanma[ timer0_m/10 ] );Delay ( 1 );
}void main ()
{Init_timer0 ();while ( 1 ){time_SMGrunning ();}
}5.编程思路重述 对定时计数器的使用在比赛中至关重要主要就是在初始化的时候对TMOD的正确设置GATE、C/T对THx和TLx的初值正确赋值然后不要忘记对TCON寄存器的TR0和TR1要赋值为1启动最后是IE寄存器里面的各个开关要打开。