首页 > 编程知识 正文

流水灯中断程序怎么写,51单片机之定时器控制流水灯实验

时间:2023-05-04 15:03:46 阅读:112215 作者:1710

一、实验目的

1、了解定时器标志位的读取和清除方法。

2、了解计时器中断的方法。

3、了解定时器的初始化设定方法。

二.实验内容

1、完成定时器溢出标志读取控制流水灯

2、完成定时器中断服务函数控制流水灯

三.实验原理

只有一个计时器:

计时器级联:

四.实验电路和程序

1、软件实验1 :读取定时器溢出标志位控制流水灯。

1 )实验要求)读取并计数定时器溢出标志的位,流水灯每秒移位一位。

2 )实验目的)1)掌握定时器初始化设置方法; 2 .掌握计时器溢出标记TF的读取和清除方法。

3 )实验说明)通过本实验,可以掌握单片机定时器初始化设置方法、定时器溢出标志TF的读取和清除方法,同时也知道单片机的编程、调试方法

4 )程序框图

5 )代码

main.c

#include reg52.h #include key.h

#include interrupt.h

int task_flag;

int axdxmfer_flag;

int axdxmfer_flag_2;

Void主() )

{

int count=0;

Config_Timer (; //初始化计时器

//Config_Timer2(;

P1=0xFE; 初始化GPIO

wile(1)//任务调度程序

{

//计时器2控制流水灯

//if(TF2 )

//{

//count;

//TF2=0;

//th2=(65536-50000 )/256;

//TL2=(65536-50000 ) 6; //12M,计时器2分配初始值

//if (计数20 )。

//{

//count=0;

//flow_forward (; //流动着流水灯

//

//}

//}

//计时器1控制流水灯

if(TF1 )//计时器1溢出时

{

出局;

TF1=0; //

th1=(65536-50000 )/256;

TL1=(65536-50000 ) 6; //12M,计时器1分配初始值,每次计数50ms

(if ) count20 ) /一次共计20次,共计1s播放灯

{

计数=0; flow_back (; //流水灯逆流}

}

}

}

key.h

#ifndef _KEY_H

#define _KEY_H

#include reg52.h

void流_前向(void;

voidflow_back(void;

#endif

key.c

# include key.hvoidflow _ forward (void ) )。

{

P1=(P11 )|) P17; //循环左移一位

}

void流_ back (void ) )。

{

P1=(P11 )|) P17; //循环向右移动一位

}

interrupt.h

# ifndef _ interrupt _ h # define _ interrupt _ h

#include reg52.h

#include key.h

未指定Intz (语音延迟;

Void配置_ timer (Void;

voidconfig_timer2(void;

#endif

interrupt.c# include interrupt.hvoidconfig _ timer (void )

{

TMOD=0x11; //将计时器0和1设为动作模式1(m1m0为01 ),向上计数th0=(65536-50000 )/256; //初始值12M石英振动定时50ms数为45872,上位TL0=(65536-50000 ) 6; //下位EA=1; //总中断ET0=1; //导通定时器0中断TR0=1; //开始计时器0 T

H1=(65536-50000)/256;//装初值12M晶振定时50ms数为45872,高位 TL1=(65536-50000)%256;//低位 EA=1;//开总中断 ET1=1;//开定时器1中断 TR1=1;//启动定时器1

}

void Config_Timer2(void)

{

TH2=(65536-50000)/256;

TL2=(65536-50000)%256; //定时器2赋初值

T2CON=0; //配置定时器2控制寄存器

IE=0xA0; //1010 0000开总中断,开外定时器2中断,可按位操作:EA=1; ET2=1;

TR2=1; //启动定时器2

}

2、软件实验二:定时器中断服务函数控制流水灯流水时间
1)实验要求:按键1按下时流水灯正流,按键0按下时流水灯反流,流水灯移位时间由定时器中断控制。
2)实验目的:1. 掌握中断服务子程序的编写方法; 2. 掌握定时器中断的配置方法。
3)实验说明:通过本实验,可以了解单片机掌握中断服务子程序的编写方法和定时器中断的配置方法,同时也可以了解单片机编程,调试方法。
4)、程序框图
1.定时时间由定时器0提供

2.定时时间由T0和T1级联提供

5)、代码
1.定时时间由定时器0或定时器2提供
main.c

