找回密码
 立即注册
楼主: 飞行者

Ai8051u擎天柱学习冲哥《8051U深度入门到32位51大型实战视频》记录贴

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 2025-8-4 12:02:20 | 显示全部楼层
11.矩阵按键

屏幕截图 2025-07-26 154436.png
io.c代码
  1. #include "io.h"
  2. u8 State1 = 0;                                        //LED1初始状态
  3. u8 State2 = 0;                                        //LED2初始状态
  4. u8 State3 = 0;                                        //LED3初始状态
  5. u16 Key_Vol = 0;                                //按键按下持续时间(几个十秒)
  6. u8 SEG_NUM[] =
  7. {
  8.         0x3F,       /*'0', 0*/
  9.     0x06,       /*'1', 1*/
  10.     0x5B,       /*'2', 2*/
  11.     0x4F,       /*'3', 3*/
  12.     0x66,       /*'4', 4*/
  13.     0x6D,       /*'5', 5*/
  14.     0x7D,       /*'6', 6*/
  15.     0x07,       /*'7', 7*/
  16.     0x7F,       /*'8', 8*/
  17.     0x6F,       /*'9', 9*/
  18.     0x77,       /*'A', 10*/
  19.     0x7C,       /*'B', 11*/
  20.     0x39,       /*'C', 12*/
  21.     0x5E,       /*'D', 13*/
  22.     0x79,       /*'E', 14*/
  23.     0x71,       /*'F', 15*/
  24.     0x40,       /*'-', 16*/
  25.     0x00,       /*' ', 17*/
  26.     0x80,       /*'.', 18*/
  27. };
  28. u8 T_NUM[8] =
  29. {
  30.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  31. };
  32. void LED0_Blink(void)
  33. {
  34.         State1 = !State1;
  35.         P00 = State1;
  36. }
  37. void LED1_Blink(void)
  38. {
  39.         State2 = !State2;
  40.         P01 = State2;
  41. }
  42. void LED2_Blink(void)
  43. {
  44.         State3 = !State3;
  45.         P02 = State3;
  46. }
  47. void Key_Task(void)
  48. {
  49.                 if( P32 == 0 )
  50.                 {
  51.                         Key_Vol++;
  52.                         if(Key_Vol == 5)
  53.                         {
  54.                                 printf("按键单击\r\n");
  55.                         }       
  56.                 }
  57.                 else
  58.                 {
  59.                         Key_Vol = 0;       
  60.                 }
  61. }
  62. /*
  63. ----------行------------
  64.         #define ROW1        P06                //定义端口
  65.         #define ROW2        P07
  66. ----------列-------------
  67.         #define COL1        P00
  68.         #define COL2        P01
  69.         #define COL3        P02                                               
  70.         #define COL4        P03
  71. */
  72. //任务1:数码管显示当前的按键号
  73. u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  74. void Task_1(void)
  75. {
  76.                         //static静态变量,只有第一次进来时才赋值,key_num =0 给按键传递一个键值
  77.        
  78. //        ①第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
  79.         COL1 = 0;
  80.         COL2 = 0;
  81.         COL3 = 0;
  82.         COL4 = 0;
  83.         ROW1 = 1;
  84.         ROW2 = 1;
  85.        
  86.         if((ROW1 == 0) || (ROW2 == 0))                        //"||"或的符号,只要满足其中之一的条件(行按键按下)
  87.         {
  88.                 if((ROW1 == 0) && (ROW2 == 0))                //如果两行都有按键按下,不处理
  89.                 {
  90.                
  91.                 }
  92.                 else if ( ((ROW1 == 1)&&(ROW2 == 0)) || ((ROW1 == 0)&&(ROW2 == 1)) )        //如果有按键按下,而且只有一颗
  93.                 {
  94.                         if( ROW1 == 0 )                                        //判断哪一行,输出行开始的序号
  95.                                 key_num = 0;
  96.                         else if(ROW2 == 0)
  97.                                 key_num = 4;
  98.                        
  99.                         //②第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
  100.                         COL1 = 1;
  101.                         COL2 = 1;
  102.                         COL3 = 1;
  103.                         COL4 = 1;
  104.                         ROW1 = 0;
  105.                         ROW2 = 0;
  106.                        
  107.                         //判断哪一列,叠加按键的序号
  108.                         if(COL1 ==0)               
  109.                         {
  110. //                                key_num = key_num +0;
  111.                         }
  112.                         else if( COL2 == 0)
  113.                         {
  114.                                 key_num = key_num +1;
  115.                         }
  116.                         else if( COL3 == 0)
  117.                         {
  118.                                 key_num = key_num +2;
  119.                         }
  120.                         else if( COL4 == 0)
  121.                         {
  122.                                 key_num = key_num +3;
  123.                         }
  124.                 }
  125.                 COL1 = 0;
  126.                 COL2 = 0;
  127.                 COL3 = 0;
  128.                 COL4 = 0;
  129.                 ROW1 = 1;
  130.                 ROW2 = 1;
  131.         }
  132.         else
  133.         {
  134.                 key_num =0xff;
  135.         }
  136.                                                                        
  137.         //        ③第三步:行列组合一下就可以判断出是哪个按键按下了。
  138. }
  139. void Init_595(void)
  140. {
  141.         HC595_SER  = 0;
  142.         HC595_RCK  = 0;
  143.         HC595_SCK  = 0;
  144. }
  145. void Send_595( u8 dat )
  146. {
  147.         u8 i;
  148.         for( i=0; i<8; i++ )
  149.         {
  150.                 dat <<= 1;                        //数值左移一位
  151.                 HC595_SER  = CY;        //数据写到引脚
  152.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  153.         HC595_SCK  = 0;
  154.         }
  155. }
  156. void Display_Seg( u8 HC595_1,u8 HC595_2)
  157. {
  158.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  159.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  160.         HC595_RCK  = 1;                        //数据输出
  161.         HC595_RCK  = 0;
  162. }
  163. //void SEG_Task(void)
  164. //{
  165. //        if(key_num == 255)
  166. //                Display_Seg( SEG_NUM[17], ~T_NUM[0]);        //数码管段码和位码
  167. //        else
  168. //                Display_Seg( SEG_NUM[key_num], ~T_NUM[0]);        //数码管段码和位码
  169. //}       
  170. //任务二:简易密码箱
  171. u8 passward[8] = { 16,16,16,16,16,16,16,16};
  172. u8 Seg_no = 0;
  173. void SEG_Task(void)
  174. {
  175.                 u8 num = 0;
  176.         if( Seg_no ==0 )                                                                //小时十位
  177.         {
  178.        
  179.                 Display_Seg( SEG_NUM[passward[0]] , ~T_NUM[0]);                //数码管刷段码和位码
  180.         }
  181.         else if( Seg_no ==1 )                                                        //小时的个位
  182.         {
  183.                
  184.                 Display_Seg( SEG_NUM[passward[1]] , ~T_NUM[1]);                //数码管刷段码和位码
  185.         }       
  186.         else if( Seg_no ==2 )                                                        //第一个横杠
  187.         {
  188.                 Display_Seg( SEG_NUM[passward[2]] , ~T_NUM[2]);                //数码管刷段码和位码
  189.         }       
  190.         else if( Seg_no ==3 )                                                        //分钟的十位
  191.         {
  192.                
  193.                 Display_Seg( SEG_NUM[passward[3]] , ~T_NUM[3]);                //数码管刷段码和位码
  194.         }
  195.         else if( Seg_no ==4 )
  196.         {
  197.                
  198.                 Display_Seg( SEG_NUM[passward[4]] , ~T_NUM[4]);                //数码管刷段码和位码
  199.         }       
  200.         else if( Seg_no ==5 )
  201.         {
  202.                 Display_Seg( SEG_NUM[passward[5]] , ~T_NUM[5]);                //数码管刷段码和位码
  203.         }       
  204.         else if( Seg_no ==6 )
  205.         {
  206.                
  207.                 Display_Seg( SEG_NUM[passward[6]] , ~T_NUM[6]);                //数码管刷段码和位码
  208.         }
  209.         else if( Seg_no ==7 )
  210.         {
  211.                
  212.                 Display_Seg( SEG_NUM[passward[7]] , ~T_NUM[7]);                //数码管刷段码和位码
  213.         }       
  214.         else
  215.         {
  216.                
  217.         }
  218.         Seg_no ++;
  219.         if( Seg_no>7 )
  220.                 Seg_no=0;               
  221. }
  222. u8 Key_Vol3 = 0;                                                //判断按钮是否按下
  223. u8 Key_no = 0;                                                        //数码管位计数
  224. //密码输入显示
  225. void PW_write_Task(void)
  226. {
  227.         if( key_num <0xff )
  228.                 {
  229.                         Key_Vol3 ++;
  230.                         if(Key_Vol3 == 5)
  231.                         {
  232.                                 if(Key_no == 0)                        //数码管没有按下时显示“-”
  233.                                 {
  234.                                         passward[0] = 16;
  235.                                         passward[1] = 16;
  236.                                         passward[2] = 16;
  237.                                         passward[3] = 16;
  238.                                         passward[4] = 16;
  239.                                         passward[5] = 16;
  240.                                         passward[6] = 16;
  241.                                         passward[7] = 16;
  242.                                 }
  243.                                 passward[Key_no] = key_num;
  244.                                 Key_no++;
  245.                                 if( Key_no == 8 )                //密码输入到了八位
  246.                                 {
  247.                                         if((passward[0]==1)&&(passward[1]==2)&&(passward[2]==3)&&(passward[3]==4)&&(passward[4]==5)&&(passward[5]==6)&&(passward[6]==7)&&(passward[7]==8))
  248.                                         {
  249.                                                 //密码正确八位数码管显示为1
  250.                                                 passward[0] = 17;
  251.                                                 passward[1] = 17;
  252.                                                 passward[2] = 17;
  253.                                                 passward[3] = 17;
  254.                                                 passward[4] = 17;
  255.                                                 passward[5] = 17;
  256.                                                 passward[6] = 17;
  257.                                                 passward[7] = 1;
  258.                                         }
  259.                                         else                                 //密码输入错误八位数码管显示为空
  260.                                         {
  261.                                                 passward[0] = 16;
  262.                                                 passward[1] = 16;
  263.                                                 passward[2] = 16;
  264.                                                 passward[3] = 16;
  265.                                                 passward[4] = 16;
  266.                                                 passward[5] = 16;
  267.                                                 passward[6] = 16;
  268.                                                 passward[7] = 16;
  269.                                         }
  270.                                         Key_no = 0;
  271.                                 }
  272.                                        
  273.                         }       
  274.                 }
  275.                 else
  276.                 {
  277.                         Key_Vol3 = 0;       
  278.                 }
  279. }
