amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 2652|回复: 68

初学单片机-单键密码锁制作日志-遇到问题

[复制链接]
发表于 2014-4-11 09:56:05 | 显示全部楼层 |阅读模式
[2]2014年4月11日早上遇到的问题--已经解决 [#]
本帖最后由 kdgj8899 于 2014-4-11 11:29 编辑

家里人有时会忘记带大门钥匙,甚至摩托车钥匙忘记拔下来,我就想搞个密码锁上去,不用钥匙了,这是大门电控板,用的是两个继电器控制卷帘门电机的正反转,板上三个按钮在一起的分别是开门、停止、关门,另外一边的那个按钮是添加遥控器用的。



我打算用单片机直接控制原板上的按钮,只要输出1秒低电平就可以了。之前在淘宝上找到一个卖成品的,可以设置成自锁和互锁,拍好后卖家说没芯片了,用汇编写的,我想请它重新帮我写下,他说太麻烦了,原来用的芯片一直没货。另一款是专门用在摩托车上的,是成品,用的是stc15F104E控制,就是这种:



我嫌它输入密码太慢,得按着开关数LED灯闪的次数,还有就是放一段时间后密码竟然输入不对了,可能是芯片不稳定。于是就萌发了我制作这么一个单片机来控制大门中控锁和摩托车锁的念头。人机交互打算用一个带灯的开关,通过灯的状态来反馈单按键的输入状态。为什么选单按键,因为好安装,不容易被破坏,容易防水,可以做的掩蔽。在多种单片机中,我选了AVR,原因之一是我的高频烙铁用的就是M8控制,然后有8脚的tiny13A芯片可选(为了能集成到摩托车点火器中)。因为怕学单片机,就想请人把代码写好了写到芯片里发给我,工时费报价也不算贵,可后来我想了下,这程序不是写来了就能用上的,万一还要修改呢,这改来改去费用可不低啊。想想算了,反正10多年前就想自己学单片机,不如这次就圆了这个梦吧。于是前久从邮购部购买了马潮avr学习版,从当当网买来第二版书,因为看过电子版的,没有讲C语言语法,发现有点不适合我这种初学单片机的人,于是又购《入把手教你学单片机C程序设计(第2版)》和《手把手教你学AVR单片机C程序设计》,相互结合着学吧。初学问题真是多,这是发问贴:为什么这个状态机识别的if语句放到switch里就出错-出新问题
http://www.amobbs.com/thread-5575902-1-1.html
(出处: amoBBS 阿莫电子论坛)
可我发现这初学之路问题太多了,还有如直接开个关于这个单键密码锁的帖子,以日志的形式来记录制作过程,然后把碰到的问题写在这里,请大家帮忙解答!

学习平台:马潮avr学习板,软件是CVAVR+AVRstudio


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-11 10:33:12 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-11 11:27 编辑

2014年4月11日遇到的问题,把void main(void)之前的一个空行删除了,仿真时默认的小箭头位置变了,这是正常时的截图



这是空行删除掉的,小箭头往下移了,如果是在之前添加代码的话,小箭头就上移了:



这到底是什么原因导致的?发现这个问题是因为我要往read_key_n()添加代码,导致仿真时不正确,然后我一步步还原就发现是添加删除oid main(void)之前的行,就会出这个问题。

这是出问题的工程压缩包

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-11 11:06:03 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-11 12:51 编辑

我新建了个工程,发现原来case后面的:被我识写成; 这样都居然能编译通过,测试后没有之前的问题了,不过如果调出之前的工程来,就算把:改回来也不行,还是没有找到问题的原因




我把相关变量定义移到状态机里,就正常了。难道是变量的定义出问题?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-11 20:58:04 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-11 21:41 编辑

今天下午还遇到一个问题,长按已经可以关门了,但是在识别第一位密码时,没有在不动按键2秒后识别密码,而是2秒内就动作了。后来查出是2秒定时器清零,我清除的只是2秒到的标志,真正的2秒计时清除没有打上,就是下图圈中的代码:



到现在,我的代码已经可以达到短按停止后,记录第一位密码的程度了,看上图,我短按了5次,在watch窗口里已经可以看到mima[0]=5了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-12 02:39:41 | 显示全部楼层
新问题来了,第二位密码不能记录:
  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[2],ysmima[2]={1,2},mimajishu,shucuo,i,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 2)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.7            // 按键输入口
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3

  44. unsigned char read_key_n(void)
  45. {
  46.     static unsigned char key_state = 0, key_time = 0;
  47.     unsigned char key_press, key_return = 0;
  48.    
  49.     key_press = key_input;                // 读按键I/O电平
  50.     switch (key_state)
  51.     {
  52.         case key_state_0:                // 按键初始态
  53.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  54.             break;
  55.         case key_state_1:                // 按键确认态
  56.             if (!key_press)
  57.             {
  58.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  59.                 key_time = 0;                // 清另按键时间计数器
  60.             }
  61.             else
  62.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  63.             break;
  64.         case key_state_2:
  65.             if (key_press)
  66.             {
  67.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  68.                 key_return = 1;            // 输出"1"
  69.                 yimiao_counter = 0;
  70.                 yimiao_ok = 0;
  71.                 if (++mimajishu >9)
  72.                  {
  73.                     mimajishu = 0;  
  74.                  }              
  75.             }
  76.             else if (++key_time >= 200)        // 按键时间计数
  77.             {
  78.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  79.                 key_time = 0;                // 清按键计数器
  80.                 key_return = 2;            // 输出"2"
  81.                 cabz = 1;      //长按标志
  82.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  83.                 yimiao_ok = 1;  //计时1秒后关门断开
  84.             }
  85.             break;
  86.         case key_state_3:
  87.             if (key_press)
  88.             {
  89.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  90.             }
  91.             break;
  92.      
  93. }   
  94.     return key_return;
  95. }  

  96. void main(void)
  97. {
  98.     PORTA = 0x00;                    // 显示控制I/O端口初始化
  99.     DDRA = 0xFF;
  100.     PORTB = 0xFF;
  101.     DDRB = 0xFF;
  102.     PORTD = 0xFF;
  103.     DDRD = 0x00;                    // PD7为输入方式
  104.     // T/C0 初始化
  105.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  106.     TCNT0 = 0x00;
  107.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  108.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  109.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  110.     #asm("sei")            // 开放全局中断  
  111.             
  112.     while (1)
  113.     {         
  114.         switch (status)
  115.        {
  116.              case 0:
  117.              if (key_stime_ok)                                // 10ms到,键处理
  118.             {  
  119.                 key_stime_ok = 0;
  120.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  121.                  {
  122.                      status = 1;
  123.                  }
  124.             }
  125.                 break;
  126.               case 1:
  127.               if (key_stime_ok)                                // 10ms到,键处理
  128.               {
  129.                    key_stime_ok = 0;
  130.                    read_key_n();
  131.                    if (yimiao_ok)
  132.                    {
  133.                      mima[0] = mimajishu;  //记录第一位密码
  134.                      mimajishu =0;
  135.                      PORTB ^= 1<<1;   //PORTB = 0xFD; //执行开门,PB1拉低
  136.                      status = 2;
  137.                    }
  138.               }
  139.                    break;
  140.               case 2:
  141.                   if (key_stime_ok)                                // 10ms到,键处理
  142.               {
  143.                    key_stime_ok = 0;
  144.                    read_key_n();
  145.                    if (yimiao_ok)
  146.                    {
  147.                      mima[1] = mimajishu;        //记录第二位密码
  148.                      mimajishu =0;
  149.                      for(i=0;i<2;i++)           //密码对比识别
  150.                     {
  151.                        if (mima[i]==ysmima[i])
  152.                        {
  153.                         cnt++;
  154.                        }
  155.                     }
  156.                     if (cnt==2){cnt=0;PORTB ^= 1<<2;status = 0;shucuo=0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  157.                     else  {status = 3;++shucuo;}
  158.                    }
  159.               }
  160.                    break;
  161.                case 3:
  162.                    if(shucuo==3)
  163.                    {
  164.                     PORTB ^= 1<<3;
  165.                     status = 0;
  166.                    }
  167.                   else status = 0;
  168.                   break;            
  169.          }  
  170.     }
  171. }
复制代码



第一位密码1已经识别,第二位没录入。全速仿真后我发现先按1和2,再按2和1就可以认为是密码输入对了,看来又出错了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-12 04:04:03 | 显示全部楼层
找到原因了,原来是很多应该清零的地方没有清零

  1.   while (1)
  2.     {         
  3.         switch (status)
  4.        {
  5.              case 0:
  6.              if (key_stime_ok)                                // 10ms到,键处理
  7.             {  
  8.                 key_stime_ok = 0;
  9.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  10.                  {
  11.                      status = 1;
  12.                  }
  13.             }
  14.                 break;
  15.               case 1:
  16.               if (key_stime_ok)                                // 10ms到,键处理
  17.               {
  18.                    key_stime_ok = 0;
  19.                    read_key_n();
  20.                    if (yimiao_ok)
  21.                    {
  22.                      mima[0] = mimajishu;  //记录第一位密码
  23.                      mimajishu =0;
  24.                      PORTB ^= 1<<1;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  25.                      status = 2;
  26.                      yimiao_counter = 0;
  27.                      yimiao_ok = 0;
  28.                    }
  29.               }
  30.                    break;
  31.               case 2:
  32.                   if (key_stime_ok)                                // 10ms到,键处理
  33.               {
  34.                    key_stime_ok = 0;
  35.                    read_key_n();
  36.                    if (yimiao_ok)
  37.                    {
  38.                      mima[1] = mimajishu;        //记录第二位密码
  39.                      mimajishu =0;
  40.                      for(i=0;i<2;i++)           //密码对比识别
  41.                     {
  42.                        if (mima[i]==ysmima[i])
  43.                        {
  44.                         cnt++;
  45.                        }
  46.                     }
  47.                     if (cnt==2){cnt=0;PORTB ^= 1<<2;status = 0;shucuo=0;mima[1] = 0; mima[0] = 0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  48.                     else  {status = 3;++shucuo;cnt=0;mima[1] = 0; mima[0] = 0;}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  49.                    }
  50.               }
  51.                    break;
  52.                case 3:
  53.                    if(shucuo==3)      //输错3次就执行某行动
  54.                    {
  55.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  56.                     PORTB ^= 1<<3;  //某行动
  57.                     status = 0;
  58.                    }
  59.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  60.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  61.          }  
  62.     }
  63. }
复制代码


现在输入2位密码,先按1,隔1秒后再输入2就开门了。如果按第一位密码后,超过2秒不按,那就默认第位密码是0了,之后立即判断这两位密码是否正确,不正确就返回等待重新输入,输入3次密码不对就动作了。如果是多位密码,这个密码之间的间隔不太好掌握,打算加个灯来反馈。
 楼主| 发表于 2014-4-12 11:55:10 | 显示全部楼层
现在加入看门狗

  1. void main(void)
  2. {
  3.     PORTA = 0x00;                    // 显示控制I/O端口初始化
  4.     DDRA = 0xFF;
  5.     PORTB = 0xFF;
  6.     DDRB = 0xFF;
  7.     PORTD = 0xFF;
  8.     DDRD = 0x00;                    // PD7为输入方式
  9.     // T/C0 初始化
  10.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  11.     TCNT0 = 0x00;
  12.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  13.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  14.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  15.      
  16.     #asm("cli")
  17.     #asm("WDR")   
  18.     WDTCR=0x08;        //看门狗约为4s
  19.     //WDTCR=0x28;
  20.     #asm("sei")            // 开放全局中断
  21.    
  22.             
  23.     while (1)
  24.     {         
  25.         switch (status)
  26.        {
  27.              case 0:
  28.              if (key_stime_ok)                                // 10ms到,键处理
  29.             {  
  30.                 key_stime_ok = 0;
  31.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  32.                  {
  33.                      status = 1;
  34.                  }
  35.             }
  36.                 break;
  37.               case 1:
  38.               if (key_stime_ok)                                // 10ms到,键处理
  39.               {
  40.                    key_stime_ok = 0;
  41.                    read_key_n();
  42.                    if (yimiao_ok)
  43.                    {
  44.                      mima[0] = mimajishu;  //记录第一位密码
  45.                      mimajishu =0;
  46.                      PORTB ^= 1<<1;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  47.                      status = 2;
  48.                      yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  49.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  50.                      ermiao_counter = 0;
  51.                      ermiao_ok = 0;   
  52.                    }
  53.               }
  54.                    break;
  55.               case 2:
  56.                   if (key_stime_ok)                                // 10ms到,键处理
  57.               {
  58.                    key_stime_ok = 0;
  59.                    read_key_n();
  60.                    if (ermiao_ok)
  61.                    {
  62.                      mima[1] = mimajishu;        //记录第二位密码
  63.                      mimajishu =0;
  64.                      for(i=0;i<2;i++)           //密码对比识别
  65.                     {
  66.                        if (mima[i]==ysmima[i])
  67.                        {
  68.                         cnt++;
  69.                        }
  70.                     }
  71.                     if (cnt==2){cnt=0;PORTB ^= 1<<2;status = 0;shucuo=0;mima[1] = 0; mima[0] = 0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  72.                     else  {status = 3;++shucuo;cnt=0;mima[1] = 0; mima[0] = 0;}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  73.                    }
  74.               }
  75.                    break;
  76.                case 3:
  77.                    if(shucuo==3)      //输错3次就执行某行动
  78.                    {
  79.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  80.                     PORTB ^= 1<<3;  //某行动
  81.                     status = 0;
  82.                    }
  83.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  84.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  85.          }
  86.          #asm("WDR")   
  87.     }
  88. }
复制代码
 楼主| 发表于 2014-4-12 11:56:13 | 显示全部楼层
怎么今天1楼就不能修改了?
 楼主| 发表于 2014-4-14 22:55:27 | 显示全部楼层
加入看门狗和掉电模式中断唤醒,INT0兼密码输入:

  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[2],ysmima[2]={5,4},mimajishu,shucuo,i,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 2)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3

  44. unsigned char read_key_n(void)
  45. {
  46.     static unsigned char key_state = 0, key_time = 0;
  47.     unsigned char key_press, key_return = 0;
  48.    
  49.     key_press = key_input;                // 读按键I/O电平
  50.     switch (key_state)
  51.     {
  52.         case key_state_0:                // 按键初始态
  53.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  54.             break;
  55.         case key_state_1:                // 按键确认态
  56.             if (!key_press)
  57.             {
  58.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  59.                 key_time = 0;                // 清另按键时间计数器
  60.             }
  61.             else
  62.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  63.             break;
  64.         case key_state_2:
  65.             if (key_press)
  66.             {
  67.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  68.                 key_return = 1;            // 输出"1"
  69.                 yimiao_counter = 0;
  70.                 yimiao_ok = 0;
  71.                 ermiao_counter = 0;
  72.                      ermiao_ok = 0;
  73.                      simiao_counter = 0;
  74.                      simiao_ok = 0;
  75.                 if (++mimajishu >9)
  76.                  {
  77.                     mimajishu = 0;  
  78.                  }              
  79.             }
  80.             else if (++key_time >= 200)        // 按键时间计数
  81.             {
  82.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  83.                 key_time = 0;                // 清按键计数器
  84.                 key_return = 2;            // 输出"2"
  85.                 cabz = 1;      //长按标志
  86.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  87.                 yimiao_ok = 1;  //计时1秒后关门断开
  88.             }  
  89.             yimiao_counter = 0;
  90.                 yimiao_ok = 0;
  91.                 ermiao_counter = 0;
  92.                      ermiao_ok = 0;
  93.                      simiao_counter = 0;
  94.                      simiao_ok = 0;
  95.             break;
  96.         case key_state_3:
  97.             if (key_press)
  98.             {
  99.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  100.             }   
  101.             yimiao_counter = 0;
  102.                 yimiao_ok = 0;
  103.                 ermiao_counter = 0;
  104.                      ermiao_ok = 0;
  105.                      simiao_counter = 0;
  106.                      simiao_ok = 0;
  107.             break;
  108.      
  109. }   
  110.     return key_return;
  111. }  

  112. void main(void)
  113. {
  114.     PORTA = 0x00;                    // 显示控制I/O端口初始化
  115.     DDRA = 0xFF;
  116.     PORTB = 0xFF;
  117.     DDRB = 0xFF;
  118.     PORTD = 0xFF;
  119.     DDRD = 0x00;                    // PD7为输入方式
  120.     MCUCR = 0x60; // 睡眠使能,掉电模式
  121.       
  122.     // T/C0 初始化
  123.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  124.     TCNT0 = 0x00;
  125.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  126.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  127.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  128.      
  129.     #asm("cli")
  130.     #asm("WDR")   
  131.    WDTCR=0x08;        //看门狗约为4s
  132.    WDTCR=0x28;
  133.     #asm("sei")            // 开放全局中断
  134.    
  135.             
  136.     while (1)
  137.     {         
  138.         switch (status)
  139.        {
  140.              case 0:
  141.              if (key_stime_ok)                                // 10ms到,键处理
  142.             {  
  143.                 key_stime_ok = 0;
  144.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  145.                  {
  146.                      status = 1;
  147.                  }
  148.             }
  149.                 break;
  150.               case 1:
  151.               if (key_stime_ok)                                // 10ms到,键处理
  152.               {
  153.                    key_stime_ok = 0;
  154.                    read_key_n();
  155.                    if (yimiao_ok)
  156.                    {
  157.                      mima[0] = mimajishu;  //记录第一位密码
  158.                      mimajishu =0;
  159.                      PORTB ^= 1<<1;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  160.                      status = 2;
  161.                      yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  162.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  163.                      ermiao_counter = 0;
  164.                      ermiao_ok = 0;   
  165.                    }
  166.               }
  167.                    break;
  168.               case 2:
  169.                   if (key_stime_ok)                                // 10ms到,键处理
  170.               {
  171.                    key_stime_ok = 0;
  172.                    read_key_n();
  173.                    if (ermiao_ok)
  174.                    {
  175.                      mima[1] = mimajishu;        //记录第二位密码
  176.                      mimajishu =0;
  177.                      yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  178.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  179.                      ermiao_counter = 0;
  180.                      ermiao_ok = 0;
  181.                      simiao_counter = 0;
  182.                      simiao_ok = 0;
  183.                      for(i=0;i<2;i++)           //密码对比识别
  184.                     {
  185.                        if (mima[i]==ysmima[i])
  186.                        {
  187.                         cnt++;
  188.                        }
  189.                     }
  190.                     if (cnt==2){cnt=0;PORTB ^= 1<<2;status = 0;shucuo=0;mima[1] = 0; mima[0] = 0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  191.                     else  {status = 3;++shucuo;cnt=0;mima[1] = 0; mima[0] = 0;}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  192.                    }
  193.               }
  194.                    break;
  195.                case 3:
  196.                    if(shucuo==3)      //输错3次就执行某行动
  197.                    {
  198.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  199.                     PORTB ^= 1<<3;  //某行动
  200.                     status = 0;
  201.                    }
  202.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  203.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  204.          }   
  205.          if (simiao_ok)         //4秒无动作后休眠
  206.          {
  207.           simiao_counter = 0;
  208.            simiao_ok = 0;
  209.           TIMSK = 0x00;   //关T/C0比较匹配中断
  210.           PORTB ^= 1<<6;       //休眠监测
  211.            WDTCR=0x18;        //关看门狗
  212.            WDTCR=0x00;
  213.            //PORTB = 0xFF;
  214.            GICR = 0x40;   //使能INT0中断  
  215.           #asm("sleep")
  216.           PORTB ^= 1<<5;     //唤醒后监测
  217.          }
  218.         #asm("WDR")   
  219.     }
  220. }

  221. interrupt[EXT_INT0]void ext_int0_isr(void)
  222.   {
  223.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  224.    simiao_counter=0;
  225.    PORTB ^= 1<<7;     //中断唤醒监测
  226.    GICR = 0x00;   //禁用INT0中断
  227.     WDTCR=0x08;        //开看门狗约为4s
  228.     WDTCR=0x28;
  229.   }
复制代码



下一步打算用两个IO口来接LED灯来显示兼密码输入和中断唤醒。
 楼主| 发表于 2014-4-14 22:56:38 | 显示全部楼层
以后再加入密码设置的话,可能TINY13A怕是装不下了。
发表于 2014-4-15 06:50:49 | 显示全部楼层
kdgj8899 发表于 2014-4-14 22:56
以后再加入密码设置的话,可能TINY13A怕是装不下了。

http://www.amobbs.com/forum.php? ... 0174&highlight=
哈哈,楼主还在研究这个啊?按我说的思路做?
 楼主| 发表于 2014-4-15 12:25:58 | 显示全部楼层
zyw19987 发表于 2014-4-15 06:50
http://www.amobbs.com/forum.php?mod=viewthread&tid=5570174&highlight=
哈哈,楼主还在研究这个啊?按 ...

谢谢你,我现在改来改去的,根据需要吧
 楼主| 发表于 2014-4-15 12:26:43 | 显示全部楼层
现在的问题是休眠后怎么电流还有7毫安左右呢?

  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[2],ysmima[2]={5,4},mimajishu,shucuo,i,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 2)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3

  44. unsigned char read_key_n(void)
  45. {
  46.     static unsigned char key_state = 0, key_time = 0;
  47.     unsigned char key_press, key_return = 0;
  48.    
  49.     key_press = key_input;                // 读按键I/O电平
  50.     switch (key_state)
  51.     {
  52.         case key_state_0:                // 按键初始态
  53.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  54.             break;
  55.         case key_state_1:                // 按键确认态
  56.             if (!key_press)
  57.             {
  58.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  59.                 key_time = 0;                // 清另按键时间计数器
  60.             }
  61.             else
  62.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  63.             break;
  64.         case key_state_2:
  65.             if (key_press)
  66.             {
  67.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  68.                 key_return = 1;            // 输出"1"
  69.                 yimiao_counter = 0;
  70.                 yimiao_ok = 0;
  71.                 ermiao_counter = 0;
  72.                      ermiao_ok = 0;
  73.                      simiao_counter = 0;
  74.                      simiao_ok = 0;
  75.                 if (++mimajishu >9)
  76.                  {
  77.                     mimajishu = 0;  
  78.                  }              
  79.             }
  80.             else if (++key_time >= 200)        // 按键时间计数
  81.             {
  82.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  83.                 key_time = 0;                // 清按键计数器
  84.                 key_return = 2;            // 输出"2"
  85.                 cabz = 1;      //长按标志
  86.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  87.                 yimiao_ok = 1;  //计时1秒后关门断开
  88.             }  
  89.             yimiao_counter = 0;
  90.                 yimiao_ok = 0;
  91.                 ermiao_counter = 0;
  92.                      ermiao_ok = 0;
  93.                      simiao_counter = 0;
  94.                      simiao_ok = 0;
  95.             break;
  96.         case key_state_3:
  97.             if (key_press)
  98.             {
  99.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  100.             }   
  101.             yimiao_counter = 0;
  102.                 yimiao_ok = 0;
  103.                 ermiao_counter = 0;
  104.                      ermiao_ok = 0;
  105.                      simiao_counter = 0;
  106.                      simiao_ok = 0;
  107.             break;
  108.      
  109. }   
  110.     return key_return;
  111. }  

  112. void main(void)
  113. {
  114.     //PORTA = 0x00;                    // 显示控制I/O端口初始化
  115.    // DDRA = 0xFF;
  116.     PORTB = 0xFF;
  117.     DDRB = 0xFF;
  118.     PORTD = 0xFF;
  119.     DDRD = 0x00;                    // PD7为输入方式
  120.    
  121.     PORTC=0x00;
  122. DDRC=0x00;
  123. PORTA=0x00;
  124. DDRA=0x00;
  125. ADCSRA=0x00;
  126. TWCR=0x00;
  127. SPCR=0x00;
  128. ACSR=0x80;
  129. SFIOR=0x00;
  130. UCSRB=0x00;

  131.    
  132.       
  133.     // T/C0 初始化
  134.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  135.     TCNT0 = 0x00;
  136.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  137.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  138.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  139.      
  140.     #asm("cli")
  141.     #asm("WDR")   
  142.    WDTCR=0x08;        //看门狗约为4s
  143.    WDTCR=0x28;
  144.     #asm("sei")            // 开放全局中断
  145.    
  146.             
  147.     while (1)
  148.     {         
  149.         switch (status)
  150.        {
  151.              case 0:
  152.              if (key_stime_ok)                                // 10ms到,键处理
  153.             {  
  154.                 key_stime_ok = 0;
  155.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  156.                  {
  157.                      status = 1;
  158.                  }
  159.             }
  160.                 break;
  161.               case 1:
  162.               if (key_stime_ok)                                // 10ms到,键处理
  163.               {
  164.                    key_stime_ok = 0;
  165.                    read_key_n();
  166.                    if (yimiao_ok)
  167.                    {
  168.                      mima[0] = mimajishu;  //记录第一位密码
  169.                      mimajishu =0;
  170.                      PORTB ^= 1<<1;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  171.                      status = 2;
  172.                      yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  173.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  174.                      ermiao_counter = 0;
  175.                      ermiao_ok = 0;   
  176.                    }
  177.               }
  178.                    break;
  179.               case 2:
  180.                   if (key_stime_ok)                                // 10ms到,键处理
  181.               {
  182.                    key_stime_ok = 0;
  183.                    read_key_n();
  184.                    if (ermiao_ok)
  185.                    {
  186.                      mima[1] = mimajishu;        //记录第二位密码
  187.                      mimajishu =0;
  188.                      yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  189.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  190.                      ermiao_counter = 0;
  191.                      ermiao_ok = 0;
  192.                      simiao_counter = 0;
  193.                      simiao_ok = 0;
  194.                      for(i=0;i<2;i++)           //密码对比识别
  195.                     {
  196.                        if (mima[i]==ysmima[i])
  197.                        {
  198.                         cnt++;
  199.                        }
  200.                     }
  201.                     if (cnt==2){cnt=0;PORTB ^= 1<<2;status = 0;shucuo=0;mima[1] = 0; mima[0] = 0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  202.                     else  {status = 3;++shucuo;cnt=0;mima[1] = 0; mima[0] = 0;}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  203.                    }
  204.               }
  205.                    break;
  206.                case 3:
  207.                    if(shucuo==3)      //输错3次就执行某行动
  208.                    {
  209.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  210.                     PORTB ^= 1<<3;  //某行动
  211.                     status = 0;
  212.                    }
  213.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  214.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  215.          }   
  216.          if (simiao_ok)         //4秒无动作后休眠
  217.          {
  218.           simiao_counter = 0;
  219.            simiao_ok = 0;
  220.           TIMSK = 0x00;   //关T/C0比较匹配中断
  221.           PORTB ^= 1<<6;       //休眠监测
  222.            WDTCR=0x18;        //关看门狗
  223.            WDTCR=0x00;
  224.            PORTB = 0xFF;     //进入休眠前关所有灯
  225.            GICR = 0x40;   //使能INT0中断
  226.            MCUCR = 0x60; // 睡眠使能,掉电模式
  227.           #asm("sleep")      //休眠
  228.           PORTB ^= 1<<5;     //唤醒后监测
  229.          }
  230.         #asm("WDR")   //喂狗
  231.     }
  232. }

  233. interrupt[EXT_INT0]void ext_int0_isr(void)
  234.   {
  235.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  236.    simiao_counter=0;
  237.    PORTB ^= 1<<7;     //中断唤醒监测
  238.    GICR = 0x00;   //禁用INT0中断
  239.     WDTCR=0x08;        //开看门狗约为4s
  240.     WDTCR=0x28;
  241.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  242.   }
复制代码
 楼主| 发表于 2014-4-15 12:27:19 | 显示全部楼层
而且如果是插在板上电流更高
发表于 2014-4-16 06:07:41 | 显示全部楼层
kdgj8899 发表于 2014-4-15 12:27
而且如果是插在板上电流更高

只靠CPU休眠是达不到你的要求的
 楼主| 发表于 2014-4-16 07:57:51 | 显示全部楼层
zyw19987 发表于 2014-4-16 06:07
只靠CPU休眠是达不到你的要求的

是啊,这个摩托车电压有14.4V,电动车有60V,如何解决这个单片机的供电和掉电模式后的供电是个问题,我测试了一下其它报警器供电电流,没报警的时候都还有7毫安呢,遥控接收电路要耗电情有可言,可我这个不需要它。还有按键开关线太长会不会产生干扰不得而知。
 楼主| 发表于 2014-4-16 08:09:40 | 显示全部楼层
刚才测试了一下,JTAG打开,4M片内,5V供电,工作电流4.5毫安,掉电模式1.9毫安,看来这个JTAG还真费电
发表于 2014-4-16 09:59:13 | 显示全部楼层
好厉害!!!!!!!!!思路很好啊!!
 楼主| 发表于 2014-4-19 02:15:50 | 显示全部楼层
之前密码处理的方式,如果密码位数多的话,将导致代码容量高,于是我把密码输入部分作成一个函数来调用,有多少位密码都只调用同一个部分。可是代码容量还是达到了1020,如果加上密码设定部分,使用tiny13a可能无望了。
  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[5],ysmima[5]={5,4,3,2,1},mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 2)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3
  44. #define key_state_4    4

  45. unsigned char read_key_n(void)
  46. {
  47.     static unsigned char key_state = 0, key_time = 0;
  48.     unsigned char key_press, key_return = 0;
  49.    
  50.     key_press = key_input;                // 读按键I/O电平
  51.     switch (key_state)
  52.     {
  53.         case key_state_0:                // 按键初始态
  54.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  55.             break;
  56.         case key_state_1:                // 按键确认态
  57.             if (!key_press)
  58.             {
  59.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  60.                 key_time = 0;                // 清另按键时间计数器
  61.             }
  62.             else
  63.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  64.             break;
  65.         case key_state_2:
  66.             if (key_press)
  67.             {
  68.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  69.                 key_return = 1;            // 输出"1" ,表示单击
  70.                 yimiao_counter = 0;
  71.                 yimiao_ok = 0;
  72.                 ermiao_counter = 0;
  73.                      ermiao_ok = 0;
  74.                      simiao_counter = 0;
  75.                      simiao_ok = 0;
  76.                 if (++mimajishu >9)
  77.                  {
  78.                     mimajishu = 0;  
  79.                  }              
  80.             }
  81.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  82.             {
  83.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  84.                 key_time = 0;                // 清按键计数器  
  85.                 key_return = 2;            // 输出"2"
  86.                 cabz = 1;      //长按标志
  87.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  88.             }  
  89.               yimiao_counter = 0;
  90.                 yimiao_ok = 0;
  91.                 ermiao_counter = 0;
  92.                      ermiao_ok = 0;
  93.                      simiao_counter = 0;
  94.                      simiao_ok = 0;
  95.             break;
  96.         case key_state_3:
  97.              if (key_press)
  98.             {
  99.               
  100.               key_state = key_state_0; //按键已释放,转换到按键初始态
  101.             }   
  102.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  103.             {
  104.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  105.                 key_time = 0;                // 清按键计数器  
  106.                 key_return = 3;         //长按2秒,进入设置界面
  107.                 PORTB ^= 1<<1;
  108.                
  109.             }
  110.              break;
  111.         case key_state_4:
  112.             if (key_press)
  113.             {
  114.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  115.             }   
  116.             yimiao_counter = 0;
  117.                 yimiao_ok = 0;
  118.                 ermiao_counter = 0;
  119.                      ermiao_ok = 0;
  120.                      simiao_counter = 0;
  121.                      simiao_ok = 0;
  122.             break;
  123.      
  124. }   
  125.     return key_return;
  126. }  

  127.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  128.    {
  129.      static unsigned char i = 0,aj_state = 0;
  130.      unsigned char key_return = 0;
  131.      
  132.      if (key_stime_ok)                                // 10ms到,键处理
  133.      {
  134.         key_stime_ok = 0;
  135.         read_key_n();
  136.        switch (aj_state)
  137.        {
  138.         case 0:               
  139.             if (yimiao_ok)
  140.            {
  141.                if(i < 5)    //密码位数设置
  142.                {
  143.                  mima[i] = mimajishu;  //记录第一位密码
  144.                  mimajishu =0;
  145.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  146.                  aj_state = 1;
  147.                  yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  148.                  yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  149.                  ermiao_counter = 0;
  150.                  ermiao_ok = 0;
  151.                  i=++i;         
  152.                }   
  153.            }
  154.             break;
  155.         case 1:               
  156.             if (i == 5)  //密码识别位数确认
  157.             {   
  158.                 i=0;
  159.                 aj_state = 0;
  160.                 key_return = 1;
  161.             }
  162.             else
  163.                  aj_state = 0;   
  164.             break;
  165.        }
  166.         return key_return;
  167.      }
  168.    }

  169. void main(void)
  170. {
  171.     PORTA=0xFF;
  172.     DDRA=0x00;
  173.     PORTB = 0xFF;
  174.     DDRB = 0xFF;
  175.     PORTC=0xFF;
  176.     DDRC=0x00;
  177.     PORTD = 0xFF;
  178.     DDRD = 0x00;                    // PD7为输入方式
  179.    
  180. ADCSRA=0x00;
  181. TWCR=0x00;
  182. SPCR=0x00;
  183. ACSR=0x80;
  184. SFIOR=0x00;
  185. UCSRB=0x00;
  186. ACSR=(1<<ACD);

  187.     // T/C0 初始化
  188.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  189.     TCNT0 = 0x00;
  190.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  191.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  192.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  193.      
  194.     #asm("cli")
  195.     #asm("WDR")   
  196.    WDTCR=0x08;        //看门狗约为4s
  197.    WDTCR=0x28;
  198.     #asm("sei")            // 开放全局中断
  199.    
  200.             
  201.     while (1)
  202.     {         
  203.         switch (status)
  204.        {     
  205.              case 0:
  206.              if (key_stime_ok)                                // 10ms到,键处理
  207.             {  
  208.                 key_stime_ok = 0;
  209.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  210.                  {
  211.                      status = 1;
  212.                  }
  213.             }
  214.                 break;
  215.              case 1:
  216.                if (read_key_driver() ==1 )
  217.             {  
  218.                 yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  219.                      yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  220.                      ermiao_counter = 0;
  221.                      ermiao_ok = 0;
  222.                      simiao_counter = 0;
  223.                      simiao_ok = 0;
  224.                      for(j=0;j<5;j++)           //密码对比识别
  225.                     {
  226.                        if (mima[j]==ysmima[j])
  227.                        {
  228.                         cnt++;
  229.                        }
  230.                     }
  231.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;mima[1] = 0; mima[0] = 0;}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  232.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  233.             }
  234.                 break;
  235.              case 2:
  236.                    if(shucuo==3)      //输错3次就执行某行动
  237.                    {
  238.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  239.                     PORTB ^= 1<<4;  //某行动
  240.                     status = 0;
  241.                    }
  242.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  243.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  244.          }   
  245.          if (simiao_ok)         //4秒无动作后休眠
  246.          {
  247.           simiao_counter = 0;
  248.            simiao_ok = 0;
  249.           TIMSK = 0x00;   //关T/C0比较匹配中断
  250.           PORTB ^= 1<<5;       //休眠监测
  251.            //WDTCR=0x18;        //关看门狗
  252.            //WDTCR=0x00;
  253.             WDTCR=(1<<WDTOE)|(1<<WDE);
  254.             WDTCR=(0<<WDE);
  255.            PORTB = 0xFF;     //进入休眠前关所有灯
  256.            GICR = 0x40;   //使能INT0中断
  257.            MCUCR = 0x60; // 睡眠使能,掉电模式
  258.            
  259.            //MCUCSR=(1<<JTD);
  260.            //MCUCSR=(1<<JTD);
  261.            
  262.          
  263.            DDRB = 0x00;
  264.             
  265.         
  266.           #asm("sleep")      //休眠
  267.           PORTB ^= 1<<6;     //唤醒后监测
  268.          }
  269.         #asm("WDR")   //喂狗
  270.     }
  271. }

  272. interrupt[EXT_INT0]void ext_int0_isr(void)
  273.   {
  274.    PORTB = 0xFF;
  275.    DDRB = 0xFF;
  276.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  277.    simiao_counter=0;
  278.    PORTB ^= 1<<7;     //中断唤醒监测
  279.    GICR = 0x00;   //禁用INT0中断
  280.     WDTCR=0x08;        //开看门狗约为4s
  281.     WDTCR=0x28;
  282.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  283.   }
