51定时器中断控制流水灯

一、实验目的
1、了解读取和清零定时器标志位的方法。
2、了解定时器中断的方法。
3、了解定时器初始化设置的方法。
二、实验内容
1、完成读取定时器溢出标志位来控制流水灯
2、完成定时器中断服务函数控制流水灯
三、实验原理
只用一个定时器:

51定时器中断控制流水灯

四、实验电路与程序
1、软件实验一:读取定时器溢出标志位来控制流水灯。
1)实验要求:读取定时器溢出标志位并计数,每过一秒钟流水灯移位一位。
2)实验目的:1. 掌握定时器初始化设置方法;2. 掌握读取和清零定时器溢出标志位TF的方法。
3)实验说明:通过本实验,可以了解单片机定时器初始化设置方法,掌握读取和清零定时器溢出标志位TF的方法,同时也可以了解单片机编程,调试方法。
4)、程序框图

51定时器中断控制流水灯

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

51定时器中断控制流水灯

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

  1. #include <reg52.h>
  2. #include <key.h>
  3. #include <interrupt.h>
  4. int task_flag;
  5. int timer_flag;
  6. int timer_flag_2;
  7. void main()
  8. {
  9. Config_EXTI();//初始化外部中断
  10. Config_Timer();//初始化定时器
  11. P1=0xFE;//初始化GPIO
  12. while(1)//任务调度器
  13. {
  14. if(timer_flag)//每1000ms执行一次任务
  15. {
  16. timer_flag=0;
  17. switch (task_flag)//判断执行哪个任务
  18. {
  19. }
  20. }
  21. }
  22. }

key.h

  1. #ifndef _KEY_H
  2. #define _KEY_H
  3. #include <reg52.h>
  4. unsigned char key_scan(void);
  5. void flow_forward(void);
  6. void flow_back(void);
  7. #endif

key.c

  1. #include <key.h>
  2. void flow_forward(void)
  3. {
  4. P1=(P1<<1)|(P1>>7);//循环左移1位
  5. }
  6. void flow_back(void)
  7. {
  8. P1=(P1>>1)|(P1<<7);//循环右移1位
  9. }

interrupt.h

  1. #ifndef _INTERRUPT_H
  2. #define _INTERRUPT_H
  3. #include <reg52.h>
  4. #include <key.h>
  5. void delay(unsigned int z);
  6. void Config_EXTI(void);
  7. void Config_Timer(void);
  8. extern int task_flag;
  9. extern int timer_flag;
  10. extern int timer_flag_2;
  11. #endif

interrupt.c

  1. #include <interrupt.h>
  2. void delay(unsigned int z)//延时ms
  3. {
  4. unsigned int x,y;
  5. for(x = z; x > 0; x–)
  6. for(y = 114; y > 0 ; y–);
  7. }
  8. void Config_Timer(void)
  9. {
  10. }
  11. void Config_EXTI(void)
  12. {
  13. EA=1;//开中断总允许
  14. IT0=1;//下降沿触发外部中断0
  15. EX0=1;//开外部中断0
  16. IT1=1;//下降沿触发外部中断1
  17. EX1=1;//开外部中断1
  18. }
  19. void EXT0_Handle() interrupt 0
  20. {
  21. delay(10);
  22. task_flag=1;//开启正向流水灯任务
  23. }
  24. void EXT1_Handle() interrupt 2
  25. {
  26. delay(10);
  27. task_flag=2;//开启反向流水灯任务
  28. }
  29. void T0_Handle() interrupt 1
  30. {
  31. //重装初值
  32. TL0=(65536-50000)%256;//低位
  33. if(num<20)//每1000ms把timer_flag置位
  34. {
  35. num++;
  36. }
  37. else
  38. {
  39. num=0;
  40. timer_flag=~timer_flag;
  41. }
  42. }
  43. void T1_Handle() interrupt 3
  44. {
  45. TL1=(65536-50000)%256;//低位
  46. if(num<20)//每1000ms把timer_flag置位
  47. {
  48. num++;
  49. }
  50. else
  51. {
  52. num=0;
  53. timer_flag_2=~timer_flag_2;
  54. }
  55. }

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

  1. #include <reg52.h>
  2. #include <key.h>
  3. #include <interrupt.h>
  4. int task_flag;
  5. int timer_flag;
  6. int timer_flag_2;
  7. void main()
  8. {
  9. Config_EXTI();//初始化外部中断
  10. Config_Timer();//初始化定时器
  11. P1=0xFE;//初始化GPIO
  12. while(1)//任务调度器
  13. {
  14. if(timer_flag)//每1000ms执行一次任务
  15. {
  16. timer_flag=0;
  17. switch (task_flag)//判断执行哪个任务
  18. {
  19. }
  20. }
  21. }
  22. }