复制代码
io.h代码
  1. #ifndef __IO_H
  2. #define __IO_H
  3. #include "config.h"        //调用头文件
  4. //定义引脚名称
  5. #define HC595_SER         P34
  6. #define HC595_RCK         P35
  7. #define HC595_SCK         P32
  8. /*-----------定义端口-------------*/
  9. #define ROW1        P06                //定义端口
  10. #define ROW2        P07
  11. #define COL1        P00
  12. #define COL2        P01
  13. #define COL3        P02
  14. #define COL4        P03
  15. extern u8 key_num ;
  16. /*-----------函数声明-------------*/
  17. void LED0_Blink(void);
  18. void LED1_Blink(void);
  19. void LED2_Blink(void);
  20. void Key_Task(void);
  21. void Task_1(void);
  22. void SEG_Task(void);
  23. void Init_595(void);
  24. void PW_write_Task(void);
  25. #endif
复制代码
task.c代码

  1. #include "task.h"
  2. #include "io.h"
  3. //========================================================================
  4. //                               本地变量声明
  5. //========================================================================
  6. static TASK_COMPONENTS Task_Comps[]=
  7. {
  8. //状态  计数  周期  函数
  9. //        {0, 300,   300,   LED0_Blink},     /* task 1 Period: 300ms */
  10. //        {0, 600,   600,   LED1_Blink},      /* task 1 Period: 600ms */
  11. //        {0, 900,   900,   LED2_Blink},      /* task 1 Period: 900ms */
  12. //        {0, 10,    10,    Key_Task},      /* task 1 Period: 50ms */
  13.         {0, 10,     10,     Task_1},      /* task 1 Period: 10ms */
  14.         {0, 1,     1,     SEG_Task},      /* task 1 Period: 10ms */
  15.         {0, 10,    10,   PW_write_Task},      /* task 1 Period: 100ms */
  16.        
  17.        
  18. };
  19. u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);
  20. //========================================================================
  21. // 函数: Task_Handler_Callback
  22. // 描述: 任务标记回调函数.
  23. // 参数: None.
  24. // 返回: None.
  25. // 版本: V1.0, 2012-10-22
  26. //========================================================================
  27. void Task_Marks_Handler_Callback(void)
  28. {
  29.     u8 i;
  30.     for(i=0; i<Tasks_Max; i++)
  31.     {
  32.         if(Task_Comps[i].TIMCount)      /* If the time is not 0 */
  33.         {
  34.             Task_Comps[i].TIMCount--;   /* Time counter decrement */
  35.             if(Task_Comps[i].TIMCount == 0) /* If time arrives */
  36.             {
  37.                 /*Resume the timer value and try again */
  38.                 Task_Comps[i].TIMCount = Task_Comps[i].TRITime;  
  39.                 Task_Comps[i].Run = 1;      /* The task can be run */
  40.             }
  41.         }
  42.     }
  43. }
  44. //========================================================================
  45. // 函数: Task_Pro_Handler_Callback
  46. // 描述: 任务处理回调函数.
  47. // 参数: None.
  48. // 返回: None.
  49. // 版本: V1.0, 2012-10-22
  50. //========================================================================
  51. void Task_Pro_Handler_Callback(void)
  52. {
  53.     u8 i;
  54.     for(i=0; i<Tasks_Max; i++)
  55.     {
  56.         if(Task_Comps[i].Run) /* If task can be run */
  57.         {
  58.             Task_Comps[i].Run = 0;      /* Flag clear 0 */
  59.             Task_Comps[i].TaskHook();   /* Run task */
  60.         }
  61.     }
  62. }
复制代码


11.矩阵按键.rar (183.66 KB, 下载次数: 6)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 2025-8-10 21:34:44 | 显示全部楼层
11课 矩阵按键 课后小练 简易洗衣机

屏幕截图 2025-08-10 205123.png
核心工作原理

1. 矩阵按键扫描原理
        硬件结构:采用 2 行(ROW1、ROW2)4 列(COL1-COL4)的矩阵按键,通过行列交叉定位按键。
        扫描逻辑:
        行检测:列输出低电平,行输出高电平,检测行电平(低电平表示该行有按键按下),确定行号(ROW1=0 对应行 0,ROW2=0 对应行 4)。
        列检测:行输出低电平,列输出高电平,检测列电平(低电平表示该列有按键按下),确定列号(COL1-COL4 对应 0-3)。
        键值计算:键值 = 行号 + 列号(如行 0 列 1 对应键值 1,行 1 列 2 对应键值 6)。

2. 数码管显示原理
        硬件驱动:通过 74HC595 芯片级联驱动 8 位数码管,实现串行数据转并行输出,节省 IO 口。
        动态扫描:通过 Seg_no 循环切换数码管位选(0-7),每次仅点亮一位数码管,利用人眼视觉暂留效应实现 “同时显示”。
        显示逻辑:仅使用第 6、7 位数码管(从 0 开始计数),非计时模式显示工作模式(如 “01” 表示模式 1),计时模式显示倒计时(如 “10” 表示 10 秒)。

3. 洗衣机工作流程
        开机:按下开机键(key_num=0),ON_OFF=1 上电,默认模式 1(workingMode=1),数码管显示 “01”。
        选模式:按下模式键 1-5(key_num=1-5),workingMode 更新为对应值,数码管同步显示。
        启动:按下启动键(key_num=6),Start_work=1 开始计时,Work_Time=1 切换到计时模式,数码管显示倒计时。
        倒计时:TIMECOUNT_Task 定期递减 timeVol(单位:ms),数码管实时刷新剩余时间。
        结束:倒计时结束(timeVol=0),自动关机(ON_OFF=0),数码管熄灭。