复制代码
 楼主| 发表于 2014-4-19 02:18:25 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-19 03:09 编辑

看来还要再优化代码,我现在看到一个清零的那堆代码,好像可以做成函数来调用,到时加入设置密码时又能省下一部分容量。现在压缩到990

  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[5],ysmima[5]={5,4,3,2,1},mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 2)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3
  44. #define key_state_4    4

  45. void qingling(void)   //清零
  46. {
  47.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  48.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  49.       ermiao_counter = 0;
  50.       ermiao_ok = 0;
  51.       simiao_counter = 0;
  52.       simiao_ok = 0;
  53.   }   

  54. unsigned char read_key_n(void)
  55.   {
  56.     static unsigned char key_state = 0, key_time = 0;
  57.     unsigned char key_press, key_return = 0;
  58.    
  59.     key_press = key_input;                // 读按键I/O电平
  60.     switch (key_state)
  61.       {
  62.         case key_state_0:                // 按键初始态
  63.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  64.             break;
  65.         case key_state_1:                // 按键确认态
  66.             if (!key_press)
  67.             {
  68.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  69.                 key_time = 0;                // 清另按键时间计数器
  70.             }
  71.             else
  72.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  73.             break;
  74.         case key_state_2:
  75.             if (key_press)
  76.             {
  77.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  78.                 key_return = 1;            // 输出"1" ,表示单击
  79.                 qingling();    //清零
  80.                 if (++mimajishu >9)
  81.                  {
  82.                     mimajishu = 0;  
  83.                  }              
  84.             }
  85.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  86.             {
  87.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  88.                 key_time = 0;                // 清按键计数器  
  89.                 key_return = 2;            // 输出"2"
  90.                 cabz = 1;      //长按标志
  91.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  92.             }  
  93.               qingling();    //清零
  94.             break;
  95.         case key_state_3:
  96.              if (key_press)
  97.             {
  98.               
  99.               key_state = key_state_0; //按键已释放,转换到按键初始态
  100.             }   
  101.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  102.             {
  103.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  104.                 key_time = 0;                // 清按键计数器  
  105.                 key_return = 3;         //长按2秒,进入设置界面
  106.                 PORTB ^= 1<<1;
  107.                
  108.             }
  109.              break;
  110.         case key_state_4:
  111.             if (key_press)
  112.             {
  113.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  114.             }   
  115.             qingling();    //清零
  116.             break;
  117.      
  118.       }   
  119.     return key_return;
  120.   }  

  121.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  122.    {
  123.      static unsigned char i = 0,aj_state = 0;
  124.      unsigned char key_return = 0;
  125.      
  126.      if (key_stime_ok)                                // 10ms到,键处理
  127.      {
  128.         key_stime_ok = 0;
  129.         read_key_n();
  130.        switch (aj_state)
  131.        {
  132.         case 0:               
  133.             if (yimiao_ok)
  134.            {
  135.                if(i < 5)    //密码位数设置
  136.                {
  137.                  mima[i] = mimajishu;  //记录第一位密码
  138.                  mimajishu =0;
  139.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  140.                  aj_state = 1;
  141.                  qingling();    //清零
  142.                  i=++i;         
  143.                }   
  144.            }
  145.             break;
  146.         case 1:               
  147.             if (i == 5)  //密码识别位数确认
  148.             {   
  149.                 i=0;
  150.                 aj_state = 0;
  151.                 key_return = 1;
  152.             }
  153.             else
  154.                  aj_state = 0;   
  155.             break;
  156.        }
  157.         return key_return;
  158.      }
  159.    }
  160.            
  161.   
  162.    
  163. void main(void)
  164. {
  165.     PORTA=0xFF;
  166.     DDRA=0x00;
  167.     PORTB = 0xFF;
  168.     DDRB = 0xFF;
  169.     PORTC=0xFF;
  170.     DDRC=0x00;
  171.     PORTD = 0xFF;
  172.     DDRD = 0x00;                    // PD7为输入方式
  173.    
  174. ADCSRA=0x00;
  175. TWCR=0x00;
  176. SPCR=0x00;
  177. ACSR=0x80;
  178. SFIOR=0x00;
  179. UCSRB=0x00;
  180. ACSR=(1<<ACD);

  181.     // T/C0 初始化
  182.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  183.     TCNT0 = 0x00;
  184.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  185.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  186.     mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  187.      
  188.     #asm("cli")
  189.     #asm("WDR")   
  190.    WDTCR=0x08;        //看门狗约为4s
  191.    WDTCR=0x28;
  192.     #asm("sei")            // 开放全局中断
  193.    
  194.             
  195.     while (1)
  196.     {         
  197.         switch (status)
  198.        {     
  199.              case 0:
  200.              if (key_stime_ok)                                // 10ms到,键处理
  201.             {  
  202.                 key_stime_ok = 0;
  203.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  204.                  {
  205.                      status = 1;
  206.                  }
  207.             }
  208.                 break;
  209.              case 1:
  210.                if (read_key_driver() ==1 )
  211.             {  
  212.                 qingling();    //清零
  213.                      for(j=0;j<5;j++)           //密码对比识别
  214.                     {
  215.                        if (mima[j]==ysmima[j])
  216.                        {
  217.                         cnt++;
  218.                        }
  219.                     }
  220.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  221.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  222.             }
  223.                 break;
  224.              case 2:
  225.                    if(shucuo==3)      //输错3次就执行某行动
  226.                    {
  227.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  228.                     PORTB ^= 1<<4;  //某行动
  229.                     status = 0;
  230.                    }
  231.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  232.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  233.          }   
  234.          if (simiao_ok)         //4秒无动作后休眠
  235.          {
  236.           qingling();    //清零
  237.           TIMSK = 0x00;   //关T/C0比较匹配中断
  238.           PORTB ^= 1<<5;       //休眠监测
  239.            //WDTCR=0x18;        //关看门狗
  240.            //WDTCR=0x00;
  241.             WDTCR=(1<<WDTOE)|(1<<WDE);
  242.             WDTCR=(0<<WDE);
  243.            PORTB = 0xFF;     //进入休眠前关所有灯
  244.            GICR = 0x40;   //使能INT0中断
  245.            MCUCR = 0x60; // 睡眠使能,掉电模式
  246.            
  247.            //MCUCSR=(1<<JTD);
  248.            //MCUCSR=(1<<JTD);
  249.            
  250.          
  251.            DDRB = 0x00;
  252.             
  253.         
  254.           #asm("sleep")      //休眠
  255.           PORTB ^= 1<<6;     //唤醒后监测
  256.          }
  257.         #asm("WDR")   //喂狗
  258.     }
  259. }

  260. interrupt[EXT_INT0]void ext_int0_isr(void)
  261.   {
  262.    PORTB = 0xFF;
  263.    DDRB = 0xFF;
  264.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  265.    //simiao_counter=0;
  266.    PORTB ^= 1<<7;     //中断唤醒监测
  267.    GICR = 0x00;   //禁用INT0中断
  268.     WDTCR=0x08;        //开看门狗约为4s
  269.     WDTCR=0x28;
  270.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  271.   }
