51单片机(十):定时器&中断的应用

一、前期准备

1. 定时器工作模式的设置

        由于定时器工作模式寄存器TMOD是不允许位寻址的,所以对在两个定时器模式的设置上存在的一些技巧进行介绍。

        ① 直接对寄存器TMOD进行十六进制形式的赋值。

        ② 对寄存器进行“按位与 按位或”形式的赋值。

例如:定时器1保持原来的工作方式,使定时器0工作在模式1下。(假设此时定时器1工作在模式0下)

//方式1
TMOD = 0x01; //0000 0001 同时对两个定时器的工作模式进行设置
//方式2
TMOD = TMOD & 0xF0; //1111 0000 将TMOD的低4位清零,高4位保持不变。
TMOD = TMOD | 0x01; //0000 0001 将TMOD的最低位置1,高4位保持不变。

        上面的方式②看似没有改变定时器1的工作模式,只改变了定时器0的工作模式。但是由于定时器工作模式寄存器TMOD是不允许位寻址的,所以虽然Timer1的工作模式没有被改变,但是它的工作模式是被重新定义过的。实际上,它的新模式与原来的模式是一样的,所以这个改变并没有引起任何实际效果。直接对TMOD进行赋值的方法更加简洁明了,而按位与和按位或操作更加灵活和精细。

2. 初值的计算&初值的设定

        1)初值的计算:

        在51单片机中,定时器初值的计算公式根据定时器的模式和需要定时的时间不同而有所不同。

公式:(2^n-初值)×(12 ÷ 晶振频率)= 定时时间

        n:定时器位数 ,由定时器模式进行决定;时钟周期 = 1 / 晶振频率机械周期 = 12 × 时钟周期 = 12 / 晶振频率,如果这里认定晶振频率为12MHz,那么对应的机械周期就是12/12MHz=1us。那么进而可以得到上述公式的变形:初值 = 2^n - 定时时间,单位均为us。

        2)初值的设定:

        ① 上面得到的“初值”是十进制形式,可以将得到的十进制数转换成16进制数,然后分别对THn和TLn进行初值的设定。

        ② 同时还可以通过对“初值”进行256取整,得到THn的值,即THn = (2^n - 定时时间) / 256;通过对“初值”进行256取余,得到TLn的值,即TLn = (2^n - 定时时间) % 256。(定时器是8位的,最大计数值位255,即2^8-1,记到256时TLn向THn进1。)

例如:使工作在模式1下的定时器0工作50ms后产生溢出。

        利用上面公式,(2^16 - x) × (12 ÷ 12) = 50ms = 50000us,解得 x = 15536,对应16进制形式为3cb0H。

//方式1
TH0 = 0x3c;
TL0 = 0xb0;

        利用“取整”+“取余”的方法,TH0 = (65536 - 50000) / 256,TL0 = (65536 - 50000) % 256。

//方式2
TH0 = (65536 - 50000) / 256;
TH0 = (65536 - 50000) % 256;

        3)给定的定时时间超过了最大定时时间65.536ms怎么办?

        定时器从开始计时到最后的溢出,期间会经历65536个机器周期,按照每个机器周期为1us来算,那么65536个机器周期相当于计时65536us,也就是65.536ms。如果想要定时的时间超过了65.536ms,可以通过添加循环进行实现。

        例如通过“TH0 = (65536 - 50000) / 256; TH0 = (65536 - 50000) % 256;”语句可以实现50ms定时,如果想要实现1s的定时,可以通过1s=50ms×20,即添加“循环”的方法进行实现。(下方实例中有相应代码详解)   

3. 中断允许设置

        由于中断使能(允许)寄存器IE是允许位寻址的,所以在对中断源允许中断的设置上存在的一些不同的实现方法。

        ① 直接对寄存器IE进行十六进制形式的赋值。

        ② 对所使用的中断源对应的控制位的状态进行单独设置。

例如:同时使用定时器T0和T1的中断。

//方法1
IE = 0x8A;   //对IE寄存器进行整体赋值,D6位和D5位默认取0。
//方式2
EA=0;
ET0=1;
ET1=1;