IO.C
  1. #include "io.h"
  2. bit ON_OFF = 0;                 //洗衣机的加电和去电,对应的开和关。1 洗衣机加电,0 洗衣机断电
  3. bit Start_work = 0;                //洗衣机的启动和停止。1 洗衣机启动工作,0 洗衣机停止工作。
  4. bit Work_Time = 0;                //工作计数。        1 工作模式开始倒计时,0 暂停工作模式。
  5. u8 Run_Key =0 ;                        //运行
  6. u8 key_num = 17;                //定义按键的初始值,11对应段码的空字符
  7. u8 workingMode = 17;    //定义密码初始值,17对应段码的空字符
  8. u8 Seg_no = 0;                         // 数码管扫描位置(0-7,控制8位数码管的刷新)
  9. u16 key_vol = 0;                        //按键延时(用于防抖)
  10. u16 timeVol = 0;                        //计时
  11. u8 SEG_NUM[] =
  12. {
  13.         0x3F,       /*'0', 0*/
  14.     0x06,       /*'1', 1*/
  15.     0x5B,       /*'2', 2*/
  16.     0x4F,       /*'3', 3*/
  17.     0x66,       /*'4', 4*/
  18.     0x6D,       /*'5', 5*/
  19.     0x7D,       /*'6', 6*/
  20.     0x07,       /*'7', 7*/
  21.     0x7F,       /*'8', 8*/
  22.     0x6F,       /*'9', 9*/
  23.     0x77,       /*'A', 10*/
  24.     0x7C,       /*'B', 11*/
  25.     0x39,       /*'C', 12*/
  26.     0x5E,       /*'D', 13*/
  27.     0x79,       /*'E', 14*/
  28.     0x71,       /*'F', 15*/
  29.     0x40,       /*'-', 16*/
  30.     0x00,       /*' ', 17*/
  31.     0x80,       /*'.', 18*/
  32. };
  33. u8 T_NUM[8] =
  34. {
  35.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  36. };
  37. /*
  38. ----------行------------
  39.         #define ROW1        P06                //定义端口
  40.         #define ROW2        P07
  41. ----------列-------------
  42.         #define COL1        P00
  43.         #define COL2        P01
  44.         #define COL3        P02                                               
  45.         #define COL4        P03
  46. */
  47. //u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  48. void Task_1( void )
  49. {
  50.         //        ①第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
  51.         COL1 = 0;
  52.         COL2 = 0;
  53.         COL3 = 0;
  54.         COL4 = 0;
  55.         ROW1 = 1;
  56.         ROW2 = 1;
  57.        
  58.         if((ROW1 == 0) || (ROW2 == 0))                        //"||"或的符号,只要满足其中之一的条件(行按键按下)
  59.         {
  60.                 if((ROW1 == 0) && (ROW2 == 0))                //如果两行都有按键按下,不处理
  61.                 {
  62.                
  63.                 }
  64.                 else if ( ((ROW1 == 1)&&(ROW2 == 0)) || ((ROW1 == 0)&&(ROW2 == 1)) )        //如果有按键按下,而且只有一颗
  65.                 {
  66.                         if( ROW1 == 0 )                                        //判断哪一行,输出行开始的序号
  67.                                 key_num = 0;
  68.                         else if(ROW2 == 0)
  69.                                 key_num = 4;
  70.                        
  71.                         //②第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
  72.                         COL1 = 1;
  73.                         COL2 = 1;
  74.                         COL3 = 1;
  75.                         COL4 = 1;
  76.                         ROW1 = 0;
  77.                         ROW2 = 0;
  78.                        
  79.                         //判断哪一列,叠加按键的序号
  80.                         if(COL1 ==0)               
  81.                         {
  82. //                                key_num = key_num +0;
  83.                         }
  84.                         else if( COL2 == 0)
  85.                         {
  86.                                 key_num = key_num +1;
  87.                         }
  88.                         else if( COL3 == 0)
  89.                         {
  90.                                 key_num = key_num +2;
  91.                         }
  92.                         else if( COL4 == 0)
  93.                         {
  94.                                 key_num = key_num +3;
  95.                         }
  96.                 }
  97.                 COL1 = 0;
  98.                 COL2 = 0;
  99.                 COL3 = 0;
  100.                 COL4 = 0;
  101.                 ROW1 = 1;
  102.                 ROW2 = 1;
  103.         }
  104.         else
  105.         {
  106.                 key_num =0xff;
  107.         }
  108.                                                                        
  109.         //        ③第三步:行列组合一下就可以判断出是哪个按键按下了。
  110. }
  111. void Init_595(void)
  112. {
  113.         HC595_SER  = 0;
  114.         HC595_RCK  = 0;
  115.         HC595_SCK  = 0;
  116. }
  117. void Send_595( u8 dat )
  118. {
  119.         u8 i;
  120.        
  121.         for( i=0; i<8; i++ )
  122.         {
  123.                 dat <<= 1;                        //数值左移一位
  124.                 HC595_SER  = CY;        //数据写到引脚
  125.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  126.         HC595_SCK  = 0;
  127.         }
  128. }
  129. void Display_Seg( u8 HC595_1,u8 HC595_2)
  130. {
  131.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  132.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  133.        
  134.         HC595_RCK  = 1;                        //数据输出
  135.         HC595_RCK  = 0;
  136. }
  137. void SEG_Task(void)
  138. {
  139.     // 只需使用两位数码管,其它位全部为空白
  140.     if (Seg_no == 0)
  141.     {
  142.         // 第0位数码管:显示空字符
  143.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  144.     }
  145.     else if (Seg_no == 1)
  146.     {
  147.         // 第1位数码管:显示空字符
  148.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  149.     }
  150.     else if (Seg_no == 2)
  151.     {
  152.         // 第2位数码管:显示空字符
  153.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  154.     }
  155.     else if (Seg_no == 3)
  156.     {
  157.         // 第3位数码管:显示空字符
  158.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  159.     }
  160.     else if (Seg_no == 4)
  161.     {
  162.         // 第4位数码管:显示空字符
  163.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  164.     }
  165.     else if (Seg_no == 5)
  166.     {
  167.         // 第5位数码管:显示空字符
  168.         Display_Seg(SEG_NUM[17], ~T_NUM[Seg_no]);
  169.     }
  170.     else if (Seg_no == 6)
  171.     {
  172.         // 第6位数码管:计时模式显示十位数,否则显示空
  173.         u8 seg_index;  // 定义段码下标变量
  174.         if (Work_Time == 1)  // 判断是否为计时模式
  175.         {
  176.             seg_index = timeVol / 10000;  // 计时模式:取倒计时十位数
  177.         }
  178.         else
  179.         {
  180.             //seg_index = workingMode / 10; // 工作模式:显示空字符
  181.                         seg_index = (workingMode == 17) ? 17 : (workingMode / 10);
  182.         }
  183.         Display_Seg(SEG_NUM[seg_index], ~T_NUM[Seg_no]);
  184.     }
  185.     else if (Seg_no == 7)
  186.     {
  187.         // 第7位数码管:计时模式显示个位数,否则显示工作模式
  188.         u8 seg_index;  // 定义段码下标变量
  189.         if (Work_Time == 1)  // 判断是否为计时模式
  190.         {
  191.             seg_index = timeVol / 1000 % 10;  // 计时模式:取倒计时个位数
  192.         }
  193.         else
  194.         {
  195.             seg_index = workingMode;  // 工作模式:显示当前模式编号
  196.         }
  197.         Display_Seg(SEG_NUM[seg_index], ~T_NUM[Seg_no]);
  198.     }
  199.     // 更新数码管扫描位置(循环0-7)
  200.     Seg_no++;
  201.     if (Seg_no > 7)
  202.     {
  203.         Seg_no = 0;
  204.     }
  205. }
  206. //倒计时
  207. void TIMECOUNT_Task(void)
  208. {
  209.         if(Start_work == 1)
  210.         {
  211.                 timeVol--;
  212.                 if(timeVol == 0)
  213.                 {
  214.                                         Start_work = 0;                          //停止计时
  215.                                         Work_Time = 0;                         //切换到工作模式状态
  216.                                         workingMode = 17;                          //清屏
  217.                                         ON_OFF = 0;                             //关机                        
  218.                 }
  219.         }
  220. }
  221. /*简易洗衣机面板
  222. 1.按下开机键后,数码管显示1,表示默认为清洗模式1;
  223. 2.用矩阵按键模拟洗衣机的操作面板,前五个按键模拟1-5的清洗模式按键,选择几的时候数码管显示数字几,表示以当前为第几个功能;
  224. 3.按下启动后,按照选择的模式对应的时间开始倒计时,倒计时结束后,数码管熄灭,表示清洗完成(清洗时间自己随意设置)
  225. */
  226. void Task_2( void )
  227. {
  228.         if(key_num < 17)
  229.         {
  230.                 key_vol++;
  231.                 if(key_vol >= 20)
  232.                 {
  233.                         // 现有case处理逻辑...
  234.             // 处理完成后可临时锁定,避免重复触发(可选)
  235.             key_vol = 20;  // 保持阈值,避免长按重复触发
  236.         }
  237.                
  238.                 else  // 按键释放状态
  239.                 {
  240.                         key_vol = 0;  // 重置防抖计数
  241.                 }
  242.                         switch(key_num)
  243.                         {
  244.                                 case 0:
  245.                                                 if(ON_OFF == 0)               
  246.                                                 {
  247.                                                                 ON_OFF = 1;
  248.                                                                 workingMode = 1;  // 开机默认模式1
  249.                                                                 timeVol = 10000;  // 默认模式时间
  250.                                                 }
  251.                                                 break;  // 新增break,避免穿透
  252.                                 case 1:                                                //1:常用模式,定时10秒
  253.                                                 if(ON_OFF == 1 && Start_work == 0)
  254.                                                 {
  255.                                                                 workingMode = 1;        //与case0共用本条,开机与设置为常用模式都置1
  256.                                                                 timeVol = 10000;
  257.                                                 }
  258.                                                 break;
  259.                                 case 2:                                                //2:标准模式,定时15秒
  260.                                                 if(ON_OFF ==1 && Start_work == 0)
  261.                                                 {
  262.                                                                 workingMode = key_num;
  263.                                                                 timeVol = 15000;
  264.                                                 }
  265.                                                 break;
  266.                                 case 3:                                                //3:快洗模式,定时5秒
  267.                                                 if(ON_OFF ==1 && Start_work == 0)
  268.                                                 {
  269.                                                                 workingMode = key_num;
  270.                                                                 timeVol = 5000;
  271.                                                 }
  272.                                                 break;
  273.                                 case 4:                                                //4:毛毯模式,定时30秒
  274.                                                 if(ON_OFF ==1 && Start_work == 0)
  275.                                                 {
  276.                                                                 workingMode = key_num;
  277.                                                                 timeVol = 30000;
  278.                                                 }
  279.                                                 break;
  280.                                 case 5:                                                //5:风干模式,定时20秒
  281.                                                 if(ON_OFF ==1 && Start_work == 0)
  282.                                                 {
  283.                                                                 workingMode = key_num;
  284.                                                                 timeVol = 20000;
  285.                                                 }
  286.                                                 break;
  287.                                 case 6:                                                //启动模式
  288.                                                 if(ON_OFF == 1)
  289.                                                 {
  290.                                                                 Start_work  = 1;        //定时器开始工作
  291.                                                                 Work_Time = 1;        //切换到计时工作状态
  292.                                                 }
  293.                                                 break;
  294.                                 default:                                        //其它情况默认不执行直接退出,比如按下按键7
  295.                                                 break;
  296.                         }
  297.                 }
  298.         }
  299.        