复制代码
 楼主| 发表于 2014-4-19 05:42:05 | 显示全部楼层
为什么设定好第5位密码后就像休眠了呢?且设定的密码只能存2位(仿真看到的)   

  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  12. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  13. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  14. // Timer 0 比较匹配中断服务,2ms定时
  15. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  16. {
  17.    
  18.     if (++key_stime_counter >=5)
  19.     {
  20.         key_stime_counter = 0;
  21.         key_stime_ok = 1;                // 10ms到
  22.         if (++yimiao_counter >= 100)
  23.         {
  24.             yimiao_counter = 0;
  25.             yimiao_ok = 1;             // 1s到  
  26.             if (++ermiao_counter >= 2)
  27.             {
  28.                 ermiao_counter = 0;
  29.                 ermiao_ok = 1;             // 2s到
  30.                 if (++simiao_counter >= 4)
  31.                 {
  32.                 simiao_counter = 0;
  33.                 simiao_ok = 1;             // 4s到
  34.                 }
  35.             }
  36.         }
  37.     }
  38. }

  39. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  40. #define key_state_0    0
  41. #define key_state_1    1
  42. #define key_state_2    2
  43. #define key_state_3    3
  44. #define key_state_4    4

  45. void qingling(void)   //清零
  46. {
  47.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  48.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  49.       ermiao_counter = 0;
  50.       ermiao_ok = 0;
  51.       simiao_counter = 0;
  52.       simiao_ok = 0;
  53.   }   

  54. unsigned char read_key_n(void)
  55.   {
  56.     static unsigned char key_state = 0, key_time = 0;
  57.     unsigned char key_press, key_return = 0;
  58.    
  59.     key_press = key_input;                // 读按键I/O电平
  60.     switch (key_state)
  61.       {
  62.         case key_state_0:                // 按键初始态
  63.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  64.             break;
  65.         case key_state_1:                // 按键确认态
  66.             if (!key_press)
  67.             {
  68.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  69.                 key_time = 0;                // 清另按键时间计数器
  70.             }
  71.             else
  72.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  73.             break;
  74.         case key_state_2:
  75.             if (key_press)
  76.             {
  77.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  78.                 key_return = 1;            // 输出"1" ,表示单击
  79.                 qingling();    //清零
  80.                 if (++mimajishu >9)
  81.                  {
  82.                     mimajishu = 0;  
  83.                  }              
  84.             }
  85.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  86.             {
  87.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  88.                 key_time = 0;                // 清按键计数器  
  89.                 key_return = 2;            // 输出"2"
  90.                 cabz = 1;      //长按标志
  91.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  92.             }  
  93.               qingling();    //清零
  94.             break;
  95.         case key_state_3:
  96.              if (key_press)
  97.             {
  98.               
  99.               key_state = key_state_0; //按键已释放,转换到按键初始态
  100.             }   
  101.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  102.             {
  103.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  104.                 key_time = 0;                // 清按键计数器  
  105.                 key_return = 3;         //长按2秒,进入设置界面
  106.                 PORTB ^= 1<<1;
  107.                
  108.             }
  109.              break;
  110.         case key_state_4:
  111.             if (key_press)
  112.             {
  113.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  114.             }   
  115.             qingling();    //清零
  116.             break;
  117.      
  118.       }   
  119.     return key_return;
  120.   }  

  121.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  122.    {
  123.      static unsigned char i = 0,aj_state = 0;
  124.      unsigned char key_return = 0;
  125.      #asm("WDR")   //喂狗
  126.      if (key_stime_ok)                                // 10ms到,键处理
  127.      {
  128.         key_stime_ok = 0;
  129.         read_key_n();
  130.        switch (aj_state)
  131.        {
  132.         case 0:               
  133.             if (yimiao_ok)
  134.            {
  135.                if(i < 5)    //密码位数设置
  136.                {
  137.                  mima[i] = mimajishu;  //记录第一位密码
  138.                  mimajishu =0;
  139.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  140.                  aj_state = 1;
  141.                  qingling();    //清零
  142.                  i=++i;         
  143.                }   
  144.            }
  145.             break;
  146.         case 1:               
  147.             if (i == 5)  //密码识别位数确认
  148.             {   
  149.                 i=0;
  150.                 aj_state = 0;
  151.                 key_return = 1;
  152.             }
  153.             else
  154.                  aj_state = 0;   
  155.             break;
  156.        }
  157.         return key_return;
  158.      }
  159.    }
  160.            
  161.   
  162.    
  163. void main(void)
  164. {
  165.     PORTA=0xFF;
  166.     DDRA=0x00;
  167.     PORTB = 0xFF;
  168.     DDRB = 0xFF;
  169.     PORTC=0xFF;
  170.     DDRC=0x00;
  171.     PORTD = 0xFF;
  172.     DDRD = 0x00;                    // PD7为输入方式  
  173.      #asm("cli")
  174.       #asm("sei")
  175.      
  176.     for(j=0;j<5;j++)           //密码对比识别
  177.     {
  178.     while(EECR &(1 <<EEWE));
  179.     EEAR = j+10;
  180.     EECR |=(1<<EERE);
  181.     ysmima[j]=EEDR;
  182.     }
  183.   #asm("cli")   
  184. ADCSRA=0x00;
  185. TWCR=0x00;
  186. SPCR=0x00;
  187. ACSR=0x80;
  188. SFIOR=0x00;
  189. UCSRB=0x00;
  190. ACSR=(1<<ACD);

  191.     // T/C0 初始化
  192.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  193.     TCNT0 = 0x00;
  194.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  195.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  196.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  197.      
  198.     #asm("cli")
  199.     #asm("WDR")   
  200.    WDTCR=0x08;        //看门狗约为4s
  201.    WDTCR=0x28;
  202.     #asm("sei")            // 开放全局中断
  203.    
  204.             
  205.     while (1)
  206.     {         
  207.         switch (status)
  208.        {     
  209.              case 0:
  210.              if (key_stime_ok)                                // 10ms到,键处理
  211.             {  
  212.                 key_stime_ok = 0;
  213.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  214.                  {
  215.                      status = 1;
  216.                  }
  217.                  if (read_key_n() == 3)    //密码设置
  218.                   {
  219.                      status = 3;                  
  220.                   }
  221.                  
  222.             }
  223.                 break;
  224.              case 1:
  225.                if (read_key_driver() ==1 )
  226.             {  
  227.                 qingling();    //清零
  228.                      for(j=0;j<5;j++)           //密码对比识别
  229.                     {
  230.                        if (mima[j]==ysmima[j])
  231.                        {
  232.                         cnt++;
  233.                        }
  234.                     }
  235.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  236.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  237.             }
  238.                 break;
  239.              case 2:
  240.                    if(shucuo==3)      //输错3次就执行某行动
  241.                    {
  242.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  243.                     PORTB ^= 1<<4;  //某行动
  244.                     status = 0;
  245.                    }
  246.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  247.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  248.              case 3:
  249.                  if (read_key_driver() ==1 )
  250.                  {   
  251.                     #asm("cli")
  252.                     #asm("sei")
  253.                      for(j=0;j<5;j++)           //保存设置密码
  254.                     {
  255.                        
  256.                      
  257.                        while(EECR &(1 <<EEWE));
  258.                        EEAR = j+10;
  259.                        EEDR = mima[j];
  260.                        EECR |=(1 <<EEMWE);
  261.                        EECR |=(1 <<EEWE);
  262.                        simiao_ok=0;
  263.                         
  264.                         
  265.                     }
  266.                     status = 0;
  267.                         qingling();    //清零
  268.                      #asm("WDR")   //喂狗
  269.                  }
  270.                 break;
  271.          }   
  272.          if (simiao_ok)         //4秒无动作后休眠
  273.          {
  274.           qingling();    //清零
  275.           TIMSK = 0x00;   //关T/C0比较匹配中断
  276.           PORTB ^= 1<<5;       //休眠监测
  277.            //WDTCR=0x18;        //关看门狗
  278.            //WDTCR=0x00;
  279.             WDTCR=(1<<WDTOE)|(1<<WDE);
  280.             WDTCR=(0<<WDE);
  281.            PORTB = 0xFF;     //进入休眠前关所有灯
  282.            GICR = 0x40;   //使能INT0中断
  283.            MCUCR = 0x60; // 睡眠使能,掉电模式
  284.            
  285.            //MCUCSR=(1<<JTD);
  286.            //MCUCSR=(1<<JTD);
  287.            
  288.          
  289.            DDRB = 0x00;
  290.             
  291.         
  292.           #asm("sleep")      //休眠
  293.           PORTB ^= 1<<6;     //唤醒后监测
  294.          }
  295.         #asm("WDR")   //喂狗
  296.     }
  297. }

  298. interrupt[EXT_INT0]void ext_int0_isr(void)
  299.   {
  300.    PORTB = 0xFF;
  301.    DDRB = 0xFF;
  302.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  303.    //simiao_counter=0;
  304.    PORTB ^= 1<<7;     //中断唤醒监测
  305.    GICR = 0x00;   //禁用INT0中断
  306.     WDTCR=0x08;        //开看门狗约为4s
  307.     WDTCR=0x28;
  308.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  309.   }