4. 中断服务函数

        中断服务函数是一种特殊的函数,用于处理单片机内部的中断事件。当中断事件发生时,单片机会暂停当前正在执行的程序,转而去执行中断服务函数,处理完中断事件后再返回原来被中断的地方,继续执行原来的程序。中断服务函数的特点是,它属于后台触发、前台执行的函数体。与其他函数不同的是,其他函数都是前台调用执行的函数体。

//中断服务函数的格式
void ISR_Name(void) interrupt ISR_Number  
{  
    // 中断处理代码  
}
//ISR_Name 是中断服务函数的名称,可以根据需求进行自定义。
//interrupt ISR_Number 指定了中断号,即中断源的唯一标识。

例如:中断服务函数来处理外部中断0(INT0)。
void Int0_Routine(void) interrupt 0
{  
    // 中断处理代码  
}

5. 外部中断的触发方式

        ① 低电平触发:指当外部中断引脚的电平为低电平时,中断请求被激活。

        ② 下降沿触发:指当外部中断引脚的电平从高电平变为低电平时,中断请求被激活。

        1)当采用低电平触发的方式时,外部中断源(输入到INT0/1)必须一直保持低电平有效,直到该中断被CPU 响应,同时在该中断服务程序执行完之前,外部中断源必须被清除(P3.2/P3.3要变为高电平),否则将产生另一次中断。即:

        · 只要P3.2(或P3.3)保持低电平,IE0(或IE1)就保持为1,并请求中断。

        · CPU响应该中断后,即使硬件会立刻将IE0(或IE1)清零,但如果P3.2(或P3.3)还保持为低电平,IE0(或IE1)将又会被置1,进而继续请求中断。

        · 中断服务程序执行完返回后,将会继续执行下一次中断,即使期间使用软件对IE0(或IE1)置零也不会使下一次中断停止。

        · 只有当P3.2(或P3.3)恢复高电平,在最后一次中断服务程序执行完,IE0(或IE1)由硬件清零之后,才不会再引发新的中断请求。

        2)当采用下降沿触发的方式时,要考虑按键抖动所产生的的影响,必须进行按键的消抖。

6. 自定义中断优先级

        由于中断优先级寄存器IP是允许位寻址的,所以在对中断优先级的设置上存在的一些不同的实现方法。

        ① 直接对寄存器IP进行十六进制形式的赋值。

        ② 对所使用的中断源对应的控制位的状态进行单独设置。

例如:将定时器T0的优先级设置为高优先级

//方式1
IP=0x02
//方式2
PT0=0;

二、应用实例

1. 定时器T0在模式1下实现流水灯,闪烁间隔为500ms。(定时器的应用)

#include <reg51.h>         
  
void main()
{
	unsigned char k,n,i; 
	
    n=0x01;   //由LED模块的公共端电平所决定
	
    k=0;
    
    // 1.报备:将定时器T0的工作模式设置为模式1(定时功能)
	TMOD=0x01;   

    // 2.置初值:设置定时时间为50ms,后续通过循环实现目标定时时间
	TH0=(65536-50000)/256;   //TH0 = 0x3c;
    TL0=(65536-50000)%256;   //TL0 = 0xb0;
	
    // 3.启动:使定时器T0开始工作
    TR0=1;
	
    while(1)
	{
		n=0x01;
        //循环8次之后,进入下一个while(1)循环
		for(i=0;i<8;i++)   //根据LED的个数,来决定i的取值范围
		{
			P0=~n;
			while(k<10)   //此处通过一个while循环实现闪烁间隔为500ms=50ms×10
			{
                // 4.等待:当定时器最高位产生溢出时,TF0会由硬件使其置1
				while(TF0==0);   //当TF0=0时,一直执行while循环,直到TF0=1

                // 5.重置初值:使每次的溢出时间保持相同
                TH0=(65536-50000)/256;
				TL0=(65536-50000)%256;

                // 6.清溢出:将中断标志位重新置0
				TF0=0;
			
				k++;	
			}
			k=0;
			n=n<<1;
		}
	}		
}

2. 定时器T0的中断法实现流水灯,工作模式为模式1,闪烁间隔为100ms。(定时器+中断)

#include <reg52.h>   