复制代码
main.c
  1. #include "config.h"
  2. #include "task.h"
  3. #include "io.h"
  4. void main(void)
  5. {
  6.        
  7.         Sys_init();                                        //系统初始化
  8.         usb_init();                 //USB CDC 接口配置
  9.        
  10.         IE2 |= 0x80;                //使能USB中断
  11.         Timer0_Init();                                //定时器初始化
  12.         Init_595();
  13.         P0 = 0XFF;                                        // 初始化IO口(置高,确保输入有效)
  14.        
  15.         EA = 1;
  16.         P40 = 0;
  17.         while(1)
  18.         {
  19.                  if (bUsbOutReady)
  20.         {
  21. //            USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
  22.             usb_OUT_done();
  23.         }
  24.                 Task_1();      // 扫描按键
  25.         Task_2();      // 处理按键
  26.         SEG_Task();    // 刷新数码管
  27.         TIMECOUNT_Task(); // 可选:添加定时器中断触发
  28.         }
  29.        
  30. }
  31. void Timer0_Isr(void) interrupt 1
  32. {
  33.        
  34.         Task_Marks_Handler_Callback();                        //系统计时
  35. ;
  36. }
复制代码

demo1.rar (191.49 KB, 下载次数: 2)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 2025-8-10 21:42:46 | 显示全部楼层
12 复位系统

屏幕截图 2025-08-02 093936.png
IO.C
  1. #include "io.h"
  2. u8 SEG_NUM[] =
  3. {
  4.     0x3F,       /*'0', 0*/
  5.     0x06,       /*'1', 1*/
  6.     0x5B,       /*'2', 2*/
  7.     0x4F,       /*'3', 3*/
  8.     0x66,       /*'4', 4*/
  9.     0x6D,       /*'5', 5*/
  10.     0x7D,       /*'6', 6*/
  11.     0x07,       /*'7', 7*/
  12.     0x7F,       /*'8', 8*/
  13.     0x6F,       /*'9', 9*/
  14.     0x77,       /*'A', 10*/
  15.     0x7C,       /*'B', 11*/
  16.     0x39,       /*'C', 12*/
  17.     0x5E,       /*'D', 13*/
  18.     0x79,       /*'E', 14*/
  19.     0x71,       /*'F', 15*/
  20.     0x54,       /*'N', 16*/
  21.     0x5C,       /*'O', 17*/
  22.     0x73,       /*'P', 18*/
  23.     0x50,       /*'R', 19*/
  24.     0x40,       /*'-', 20*/
  25.     0x00,       /*' ', 21*/
  26.     0x80,       /*'.', 22*/
  27. };
  28. u8 T_NUM[8] =
  29. {
  30.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  31. };
  32. /*
  33. ----------行------------
  34.         #define ROW1        P06                //定义端口
  35.         #define ROW2        P07
  36. ----------列-------------
  37.         #define COL1        P00
  38.         #define COL2        P01
  39.         #define COL3        P02                                               
  40.         #define COL4        P03
  41. */
  42. u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  43. void Task_1( void )
  44. {
  45.         //        ①第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
  46.         COL1 = 0;
  47.         COL2 = 0;
  48.         COL3 = 0;
  49.         COL4 = 0;
  50.         ROW1 = 1;
  51.         ROW2 = 1;
  52.        
  53.         if((ROW1 == 0) || (ROW2 == 0))                        //"||"或的符号,只要满足其中之一的条件(行按键按下)
  54.         {
  55.                 if((ROW1 == 0) && (ROW2 == 0))                //如果两行都有按键按下,不处理
  56.                 {
  57.                
  58.                 }
  59.                 else if ( ((ROW1 == 1)&&(ROW2 == 0)) || ((ROW1 == 0)&&(ROW2 == 1)) )        //如果有按键按下,而且只有一颗
  60.                 {
  61.                         if( ROW1 == 0 )                                        //判断哪一行,输出行开始的序号
  62.                                 key_num = 0;
  63.                         else if(ROW2 == 0)
  64.                                 key_num = 4;
  65.                        
  66.                         //②第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
  67.                         COL1 = 1;
  68.                         COL2 = 1;
  69.                         COL3 = 1;
  70.                         COL4 = 1;
  71.                         ROW1 = 0;
  72.                         ROW2 = 0;
  73.                        
  74.                         //判断哪一列,叠加按键的序号
  75.                         if(COL1 ==0)               
  76.                         {
  77. //                                key_num = key_num +0;
  78.                         }
  79.                         else if( COL2 == 0)
  80.                         {
  81.                                 key_num = key_num +1;
  82.                         }
  83.                         else if( COL3 == 0)
  84.                         {
  85.                                 key_num = key_num +2;
  86.                         }
  87.                         else if( COL4 == 0)
  88.                         {
  89.                                 key_num = key_num +3;
  90.                         }
  91.                 }
  92.                 COL1 = 0;
  93.                 COL2 = 0;
  94.                 COL3 = 0;
  95.                 COL4 = 0;
  96.                 ROW1 = 1;
  97.                 ROW2 = 1;
  98.         }
  99.         else
  100.         {
  101.                 key_num =0xff;
  102.         }
  103.                                                                        
  104.         //        ③第三步:行列组合一下就可以判断出是哪个按键按下了。
  105. }u8 Key_vol = 0;
  106. void KEY_Task(void)
  107. {
  108.         if(P33 == 0)
  109.         {
  110.                 Key_vol++;
  111.                 if(Key_vol == 5)
  112.                 {
  113.                         USB_Reset_U();
  114.                         IAP_CONTR = 0X20;
  115.                 }
  116.         }
  117.                
  118. }
  119. void Init_595(void)
  120. {
  121.         HC595_SER  = 0;
  122.         HC595_RCK  = 0;
  123.         HC595_SCK  = 0;
  124. }
  125. void Send_595( u8 dat )
  126. {
  127.         u8 i;
  128.        
  129.         for( i=0; i<8; i++ )
  130.         {
  131.                 dat <<= 1;                        //数值左移一位
  132.                 HC595_SER  = CY;        //数据写到引脚
  133.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  134.         HC595_SCK  = 0;
  135.         }
  136. }
  137. void Display_Seg( u8 HC595_1,u8 HC595_2)
  138. {
  139.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  140.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  141.        
  142.         HC595_RCK  = 1;                        //数据输出
  143.         HC595_RCK  = 0;
  144. }
  145. //void SEG_Task(void)
  146. //{
  147. //        if(key_num == 255)
  148. //                Display_Seg( SEG_NUM[17], ~T_NUM[0]);        //数码管段码和位码
  149. //        else
  150. //                Display_Seg( SEG_NUM[ key_num ], ~T_NUM[0]);        //数码管段码和位码
  151. //}       
  152. //任务二:简易密码箱
  153. u8 passward[8] = { 20,20,20,20,20,20,20,20};
  154. u8 Seg_no = 0;
  155. void SEG_Task(void)
  156. {
  157.                 u8 num = 0;
  158.         switch(Seg_no){
  159.                 case 0: Display_Seg( SEG_NUM[passward[0]], ~T_NUM[0] );                   break;
  160.                 case 1: Display_Seg( SEG_NUM[passward[1]], ~T_NUM[1] );         break;
  161.                 case 2: Display_Seg( SEG_NUM[passward[2]], ~T_NUM[2] );                   break;
  162.                 case 3: Display_Seg( SEG_NUM[passward[3]], ~T_NUM[3] );                   break;
  163.                 case 4: Display_Seg( SEG_NUM[passward[4]], ~T_NUM[4] );                   break;
  164.                 case 5: Display_Seg( SEG_NUM[passward[5]], ~T_NUM[5] );                   break;
  165.                 case 6: Display_Seg( SEG_NUM[passward[6]], ~T_NUM[6] );         break;
  166.                 case 7: Display_Seg( SEG_NUM[passward[7]], ~T_NUM[7] );         break;
  167.         }
  168.         Seg_no ++;
  169.         if( Seg_no>7 )
  170.                 Seg_no=0;               
  171. }
  172. u8 Key_Vol3 = 0;                                                //判断按钮是否按下
  173. u8 Key_no = 0;                                                        //数码管位计数
  174. //密码输入显示
  175. void PW_write_Task(void)
  176. {
  177.         if( key_num <0xff )
  178.                 {
  179.                         Key_Vol3 ++;
  180.                         if(Key_Vol3 == 5)                        //是否延时50m秒
  181.                           {
  182.                                 if(Key_no == 0)                        //数码管没有按下时显示“--------”
  183.                                 {
  184.                                         passward[0] = 20;
  185.                                         passward[1] = 20;
  186.                                         passward[2] = 20;
  187.                                         passward[3] = 20;
  188.                                         passward[4] = 20;
  189.                                         passward[5] = 20;
  190.                                         passward[6] = 20;
  191.                                         passward[7] = 20;
  192.                                        
  193.                                 }
  194.                                 passward[Key_no] = key_num; //键值传递
  195.                                 Key_no++;
  196.                                 if( Key_no == 8 )                //密码输入到了八位
  197.                                 {
  198.                                         if((passward[0]==1)&&(passward[1]==2)&&(passward[2]==3)&&(passward[3]==4)&&(passward[4]==5)&&(passward[5]==6)&&(passward[6]==7)&&(passward[7]==0))
  199.                                         {
  200.                                                 //密码正确八位数码管显示为1
  201.                                                 passward[0] = 20;
  202.                                                 passward[1] = 20;
  203.                                                 passward[2] = 17;
  204.                                                 passward[3] = 18;
  205.                                                 passward[4] = 14;
  206.                                                 passward[5] = 16;
  207.                                                 passward[6] = 20;
  208.                                                 passward[7] = 20;
  209.                                                
  210.                                         }
  211.                                         else                                 //密码输入错误八位数码管显示为空
  212.                                         {
  213.                                                 passward[0] = 20;
  214.                                                 passward[1] = 20;
  215.                                                 passward[2] = 20;
  216.                                                 passward[3] = 20;
  217.                                                 passward[4] = 20;
  218.                                                 passward[5] = 20;
  219.                                                 passward[6] = 20;
  220.                                                 passward[7] = 20;
  221.                                         }                 
  222.                                         Key_no = 0;
  223.                                 }
  224.                                        
  225.                         }       
  226.                 }
  227.                 else
  228.                 {
  229.                         Key_Vol3 = 0;       
  230.                 }
  231. }