复制代码
 楼主| 发表于 2014-4-19 05:45:54 | 显示全部楼层
也不像是休眠,应该是全部灯灭了
 楼主| 发表于 2014-4-19 10:19:49 | 显示全部楼层
找到原因了,是EEPROM读写没有给足够的时间

  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. #include<delay.h>
  12. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  13. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  14. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  15. // Timer 0 比较匹配中断服务,2ms定时
  16. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  17. {
  18.    
  19.     if (++key_stime_counter >=5)
  20.     {
  21.         key_stime_counter = 0;
  22.         key_stime_ok = 1;                // 10ms到
  23.         if (++yimiao_counter >= 100)
  24.         {
  25.             yimiao_counter = 0;
  26.             yimiao_ok = 1;             // 1s到  
  27.             if (++ermiao_counter >= 2)
  28.             {
  29.                 ermiao_counter = 0;
  30.                 ermiao_ok = 1;             // 2s到
  31.                 if (++simiao_counter >= 4)
  32.                 {
  33.                 simiao_counter = 0;
  34.                 simiao_ok = 1;             // 4s到
  35.                 }
  36.             }
  37.         }
  38.     }
  39. }

  40. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  41. #define key_state_0    0
  42. #define key_state_1    1
  43. #define key_state_2    2
  44. #define key_state_3    3
  45. #define key_state_4    4

  46. void qingling(void)   //清零
  47. {
  48.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  49.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  50.       ermiao_counter = 0;
  51.       ermiao_ok = 0;
  52.       simiao_counter = 0;
  53.       simiao_ok = 0;
  54.   }   

  55. unsigned char read_key_n(void)
  56.   {
  57.     static unsigned char key_state = 0, key_time = 0;
  58.     unsigned char key_press, key_return = 0;
  59.    
  60.     key_press = key_input;                // 读按键I/O电平
  61.     switch (key_state)
  62.       {
  63.         case key_state_0:                // 按键初始态
  64.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  65.             break;
  66.         case key_state_1:                // 按键确认态
  67.             if (!key_press)
  68.             {
  69.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  70.                 key_time = 0;                // 清另按键时间计数器
  71.             }
  72.             else
  73.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  74.             break;
  75.         case key_state_2:
  76.             if (key_press)
  77.             {
  78.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  79.                 key_return = 1;            // 输出"1" ,表示单击
  80.                 qingling();    //清零
  81.                 if (++mimajishu >9)
  82.                  {
  83.                     mimajishu = 0;  
  84.                  }              
  85.             }
  86.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  87.             {
  88.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  89.                 key_time = 0;                // 清按键计数器  
  90.                 key_return = 2;            // 输出"2"
  91.                 cabz = 1;      //长按标志
  92.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  93.             }  
  94.               qingling();    //清零
  95.             break;
  96.         case key_state_3:
  97.              if (key_press)
  98.             {
  99.               
  100.               key_state = key_state_0; //按键已释放,转换到按键初始态
  101.             }   
  102.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  103.             {
  104.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  105.                 key_time = 0;                // 清按键计数器  
  106.                 key_return = 3;         //长按2秒,进入设置界面
  107.                 PORTB ^= 1<<1;
  108.                
  109.             }
  110.              break;
  111.         case key_state_4:
  112.             if (key_press)
  113.             {
  114.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  115.             }   
  116.             qingling();    //清零
  117.             break;
  118.      
  119.       }   
  120.     return key_return;
  121.   }  

  122.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  123.    {
  124.      static unsigned char i = 0,aj_state = 0;
  125.      unsigned char key_return = 0;
  126.      #asm("WDR")   //喂狗
  127.      if (key_stime_ok)                                // 10ms到,键处理
  128.      {
  129.         key_stime_ok = 0;
  130.         read_key_n();
  131.        switch (aj_state)
  132.        {
  133.         case 0:               
  134.             if (yimiao_ok)
  135.            {
  136.                if(i < 5)    //密码位数设置
  137.                {
  138.                  mima[i] = mimajishu;  //记录第一位密码
  139.                  mimajishu =0;
  140.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  141.                  aj_state = 1;
  142.                  qingling();    //清零
  143.                  i=++i;         
  144.                }   
  145.            }
  146.             break;
  147.         case 1:               
  148.             if (i == 5)  //密码识别位数确认
  149.             {   
  150.                 i=0;
  151.                 aj_state = 0;
  152.                 key_return = 1;
  153.             }
  154.             else
  155.                  aj_state = 0;   
  156.             break;
  157.        }
  158.         return key_return;
  159.      }
  160.    }
  161.            
  162.   
  163.    
  164. void main(void)
  165. {
  166.     PORTA=0xFF;
  167.     DDRA=0x00;
  168.     PORTB = 0xFF;
  169.     DDRB = 0xFF;
  170.     PORTC=0xFF;
  171.     DDRC=0x00;
  172.     PORTD = 0xFF;
  173.     DDRD = 0x00;                    // PD7为输入方式  
  174.      #asm("cli")
  175.       #asm("sei")
  176.      
  177.     for(j=0;j<5;j++)           //密码对比识别
  178.     {
  179.     while(EECR &(1 <<EEWE));
  180.     EEAR = j+10;
  181.     EECR |=(1<<EERE);
  182.     ysmima[j]=EEDR;
  183.     delay_ms(10);
  184.     }
  185.   #asm("cli")   
  186. ADCSRA=0x00;
  187. TWCR=0x00;
  188. SPCR=0x00;
  189. ACSR=0x80;
  190. SFIOR=0x00;
  191. UCSRB=0x00;
  192. ACSR=(1<<ACD);

  193.     // T/C0 初始化
  194.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  195.     TCNT0 = 0x00;
  196.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  197.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  198.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  199.      
  200.     #asm("cli")
  201.     #asm("WDR")   
  202.    WDTCR=0x08;        //看门狗约为4s
  203.    WDTCR=0x28;
  204.     #asm("sei")            // 开放全局中断
  205.    
  206.             
  207.     while (1)
  208.     {         
  209.         switch (status)
  210.        {     
  211.              case 0:
  212.              if (key_stime_ok)                                // 10ms到,键处理
  213.             {  
  214.                 key_stime_ok = 0;
  215.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  216.                  {
  217.                      status = 1;
  218.                  }
  219.                  if (read_key_n() == 3)    //密码设置
  220.                   {
  221.                      status = 3;                  
  222.                   }
  223.                  
  224.             }
  225.                 break;
  226.              case 1:
  227.                if (read_key_driver() ==1 )
  228.             {  
  229.                 qingling();    //清零
  230.                      for(j=0;j<5;j++)           //密码对比识别
  231.                     {
  232.                        if (mima[j]==ysmima[j])
  233.                        {
  234.                         cnt++;
  235.                        }
  236.                     }
  237.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  238.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  239.             }
  240.                 break;
  241.              case 2:
  242.                    if(shucuo==3)      //输错3次就执行某行动
  243.                    {
  244.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  245.                     PORTB ^= 1<<4;  //某行动
  246.                     status = 0;
  247.                    }
  248.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  249.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  250.              case 3:
  251.                  if (read_key_driver() ==1 )
  252.                  {   
  253.                     PORTB = 0x00;     //进入休眠前关所有灯
  254.                     #asm("cli")
  255.                     #asm("sei")
  256.                      for(j=0;j<5;j++)           //保存设置密码
  257.                     {
  258.                        
  259.                      
  260.                        while(EECR &(1 <<EEWE));
  261.                        EEAR = j+10;
  262.                        EEDR = mima[j];
  263.                        EECR |=(1 <<EEMWE);
  264.                        EECR |=(1 <<EEWE);
  265.                        simiao_ok=0;
  266.                        delay_ms(10);
  267.                         
  268.                         
  269.                     }
  270.                     status = 0;
  271.                         qingling();    //清零
  272.                      #asm("WDR")   //喂狗
  273.                      
  274.                      
  275.                  }
  276.                 break;
  277.          }   
  278.          if (simiao_ok)         //4秒无动作后休眠
  279.          {
  280.           qingling();    //清零
  281.           TIMSK = 0x00;   //关T/C0比较匹配中断
  282.           PORTB ^= 1<<5;       //休眠监测
  283.            //WDTCR=0x18;        //关看门狗
  284.            //WDTCR=0x00;
  285.             WDTCR=(1<<WDTOE)|(1<<WDE);
  286.             WDTCR=(0<<WDE);
  287.            PORTB = 0xFF;     //进入休眠前关所有灯
  288.            GICR = 0x40;   //使能INT0中断
  289.            MCUCR = 0x60; // 睡眠使能,掉电模式
  290.            
  291.            //MCUCSR=(1<<JTD);
  292.            //MCUCSR=(1<<JTD);
  293.            
  294.          
  295.            DDRB = 0x00;
  296.             
  297.         
  298.           #asm("sleep")      //休眠
  299.           PORTB ^= 1<<6;     //唤醒后监测
  300.          }
  301.         #asm("WDR")   //喂狗
  302.     }
  303. }

  304. interrupt[EXT_INT0]void ext_int0_isr(void)
  305.   {
  306.    PORTB = 0xFF;
  307.    DDRB = 0xFF;
  308.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  309.    simiao_counter=0;
  310.    PORTB ^= 1<<7;     //中断唤醒监测
  311.    GICR = 0x00;   //禁用INT0中断
  312.     WDTCR=0x08;        //开看门狗约为4s
  313.     WDTCR=0x28;
  314.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  315.   }