unsigned char k;   //main函数和中断服务函数中均用到了k,所以k不能在main函数中进行定义      

//中断服务函数
void Timer0_Routine (void) interrupt 1
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;   //重置初值,再次进行50ms计时

	k++;	
}

void main()
{
	unsigned char n,i;      
                  
	k=0;

	P0=n;

	TMOD=0x01;   //将定时器T0的工作模式设置为模式1(定时功能)

	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;   //设置定时时间为50ms,通过多次执行中断服务函数实现目标定时时间

    //配置定时器T0的中断开关
	EA=1;   //闭合中断总开关
	ET0=1;   //闭合定时器T0的中断允许开关

	TR0=1;   //定时器T0开始工作

	while(1)
	{
		n=0x01;   //由LED模块的公共端电平决定

        //循环8次之后,进入下一个while(1)循环
		for(i=0;i<8;i++)   //根据LED的个数,来决定i的取值范围
		{
			P0=~n;

			while(k<2);   //此处通过中断服务函数实现闪烁间隔为100ms=50ms×2

			k=0;
			n=n<<1;
		}
	}
}

        问:和上面的程序1相比,程序2中并没有“清溢出”这一步骤。那是不是在“定时器”和“中断”同时使用时,定时器溢出标志位TFn不起作用?如果定时器溢出标志位TFn起作用,那为什么不用对其进行清零?

        答:显然,定时器溢出标志位 TFn 在定时加中断的情况下依然会被使用。TFn 是用来指示定时器是否溢出的标志位,当定时器计数达到设定值时,TFn 会被设置为 1,表示定时器已经溢出。这时,如果开启了中断,那么中断会被触发,TFn会被硬件电路自动清零。程序1中,之所以要进行手动TF0清零,是因为程1序没有使用中断,无法被自动清零。

3. 定时器T0在模式2下实现流水灯,闪烁间隔为100ms。(模式2下的定时器中断)

#include <reg52.h>         

unsigned int k;   //main函数和中断服务函数中均用到了k,所以k不能再main函数中进行定义

//中断服务函数
void Timer0_Routine (void) interrupt 1
{
	k++;	
}

void main()
{
	unsigned char n,i;  
                      
	k=0;

	TMOD=0x02;   //将定时器T0的工作模式设置为模式2(定时功能) 

	TH0=56;   //初值=256-定时时间   56=256-200
	TL0=56;   //设置定时时间为200us

    //配置定时器T0的中断开关
	EA=1;   //闭合总中断开关
	ET0=1;   //闭合定时器T0的中断允许开关

	TR0=1;   //定时器T0开始工作

	while(1)
	{
		n=0x01;   //由LED模块的公共端电平决定

        //循环8次之后,进入下一个while(1)循环
		for(i=0;i<8;i++)   //根据LED的个数,来决定i的取值范围
		{
			P0=~n;

			while(k<500);   //此处通过中断服务函数实现闪烁间隔为100ms=200us×500

			k=0;
			n=n<<1;
		}
	}
}

注意:

        1) 定时器在模式2下工作时,TLi的溢出不仅置位TFi,而且将THi中的内容重新装入TLi,该过程是由硬件自动实现的,不需要再利用软件进行重置初值。THi中的内容由软件预置,重装时THi内容保持不变,因此计算出初值后对THn和TLn同时赋初值即可。

        2) 由于此处实现闪烁间隔为100ms是利用100ms=200us×500进行实现的,对于变量k的取值范围需要大于500,我们知道unsigned char类型所能表示的数值范围为0~255,unsigned int类型所能表示的数值范围为0~65535,因此将k定义为unsigned int类型。

4. 按键采用外部中断法实现流水灯的启停控制(外部中断与定时器中断)

#include <reg52.h>   

sbit key1=P3^2;   //将P3端口的第2位定义为名为key1的位变量

unsigned char k;   //main函数和中断服务函数中均用到了k,所以k不能再main函数中进行定义

unsigned char led[]={0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80};   //8个状态,形成流水灯现象