复制代码
config.c部分代码
  1. //config.c部分代码
  2. #include "config.h"
  3. void Delay10ms(void)        //@24.000MHz
  4. {
  5.         unsigned long edata i;
  6.         _nop_();
  7.         _nop_();
  8.         _nop_();
  9.         i = 59998UL;
  10.         while (i) i--;
  11. }
  12. void USB_Reset_U(void)
  13. {
  14.                 P3M0 = 0x00;
  15.         P3M1 = 0x00;
  16.         P3M0 &= ~0x03;
  17.         P3M1 |= 0x03;
  18.         USBCON = 0X00;
  19.         USBCLK = 0X00;
  20.         IRC48MCR = 0X00;
  21.         Delay10ms();
  22. }
  23. void Sys_init(void)
  24. {
  25.         WTST = 0;                                          //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  26.     EAXFR = 1;                                         //扩展寄存器(XFR)访问使能
  27.     CKCON = 0;                                         //提高访问XRAM速度
  28.        
  29.         P0M1 = 0x00;   P0M0 = 0x00;
  30.     P1M1 = 0x00;   P1M0 = 0x00;
  31.     P2M1 = 0x00;   P2M0 = 0x00;
  32.     P3M1 = 0x00;   P3M0 = 0x00;
  33.     P4M1 = 0x00;   P4M0 = 0x00;
  34.     P5M1 = 0x00;   P5M0 = 0x00;
  35.     P6M1 = 0x00;   P6M0 = 0x00;
  36.     P7M1 = 0x00;   P7M0 = 0x00;
  37.        
  38.         USB_Reset_U();
  39. }
复制代码
config.h代码
  1. //config.h代码
  2. #ifndef __CONFIG_H
  3. #define __CONFIG_H
  4. #include "ai8051u.h"                        //调用头文件
  5. #include "AI_usb.h"                                //调用头文件
  6. #include "intrins.h"                        //d调用头文件
  7. void Sys_init(void);                        //函数声明
  8. void Timer0_Init(void);
  9. void USB_Reset_U(void);
  10. #endif
  11. //
复制代码
main.c
  1. //main.c代码
  2. #include "config.h"
  3. #include "task.h"
  4. #include "io.h"
  5. void main(void)
  6. {
  7.        
  8.         Sys_init();                                        //系统初始化
  9.         usb_init();                 //USB CDC 接口配置
  10.        
  11.         IE2 |= 0x80;                                    //使能USB中断
  12.         Timer0_Init();                                                                        //定时器初始化
  13.         Init_595();
  14.         EA = 1;
  15.         P40 = 0;
  16.         WDT_CONTR = 0X24;
  17.         while(1)
  18.         {
  19.                  if (bUsbOutReady)
  20.         {
  21. //            USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
  22.             usb_OUT_done();
  23.         }
  24.                 Task_Pro_Handler_Callback();                                //执行功能函数
  25.                 WDT_CONTR = 0X34;
  26.         }
  27.        
  28. }
  29. void Timer0_Isr(void) interrupt 1
  30. {
  31.        
  32.         Task_Marks_Handler_Callback();                        //系统计时
  33. ;
  34. }
复制代码

demo1.rar (183.73 KB, 下载次数: 2)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 2025-8-12 07:25:49 | 显示全部楼层
12 复位系统  课后小练

密码锁
1.没有输入时,显示“- - - - - - - -”
2.有输入时,按下一个按键,开始按顺序写入
    例如,第一个按下1,显示“1 - - - - - - -”   
    例如,第二个按下3,显示“1 3 - - - - - -”
3.当按下的密码为“ 1 2 3 4 5 6 7 0”时,数码管显示open的字符,否则,还是显示“- - - - - - - -”

新增:
1.看门狗,超时1秒自动复位
2.增加开机版本号,开机显示三秒的U 1.00 版本号
3.增加手动复位,P33按钮按下时重启(方便查看版本号和清除密码)