#include <reg52.h>#include <key.h>#include <interrupt.h>int task_flag;int axdxmfer_flag;int axdxmfer_flag_2;void main(){Config_EXTI();//初始化外部中断Config_Timer();//初始化定时器P1=0xFE;//初始化GPIOwhile(1)//任务调度器{if(axdxmfer_flag)//每1000ms执行一次任务{axdxmfer_flag=0;switch (task_flag)//判断执行哪个任务{ case 1 :flow_forward();//流水灯正流 break; case 2 :flow_back();//流水灯反流 break; }}}}

key.h

#ifndef _KEY_H#define _KEY_H#include <reg52.h>unsigned char key_scan(void);void flow_forward(void);void flow_back(void);#endif

key.c

#include <key.h>void flow_forward(void){P1=(P1<<1)|(P1>>7);//循环左移1位}void flow_back(void){P1=(P1>>1)|(P1<<7);//循环右移1位}

interrupt.h

#ifndef _INTERRUPT_H#define _INTERRUPT_H#include <reg52.h>#include <key.h>void delay(unsigned int z);void Config_EXTI(void);void Config_Timer(void);extern int task_flag;extern int axdxmfer_flag;extern int axdxmfer_flag_2;#endif

interrupt.c

#include <interrupt.h>void delay(unsigned int z)//延时ms{unsigned int x,y;for(x = z; x > 0; x–)for(y = 114; y > 0 ; y–);}void Config_Timer(void){ TMOD=0x11;//设定时器0和1为工作方式1(M1 M0为01),是向上计数 TH0=(65536-50000)/256;//装初值11.0582晶振定时50ms数为45872,高位 TL0=(65536-50000)%256;//低位 EA=1;//开总中断 ET0=1;//开定时器0中断 TR0=1;//启动定时器0 TH1=(65536-50000)/256;//装初值11.0582晶振定时50ms数为45872,高位 TL1=(65536-50000)%256;//低位 EA=1;//开总中断 ET1=1;//开定时器1中断 TR1=1;//启动定时器1 }void Config_EXTI(void){EA=1;//开中断总允许IT0=1;//下降沿触发外部中断0EX0=1;//开外部中断0IT1=1;//下降沿触发外部中断1EX1=1;//开外部中断1}void EXT0_Handle() interrupt 0{delay(10);task_flag=1;//开启正向流水灯任务}void EXT1_Handle() interrupt 2{delay(10);task_flag=2;//开启反向流水灯任务}void T0_Handle() interrupt 1{ static int num=0; //重装初值 TH0=(65536-50000)/256;//高位 TL0=(65536-50000)%256;//低位if(num<20)//每1000ms把axdxmfer_flag置位{num++;}else{num=0;axdxmfer_flag=~axdxmfer_flag;}}void T1_Handle() interrupt 3{ static int num=0; TH1=(65536-50000)/256;//高位 TL1=(65536-50000)%256;//低位if(num<20)//每1000ms把axdxmfer_flag置位{num++;}else{num=0;axdxmfer_flag_2=~axdxmfer_flag_2;}}

2.定时时间由T0和T1级联提供
main.c

#include <reg52.h>#include <key.h>#include <interrupt.h>int task_flag;int axdxmfer_flag;int axdxmfer_flag_2;void main(){Config_EXTI();//初始化外部中断Config_Timer();//初始化定时器P1=0xFE;//初始化GPIOwhile(1)//任务调度器{if(axdxmfer_flag)//每1000ms执行一次任务{axdxmfer_flag=0;switch (task_flag)//判断执行哪个任务{ case 1 :flow_forward();//流水灯正流 break; case 2 :flow_back();//流水灯反流 break; }}}}

interrupt.h

#ifndef _INTERRUPT_H#define _INTERRUPT_H#include <reg52.h>#include <key.h>void delay(unsigned int z);void Config_EXTI(void);void Config_Timer(void);extern int task_flag;extern int axdxmfer_flag;extern int axdxmfer_flag_2;sbit P2_0=P2^0;#endif

interrupt.c