//延时函数 实现1ms的延时
void Delay(unsigned int xms)		//@12.0000MHz
{
	unsigned char i, j;
	while(xms)
	{	//_nop_();
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

//外部中断Int0的中断服务程序 —— 控制流水灯的启停
void Int0_Routine (void) interrupt 0
{
	Delay(10);   //检测到下降沿在进入到Int0()后,首先进行10ms的延时,防止按键抖动造成的影响
	if(!key1)   //检测按键是否按下,如果key1为低电平表示按键按下,程序就会继续执行
		TR0=~TR0;   //对定时器运行控制位进行取反,实现“启停”功能
}

//定时器中断T0的中断服务程序 —— 实现50ms延时
void Timer0_Routine (void) interrupt 1
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;   //重置初值,再次进行50ms计时

	k++;	
}

void main()
{
	unsigned char i;  
                      
	k=0;

	TMOD=0x01;   //将定时器T0的工作模式设置为模式1(定时功能)
   
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;   //设置定时时间为50ms,通过多次执行中断服务函数实现目标定时时间

    //配置中断开关
	EA=1;   //闭合中断总开关
	ET0=1;   //闭合定时器T0的中断允许开关
	EX0=1;   //闭合外部中断Int0的中断允许开关   
	
    IT0=1;   //将外部中断设置为下降沿触发

	TR0=1;   //定时器T0开始工作

	while(1)   //循环上面设置的LED的8种状态
	{
		for(i=0;i<8;i++)
		{
			P0=led[i];

			while(k<4);   //使状态转换时长为200ms=50ms×4

			k=0;
		}
	}
}

注意:        

        1) 上面的程序中“流水灯的启停”和“状态转换时长”分别由“外部中断Int0”和“内部定时器T0”进行控制,因此“外部中断Int0的中断服务程序”中的“Delay(10);”语句并不会影响LED的状态转换时长。

        2) 同时,在“流水灯的启停”过程中,其“状态转换时长”也不会发生改变。LED各状态之间转换的时间为200ms,若在按键按下之前,距离上一次的状态改变已经经过了100ms,那么当按键再次按下时,计时时间会继续从100ms开始累加计时,等过了100ms后LED的状态就会再次发生改变。(可以将上述代码中的变量k定义为unsigned int类型,并将while(k<4)中的4换为一个较大的数,然后观察现象即可。比如将4换为40,状态转换时间就变为了:50ms×40=2000ms=2s,方便观察。)

5. 按键采用计数器中断实现LED灯的点亮和熄灭(计数器中断)

//按键按下3次,LED灯的状态变化一次

#include <reg52.h> 

//中断服务函数
void Timer0_Routine () interrupt 1 
{
	P0=~P0;   //通过对LED的状态进行取反,来实现LED的亮灭                              
}

void main()                           
{
	P0=0x00;   //LED灯状态初始化,全亮
                           
	TMOD=0x06;   //T0作为计数器,工作模式为模式3  P3.4引脚接收到一次下降沿,计数器加1
                          
	TH0=0xfd;   //256-初值=3 初值=(253)D=(11111101)B=(FD)H                
	TL0=0xfd;   //计数器T0工作在模式3下,将初值同时赋值给TH0和TL0
             
	EA=1;   //闭合中断总开关                       
	ET0=1;   //闭合计数器T0的中断总开关 
               
	TR0=1;   //计数器T0开始工作
                  
	while(1);                
}

注意:

        1) 如果用按键模拟下降沿,LED可能不会按照理想状态进行亮灭,可以使用红外对管模块进行替代。

        2) 注意区分“外部中断”和“计数器中断”。

        · 外部中断:是针对外部设备或环境事件(如按键、定时器、串行口等)的中断。

        · 计数器中断:是由定时器(如T0、T1等)接收外部信号的下降沿产生计数溢出实现的。

6. 按键控制流水灯的状态(中断优先级及中断嵌套)

        1)外部中断INT0(P3.2)和INT1(P3.3)分别与按键key1和key2相连,key1控制LED灯循环左移,key2控制LED灯循环右移;定时器T0控制LED状态改变的间隔。

#include <reg52.h>

sbit key1=P3^2;   //将P3端口的第2位定义为名为key1的位变量
sbit key2=P3^3;   //将P3端口的第3位定义为名为key2的位变量

unsigned char k=0;   //main函数和中断服务函数中均用到了k,所以k不能再main函数中进行定义    