屏幕截图 2025-08-12 062115.png
io.c
  1. #include "io.h"
  2. u8 State1 = 0;                                        //LED1初始状态
  3. u8 State2 = 0;                                        //LED2初始状态
  4. u8 State3 = 0;                                        //LED3初始状态
  5. u16 Key_Vol ;                                //按键按下持续时间
  6. u8 SEG_NUM[] =
  7. {
  8.     0x3F,       /*'0', 0*/
  9.     0x06,       /*'1', 1*/
  10.     0x5B,       /*'2', 2*/
  11.     0x4F,       /*'3', 3*/
  12.     0x66,       /*'4', 4*/
  13.     0x6D,       /*'5', 5*/
  14.     0x7D,       /*'6', 6*/
  15.     0x07,       /*'7', 7*/
  16.     0x7F,       /*'8', 8*/
  17.     0x6F,       /*'9', 9*/
  18.     0x77,       /*'A', 10*/
  19.     0x7C,       /*'B', 11*/
  20.     0x39,       /*'C', 12*/
  21.     0x5E,       /*'D', 13*/
  22.     0x79,       /*'E', 14*/
  23.     0x71,       /*'F', 15*/
  24.     0x54,       /*'N', 16*/
  25.     0x5C,       /*'O', 17*/
  26.     0x73,       /*'P', 18*/
  27.     0x3E,       /*'U', 19*/
  28.     0x40,       /*'-', 20*/
  29.     0x86,       /*'1', 21*/
  30.     0x00,       /*' ', 22*/
  31.     0x80,       /*'.', 23*/
  32. };
  33. u8 T_NUM[8] =
  34. {
  35.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  36. };
  37. void LED1_Blink(void)
  38. {
  39.         State2 = !State2;
  40.         P01 = State2;
  41. }
  42. void LED2_Blink(void)
  43. {
  44.         State3 = !State3;
  45.         P02 = State3;
  46. }
  47. void KEY_Task(void)
  48. {
  49.         if( P33 == 0 )
  50.         {
  51.                 Key_Vol++;
  52.                 if( Key_Vol==5 )
  53.                 {
  54.                         //按键按下的任务
  55. //                        printf( "按键单击\r\n" );
  56.                        
  57.                         USB_Reset_U();
  58.                        
  59.                         IAP_CONTR = 0X20;
  60.                 }
  61.         }
  62.         else
  63.         {
  64.                 Key_Vol = 0;
  65.         }
  66.        
  67. }
  68. /*
  69. ----------行------------
  70.         #define ROW1        P06                //定义端口
  71.         #define ROW2        P07
  72. ----------列-------------
  73.         #define COL1        P00
  74.         #define COL2        P01
  75.         #define COL3        P02                                               
  76.         #define COL4        P03
  77. */
  78. u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  79. void Task_1( void )
  80. {
  81.         //        ①第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
  82.         COL1 = 0;
  83.         COL2 = 0;
  84.         COL3 = 0;
  85.         COL4 = 0;
  86.         ROW1 = 1;
  87.         ROW2 = 1;
  88.        
  89.         if((ROW1 == 0) || (ROW2 == 0))                        //"||"或的符号,只要满足其中之一的条件(行按键按下)
  90.         {
  91.                 if((ROW1 == 0) && (ROW2 == 0))                //如果两行都有按键按下,不处理
  92.                 {
  93.                
  94.                 }
  95.                 else if ( ((ROW1 == 1)&&(ROW2 == 0)) || ((ROW1 == 0)&&(ROW2 == 1)) )        //如果有按键按下,而且只有一颗
  96.                 {
  97.                         if( ROW1 == 0 )                                        //判断哪一行,输出行开始的序号
  98.                                 key_num = 0;
  99.                         else if(ROW2 == 0)
  100.                                 key_num = 4;
  101.                        
  102.                         //②第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
  103.                         COL1 = 1;
  104.                         COL2 = 1;
  105.                         COL3 = 1;
  106.                         COL4 = 1;
  107.                         ROW1 = 0;
  108.                         ROW2 = 0;
  109.                        
  110.                         //判断哪一列,叠加按键的序号
  111.                         if(COL1 ==0)               
  112.                         {
  113. //                                key_num = key_num +0;
  114.                         }
  115.                         else if( COL2 == 0)
  116.                         {
  117.                                 key_num = key_num +1;
  118.                         }
  119.                         else if( COL3 == 0)
  120.                         {
  121.                                 key_num = key_num +2;
  122.                         }
  123.                         else if( COL4 == 0)
  124.                         {
  125.                                 key_num = key_num +3;
  126.                         }
  127.                 }
  128.                 COL1 = 0;
  129.                 COL2 = 0;
  130.                 COL3 = 0;
  131.                 COL4 = 0;
  132.                 ROW1 = 1;
  133.                 ROW2 = 1;
  134.         }
  135.         else
  136.         {
  137.                 key_num =0xff;
  138.         }
  139.                                                                        
  140.         //        ③第三步:行列组合一下就可以判断出是哪个按键按下了。
  141. }
  142. void Init_595(void)
  143. {
  144.         HC595_SER  = 0;
  145.         HC595_RCK  = 0;
  146.         HC595_SCK  = 0;
  147. }
  148. void Send_595( u8 dat )
  149. {
  150.         u8 i;
  151.        
  152.         for( i=0; i<8; i++ )
  153.         {
  154.                 dat <<= 1;                        //数值左移一位
  155.                 HC595_SER  = CY;        //数据写到引脚
  156.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  157.         HC595_SCK  = 0;
  158.         }
  159. }
  160. void Display_Seg( u8 HC595_1,u8 HC595_2)
  161. {
  162.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  163.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  164.        
  165.         HC595_RCK  = 1;                        //数据输出
  166.         HC595_RCK  = 0;
  167. }
  168. //void SEG_Task(void)
  169. //{
  170. //        if(key_num == 255)
  171. //                Display_Seg( SEG_NUM[17], ~T_NUM[0]);        //数码管段码和位码
  172. //        else
  173. //                Display_Seg( SEG_NUM[ key_num ], ~T_NUM[0]);        //数码管段码和位码
  174. //}       
  175. //任务二:简易密码箱
  176. u8 passward[8] = { 22,22,22,22,19,21,0,0};
  177. extern u16 Ms_Time;
  178. u8 Start_ms=0;
  179. //延时三秒函数
  180. void Timing_Start(void)
  181. {
  182.        
  183.         if(Start_ms==0)
  184.                 {
  185.                
  186.                 if(Ms_Time==3000)
  187.                 {
  188.                         passward[0] = 20;
  189.                         passward[1] = 20;
  190.                         passward[2] = 20;
  191.                         passward[3] = 20;
  192.                         passward[4] = 20;
  193.                         passward[5] = 20;
  194.                         passward[6] = 20;
  195.                         passward[7] = 20;                       
  196.                        
  197.                         Start_ms=1;
  198.                 }
  199.                 }
  200. }
  201. u8 Seg_no = 0;
  202. void SEG_Task(void)
  203. {
  204.                 u8 num = 0;
  205.         switch(Seg_no){
  206.                 case 0: Display_Seg( SEG_NUM[passward[0]], ~T_NUM[0] );                   break;
  207.                 case 1: Display_Seg( SEG_NUM[passward[1]], ~T_NUM[1] );         break;
  208.                 case 2: Display_Seg( SEG_NUM[passward[2]], ~T_NUM[2] );                   break;
  209.                 case 3: Display_Seg( SEG_NUM[passward[3]], ~T_NUM[3] );                   break;
  210.                 case 4: Display_Seg( SEG_NUM[passward[4]], ~T_NUM[4] );                   break;
  211.                 case 5: Display_Seg( SEG_NUM[passward[5]], ~T_NUM[5] );                   break;
  212.                 case 6: Display_Seg( SEG_NUM[passward[6]], ~T_NUM[6] );         break;
  213.                 case 7: Display_Seg( SEG_NUM[passward[7]], ~T_NUM[7] );         break;
  214.         }
  215.         Seg_no ++;
  216.         if( Seg_no>7 )
  217.                 Seg_no=0;               
  218. }
  219. u8 Key_Vol3 = 0;                                                //判断按钮是否按下
  220. u8 Key_no = 0;                                                        //数码管位计数
  221. //密码输入显示
  222. void PW_write_Task(void)
  223. {
  224.         if( key_num <0xff )
  225.                 {
  226.                         Key_Vol3 ++;
  227.                         if(Key_Vol3 == 5)                        //是否延时50m秒
  228.                           {
  229.                                 passward[Key_no] = key_num; //键值传递
  230.                                 Key_no++;
  231.                                 if( Key_no == 8 )                //密码输入到了八位
  232.                                 {
  233.                                         if((passward[0]==1)&&(passward[1]==2)&&(passward[2]==3)&&(passward[3]==4)&&(passward[4]==5)&&(passward[5]==6)&&(passward[6]==7)&&(passward[7]==0))
  234.                                         {
  235.                                                 //密码正确八位数码管显示为1
  236.                                                 passward[0] = 21;
  237.                                                 passward[1] = 21;
  238.                                                 passward[2] = 17;
  239.                                                 passward[3] = 18;
  240.                                                 passward[4] = 14;
  241.                                                 passward[5] = 16;
  242.                                                 passward[6] = 21;
  243.                                                 passward[7] = 21;
  244.                                                
  245.                                         }
  246.                                         else                                 //密码输入错误八位数码管显示为空
  247.                                         {
  248.                                                 passward[0] = 20;
  249.                                                 passward[1] = 20;
  250.                                                 passward[2] = 20;
  251.                                                 passward[3] = 20;
  252.                                                 passward[4] = 20;
  253.                                                 passward[5] = 20;
  254.                                                 passward[6] = 20;
  255.                                                 passward[7] = 20;
  256.                                         }
  257.                                        
  258.                                        
  259.                                         Key_no = 0;
  260.                                 }
  261.                                        
  262.                         }       
  263.                 }
  264.                 else
  265.                 {
  266.                         Key_Vol3 = 0;       
  267.                 }
  268. }
复制代码

demo1.rar (192.55 KB, 下载次数: 0)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 2025-8-16 15:33:28 | 显示全部楼层
13 外部中断

屏幕截图 2025-08-06 154347.png
  1. io.c
  2. //外部中断INT1 函数
  3. void INT1_Init(void)
  4. {
  5.         IT1 = 1;                //下降沿中断
  6.         EX1 = 1;                //下降中断允许
  7.         EA = 1;                        //打开总中断
  8. }
  9. //中断服务函数,一旦发生了中断就先执行“中断服务函数”
  10. void INI1_Isr(void) interrupt 2
  11. {
  12.         P01 = !P01;
  13. }
  14. io.h
  15. void INT1_Init(void);  外部中断INT1 函数声明
  16. main.c
  17. #include "config.h"
  18. #include "task.h"
  19. #include "io.h"
  20. //延时函数
  21. void Delay3000ms(void)        //@24.000MHz
  22. {
  23.         unsigned long edata i;
  24.         _nop_();
  25.         _nop_();
  26.         i = 17999998UL;
  27.         while (i) i--;
  28. }
  29. void main(void)
  30. {
  31.        
  32.         Sys_init();                                        //系统初始化
  33.         usb_init();                 //USB CDC 接口配置
  34.        
  35.         IE2 |= 0x80;                //使能USB中断
  36.         Timer0_Init();                                //定时器初始化
  37.         Init_595();
  38.         INT1_Init();                                //外部中断int1初始化
  39.        
  40.         EA = 1;
  41.         P40 = 0;
  42. //        WDT_CONTR = 0X24;
  43.         while(1)
  44.         {
  45.                  if (bUsbOutReady)
  46.         {
  47. //            USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
  48.             usb_OUT_done();
  49.         }
  50. //                Task_Pro_Handler_Callback();                                //执行功能函数
  51. //                WDT_CONTR = 0X34;
  52.                
  53.                 /*延时三秒钟P00LED灯取反一次 */
  54.                 P00 = !P00;
  55.                 Delay3000ms();
  56.                        
  57.                
  58.         }
  59.        
  60. }
  61. void Timer0_Isr(void) interrupt 1
  62. {
  63.        
  64.         Task_Marks_Handler_Callback();                        //系统计时
  65. ;
  66. }
复制代码

demo1.rar (185.4 KB, 下载次数: 0)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 昨天 20:03 | 显示全部楼层
13.外部中断 课后小练 雕刻机保护系统