#include <interrupt.h>void delay(unsigned int z)//延时ms{unsigned int x,y;for(x = z; x > 0; x–)for(y = 114; y > 0 ; y–);}void Config_Timer(void){TMOD=0x61;//axdxmfer0方式1,axdxmfer1方式2 TH0=(65536-50000)/256;//装初值12M晶振定时50ms数为45872,高位 TL0=(65536-50000)%256;//低位 TH1=256-10;//axdxmfe1装初值20TH1=256-10;IP=0x05;EA=1;ET0=1;ET1=1;TR0=1;TR1=1;}void Config_EXTI(void){EA=1;//开中断总允许IT0=1;//下降沿触发外部中断0EX0=1;//开外部中断0IT1=1;//下降沿触发外部中断1EX1=1;//开外部中断1}void EXT0_Handle() interrupt 0{delay(10);task_flag=1;//开启正向流水灯任务}void EXT1_Handle() interrupt 2{delay(10);task_flag=2;//开启反向流水灯任务}void T0_Handle() interrupt 1{ static int num=0; //重装初值 TH0=(65536-50000)/256;//高位 TL0=(65536-50000)%256;//低位P2_0=!P2_0;//P2_0连T1输入T1=P2_0;//如果P2_0直接连T1,这句可以注释掉}void T1_Handle() interrupt 3{axdxmfer_flag=~axdxmfer_flag;}

key.h

#ifndef _KEY_H#define _KEY_H#include <reg52.h>unsigned char key_scan(void);void flow_forward(void);void flow_back(void);#endif

key.c

#include <key.h>void flow_forward(void){P1=(P1<<1)|(P1>>7);//循环左移1位}void flow_back(void){P1=(P1>>1)|(P1<<7);//循环右移1位}
汇编程序:ORG 0000H ;程序执行的起始地址LJMP Main ;跳转到main函数ORG 000BH ;定时器中断0起始地址LJMP 0100H ;定时器中断0服务子程序地址ORG 001BH ;定时器中断1起始地址LJMP 0200H ;定时器中断1服务子程序地址Main: ;主函数MOV P1, #0FEH ;P1口初始化MOV P2, #001H ;P2口初始化SETB EA ;开定时器中断SETB ET0SETB ET1SETB TR0SETB TR1MOV TMOD, #061H ;axdxmf0方式1,axdxmf1方式2MOV TH0, #03CH ;(65536-45872)/256MOV TL0, #0B0H ;12M晶振定时50msMOV TH1, #0F6H ;MOV TL1, #0F6H ;自动加载值,每次计10次溢出LOOP: JMP LOOP ;while(1)死循环ORG 0100H ;定时器中断0服务子程序淡定的丝袜0:MOV A, P2XRL A, #01HMOV P2, A ;通过P2^0给T1中断信号MOV TH0, #03CH ;(65536-45872)/256MOV TL0, #0B0H ;12M晶振定时50msRETI ;中断返回ORG 0200H ;定时器中断1服务子程序淡定的丝袜1:MOV A, P1RL AMOV P1, A ;P1移位一位,流水灯RETIEND

五、实验总结

在键盘扫描程序中,卡的比较久时间的是点灯。后面发现不同的开发板,灯的位置不一样。第二个卡的比较久的地方是判断P3口时,没有考虑到高四位的情况,考虑进去之后,switch p3就正常了。
2.设计键盘外部中断的时候,考虑到如果把流水灯放在中断回调函数里面进行的话,会导致执行回调函数的时候,别的中断来了会很麻烦。于是改为在回调函数里面设置标志位,while(1)里面根据标志位来选择执行哪个点灯代码。但是流水灯需要延时,如果用跑空循环来作延时的话,有点像是阻塞型任务,别的中断来的时候,中断套中断,就很麻烦。于是就开了一个定时器,定时器中断里面设置一个flag,每1秒钟flag置位一下,然后去看看要不要切换任务,以及执行哪个任务。这样子就给单片机节省出大量的资源来了。汇编代码比较遗憾的地方是没有加进定时器中断,delay用跑空循环实现。
4.keil在option里面的target应该设置时钟的频率,proteus也应该设置晶振频率,否则在proteus里面仿真的时候,定时器的实际定时时间可能会有出入。
5.proteus如果接的上拉电阻名字叫“pullup”,则与之相连的单片机io口会一直是高电平,导致流水灯流不起来(因为FF移位之后还是FF),因此要使用普通电阻。
6.keil汇编时,十六进制数如果是以字母开头的,要加0,例如0FEH,不然会报错。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。