• 使用定时器按键扫描数码管制作一个可存储数据的秒表


    目录

    1.前言

    1.1实验现象

    1.2 项目资源

    2.主要程序及解释

    2.1中断中进行按键扫描

    2.2 中断中进行数码管扫描

    2.3中断中进行秒表的驱动

    2.4主函数


    1.前言

    1.1实验现象

    实验现象:按下K1并松开按键秒表开始计时,按下K2并松开按键秒表停止计时,按下K3并松开数据存储到AT24C02中,按下K4并松开读取AT24C02中存储的数据显示在数码管上;

    1.2 项目资源

    https://download.csdn.net/download/YLG_lin/86544425

    2.主要程序及解释

    本次实验用到数码管扫描;按键扫描;AT24C02;还有就是定时器;秒表在运行中按键与数码管都要用到定时器进行不断的定时扫描,但1个定时器只能有1个中断;为了解决这个问题,我们只需要在中断里不断调用按键扫描与数码管扫描这两个模块就ok了;

    2.1中断中进行按键扫描

    1. void Timer0_Routine() interrupt 1
    2. {
    3. static unsigned int T0Count1,T0Count2,T0Count3;
    4. TL0 = 0x18; //设置定时初值
    5. TH0 = 0xFC; //设置定时初值(1ms)
    6. T0Count1++;
    7. if(T0Count1>=20)
    8. {
    9. T0Count1=0;
    10. Key_Loop(); //20ms调用一次按键驱动函数
    11. }
    12. T0Count2++;
    13. if(T0Count2>=2)
    14. {
    15. T0Count2=0;
    16. xianshi_Loop();//2ms调用一次数码管驱动函数
    17. }
    18. T0Count3++;
    19. if(T0Count3>=10)
    20. {
    21. T0Count3=0;
    22. Sec_Loop(); //10ms调用一次数秒表驱动函数
    23. }
    24. }
    1. unsigned char Key_KeyNumber;
    2. /**
    3. * @brief 获取按键键码
    4. * @param 无
    5. * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
    6. */
    7. unsigned char Key(void)
    8. {
    9. unsigned char Temp=0;
    10. Temp=Key_KeyNumber;
    11. Key_KeyNumber=0;
    12. return Temp;
    13. }
    14. /**
    15. * @brief 获取当前按键的状态,无消抖及松手检测
    16. * @param 无
    17. * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
    18. */
    19. unsigned char Key_GetState()
    20. {
    21. unsigned char KeyNumber=0;
    22. if(P3_1==0){KeyNumber=1;}
    23. if(P3_0==0){KeyNumber=2;}
    24. if(P3_2==0){KeyNumber=3;}
    25. if(P3_3==0){KeyNumber=4;}
    26. return KeyNumber;
    27. }
    28. /**
    29. * @brief 按键驱动函数,在中断中调用
    30. * @param 无
    31. * @retval 无
    32. */
    33. void Key_Loop(void)
    34. {
    35. static unsigned char NowState,LastState;
    36. LastState=NowState; //按键状态更新
    37. NowState=Key_GetState(); //获取当前按键状态
    38. //如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
    39. if(LastState==1 && NowState==0)
    40. {
    41. Key_KeyNumber=1;
    42. }
    43. if(LastState==2 && NowState==0)
    44. {
    45. Key_KeyNumber=2;
    46. }
    47. if(LastState==3 && NowState==0)
    48. {
    49. Key_KeyNumber=3;
    50. }
    51. if(LastState==4 && NowState==0)
    52. {
    53. Key_KeyNumber=4;
    54. }
    55. }

    2.2 中断中进行数码管扫描

    1. void Timer0_Routine() interrupt 1
    2. {
    3. static unsigned int T0Count1,T0Count2,T0Count3;
    4. TL0 = 0x18; //设置定时初值(1ms)
    5. TH0 = 0xFC; //设置定时初值
    6. T0Count1++;
    7. if(T0Count1>=20)
    8. {
    9. T0Count1=0;
    10. Key_Loop(); //20ms调用一次按键驱动函数
    11. }
    12. T0Count2++;
    13. if(T0Count2>=2)
    14. {
    15. T0Count2=0;
    16. xianshi_Loop();//2ms调用一次数码管驱动函数
    17. }
    18. T0Count3++;
    19. if(T0Count3>=10)
    20. {
    21. T0Count3=0;
    22. Sec_Loop(); //10ms调用一次数秒表驱动函数
    23. }
    24. }
    1. //数码管显示缓存区
    2. unsigned char xianshi_Buf[9]={0,10,10,10,10,10,10,10,10};
    3. //数码管段码表
    4. unsigned char xianshi_Table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};
    5. /**
    6. * @brief 设置显示缓存区
    7. * @param Location 要设置的位置,范围:1~8
    8. * @param Number 要设置的数字,范围:段码表索引范围
    9. * @retval 无
    10. */
    11. void xianshi_SetBuf(unsigned char Location,Number)
    12. {
    13. xianshi_Buf[Location]=Number;
    14. }
    15. /**
    16. * @brief 数码管扫描显示
    17. * @param Location 要显示的位置,范围:1~8
    18. * @param Number 要显示的数字,范围:段码表索引范围
    19. * @retval 无
    20. */
    21. void xianshi_Scan(unsigned char Location,Number)
    22. {
    23. P0=0x00; //段码清0,消影
    24. switch(Location) //位码输出
    25. {
    26. case 1:P2_4=1;P2_3=1;P2_2=1;break;
    27. case 2:P2_4=1;P2_3=1;P2_2=0;break;
    28. case 3:P2_4=1;P2_3=0;P2_2=1;break;
    29. case 4:P2_4=1;P2_3=0;P2_2=0;break;
    30. case 5:P2_4=0;P2_3=1;P2_2=1;break;
    31. case 6:P2_4=0;P2_3=1;P2_2=0;break;
    32. case 7:P2_4=0;P2_3=0;P2_2=1;break;
    33. case 8:P2_4=0;P2_3=0;P2_2=0;break;
    34. }
    35. P0=xianshi_Table[Number]; //段码输出
    36. }
    37. /**
    38. * @brief 数码管驱动函数,在中断中调用
    39. * @param 无
    40. * @retval 无
    41. */
    42. void xianshi_Loop(void)
    43. {
    44. static unsigned char i=1;
    45. xianshi_Scan(i,xianshi_Buf[i]);
    46. i++;
    47. if(i>=9){i=1;}
    48. }

    2.3中断中进行秒表的驱动

    static 修饰的是静态变量;把值放到静态区,直到程序全部运行完毕才会销毁;

    1. void Timer0_Routine() interrupt 1
    2. {
    3. static unsigned int T0Count1,T0Count2,T0Count3;
    4. TL0 = 0x18; //设置定时初值
    5. TH0 = 0xFC; //设置定时初值(1ms)
    6. T0Count1++;
    7. if(T0Count1>=20)
    8. {
    9. T0Count1=0;
    10. Key_Loop(); //20ms调用一次按键驱动函数
    11. }
    12. T0Count2++;
    13. if(T0Count2>=2)
    14. {
    15. T0Count2=0;
    16. xianshi_Loop();//2ms调用一次数码管驱动函数
    17. }
    18. T0Count3++;
    19. if(T0Count3>=10)
    20. {
    21. T0Count3=0;
    22. Sec_Loop(); //10ms调用一次数秒表驱动函数
    23. }
    24. }
    1. /**
    2. * @brief 秒表驱动函数,在中断中调用
    3. * @param 无
    4. * @retval 无
    5. */
    6. void Sec_Loop(void)
    7. {
    8. if(RunFlag)
    9. {
    10. MiniSec++;
    11. if(MiniSec>=100)
    12. {
    13. MiniSec=0;
    14. Sec++;
    15. if(Sec>=60)
    16. {
    17. Sec=0;
    18. Min++;
    19. if(Min>=60)
    20. {
    21. Min=0;
    22. }
    23. }
    24. }
    25. }
    26. }

    2.4主函数

    首先定时器进行初始化(设置初值,定时器工作模式等),在while循环中不断进行着按键扫描与数码管扫描;其中RunFlag 为启动标志位;AT24C02写周期需要延迟5ms,具体可以查看芯片手册;把分写进0地址,把秒写进1地址;Min/10取十位,Min%10取个位. . .

    1. unsigned char KeyNum;
    2. unsigned char Min,Sec,MiniSec;
    3. unsigned char RunFlag;
    4. void main()
    5. {
    6. Timer0_Init();
    7. while(1)
    8. {
    9. KeyNum=Key();
    10. if(KeyNum==1) //K1按键按下
    11. {
    12. RunFlag=!RunFlag;
    13. }
    14. if(KeyNum==2) //K2按键按下
    15. {
    16. Min=0; //分秒清0
    17. Sec=0;
    18. MiniSec=0;
    19. }
    20. if(KeyNum==3) //K3按键按下
    21. {
    22. AT24C02_WriteByte(0,Min); //将分秒写入AT24C02
    23. Delay(5);
    24. AT24C02_WriteByte(1,Sec);
    25. Delay(5);
    26. AT24C02_WriteByte(2,MiniSec);
    27. Delay(5);
    28. }
    29. if(KeyNum==4) //K4按键按下
    30. {
    31. Min=AT24C02_ReadByte(0); //读出AT24C02数据
    32. Sec=AT24C02_ReadByte(1);
    33. MiniSec=AT24C02_ReadByte(2);
    34. }
    35. xianshi_SetBuf(1,Min/10); //设置显示缓存,显示数据
    36. xianshi_SetBuf(2,Min%10);
    37. xianshi_SetBuf(3,11); //显示——
    38. xianshi_SetBuf(4,Sec/10);
    39. xianshi_SetBuf(5,Sec%10);
    40. xianshi_SetBuf(6,11); //显示——
    41. xianshi_SetBuf(7,MiniSec/10);
    42. xianshi_SetBuf(8,MiniSec%10);
    43. }
    44. }

  • 相关阅读:
    Spring boot 使用 Swagger3 生成API接口文档
    LeetCode 187. 重复的DNA序列
    Redis关闭持久化
    logback.xml文件例子
    Python爬虫-使用代理伪装IP
    为 Serverless Devs 插上 Terraform 的翅膀,解耦代码和基础设施,实现企业级多环境部署(下)
    基于SSM的超市管理系统
    超越创意,从用户创造内容到AI生成内容的新时代
    【LeetCode热题100】--155.最小栈
    词对齐任务:依附于机器翻译
  • 原文地址:https://blog.csdn.net/YLG_lin/article/details/126921928