屏幕截图 2025-08-23 195146.png
io.c代码
  1. #include "io.h"
  2. #define LED04 P04
  3. u8 SEG_NUM[] =
  4. {
  5.     0x3F,       /*'0', 0*/
  6.     0x06,       /*'1', 1*/
  7.     0x5B,       /*'2', 2*/
  8.     0x4F,       /*'3', 3*/
  9.     0x66,       /*'4', 4*/
  10.     0x6D,       /*'5', 5*/
  11.     0x7D,       /*'6', 6*/
  12.     0x07,       /*'7', 7*/
  13.     0x7F,       /*'8', 8*/
  14.     0x6F,       /*'9', 9*/
  15.     0x77,       /*'A', 10*/
  16.     0x7C,       /*'B', 11*/
  17.     0x39,       /*'C', 12*/
  18.     0x5E,       /*'D', 13*/
  19.     0x79,       /*'E', 14*/
  20.     0x71,       /*'F', 15*/
  21.     0x54,       /*'N', 16*/
  22.     0x5C,       /*'O', 17*/
  23.     0x73,       /*'P', 18*/
  24.     0x50,       /*'R', 19*/
  25.     0x40,       /*'-', 20*/
  26.     0x00,       /*' ', 21*/
  27.     0x80,       /*'.', 22*/
  28. };
  29. u8 T_NUM[8] =
  30. {
  31.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  32. };
  33. /*
  34. ----------行------------
  35.         #define ROW1        P06                //定义端口
  36.         #define ROW2        P07
  37. ----------列-------------
  38.         #define COL1        P00
  39.         #define COL2        P01
  40.         #define COL3        P02                                                
  41.         #define COL4        P03
  42. */
  43. u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  44. //矩阵键盘扫描
  45. void Task_1( void )
  46. {
  47.         //        ①第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
  48.          COL1 = 0;
  49.         COL2 = 0;
  50.         COL3 = 0;
  51.         COL4 = 0;
  52.         ROW1 = 1;
  53.         ROW2 = 1;
  54.         
  55.         if((ROW1 == 0) || (ROW2 == 0))                        //"||"或的符号,只要满足其中之一的条件(行按键按下)
  56.         {
  57.                 if((ROW1 == 0) && (ROW2 == 0))                //如果两行都有按键按下,不处理
  58.                 {
  59.                         key_num = 0xff;
  60.                 }
  61.                 else if ( ((ROW1 == 1)&&(ROW2 == 0)) || ((ROW1 == 0)&&(ROW2 == 1)) )        //如果有按键按下,而且只有一颗
  62.                 {
  63.                         if( ROW1 == 0 )                                        //判断哪一行,输出行开始的序号
  64.                                 key_num = 0;
  65.                         else if(ROW2 == 0)
  66.                                 key_num = 4;
  67.                         
  68.                         //②第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
  69.                         COL1 = 1;
  70.                         COL2 = 1;
  71.                         COL3 = 1;
  72.                         COL4 = 1;
  73.                         ROW1 = 0;
  74.                         ROW2 = 0;
  75.                         
  76.                         //判断哪一列,叠加按键的序号
  77.                         if(COL1 == 0)                key_num += 0;
  78.                         else if(COL2 == 0)        key_num += 1;
  79.                         else if(COL3 == 0)        key_num += 2;
  80.                         else if(COL4 == 0)        key_num += 3;               
  81.                 }
  82.         }
  83.         else
  84.         {
  85.                 key_num = 0xff;                // 无按键按下
  86.         }
  87.                
  88.                                                                
  89.         //        ③第三步:行列组合一下就可以判断出是哪个按键按下了。
  90.         COL1 = 1;
  91.         COL2 = 1;
  92.         COL3 = 1;
  93.         COL4 = 1;
  94.         ROW1 = 1;
  95.         ROW2 = 1;
  96. }
  97. void LED_Control_Task(void)
  98. {        
  99.             // 根据工作状态控制LED0
  100.     if(is_working)
  101.         LED0 = 0;  // 低电平点亮LED0
  102.     else
  103.         LED0 = 1;  // 高电平熄灭LED0
  104. }
  105. u8 Key_vol = 0;
  106. u8 is_working = 0;      // 工作状态:0-停止,1-工作
  107. u8 key_press_flag = 0;  // 按键消抖标志(防止重复触发)
  108. void KEY_Task(void)
  109. {
  110.          //static u8 key_press_flag = 0;  // 按键按下标志
  111.    
  112.     // 检测到按钮1按下且未处理过
  113.     if(key_num == 1 && key_press_flag == 0)
  114.     {
  115.         key_press_flag = 1;         // 标记为已处理
  116.         is_working = !is_working;   // 切换工作状态
  117.     }
  118.     // 按键释放后重置标志
  119.     else if(key_num == 0xff)
  120.     {
  121.         key_press_flag = 0;
  122.     }
  123.                
  124. }
  125. void Init_595(void)
  126. {
  127.         HC595_SER  = 0;
  128.         HC595_RCK  = 0;
  129.         HC595_SCK  = 0;
  130. }
  131. void Send_595( u8 dat )
  132. {
  133.         u8 i;
  134.         
  135.         for( i=0; i<8; i++ )
  136.         {
  137.                 dat <<= 1;                        //数值左移一位
  138.                 HC595_SER  = CY;        //数据写到引脚
  139.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  140.         HC595_SCK  = 0;
  141.         }
  142. }
  143. void Display_Seg( u8 HC595_1,u8 HC595_2)
  144. {
  145.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  146.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  147.         
  148.         HC595_RCK  = 1;                        //数据输出
  149.         HC595_RCK  = 0;
  150. }
  151. u8 Seg_no = 0;
  152. void SEG_Task(void)
  153. {
  154.             // 显示工作状态:1表示工作,0表示停止
  155.     u8 disp_num = is_working ? 1 : 0;
  156.    
  157.     switch(Seg_no)
  158.     {
  159.         case 0: Display_Seg(SEG_NUM[disp_num], ~T_NUM[0]); break;
  160.         case 1: Display_Seg(SEG_NUM[21], ~T_NUM[1]); break;  // 空格
  161.         // 其他位不显示
  162.         case 2: Display_Seg(SEG_NUM[21], ~T_NUM[2]); break;
  163.         case 3: Display_Seg(SEG_NUM[21], ~T_NUM[3]); break;
  164.         case 4: Display_Seg(SEG_NUM[21], ~T_NUM[4]); break;
  165.         case 5: Display_Seg(SEG_NUM[21], ~T_NUM[5]); break;
  166.         case 6: Display_Seg(SEG_NUM[21], ~T_NUM[6]); break;
  167.         case 7: Display_Seg(SEG_NUM[21], ~T_NUM[7]); break;
  168.     }
  169.     Seg_no = (Seg_no + 1) % 8;
  170. }
  171. //外部中断INT1 函数
  172. void INT1_Init(void)
  173. {
  174.         IT1 = 1;                //下降沿中断
  175.         EX1 = 1;                //下降中断允许
  176.         EA = 1;                        //打开总中断
  177.         P33 = 1;
  178. }
  179. //中断服务函数,一旦发生了中断就先执行“中断服务函数”
  180. void INT1_Isr(void) interrupt 2
  181. {
  182.     // 测试:按下P33时,数码管0位显示0(模拟切断电源)
  183.     is_working = 0;  // 停止工作状态
  184.     // 清除中断标志(部分单片机需手动清除,防止重复触发)
  185.     IE1 = 0;        // 显式清除INT1中断标志
  186. }
复制代码

demo1.rar (185.12 KB, 下载次数: 0)

回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 昨天 20:08 | 显示全部楼层
14.IO中断(所有普通IO都支持“外部中断”)

屏幕截图 2025-08-20 170442.png
io.c
  1. //IO口中断函数
  2. //数码管显示0:执行while函数  1:执行P3_IO中断   2:执行P4_IO中断
  3. void P3_IO_Init(void)
  4. {
  5.         P3IM0 = 0x00;                //选择合适的中断模式--下降沿中断
  6.         P3IM1 = 0xff;
  7.        
  8.         P3INTE = 0x08;                //使能端口中断功能
  9. }
  10. void P3_IO_ISR(void) interrupt 40
  11. {
  12.         u8 intf;
  13.        
  14.         intf = P3INTF;
  15.        
  16.         if(intf)
  17.         {
  18.                 P3INTF = 0;
  19.                
  20.                 if(intf & 0x08)
  21.                 {
  22.                         passward[0] = 1;
  23.                         //P01 = !P01;
  24.                 }
  25.         }
  26. }
  27. void P4_IO_Init(void)
  28. {
  29.         P4IM0 = 0x00;                //选择合适的中断模式--低电平中断
  30.         P4IM1 = 0xff;
  31.        
  32.         P4INTE = 0x80;                //使能端口中断功能
  33.        
  34.         PINIPH = 0X00;
  35.         PINIPL = 0X10;
  36. }
  37. void P4_IO_ISR(void) interrupt 41
  38. {
  39.         u8 intf;
  40.        
  41.         intf = P4INTF;
  42.        
  43.         if(intf)
  44.         {
  45.                 P4INTF = 0;
  46.                
  47.                 if(intf & 0x80)
  48.                 {
  49.                         passward[0] = 2;
  50.                         //P01 = !P01;
  51.                 }
  52.         }
  53. }
复制代码
main.c文件部分代码
  1. main.c文件部分代码
  2. void main(void)
  3. {
  4.        
  5.         Sys_init();                                        //系统初始化
  6.         usb_init();                 //USB CDC 接口配置
  7.        
  8.         IE2 |= 0x80;                //使能USB中断
  9.         Timer0_Init();                                //定时器初始化
  10.         Init_595();
  11. //        INT1_Init();                                //外部中断int1初始化
  12.         P3_IO_Init();                                //IO中断初始化
  13.         P4_IO_Init();
  14.        
  15.         EA = 1;
  16.         P40 = 0;
  17. //        WDT_CONTR = 0X24;
  18.         while(1)
  19.         {
  20.                  if (bUsbOutReady)
  21.         {
  22. //            USB_SendData(UsbOutBuffer,OutNumber);   //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
  23.             usb_OUT_done();
  24.         }
  25.                 Task_Pro_Handler_Callback();                                //执行功能函数
  26.                
  27.                 passward[0] = 0;
  28. //                WDT_CONTR = 0X34;
  29.                
  30.                 /*延时三秒钟P00LED灯取反一次 */
  31. //                P00 = !P00;
  32. //                Delay3000ms();
  33.        
  34.         }
  35.        
  36. }
  37. config.c部分代码
  38. void Timer0_Init(void)                //1毫秒@24.000MHz                //定时器函数定义
  39. {
  40.         TM0PS = 0x00;                        //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )
  41.         AUXR &= 0x7F;                        //定时器时钟12T模式
  42.         TMOD &= 0xF0;                        //设置定时器模式
  43.         TL0 = 0x30;                                //设置定时初始值
  44.         TH0 = 0xF8;                                //设置定时初始值
  45.         TF0 = 0;                                //清除TF0标志
  46.         TR0 = 1;                                //定时器0开始计时
  47.         ET0 = 1;                                //使能定时器0中断
  48.        
  49.         IPH |= (1<<1);
  50.         IP  |= (1<<1);
  51. }