复制代码
 楼主| 发表于 2014-4-19 10:41:50 | 显示全部楼层
为什么运行后设置好密码后不能识别呢?原来得重启才能生效,现在改动一下就能让设置的密码不用重启就能立即生效。仿真时eepromw数据会被全部置FF,这个要在哪里设置取消这个功能?
  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. #include<delay.h>
  12. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  13. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status;        // 时间计数单元,
  14. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;

  15. // Timer 0 比较匹配中断服务,2ms定时
  16. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  17. {
  18.    
  19.     if (++key_stime_counter >=5)
  20.     {
  21.         key_stime_counter = 0;
  22.         key_stime_ok = 1;                // 10ms到
  23.         if (++yimiao_counter >= 100)
  24.         {
  25.             yimiao_counter = 0;
  26.             yimiao_ok = 1;             // 1s到  
  27.             if (++ermiao_counter >= 2)
  28.             {
  29.                 ermiao_counter = 0;
  30.                 ermiao_ok = 1;             // 2s到
  31.                 if (++simiao_counter >= 4)
  32.                 {
  33.                 simiao_counter = 0;
  34.                 simiao_ok = 1;             // 4s到
  35.                 }
  36.             }
  37.         }
  38.     }
  39. }

  40. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  41. #define key_state_0    0
  42. #define key_state_1    1
  43. #define key_state_2    2
  44. #define key_state_3    3
  45. #define key_state_4    4

  46. void qingling(void)   //清零
  47. {
  48.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  49.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  50.       ermiao_counter = 0;
  51.       ermiao_ok = 0;
  52.       simiao_counter = 0;
  53.       simiao_ok = 0;
  54.   }   

  55. unsigned char read_key_n(void)
  56.   {
  57.     static unsigned char key_state = 0, key_time = 0;
  58.     unsigned char key_press, key_return = 0;
  59.    
  60.     key_press = key_input;                // 读按键I/O电平
  61.     switch (key_state)
  62.       {
  63.         case key_state_0:                // 按键初始态
  64.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  65.             break;
  66.         case key_state_1:                // 按键确认态
  67.             if (!key_press)
  68.             {
  69.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  70.                 key_time = 0;                // 清另按键时间计数器
  71.             }
  72.             else
  73.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  74.             break;
  75.         case key_state_2:
  76.             if (key_press)
  77.             {
  78.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  79.                 key_return = 1;            // 输出"1" ,表示单击
  80.                 qingling();    //清零
  81.                 if (++mimajishu >9)
  82.                  {
  83.                     mimajishu = 0;  
  84.                  }              
  85.             }
  86.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  87.             {
  88.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  89.                 key_time = 0;                // 清按键计数器  
  90.                 key_return = 2;            // 输出"2"
  91.                 cabz = 1;      //长按标志
  92.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  93.             }  
  94.               qingling();    //清零
  95.             break;
  96.         case key_state_3:
  97.              if (key_press)
  98.             {
  99.               
  100.               key_state = key_state_0; //按键已释放,转换到按键初始态
  101.             }   
  102.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  103.             {
  104.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  105.                 key_time = 0;                // 清按键计数器  
  106.                 key_return = 3;         //长按2秒,进入设置界面
  107.                 PORTB ^= 1<<1;
  108.                
  109.             }
  110.              break;
  111.         case key_state_4:
  112.             if (key_press)
  113.             {
  114.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  115.             }   
  116.             qingling();    //清零
  117.             break;
  118.      
  119.       }   
  120.     return key_return;
  121.   }  

  122.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  123.    {
  124.      static unsigned char i = 0,aj_state = 0;
  125.      unsigned char key_return = 0;
  126.      #asm("WDR")   //喂狗
  127.      if (key_stime_ok)                                // 10ms到,键处理
  128.      {
  129.         key_stime_ok = 0;
  130.         read_key_n();
  131.        switch (aj_state)
  132.        {
  133.         case 0:               
  134.             if (yimiao_ok)
  135.            {
  136.                if(i < 5)    //密码位数设置
  137.                {
  138.                  mima[i] = mimajishu;  //记录第一位密码
  139.                  mimajishu =0;
  140.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  141.                  aj_state = 1;
  142.                  qingling();    //清零
  143.                  i=++i;         
  144.                }   
  145.            }
  146.             break;
  147.         case 1:               
  148.             if (i == 5)  //密码识别位数确认
  149.             {   
  150.                 i=0;
  151.                 aj_state = 0;
  152.                 key_return = 1;
  153.             }
  154.             else
  155.                  aj_state = 0;   
  156.             break;
  157.        }
  158.         return key_return;
  159.      }
  160.    }
  161.            
  162.   
  163.    
  164. void main(void)
  165. {
  166.     PORTA=0xFF;
  167.     DDRA=0x00;
  168.     PORTB = 0xFF;
  169.     DDRB = 0xFF;
  170.     PORTC=0xFF;
  171.     DDRC=0x00;
  172.     PORTD = 0xFF;
  173.     DDRD = 0x00;                    // PD7为输入方式  
  174.      #asm("cli")
  175.       #asm("sei")
  176.      
  177.     for(j=0;j<5;j++)           //密码对比识别
  178.     {
  179.     while(EECR &(1 <<EEWE));
  180.     EEAR = j+10;
  181.     EECR |=(1<<EERE);
  182.     ysmima[j]=EEDR;
  183.     delay_ms(10);
  184.     }
  185.   #asm("cli")   
  186. ADCSRA=0x00;
  187. TWCR=0x00;
  188. SPCR=0x00;
  189. ACSR=0x80;
  190. SFIOR=0x00;
  191. UCSRB=0x00;
  192. ACSR=(1<<ACD);

  193.     // T/C0 初始化
  194.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  195.     TCNT0 = 0x00;
  196.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  197.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  198.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  199.      
  200.     #asm("cli")
  201.     #asm("WDR")   
  202.    WDTCR=0x08;        //看门狗约为4s
  203.    WDTCR=0x28;
  204.     #asm("sei")            // 开放全局中断
  205.    
  206.             
  207.     while (1)
  208.     {         
  209.         switch (status)
  210.        {     
  211.              case 0:
  212.              if (key_stime_ok)                                // 10ms到,键处理
  213.             {  
  214.                 key_stime_ok = 0;
  215.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  216.                  {
  217.                      status = 1;
  218.                  }
  219.                  if (read_key_n() == 3)    //密码设置
  220.                   {
  221.                      status = 3;                  
  222.                   }
  223.                  
  224.             }
  225.                 break;
  226.              case 1:
  227.                if (read_key_driver() ==1 )
  228.             {  
  229.                 qingling();    //清零
  230.                      for(j=0;j<5;j++)           //密码对比识别
  231.                     {
  232.                        if (mima[j]==ysmima[j])
  233.                        {
  234.                         cnt++;
  235.                        }
  236.                     }
  237.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  238.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  239.             }
  240.                 break;
  241.              case 2:
  242.                    if(shucuo==3)      //输错3次就执行某行动
  243.                    {
  244.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  245.                     PORTB ^= 1<<4;  //某行动
  246.                     status = 0;
  247.                    }
  248.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  249.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  250.              case 3:
  251.                  if (read_key_driver() ==1 )
  252.                  {   
  253.                     PORTB = 0x00;     //密码进入记录阶段
  254.                     #asm("cli")
  255.                     #asm("sei")
  256.                      for(j=0;j<5;j++)           //保存设置密码
  257.                     {
  258.                        
  259.                      
  260.                        while(EECR &(1 <<EEWE));
  261.                        EEAR = j+10;
  262.                        EEDR = mima[j];
  263.                        EECR |=(1 <<EEMWE);
  264.                        EECR |=(1 <<EEWE);
  265.                         ysmima[j] =  mima[j]; //密码立即生效
  266.                        simiao_ok=0;
  267.                        delay_ms(10);                       
  268.                         
  269.                     }
  270.                   
  271.                     status = 0;
  272.                         qingling();    //清零
  273.                      #asm("WDR")   //喂狗
  274.                      
  275.                      
  276.                  }
  277.                 break;
  278.          }   
  279.          if (simiao_ok)         //4秒无动作后休眠
  280.          {
  281.           qingling();    //清零
  282.           TIMSK = 0x00;   //关T/C0比较匹配中断
  283.           PORTB ^= 1<<5;       //休眠监测
  284.            //WDTCR=0x18;        //关看门狗
  285.            //WDTCR=0x00;
  286.             WDTCR=(1<<WDTOE)|(1<<WDE);
  287.             WDTCR=(0<<WDE);
  288.            PORTB = 0xFF;     //进入休眠前关所有灯
  289.            GICR = 0x40;   //使能INT0中断
  290.            MCUCR = 0x60; // 睡眠使能,掉电模式
  291.            
  292.            //MCUCSR=(1<<JTD);
  293.            //MCUCSR=(1<<JTD);
  294.            
  295.          
  296.            DDRB = 0x00;
  297.             
  298.         
  299.           #asm("sleep")      //休眠
  300.           PORTB ^= 1<<6;     //唤醒后监测
  301.          }
  302.         #asm("WDR")   //喂狗
  303.     }
  304. }

  305. interrupt[EXT_INT0]void ext_int0_isr(void)
  306.   {
  307.    PORTB = 0xFF;
  308.    DDRB = 0xFF;
  309.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  310.    simiao_counter=0;
  311.    PORTB ^= 1<<7;     //中断唤醒监测
  312.    GICR = 0x00;   //禁用INT0中断
  313.     WDTCR=0x08;        //开看门狗约为4s
  314.     WDTCR=0x28;
  315.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  316.   }