bit mode=0;   //定义一个名为mode的位变量,并将该位变量进行初始化

//定时器中断T0 —— 控制LED状态改变的时间间隔
void Timer0_Routine () interrupt 1
{
	TH0=0x3c;
	TL0=0xb0;   //重置初值,中再次进行50ms计时

	k++;
}

//外部中断Int0 —— key1控制,进行左移操作
void Int0_Routine () interrupt 0
{			
    mode=0;   	
}

//外部中断Int1 —— key2控制,进行右移操作
void Int1_Routine () interrupt 2
{
	mode=1;   
}

void main()
{
	unsigned char n=0x01;   //LED初始状态,由LED模块的公共端电平决定

	TMOD=0x01;   //将定时器T0的工作模式设置为模式1(定时功能)

	TH0=0x3c;   
	TL0=0xb0;   //设置定时时间为50ms,通过多次执行中断服务函数实现目标定时时间

	IE=0x87;   //1000 0111 EA=1 EX1=1 ET0=1 EX0=1

	IT0=1;
	IT1=1;   //将两外部中断的触发方式设置为下降沿触发

	TR0=1;   //定时器T0开始工作

	while(1)
	{
		P0=~n;

		if(k==10)   //状态改变间隔为500m=50ms×10
		{
			k=0;   //现将计数变量进行清零

			if(!mode)   
			{
				n=n<<1;   //如果mode为0,进行状态左移

                //如果n为0,相当于1"向左"溢出,对n进行重新赋值 第8个灯亮完,第1个灯亮
				if(!n)   //if(n==0x00)
					n=0x01;   
			}
			else
			{
				n=n>>1;   //如果mode为1,进行状态右移
                
                //如果n为0,相当于1“向右”溢出,对n进行重新赋值 第1个灯亮完,第8个灯亮
				if(!n)   //if(n==0x00)
					n=0x80;   
			}
		}
	}	
}	

        考虑到按键的抖动可能会对结果产生影响,在此对上面程序进行改进。

        2) 外部中断INT0(P3.2)和INT1(P3.3)分别与按键key1和key2相连,key1控制LED灯状态的改变,key2控制LED灯的启停;定时器T0控制LED状态改变的间隔。

#include <reg52.h>

sbit key1=P3^2;   //将P3端口的第2位定义为名为key1的位变量
sbit key2=P3^3;   //将P3端口的第3位定义为名为key2的位变量

unsigned char k=0;   //main函数和中断服务函数中均用到了k,所以k不能再main函数中进行定义    

bit mode=0;   //定义一个名为mode的位变量,并将该位变量进行初始化