复制代码

demo1.rar (187.51 KB, 下载次数: 0)
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:107
  • 最近打卡:2025-08-23 08:40:09

2

主题

47

回帖

205

积分

中级会员

积分
205
发表于 昨天 22:07 | 显示全部楼层
14 IO中断(所有普通IO都支持“外部中断”) 课后小练  多路抢答器

屏幕截图 2025-08-23 201059.png

功能说明
1核心功能:
        上电后第一位数码管显示0(等待抢答)。
        矩阵键盘按键 1(第一行第一列)对应用户 1,按下后显示1并锁定。
        矩阵键盘按键 2(第一行第二列)对应用户 2,按下后显示2并锁定。
        矩阵键盘按键 3(第一行第三列)对应用户 3,按下后显示3并锁定。
        锁定后不再响应其他按键,确保优先抢答的公平性。
2复位功能:
        按矩阵键盘按键 4(第一行第四列)可复位,数码管恢复显示0,解除锁定,允许新一轮抢答。v

io.c
  1. #include "io.h"
  2. u8 SEG_NUM[] =
  3. {
  4.     0x3F,       /*'0', 0*/
  5.     0x06,       /*'1', 1*/
  6.     0x5B,       /*'2', 2*/
  7.     0x4F,       /*'3', 3*/
  8.     0x66,       /*'4', 4*/
  9.     0x6D,       /*'5', 5*/
  10.     0x7D,       /*'6', 6*/
  11.     0x07,       /*'7', 7*/
  12.     0x7F,       /*'8', 8*/
  13.     0x6F,       /*'9', 9*/
  14.     0x77,       /*'A', 10*/
  15.     0x7C,       /*'B', 11*/
  16.     0x39,       /*'C', 12*/
  17.     0x5E,       /*'D', 13*/
  18.     0x79,       /*'E', 14*/
  19.     0x71,       /*'F', 15*/
  20.     0x54,       /*'N', 16*/
  21.     0x5C,       /*'O', 17*/
  22.     0x73,       /*'P', 18*/
  23.     0x50,       /*'R', 19*/
  24.     0x40,       /*'-', 20*/
  25.     0x00,       /*' ', 21*/
  26.     0x80,       /*'.', 22*/
  27. };
  28. u8 T_NUM[8] =
  29. {
  30.         0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  31. };
  32. /*
  33. ----------行------------
  34.         #define ROW1        P06                //定义端口
  35.         #define ROW2        P07
  36. ----------列-------------
  37.         #define COL1        P00
  38.         #define COL2        P01
  39.         #define COL3        P02                                               
  40.         #define COL4        P03
  41. */
  42. u8 key_num = 0xff;                //key_num =0 给按键传递一个键值
  43. // 抢答核心变量
  44. u8 answerFlag = 0;                // 抢答结果(0-未抢答,1-3对应用户1-3)
  45. bit isAnswered = 0;                // 抢答锁定标志(0-未锁定,1-已锁定)
  46. //显示缓存
  47. u8 passward[8] = { 21,21,21,21,21,21,21,21};
  48. u8 Seg_no = 0;
  49. // 延时函数(消抖用)
  50. void delay_ms(u16 ms)
  51. {
  52.     u16 i, j;
  53.     for(i = 0; i < ms; i++)
  54.         for(j = 0; j < 120; j++);
  55. }
  56. void Init_595(void)
  57. {
  58.         HC595_SER  = 0;
  59.         HC595_RCK  = 0;
  60.         HC595_SCK  = 0;
  61. }
  62. void Send_595( u8 dat )
  63. {
  64.         u8 i;
  65.        
  66.         for( i=0; i<8; i++ )
  67.         {
  68.                 dat <<= 1;                        //数值左移一位
  69.                 HC595_SER  = CY;        //数据写到引脚
  70.             HC595_SCK  = 1;                //输出上升沿的时钟信号
  71.         HC595_SCK  = 0;
  72.         }
  73. }
  74. void Display_Seg( u8 HC595_1,u8 HC595_2)
  75. {
  76.         Send_595(HC595_1);                //数码管段码输出        高电平点亮
  77.         Send_595(HC595_2);                //数码管位码输出        低电平点亮
  78.        
  79.         HC595_RCK  = 1;                        //数据输出
  80.         HC595_RCK  = 0;
  81. }
  82. void SEG_Task(void)
  83. {
  84.                 u8 num = 0;
  85.         switch(Seg_no){
  86.                 case 0: Display_Seg( SEG_NUM[passward[0]], ~T_NUM[0] );                   break;
  87.                 case 1: Display_Seg( SEG_NUM[passward[1]], ~T_NUM[1] );         break;
  88.                 case 2: Display_Seg( SEG_NUM[passward[2]], ~T_NUM[2] );                   break;
  89.                 case 3: Display_Seg( SEG_NUM[passward[3]], ~T_NUM[3] );                   break;
  90.                 case 4: Display_Seg( SEG_NUM[passward[4]], ~T_NUM[4] );                   break;
  91.                 case 5: Display_Seg( SEG_NUM[passward[5]], ~T_NUM[5] );                   break;
  92.                 case 6: Display_Seg( SEG_NUM[passward[6]], ~T_NUM[6] );         break;
  93.                 case 7: Display_Seg( SEG_NUM[passward[7]], ~T_NUM[7] );         break;
  94.         }
  95.         Seg_no ++;
  96.         if( Seg_no>7 )
  97.                 Seg_no=0;               
  98. }
  99. // 矩阵键盘扫描任务(核心修改:识别1、2、3键并处理抢答)
  100. void Task_1(void) {
  101.     static u8 key_stable = 0;  // 按键稳定计数(消抖)
  102.     // 第一步:扫描行
  103.     COL1 = 0; COL2 = 0; COL3 = 0; COL4 = 0;  // 列线拉低
  104.     ROW1 = 1; ROW2 = 1;                      // 行线拉高
  105.     delay_ms(1);  // 稳定电平
  106.     // 检测是否有按键按下
  107.     if((ROW1 == 0) || (ROW2 == 0)) {
  108.         key_stable++;
  109.         if(key_stable >= 3) {  // 连续3次检测到按键(消抖)
  110.             // 第二步:确定行
  111.             if(ROW1 == 0) {  // 第一行(对应按键1、2、3、4)
  112.                 // 第三步:扫描列确定具体按键
  113.                 ROW1 = 0; ROW2 = 1;  // 锁定第一行
  114.                 COL1 = 1; COL2 = 1; COL3 = 1; COL4 = 1;  // 列线拉高
  115.                 delay_ms(1);
  116.                 if(COL1 == 0) key_num = 0;  // 按键1(第一行第一列)
  117.                 else if(COL2 == 0) key_num = 1;  // 按键2(第一行第二列)
  118.                 else if(COL3 == 0) key_num = 2;  // 按键3(第一行第三列)
  119.                 else if(COL4 == 0) key_num = 3;  // 按键4(作为复位键)
  120.             }
  121.             // 处理抢答逻辑
  122.             if(!isAnswered) {  // 未锁定时响应
  123.                 switch(key_num) {
  124.                     case 0:  // 用户1(按键1)
  125.                         answerFlag = 1;
  126.                         passward[0] = 1;  // 显示1
  127.                         isAnswered = 1;  // 锁定
  128.                         break;
  129.                     case 1:  // 用户2(按键2)
  130.                         answerFlag = 2;
  131.                         passward[0] = 2;  // 显示2
  132.                         isAnswered = 1;  // 锁定
  133.                         break;
  134.                     case 2:  // 用户3(按键3)
  135.                         answerFlag = 3;
  136.                         passward[0] = 3;  // 显示3
  137.                         isAnswered = 1;  // 锁定
  138.                         break;
  139.                 }
  140.             }
  141.             // 复位功能(按键4作为复位键)
  142.             if(key_num == 3) {
  143.                 delay_ms(10);
  144.                 if(COL4 == 0) {
  145.                     answerFlag = 0;
  146.                     passward[0] = 0;  // 恢复显示0
  147.                     isAnswered = 0;  // 解除锁定
  148.                 }
  149.             }
  150.         }
  151.     } else {
  152.         key_num = 0xff;  // 无按键
  153.         key_stable = 0;  // 重置稳定计数
  154.     }
  155.     // 恢复引脚状态
  156.     COL1 = 0; COL2 = 0; COL3 = 0; COL4 = 0;
  157.     ROW1 = 1; ROW2 = 1;
  158. }
  159. // 初始化显示(上电显示0)
  160. void Display_Init(void) {
  161.     Init_595();
  162.     passward[0] = 0;  // 初始显示0
  163. }
  164. // 注释不需要的IO中断函数(改用矩阵键盘扫描)
  165. void P3_IO_Init(void) {
  166.     // 禁用原P3中断,避免冲突
  167.     P3INTE = 0x00;
  168. }
  169. void P4_IO_Init(void) {
  170.     // 禁用原P4中断,避免冲突
  171.     P4INTE = 0x00;
  172. }
复制代码

demo1.rar (184.29 KB, 下载次数: 0)
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-8-24 04:07 , Processed in 1.748875 second(s), 90 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表