复制代码
 楼主| 发表于 2014-4-19 10:55:33 | 显示全部楼层
我找到了,原来要在这里设置JTAGICE调试选项,“Preserve EEPROM contents when reprogramming device”选框
该选框的值会改变目标芯片中“保护EEPROM熔丝 位”的值,如果该选框被选中,那么在
重编程芯片或做芯片擦除时,目标芯片内EEPROM的数据就不会被清除。
 楼主| 发表于 2014-4-20 08:57:03 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-21 01:13 编辑

现在加入单按键兼LED显示和休眠后唤醒,也就是在按键上并接一个LED灯,然后串接一个电阻后接到两个IO口上,实现多功能,闪灯程序通过设置闪灯标志和预设闪灯计数初值来实现快闪慢闪,从而表示不同的含义。
  1. /*********************************************
  2. File name                        : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. #include<delay.h>
  12. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                                        // 2位密码计数单元
  13. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status,shangdeng;        // 时间计数单元,闪灯标志,闪灯时长
  14. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;
  15. unsigned int shangdengtime;

  16. // Timer 0 比较匹配中断服务,2ms定时
  17. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  18. {
  19.    
  20.     if (++key_stime_counter >=5)
  21.     {
  22.         key_stime_counter = 0;
  23.         key_stime_ok = 1;                // 10ms到
  24.         if (++yimiao_counter >= 100)
  25.         {
  26.             yimiao_counter = 0;
  27.             yimiao_ok = 1;             // 1s到  
  28.             if (++ermiao_counter >= 2)
  29.             {
  30.                 ermiao_counter = 0;
  31.                 ermiao_ok = 1;             // 2s到
  32.                 if (++simiao_counter >= 4)
  33.                 {
  34.                 simiao_counter = 0;
  35.                 simiao_ok = 1;             // 4s到
  36.                 }
  37.             }
  38.         }
  39.     }
  40. }

  41. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  42. #define key_state_0    0
  43. #define key_state_1    1
  44. #define key_state_2    2
  45. #define key_state_3    3
  46. #define key_state_4    4

  47. void qingling(void)   //清零
  48. {
  49.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  50.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  51.       ermiao_counter = 0;
  52.       ermiao_ok = 0;
  53.       simiao_counter = 0;
  54.       simiao_ok = 0;
  55.   }   

  56. unsigned char read_key_n(void)
  57.   {
  58.     static unsigned char key_state = 0, key_time = 0;
  59.     unsigned char key_press, key_return = 0;
  60.    
  61.     key_press = key_input;                // 读按键I/O电平
  62.     switch (key_state)
  63.       {
  64.         case key_state_0:                // 按键初始态
  65.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  66.             break;
  67.         case key_state_1:                // 按键确认态
  68.             if (!key_press)
  69.             {
  70.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  71.                 key_time = 0;                // 清另按键时间计数器
  72.             }
  73.             else
  74.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  75.             break;
  76.         case key_state_2:
  77.             if (key_press)
  78.             {
  79.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  80.                 key_return = 1;            // 输出"1" ,表示单击
  81.                 qingling();    //清零
  82.                 if (++mimajishu >9)
  83.                  {
  84.                     mimajishu = 0;  
  85.                  }              
  86.             }
  87.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  88.             {
  89.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  90.                 key_time = 0;                // 清按键计数器  
  91.                 key_return = 2;            // 输出"2"
  92.                 cabz = 1;      //长按标志
  93.                 PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  94.             }  
  95.               qingling();    //清零
  96.             break;
  97.         case key_state_3:
  98.              if (key_press)
  99.             {
  100.               
  101.               key_state = key_state_0; //按键已释放,转换到按键初始态
  102.             }   
  103.               else if (++key_time >= 100)        // 长按2秒按键时间计数
  104.             {
  105.                 key_state = key_state_4;    // 按下时间>1s,状态转换到计时2
  106.                 key_time = 0;                // 清按键计数器  
  107.                 key_return = 3;         //长按2秒,进入设置界面
  108.                 PORTB ^= 1<<1;
  109.                
  110.             }
  111.              break;
  112.         case key_state_4:
  113.             if (key_press)
  114.             {
  115.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  116.             }   
  117.             qingling();    //清零
  118.             break;
  119.      
  120.       }   
  121.     return key_return;
  122.   }  

  123.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  124.    {
  125.      static unsigned char i = 0,aj_state = 0;
  126.      unsigned char key_return = 0;
  127.      #asm("WDR")   //喂狗
  128.      if (key_stime_ok)                                // 10ms到,键处理
  129.      {
  130.         key_stime_ok = 0;
  131.         read_key_n();
  132.        switch (aj_state)
  133.        {
  134.         case 0:               
  135.             if (yimiao_ok)
  136.            {
  137.                if(i < 5)    //密码位数设置
  138.                {
  139.                  mima[i] = mimajishu;  //记录第一位密码
  140.                  mimajishu =0;
  141.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  142.                  aj_state = 1;
  143.                  qingling();    //清零
  144.                  i=++i;
  145.                  shangdeng = 1;    //并闪灯
  146.                  shangdengtime = 54000;    //设置闪灯时间      
  147.                }   
  148.            }
  149.             break;
  150.         case 1:               
  151.             if (i == 5)  //密码识别位数确认
  152.             {   
  153.                 i=0;
  154.                 aj_state = 0;
  155.                 key_return = 1;
  156.                 shangdeng = 1;    //并闪灯
  157.                 shangdengtime = 0;    //设置长闪灯时间
  158.             }
  159.             else
  160.                  aj_state = 0;   
  161.             break;
  162.        }
  163.         return key_return;
  164.      }
  165.    }
  166.            
  167.   
  168.    
  169. void main(void)
  170. {
  171.     PORTA=0xFF;
  172.     DDRA=0x00;
  173.     PORTB = 0xFF;
  174.     DDRB = 0xFF;
  175.     PORTC=0xFF;
  176.     DDRC=0x00;
  177.     PORTD = 0x7F;
  178.     DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  179.       
  180.      #asm("cli")
  181.       #asm("sei")
  182.      
  183.     for(j=0;j<5;j++)           //密码对比识别
  184.     {
  185.     while(EECR &(1 <<EEWE));
  186.     EEAR = j+10;
  187.     EECR |=(1<<EERE);
  188.     ysmima[j]=EEDR;
  189.     delay_ms(10);
  190.     }
  191.   #asm("cli")   
  192. ADCSRA=0x00;
  193. TWCR=0x00;
  194. SPCR=0x00;
  195. ACSR=0x80;
  196. SFIOR=0x00;
  197. UCSRB=0x00;
  198. ACSR=(1<<ACD);

  199.     // T/C0 初始化
  200.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  201.     TCNT0 = 0x00;
  202.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  203.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  204.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  205.      
  206.     #asm("cli")
  207.     #asm("WDR")   
  208.    WDTCR=0x08;        //看门狗约为4s
  209.    WDTCR=0x28;
  210.     #asm("sei")            // 开放全局中断
  211.    
  212.             
  213.     while (1)
  214.     {         
  215.         switch (status)
  216.        {     
  217.              case 0:
  218.              if (key_stime_ok)                                // 10ms到,键处理
  219.             {  
  220.                 key_stime_ok = 0;
  221.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码处理
  222.                  {
  223.                      status = 1;
  224.                  }
  225.                  if (read_key_n() == 3)    //密码设置
  226.                   {
  227.                      status = 3;                  
  228.                   }
  229.                  
  230.             }
  231.                 break;
  232.              case 1:
  233.                if (read_key_driver() ==1 )
  234.             {  
  235.                 qingling();    //清零
  236.                      for(j=0;j<5;j++)           //密码对比识别
  237.                     {
  238.                        if (mima[j]==ysmima[j])
  239.                        {
  240.                         cnt++;
  241.                        }
  242.                     }
  243.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  244.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  245.             }
  246.                 break;
  247.              case 2:
  248.                    if(shucuo==3)      //输错3次就执行某行动
  249.                    {
  250.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  251.                     PORTB ^= 1<<4;  //某行动
  252.                     status = 0;
  253.                    }
  254.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  255.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  256.              case 3:
  257.                  if (read_key_driver() ==1 )
  258.                  {   
  259.                     PORTB = 0x00;     //密码进入记录阶段
  260.                     #asm("cli")
  261.                     #asm("sei")
  262.                      for(j=0;j<5;j++)           //保存设置密码
  263.                     {
  264.                        
  265.                      
  266.                        while(EECR &(1 <<EEWE));
  267.                        EEAR = j+10;
  268.                        EEDR = mima[j];
  269.                        EECR |=(1 <<EEMWE);
  270.                        EECR |=(1 <<EEWE);
  271.                         ysmima[j] =  mima[j]; //密码立即生效
  272.                        simiao_ok=0;
  273.                        delay_ms(10);                       
  274.                         
  275.                     }
  276.                   
  277.                     status = 0;
  278.                         //qingling();    //清零
  279.                      //#asm("WDR")   //喂狗
  280.                      
  281.                      
  282.                  }
  283.                 break;
  284.          }   
  285.          if (simiao_ok)         //4秒无动作后休眠
  286.          {
  287.           qingling();    //清零
  288.           TIMSK = 0x00;   //关T/C0比较匹配中断
  289.           PORTB ^= 1<<5;       //休眠监测
  290.            //WDTCR=0x18;        //关看门狗
  291.            //WDTCR=0x00;
  292.             WDTCR=(1<<WDTOE)|(1<<WDE);
  293.             WDTCR=(0<<WDE);
  294.            PORTB = 0xFF;     //进入休眠前关所有灯
  295.            GICR = 0x40;   //使能INT0中断
  296.            MCUCR = 0x60; // 睡眠使能,掉电模式
  297.            
  298.            //MCUCSR=(1<<JTD);
  299.            //MCUCSR=(1<<JTD);
  300.            
  301.          
  302.            DDRB = 0x00;
  303.             
  304.         
  305.           #asm("sleep")      //休眠
  306.           PORTB ^= 1<<6;     //唤醒后监测
  307.          }
  308.         #asm("WDR")   //喂狗
  309.         if(shangdeng==1)    //闪灯
  310.         {
  311.           PORTD |=( 1<<7);   //PD7输出高
  312.           PORTD &=~( 1<<2);  //INT0拉低
  313.            DDRD = 0xFF;
  314.           if (++shangdengtime >= 60000)   //按键闪灯指示程序
  315.           {
  316.            shangdeng = 0;
  317.            shangdengtime = 0;
  318.           }
  319.         }
  320.          PORTD = 0x7F;                  //恢复端口检测
  321.          DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  322.     }
  323. }

  324. interrupt[EXT_INT0]void ext_int0_isr(void)
  325.   {
  326.    PORTB = 0xFF;
  327.    DDRB = 0xFF;
  328.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  329.    simiao_counter=0;
  330.    PORTB ^= 1<<7;     //中断唤醒监测
  331.    GICR = 0x00;   //禁用INT0中断
  332.     WDTCR=0x08;        //开看门狗约为4s
  333.     WDTCR=0x28;
  334.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  335.   }
复制代码



奇怪,为什么把108行里“else if (++key_time >= 100)        // 长按2秒按键时间计数”的100改成255后,就不能进入密码设置?
也就是不能执行234行的“status = 3; ”,仿真时,应该看到key_return = 3了呢,可为什么还是不能第执行234行呢?一旦把255改成其它就可以包括254。
 楼主| 发表于 2014-4-20 09:45:43 | 显示全部楼层
这是按键电路图,左边是之前的,右边是改进的,因为按键检测和闪灯是实时的,所以这样改进,按键检测的时候也不影响闪灯。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2014-4-20 09:52:00 | 显示全部楼层
不过现在的程序怎么会实现INT0唤醒了呢?休眠的时候PD.2应该被拉低才能唤醒,可是我看程序是把PD.7设置为输入带上拉呢!
 楼主| 发表于 2014-4-21 04:24:24 | 显示全部楼层
现在加入设置新密码要先验证老密码,下一步应该要加入如何恢复原始密码了。

  1. /*********************************************
  2. File name            : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. #include<delay.h>
  12. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                    // 2位密码计数单元
  13. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status,shangdeng;        // 时间计数单元,闪灯标志,闪灯时长
  14. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;
  15. unsigned int shangdengtime;

  16. // Timer 0 比较匹配中断服务,2ms定时
  17. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  18. {
  19.    
  20.     if (++key_stime_counter >=5)
  21.     {
  22.         key_stime_counter = 0;
  23.         key_stime_ok = 1;                // 10ms到
  24.         if (++yimiao_counter >= 100)
  25.         {
  26.             yimiao_counter = 0;
  27.             yimiao_ok = 1;             // 1s到  
  28.             if (++ermiao_counter >= 2)
  29.             {
  30.                 ermiao_counter = 0;
  31.                 ermiao_ok = 1;             // 2s到
  32.                 if (++simiao_counter >= 4)
  33.                 {
  34.                 simiao_counter = 0;
  35.                 simiao_ok = 1;             // 4s到
  36.                 }
  37.             }
  38.         }
  39.     }
  40. }

  41. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  42. #define key_state_0    0
  43. #define key_state_1    1
  44. #define key_state_2    2
  45. #define key_state_3    3
  46. #define key_state_4    4

  47. void qingling(void)   //清零
  48. {
  49.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  50.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  51.       ermiao_counter = 0;
  52.       ermiao_ok = 0;
  53.       simiao_counter = 0;
  54.       simiao_ok = 0;
  55.   }   

  56. unsigned char read_key_n(void)
  57.   {
  58.     static unsigned char key_state = 0, key_time = 0;
  59.     unsigned char key_press, key_return = 0;
  60.    
  61.     key_press = key_input;                // 读按键I/O电平
  62.     switch (key_state)
  63.       {
  64.         case key_state_0:                // 按键初始态
  65.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  66.             break;
  67.         case key_state_1:                // 按键确认态
  68.             if (!key_press)
  69.             {
  70.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  71.                 key_time = 0;                // 清另按键时间计数器
  72.             }
  73.             else
  74.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  75.             break;
  76.         case key_state_2:
  77.             if (key_press)
  78.             {
  79.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  80.                 key_return = 1;            // 输出"1" ,表示单击
  81.                 shangdeng = 1;    //开短闪灯 ,告知按下按键成功短按一次
  82.                 shangdengtime = 65000;    //设置闪灯时间
  83.                 if (++mimajishu >9)
  84.                  {
  85.                     mimajishu = 0;  
  86.                  }              
  87.             }
  88.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  89.             {
  90.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  91.                 key_time = 0;                // 清按键计数器  
  92.                 shangdeng = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  93.                 shangdengtime = 54000;    //设置闪灯时间
  94.                
  95.             }  
  96.               qingling();    //清零
  97.             break;
  98.         case key_state_3:
  99.              if (key_press)
  100.             {
  101.               
  102.               key_state = key_state_0; //按键已释放,转换到按键初始态
  103.               cabz = 1;      //长按标志
  104.               PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  105.               
  106.               key_return = 2;            // 长按超过1秒后输出"2" ,
  107.             }   
  108.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  109.             {
  110.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  111.                 key_time = 0;                // 清按键计数器  
  112.                 key_return = 3;         //长按2秒,进入设置界面
  113.                 PORTB ^= 1<<1;
  114.                 shangdeng = 1;    //开长闪灯
  115.                 shangdengtime = 30000;    //设置长闪灯时间
  116.                
  117.             }
  118.             qingling();    //清零   
  119.              break;
  120.         case key_state_4:
  121.             if (key_press)
  122.             {
  123.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  124.             }   
  125.             qingling();    //清零
  126.             break;
  127.      
  128.       }   
  129.     return key_return;
  130.   }  

  131.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  132.    {
  133.      static unsigned char i = 0,aj_state = 0;
  134.      unsigned char key_return = 0;
  135.      #asm("WDR")   //喂狗
  136.      if (key_stime_ok)                // 10ms到,键处理
  137.      {
  138.         key_stime_ok = 0;
  139.         read_key_n();
  140.        switch (aj_state)
  141.        {
  142.         case 0:               
  143.             if (ermiao_ok)
  144.            {
  145.                if(i < 5)    //密码位数设置
  146.                {
  147.                  mima[i] = mimajishu;  //记录第一位密码
  148.                  mimajishu =0;
  149.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  150.                  aj_state = 1;
  151.                  qingling();    //清零
  152.                  i=++i;
  153.                  shangdeng = 1;    //开短闪灯标示刚才输入一位密码成功
  154.                  shangdengtime = 60000;    //设置闪灯时间      
  155.                }   
  156.            }
  157.             break;
  158.         case 1:               
  159.             if (i == 5)  //密码识别位数确认
  160.             {   
  161.                 i=0;
  162.                 aj_state = 0;
  163.                 key_return = 1;
  164.                 shangdeng = 1;    //开长闪灯表示密码输入完成
  165.                 shangdengtime = 30000;    //设置长闪灯时间
  166.             }
  167.             else
  168.                  aj_state = 0;   
  169.             break;
  170.        }
  171.         return key_return;
  172.      }
  173.    }
  174.            
  175.   
  176.    
  177. void main(void)
  178. {
  179.     PORTA=0xFF;
  180.     DDRA=0x00;
  181.     PORTB = 0xFF;
  182.     DDRB = 0xFF;
  183.     PORTC=0xFF;
  184.     DDRC=0x00;
  185.     PORTD = 0x7F;
  186.     DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  187.       
  188.      #asm("cli")
  189.       #asm("sei")
  190.      
  191.     for(j=0;j<5;j++)           //读出原密码
  192.     {
  193.     while(EECR &(1 <<EEWE));
  194.     EEAR = j+10;
  195.     EECR |=(1<<EERE);
  196.     ysmima[j]=EEDR;
  197.     delay_ms(10);
  198.     }
  199.   #asm("cli")   
  200. ADCSRA=0x00;
  201. TWCR=0x00;
  202. SPCR=0x00;
  203. ACSR=0x80;
  204. SFIOR=0x00;
  205. UCSRB=0x00;
  206. ACSR=(1<<ACD);

  207.     // T/C0 初始化
  208.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  209.     TCNT0 = 0x00;
  210.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  211.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  212.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  213.      
  214.     #asm("cli")
  215.     #asm("WDR")   
  216.    WDTCR=0x08;        //看门狗约为16.3ms
  217.    WDTCR=0x28;
  218.     #asm("sei")            // 开放全局中断
  219.    
  220.             
  221.     while (1)
  222.     {         
  223.         switch (status)
  224.        {     
  225.              case 0:
  226.              if (key_stime_ok)                // 10ms到,键处理
  227.             {  
  228.                 key_stime_ok = 0;
  229.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码输入处理部分
  230.                  {
  231.                      status = 1;
  232.                  }
  233.                  if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  234.                   {
  235.                      status = 11;                  
  236.                   }
  237.                  
  238.             }
  239.                 break;
  240.              case 1:
  241.                if (read_key_driver() ==1 )
  242.             {  
  243.                 qingling();    //清零
  244.                      for(j=0;j<5;j++)           //密码对比识别
  245.                     {
  246.                        if (mima[j]==ysmima[j])
  247.                        {
  248.                         cnt++;
  249.                        }
  250.                     }
  251.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  252.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  253.             }
  254.                 break;
  255.              case 2:
  256.                    if(shucuo==3)      //输错3次就执行某行动
  257.                    {
  258.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  259.                     PORTB ^= 1<<4;  //某行动
  260.                     status = 0;
  261.                    }
  262.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  263.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  264.              case 11:         //密码设置第一步:输入原密码,正确后才能设置新密码
  265.                if (read_key_driver() ==1 )
  266.             {  
  267.                 qingling();    //清零
  268.                      for(j=0;j<5;j++)           //密码对比识别
  269.                     {
  270.                        if (mima[j]==ysmima[j])
  271.                        {
  272.                         cnt++;
  273.                        }
  274.                     }
  275.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 12;shucuo=0;shangdeng = 1;shangdengtime = 0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  276.                     else  {status = 0;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  277.             }
  278.                 break;                     
  279.              case 12:               //老密码输入对,开始第一次输入新密码
  280.                  if (read_key_driver() ==1 )
  281.                  {   
  282.                     for(j=0;j<5;j++)
  283.                        {
  284.                         ysmima[j]=mima[j];
  285.                        }
  286.                      status = 13;
  287.                  }  
  288.                    break;
  289.              case 13:               //开始第二次输入新密码,并和第一次的对比
  290.                  if (read_key_driver() ==1 )
  291.                  {   
  292.                     for(j=0;j<5;j++)           //密码对比识别
  293.                     {
  294.                        if (mima[j]==ysmima[j])
  295.                        {
  296.                         cnt++;
  297.                        }
  298.                     }
  299.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 14;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  300.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  301.                  }  
  302.                    break;
  303.                case 14:               //开始第三次输入新密码,并和第一次的对比
  304.                  if (read_key_driver() ==1 )
  305.                  {   
  306.                     for(j=0;j<5;j++)           //密码对比识别
  307.                     {
  308.                        if (mima[j]==ysmima[j])
  309.                        {
  310.                         cnt++;
  311.                        }
  312.                     }
  313.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 15;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  314.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  315.                  }  
  316.                    break;               
  317.                        
  318.                 case 15:        //第三次输对新密码后,开始记录                                                        
  319.                     PORTB = 0x00;     //全亮灯密码进入记录阶段
  320.                     for(j=0;j<5;j++)           //写入新设置密码
  321.                     {
  322.                        #asm("cli")                     
  323.                        while(EECR &(1 <<EEWE));
  324.                        EEAR = j+10;
  325.                        EEDR = mima[j];
  326.                        EECR |=(1 <<EEMWE);
  327.                        EECR |=(1 <<EEWE);
  328.                         ysmima[j] =  mima[j]; //密码立即生效
  329.                        simiao_ok=0;
  330.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  331.                        delay_ms(10);
  332.                        #asm("sei")                       
  333.                         
  334.                     }                  
  335.                     status = 0;                                       
  336.                 break;
  337.                 case 16:
  338.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  339.                    {
  340.                     for(j=0;j<5;j++)           //读出原密码继续使用
  341.                     {
  342.                       #asm("cli")
  343.                       while(EECR &(1 <<EEWE));
  344.                       EEAR = j+10;
  345.                       EECR |=(1<<EERE);
  346.                       ysmima[j]=EEDR;
  347.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  348.                       delay_ms(10);
  349.                       #asm("sei")
  350.                     }
  351.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  352.                     PORTB ^= 1<<4;  //某行动
  353.                     status = 0;
  354.                    }
  355.                   else status = 12;   
  356.                 break;               
  357.          }   
  358.          if (simiao_ok)         //4秒无动作后休眠
  359.          {
  360.           qingling();    //清零
  361.           TIMSK = 0x00;   //关T/C0比较匹配中断
  362.           PORTB ^= 1<<5;       //休眠监测
  363.            //WDTCR=0x18;        //关看门狗
  364.            //WDTCR=0x00;
  365.             WDTCR=(1<<WDTOE)|(1<<WDE);
  366.             WDTCR=(0<<WDE);
  367.            PORTB = 0xFF;     //进入休眠前关所有灯
  368.            GICR = 0x40;   //使能INT0中断
  369.            MCUCR = 0x60; // 睡眠使能,掉电模式
  370.            
  371.            //MCUCSR=(1<<JTD);
  372.            //MCUCSR=(1<<JTD);
  373.            
  374.          
  375.            DDRB = 0x00;
  376.             
  377.           #asm("sleep")      //休眠
  378.           PORTB ^= 1<<6;     //唤醒后监测
  379.          }
  380.         #asm("WDR")   //喂狗
  381.         if(shangdeng==1)    //闪灯
  382.         {
  383.           qingling();    //清零
  384.           PORTD |=( 1<<7);   //PD7输出高
  385.           PORTD &=~( 1<<2);  //INT0拉低
  386.            DDRD = 0xFF;
  387.           if (++shangdengtime >= 65530)   //按键闪灯指示程序
  388.           {
  389.            shangdeng = 0;
  390.            shangdengtime = 0;
  391.           }
  392.         }
  393.          PORTD = 0x7F;                  //恢复端口检测
  394.          DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  395.     }
  396. }

  397. interrupt[EXT_INT0]void ext_int0_isr(void)
  398.   {
  399.    PORTB = 0xFF;
  400.    DDRB = 0xFF;
  401.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  402.    simiao_counter=0;
  403.    PORTB ^= 1<<7;     //中断唤醒监测
  404.    GICR = 0x00;   //禁用INT0中断
  405.     WDTCR=0x08;        //开看门狗约为4s
  406.     WDTCR=0x28;
  407.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  408.   }
复制代码
 楼主| 发表于 2014-4-21 04:27:26 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-21 04:28 编辑

还要加LED灯快速闪几次,方便表达某些意义。这路越走,离tiny13a越远了。
 楼主| 发表于 2014-4-22 02:13:58 | 显示全部楼层
现在加入闪灯程序和按一下PD.7恢复初始密码

  1. /*********************************************
  2. File name            : demo_9_2.c
  3. Chip type           : ATmega16
  4. Program type        : Application
  5. Clock frequency     : 4.000000 MHz
  6. Memory model        : Small
  7. External SRAM size  : 0
  8. Data Stack size     : 256
  9. *********************************************/

  10. #include <mega16.h>
  11. #include<delay.h>
  12. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt,cabz; //密码计数,录入密码数组,原始密码数组,长按标志                    // 2位密码计数单元
  13. unsigned char simiao_counter,ermiao_counter,yimiao_counter,key_stime_counter,status,shangdengcishu;        // 时间计数单元,闪灯时长、次数
  14. unsigned char simiao_ok,ermiao_ok,yimiao_ok,key_stime_ok;
  15. unsigned int shangdengtime;
  16. unsigned char huifu[5]={1,2,3,4,5};

  17. // Timer 0 比较匹配中断服务,2ms定时
  18. interrupt [TIM0_COMP] void timer0_comp_isr(void)
  19. {
  20.    
  21.     if (++key_stime_counter >=5)
  22.     {
  23.         key_stime_counter = 0;
  24.         key_stime_ok = 1;                // 10ms到
  25.         if (++yimiao_counter >= 100)
  26.         {
  27.             yimiao_counter = 0;
  28.             yimiao_ok = 1;             // 1s到  
  29.             if (++ermiao_counter >= 2)
  30.             {
  31.                 ermiao_counter = 0;
  32.                 ermiao_ok = 1;             // 2s到
  33.                 if (++simiao_counter >= 4)
  34.                 {
  35.                 simiao_counter = 0;
  36.                 simiao_ok = 1;             // 4s到
  37.                 }
  38.             }
  39.         }
  40.     }
  41. }

  42. #define key_input    PIND.2            // 按键输入口兼INTO中断唤醒
  43. #define key_state_0    0
  44. #define key_state_1    1
  45. #define key_state_2    2
  46. #define key_state_3    3
  47. #define key_state_4    4

  48. void qingling(void)   //清零
  49. {
  50.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  51.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  52.       ermiao_counter = 0;
  53.       ermiao_ok = 0;
  54.       simiao_counter = 0;
  55.       simiao_ok = 0;
  56.   }   
  57.   
  58.   void shangdeng(void)   //闪灯
  59.    {
  60.      static unsigned char status;
  61.      static unsigned int i;
  62.      if(shangdengcishu >0)  //闪灯次数  类似倒计时程序
  63.         {
  64.           switch (status)
  65.           {
  66.             case 0:
  67.               qingling();    //清零
  68.               PORTD |=( 1<<7);   //PD7输出高
  69.               PORTD &=~( 1<<2);  //INT0拉低
  70.               DDRD = 0xFF;
  71.               if (++i >= shangdengtime)   //按键闪灯指示程序
  72.               {
  73.                status=1;
  74.                i=0;
  75.               }            
  76.               break;
  77.             case 1:
  78.               if (++i >= shangdengtime+10000)   //按键闪灯指示程序
  79.                {
  80.                  i=0;
  81.                  status=0;
  82.                  --shangdengcishu ;
  83.                 }
  84.               break;
  85.           }              
  86.         }
  87.    }
  88.   
  89. unsigned char read_key_n(void)
  90.   {
  91.     static unsigned char key_state = 0, key_time = 0;
  92.     unsigned char key_press, key_return = 0;
  93.    
  94.     key_press = key_input;                // 读按键I/O电平
  95.     switch (key_state)
  96.       {
  97.         case key_state_0:                // 按键初始态
  98.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  99.             break;
  100.         case key_state_1:                // 按键确认态
  101.             if (!key_press)
  102.             {
  103.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  104.                 key_time = 0;                // 清另按键时间计数器
  105.             }
  106.             else
  107.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  108.             break;
  109.         case key_state_2:
  110.             if (key_press)
  111.             {
  112.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  113.                 key_return = 1;            // 输出"1" ,表示单击
  114.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键成功短按一次
  115.                 shangdengtime = 2500;    //设置闪灯时间
  116.                 if (++mimajishu >9)
  117.                  {
  118.                     mimajishu = 0;  
  119.                  }              
  120.             }
  121.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  122.             {
  123.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  124.                 key_time = 0;                // 清按键计数器  
  125.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  126.                 shangdengtime = 11000;    //设置闪灯时间
  127.                
  128.             }  
  129.               qingling();    //清零
  130.             break;
  131.         case key_state_3:
  132.              if (key_press)
  133.             {
  134.               
  135.               key_state = key_state_0; //按键已释放,转换到按键初始态
  136.               cabz = 1;      //长按标志
  137.               PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  138.               key_return = 2;            // 长按超过1秒后输出"2" ,
  139.             }   
  140.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  141.             {
  142.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  143.                 key_time = 0;                // 清按键计数器  
  144.                 key_return = 3;         //长按2秒,进入设置界面
  145.                 PORTB ^= 1<<1;
  146.                 shangdengcishu = 1;    //开长闪灯
  147.                 shangdengtime = 50000;    //设置长闪灯时间
  148.                
  149.             }
  150.             qingling();    //清零   
  151.              break;
  152.         case key_state_4:
  153.             if (key_press)
  154.             {
  155.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  156.             }   
  157.             qingling();    //清零
  158.             break;
  159.      
  160.       }   
  161.     return key_return;
  162.   }  

  163.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  164.    {
  165.      static unsigned char i = 0,aj_state = 0;
  166.      unsigned char key_return = 0;
  167.      #asm("WDR")   //喂狗
  168.      if (key_stime_ok)                // 10ms到,键处理
  169.      {
  170.         key_stime_ok = 0;
  171.         read_key_n();
  172.        switch (aj_state)
  173.        {
  174.         case 0:               
  175.             if (ermiao_ok)
  176.            {
  177.                if(i < 5)    //密码位数设置
  178.                {
  179.                  mima[i] = mimajishu;  //记录第一位密码
  180.                  mimajishu =0;
  181.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  182.                  aj_state = 1;
  183.                  qingling();    //清零
  184.                  i=++i;                  
  185.                  shangdengcishu = i;    //开短闪灯标示刚才输入一位密码成功
  186.                  shangdengtime = 1500;    //设置闪灯时间   
  187.                     
  188.                }   
  189.            }
  190.             break;
  191.         case 1:               
  192.             if (i == 5)  //密码识别位数确认 ,闪2次标示密码输完
  193.             {   
  194.                 i=0;
  195.                 aj_state = 0;
  196.                 key_return = 1;
  197.             }
  198.             else
  199.                  aj_state = 0;   
  200.             break;
  201.        }
  202.         return key_return;
  203.      }
  204.    }
  205.            
  206.   
  207.    
  208. void main(void)
  209. {
  210.     PORTA=0xFF;
  211.     DDRA=0x00;
  212.     PORTB = 0xFF;
  213.     DDRB = 0xFF;
  214.     PORTC=0xFF;
  215.     DDRC=0x00;
  216.     PORTD = 0x7F;
  217.     DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  218.       
  219.      #asm("cli")
  220.       #asm("sei")
  221.      
  222.     for(j=0;j<5;j++)           //读出原密码
  223.     {
  224.     while(EECR &(1 <<EEWE));
  225.     EEAR = j+10;
  226.     EECR |=(1<<EERE);
  227.     ysmima[j]=EEDR;
  228.     delay_ms(10);
  229.     }
  230.   #asm("cli")   
  231. ADCSRA=0x00;
  232. TWCR=0x00;
  233. SPCR=0x00;
  234. ACSR=0x80;
  235. SFIOR=0x00;
  236. UCSRB=0x00;
  237. ACSR=(1<<ACD);

  238.     // T/C0 初始化
  239.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  240.     TCNT0 = 0x00;
  241.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  242.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  243.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  244.      
  245.     #asm("cli")
  246.     #asm("WDR")   
  247.    WDTCR=0x08;        //看门狗约为16.3ms
  248.    WDTCR=0x28;
  249.     #asm("sei")            // 开放全局中断
  250.    
  251.             
  252.     while (1)
  253.     {         
  254.         switch (status)
  255.        {     
  256.              case 0:
  257.              if (key_stime_ok)                // 10ms到,键处理
  258.             {  
  259.                 key_stime_ok = 0;
  260.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码输入处理部分
  261.                  {
  262.                      status = 1;
  263.                  }
  264.                  if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  265.                   {
  266.                      status = 11;                  
  267.                   }
  268.                   PORTD |=( 1<<7);   //PD7输出高
  269.                   DDRD &=~( 1<<7);  //PD7设置成输入  
  270.                  if(PIND.7 == 0)    //若PD7拉低就把密码恢复出厂设置
  271.                   {
  272.                     shangdengcishu = 5;    //开短闪灯标示刚才输入一位密码成功
  273.                     shangdengtime = 1500;    //设置闪灯时间
  274.                     //unsigned char mima[5]={1,2,3,4,5};
  275.                     for(j=0;j<5;j++)           //写入新设置密码
  276.                     {
  277.                        #asm("cli")                     
  278.                        while(EECR &(1 <<EEWE));
  279.                        EEAR = j+10;
  280.                        EEDR = huifu[j];
  281.                        EECR |=(1 <<EEMWE);
  282.                        EECR |=(1 <<EEWE);
  283.                         ysmima[j] =  huifu[j]; //密码立即生效
  284.                        simiao_ok=0;
  285.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  286.                        delay_ms(10);
  287.                        #asm("sei")                    
  288.                     }                  
  289.                   }
  290.                   PORTD = 0x7F;
  291.                   DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  292.             }
  293.                 break;
  294.              case 1:
  295.                if (read_key_driver() ==1 )
  296.             {  
  297.                 qingling();    //清零
  298.                      for(j=0;j<5;j++)           //密码对比识别
  299.                     {
  300.                        if (mima[j]==ysmima[j])
  301.                        {
  302.                         cnt++;
  303.                        }
  304.                     }
  305.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  306.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  307.             }
  308.                 break;
  309.              case 2:
  310.                    if(shucuo==3)      //输错3次就执行某行动
  311.                    {
  312.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  313.                     PORTB ^= 1<<4;  //某行动
  314.                     status = 0;
  315.                    }
  316.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  317.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  318.              case 11:         //密码设置第一步:输入原密码,正确后闪烁3次,然后开始设置新密码
  319.                if (read_key_driver() ==1 )
  320.             {  
  321.                 qingling();    //清零
  322.                      for(j=0;j<5;j++)           //密码对比识别
  323.                     {
  324.                        if (mima[j]==ysmima[j])
  325.                        {
  326.                         cnt++;
  327.                        }
  328.                     }
  329.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 12;shucuo=0;shangdengcishu = 3;shangdengtime = 50000;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  330.                     else  {status = 0;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  331.             }
  332.                 break;                     
  333.              case 12:               //老密码输入对,开始第一次输入新密码
  334.                  if (read_key_driver() ==1 )
  335.                  {   
  336.                     for(j=0;j<5;j++)
  337.                        {
  338.                         ysmima[j]=mima[j];
  339.                        }
  340.                      status = 13;
  341.                  }  
  342.                    break;
  343.              case 13:               //开始第二次输入新密码,并和第一次的对比
  344.                  if (read_key_driver() ==1 )
  345.                  {   
  346.                     for(j=0;j<5;j++)           //密码对比识别
  347.                     {
  348.                        if (mima[j]==ysmima[j])
  349.                        {
  350.                         cnt++;
  351.                        }
  352.                     }
  353.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 14;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  354.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  355.                  }  
  356.                    break;
  357.                case 14:               //开始第三次输入新密码,并和第一次的对比
  358.                  if (read_key_driver() ==1 )
  359.                  {   
  360.