//延时函数 实现1ms的延时 —— 用于按键的消抖
void Delay(unsigned int xms)		//@12.0000MHz
{
	unsigned char i, j;
	while(xms)
	{	//_nop_();
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

//定时器中断T0 —— 控制LED状态改变的时间间隔
void Timer0_Routine () interrupt 1
{
	TH0=0x3c;
	TL0=0xb0;   //重置初值,中再次进行50ms计时

	k++;
}

//外部中断Int0 —— 按下key1,LED灯的状态就会发生改变
void Int0_Routine () interrupt 0
{	
    Delay(10);
    if(key1==0)		
        mode=~mode;   
}

//外部中断Int1 —— key2控制LED的启停
void Int1_Routine () interrupt 2
{
    Delay(10);
    if(key2==0)		
        TR0=~TR0;   	   
}

void main()
{
	unsigned char n=0x01;   //LED初始状态,由LED模块的公共端电平决定

	TMOD=0x01;   //将定时器T0的工作模式设置为模式1(定时功能)

	TH0=0x3c;   
	TL0=0xb0;   //设置定时时间为50ms,通过多次执行中断服务函数实现目标定时时间

	IE=0x87;   //1000 0111 EA=1 EX1=1 ET0=1 EX0=1

	IT0=1;
	IT1=1;   //将两外部中断的触发方式设置为下降沿触发

	TR0=1;   //定时器T0开始工作

	while(1)
	{
		P0=~n;

		if(k==10)   //状态改变间隔为500m=50ms×10
		{
			k=0;   //现将计数变量进行清零

			if(!mode)   
			{
				n=n<<1;   //如果mode为0,进行状态左移

                //如果n为0,相当于1"向左"溢出,对n进行重新赋值 第8个灯亮完,第1个灯亮
				if(!n)   //if(n==0x00)
					n=0x01;   
			}
			else
			{
				n=n>>1;   //如果mode为1,进行状态右移
                
                //如果n为0,相当于1“向右”溢出,对n进行重新赋值 第1个灯亮完,第8个灯亮
				if(!n)   //if(n==0x00)
					n=0x80;   
			}
		}
	}	
}	

        考虑到中断优先级的问题,由于“外部中断Int0/Int1的固有优先级”高于“定时器T0的固有优先级”,所以当“定时器中断”和“外部按键中断”同时来临时(概率很小),CPU会优先响应Int0/Int1的中断。但是由于按键的消抖会进行10ms的延时(此处不考虑程序执行时间),所以当定时器中断被响应后,LED灯的状态改变的时间会多出10ms。若对LED状态改变的时间要求特别严格的话,可以对程序进行以下改进。(此处不考虑两外部中断同时来临的问题,因为两按键同时按下几乎不可能。)

        3) 外部中断INT0(P3.2)和INT1(P3.3)分别与按键key1和key2相连,key1控制LED灯状态的改变,key2控制LED灯的启停;定时器T0控制LED状态改变的间隔。  —— 提高T0的中断优先级

#include <reg52.h>

sbit key1=P3^2;   //将P3端口的第2位定义为名为key1的位变量
sbit key2=P3^3;   //将P3端口的第3位定义为名为key2的位变量

unsigned char k=0;   //main函数和中断服务函数中均用到了k,所以k不能再main函数中进行定义    

bit mode=0;   //定义一个名为mode的位变量,并将该位变量进行初始化

//延时函数 实现1ms的延时 —— 用于按键的消抖
void Delay(unsigned int xms)		//@12.0000MHz
{
	unsigned char i, j;
	while(xms)
	{	//_nop_();
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

//定时器中断T0 —— 控制LED状态改变的时间间隔
void Timer0_Routine () interrupt 1
{
	TH0=0x3c;
	TL0=0xb0;   //重置初值,中再次进行50ms计时

	k++;
}

//外部中断Int0 —— 按下key1,LED灯的状态就会发生改变
void Int0_Routine () interrupt 0
{	
    Delay(10);
    if(key1==0)		
        mode=~mode;   
}

//外部中断Int1 —— key2控制LED的启停
void Int1_Routine () interrupt 2
{
    Delay(10);
    if(key2==0)		
        TR0=~TR0;   	   
}

void main()
{
	unsigned char n=0x01;   //LED初始状态,由LED模块的公共端电平决定

	TMOD=0x01;   //将定时器T0的工作模式设置为模式1(定时功能)

	TH0=0x3c;   
	TL0=0xb0;   //设置定时时间为50ms,通过多次执行中断服务函数实现目标定时时间

	IE=0x87;   //1000 0111 EA=1 EX1=1 ET0=1 EX0=1

	IT0=1;
	IT1=1;   //将两外部中断的触发方式设置为下降沿触发

    PT0=1;   //将定时器T0的优先级设置为高优先级

	TR0=1;   //定时器T0开始工作

	while(1)
	{
		P0=~n;

		if(k==10)   //状态改变间隔为500m=50ms×10
		{
			k=0;   //现将计数变量进行清零

			if(!mode)   
			{
				n=n<<1;   //如果mode为0,进行状态左移

                //如果n为0,相当于1"向左"溢出,对n进行重新赋值 第8个灯亮完,第1个灯亮
				if(!n)   //if(n==0x00)
					n=0x01;   
			}
			else
			{
				n=n>>1;   //如果mode为1,进行状态右移
                
                //如果n为0,相当于1“向右”溢出,对n进行重新赋值 第1个灯亮完,第8个灯亮
				if(!n)   //if(n==0x00)
					n=0x80;   
			}
		}
	}	
}	

51单片机基础应用设计C语言实例(400例)合集: 10-LED循环左移 100-24c02记忆开机次数 101-24c02存储上次使用中状态 102-DS1302 时钟原理 103-DS1302可调时钟 104-DS1302时钟串口自动更新时间 105-1602液晶显示DS1302时钟 106-字库ST7920 12864液晶基础显示 107-按键 12864显示 108-PCF8591 1路AD数码管显示 109-PCF8591 4路AD数码管显示 11-LED循环右移 110-PCF8591 DA输出模拟 111-PCF8591 输出锯齿波 112-PCF8591 1602液晶显示 113-串口通讯 114-串口通讯中断应用 115-RS485基本通讯原理 116-红外接收原理 117-红外解码数码管显示 118-红外解码1602液晶显示 119-红外发射原理 12-查表显示LED灯 120-红外收发测试 121-双红外发射避障原理测试 122-1个18B20 温度传感器 数码管显示 123-1个18b20温度传感器1602液晶显示 124-多个18b20温度传感器1602液晶显示 125-超温报警测试 126-温度可调上下限1602 126-温度可调上下限1602显示 127-PS2键盘输入1602液晶显示 128-双色点阵1种颜色显示测试 129-双色点阵2种颜色显示测试 13-双灯左移右移闪烁 130-双色点阵显示特定图形 131-双色点阵交替图形显示 132-双色点阵双色交替动态显示 133-热敏电阻测试数码管显示 134-光敏电阻测试数码管显示 135-自动调光测试 136-串转并数字芯片测试 137-非门数字芯片测试 138-电子琴 139-实用99分钟倒计时器 14-花样灯 140-外部频率测试 141-定时做普通时钟可调 142-1602液晶显示的密码锁 143-实用密码锁 144-1602液晶显示的计算器 145-秒表 146-串口测温电脑显示 147-交通灯测试 148-点阵模拟电梯上行下行 149-点阵流动广告模拟 15-PWM调光 150-综合测试程序 151-12位AD_DS1621与12864液晶 152-闪烁灯一 153-闪烁灯二 154-流水灯A 155-51单片机12864大液晶屏proteus仿真 156-流水灯B 157-数码管显示 158-12864LCD显示计算器键盘按键实验 159-数码管显示(锁存器) 16-共阳数码管静态显示 160-数码管动态显示 161-数码管滚动显示 162-数码管字符显示 163-独立按键 164-矩阵键盘 165-矩阵键盘(LCD) 166-用DS1302与12864LCD设计的可调式中文电子日历 167-定时器的使用(方式1) 168-12864LCD图形滚动演示 169-用PG12864LCD设计的指针式电子钟 17-1个共阳数码管显示变化数字 170-定时器的使用(方式2) 171-外部中断的使用 172-定时器和外部中断 173-开关控制12864LCD串行模式显示 174-点阵显示 175-液晶1602显示 176-12864带字库测试程序 177-串行12864显示 178-遥控键值解码-12864LCD显示 179-液晶12864并行 18-单个数码管模拟水流 180-液晶12864并行2 181-串口发送试验 182-串口接收试验 183-串口接收(1602) 184-蜂鸣器发声 185-直流电机调速 186-蜂鸣器间断发声 187-lcd-12864应用 188-继电器控制 189-直流电机调速 19-按键控制单个数码管显示 190-步进电机 191-存储AT24C02 192-PCF8591T AD实验 193-PCF8591T芯片DA实验 194-温度采集DS18B20 195-EEPROM_24C02 196-12864LCD显示24C08保存的开机画面 197-红外解码 198-12864LCD显示EPROM2764保存的开机画面 199-时钟DS1302(LCD) 2-IO输出-点亮1个LED灯方法2 20-单个数码管指示逻辑电平 200-宏晶看门狗 201-SD卡 202-秒表 203-普通定时器时钟 204-彩屏控制 205-彩屏图片显示 206-12864+DS1302时钟+18B20温度计 207-12864测试程序 208-12864串行驱动演示 209-12864生产厂程序 21-8位数码管显示其中之一 210-12864中文显示测试 211-LCD12864 212-12864M液晶显示(有字库)程序(汇编) 213-超声波测距LCD12864显示 214-红外遥控键值解码12864液晶显示(汇编语言)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值