interrupt.h

  1. #ifndef _INTERRUPT_H
  2. #define _INTERRUPT_H
  3. #include <reg52.h>
  4. #include <key.h>
  5. void delay(unsigned int z);
  6. void Config_EXTI(void);
  7. void Config_Timer(void);
  8. extern int task_flag;
  9. extern int timer_flag;
  10. extern int timer_flag_2;
  11. sbit P2_0=P2^0;
  12. #endif

interrupt.c

  1. #include <interrupt.h>
  2. void delay(unsigned int z)//延时ms
  3. {
  4. unsigned int x,y;
  5. for(x = z; x > 0; x–)
  6. for(y = 114; y > 0 ; y–);
  7. }
  8. void Config_Timer(void)
  9. {
  10. TMOD=0x61;//timer0方式1,timer1方式2
  11. TH1=256-10;//time1装初值20
  12. TH1=256-10;
  13. IP=0x05;
  14. EA=1;
  15. ET0=1;
  16. ET1=1;
  17. TR0=1;
  18. TR1=1;
  19. }
  20. void Config_EXTI(void)
  21. {
  22. EA=1;//开中断总允许
  23. IT0=1;//下降沿触发外部中断0
  24. EX0=1;//开外部中断0
  25. IT1=1;//下降沿触发外部中断1
  26. EX1=1;//开外部中断1
  27. }
  28. void EXT0_Handle() interrupt 0
  29. {
  30. delay(10);
  31. task_flag=1;//开启正向流水灯任务
  32. }
  33. void EXT1_Handle() interrupt 2
  34. {
  35. delay(10);
  36. task_flag=2;//开启反向流水灯任务
  37. }
  38. void T0_Handle() interrupt 1
  39. {
  40. //重装初值
  41. TL0=(65536-50000)%256;//低位
  42. P2_0=!P2_0;//P2_0连T1输入
  43. T1=P2_0;//如果P2_0直接连T1,这句可以注释掉
  44. }
  45. void T1_Handle() interrupt 3
  46. {
  47. timer_flag=~timer_flag;
  48. }

key.h

  1. #ifndef _KEY_H
  2. #define _KEY_H
  3. #include <reg52.h>
  4. unsigned char key_scan(void);
  5. void flow_forward(void);
  6. void flow_back(void);
  7. #endif

key.c

  1. #include <key.h>
  2. void flow_forward(void)
  3. {
  4. P1=(P1<<1)|(P1>>7);//循环左移1位
  5. }
  6. void flow_back(void)
  7. {
  8. P1=(P1>>1)|(P1<<7);//循环右移1位
  9. }
    汇编程序:
  10. ORG 0000H ;程序执行的起始地址
  11. LJMP Main ;跳转到main函数
  12. ORG 000BH ;定时器中断0起始地址
  13. LJMP 0100H ;定时器中断0服务子程序地址
  14. ORG 001BH ;定时器中断1起始地址
  15. LJMP 0200H ;定时器中断1服务子程序地址
  16. Main: ;主函数
  17. MOV P1, #0FEH ;P1口初始化
  18. MOV P2, #001H ;P2口初始化
  19. SETB EA ;开定时器中断
  20. SETB ET0
  21. SETB ET1
  22. SETB TR0
  23. SETB TR1
  24. MOV TMOD, #061H ;tim0方式1,tim1方式2
  25. MOV TH0, #03CH ;(65536-45872)/256
  26. MOV TL0, #0B0H ;12M晶振定时50ms
  27. MOV TH1, #0F6H ;
  28. MOV TL1, #0F6H ;自动加载值,每次计10次溢出
  29. LOOP: JMP LOOP ;while(1)死循环
  30. ORG 0100H ;定时器中断0服务子程序
  31. TIM0:
  32. MOV A, P2
  33. XRL A, #01H
  34. MOV P2, A ;通过P2^0给T1中断信号
  35. MOV TH0, #03CH ;(65536-45872)/256
  36. MOV TL0, #0B0H ;12M晶振定时50ms
  37. RETI ;中断返回
  38. ORG 0200H ;定时器中断1服务子程序
  39. TIM1:
  40. MOV A, P1
  41. RL A
  42. MOV P1, A ;P1移位一位,流水灯
  43. RETI
  44. END

五、实验总结

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

来源:waiting不是违停

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年1月1日
下一篇 2021年1月1日

相关推荐