amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 2578|回复: 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.                     for(j=0;j<5;j++)           //密码对比识别
  361.                     {
  362.                        if (mima[j]==ysmima[j])
  363.                        {
  364.                         cnt++;
  365.                        }
  366.                     }
  367.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 15;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  368.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  369.                  }  
  370.                    break;               
  371.                        
  372.                 case 15:        //第三次输对新密码后,开始记录                                                        
  373.                     PORTB = 0x00;     //全亮灯密码进入记录阶段
  374.                     for(j=0;j<5;j++)           //写入新设置密码
  375.                     {
  376.                        #asm("cli")                     
  377.                        while(EECR &(1 <<EEWE));
  378.                        EEAR = j+10;
  379.                        EEDR = mima[j];
  380.                        EECR |=(1 <<EEMWE);
  381.                        EECR |=(1 <<EEWE);
  382.                         ysmima[j] =  mima[j]; //密码立即生效
  383.                        simiao_ok=0;
  384.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  385.                        delay_ms(10);
  386.                        #asm("sei")                       
  387.                         
  388.                     }                  
  389.                     status = 0;                                       
  390.                 break;
  391.                 case 16:
  392.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  393.                    {
  394.                     for(j=0;j<5;j++)           //读出原密码继续使用
  395.                     {
  396.                       #asm("cli")
  397.                       while(EECR &(1 <<EEWE));
  398.                       EEAR = j+10;
  399.                       EECR |=(1<<EERE);
  400.                       ysmima[j]=EEDR;
  401.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  402.                       delay_ms(10);
  403.                       #asm("sei")
  404.                     }
  405.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  406.                     PORTB ^= 1<<4;  //某行动
  407.                     status = 0;
  408.                    }
  409.                   else status = 12;   
  410.                 break;               
  411.          }   
  412.          if (simiao_ok)         //4秒无动作后休眠
  413.          {
  414.           qingling();    //清零
  415.           TIMSK = 0x00;   //关T/C0比较匹配中断
  416.           PORTB ^= 1<<5;       //休眠监测
  417.            //WDTCR=0x18;        //关看门狗
  418.            //WDTCR=0x00;
  419.             WDTCR=(1<<WDTOE)|(1<<WDE);
  420.             WDTCR=(0<<WDE);
  421.            PORTB = 0xFF;     //进入休眠前关所有灯
  422.            GICR = 0x40;   //使能INT0中断
  423.            MCUCR = 0x60; // 睡眠使能,掉电模式
  424.            
  425.            //MCUCSR=(1<<JTD);
  426.            //MCUCSR=(1<<JTD);
  427.            
  428.          
  429.            DDRB = 0x00;
  430.             
  431.           #asm("sleep")      //休眠
  432.           PORTB ^= 1<<6;     //唤醒后监测
  433.          }
  434.         #asm("WDR")   //喂狗
  435.         shangdeng(); //扫描闪灯
  436.          PORTD = 0x7F;                  //恢复端口检测
  437.          DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  438.     }
  439. }

  440. interrupt[EXT_INT0]void ext_int0_isr(void)
  441.   {
  442.    PORTB = 0xFF;
  443.    DDRB = 0xFF;
  444.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  445.    simiao_counter=0;
  446.    PORTB ^= 1<<7;     //中断唤醒监测
  447.    GICR = 0x00;   //禁用INT0中断
  448.     WDTCR=0x08;        //开看门狗约为4s
  449.     WDTCR=0x28;
  450.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  451.   }
复制代码
 楼主| 发表于 2014-4-22 08:54:36 | 显示全部楼层
之前快速按键,闪灯会眼不上节奏,这是因为关灯时间不可调,是10000,现在把它设成一个变量,对于只亮一次的就设为0,闪多次的就设回来10000。
  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,guangdengtime;
  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+guangdengtime)   //按键闪灯指示程序
  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 = 1500;    //设置闪灯时间
  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.                 guangdengtime = 0;    //设置关灯时间
  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.                 guangdengtime = 0;    //设置关灯时间
  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.                  guangdengtime = 10000;    //设置关灯时间   
  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.                     guangdengtime = 10000;    //设置关灯时间
  275.                     //unsigned char mima[5]={1,2,3,4,5};
  276.                     for(j=0;j<5;j++)           //写入新设置密码
  277.                     {
  278.                        #asm("cli")                     
  279.                        while(EECR &(1 <<EEWE));
  280.                        EEAR = j+10;
  281.                        EEDR = huifu[j];
  282.                        EECR |=(1 <<EEMWE);
  283.                        EECR |=(1 <<EEWE);
  284.                         ysmima[j] =  huifu[j]; //密码立即生效
  285.                        simiao_ok=0;
  286.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  287.                        delay_ms(10);
  288.                        #asm("sei")                    
  289.                     }                  
  290.                   }
  291.                   PORTD = 0x7F;
  292.                   DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  293.             }
  294.                 break;
  295.              case 1:
  296.                if (read_key_driver() ==1 )
  297.             {  
  298.                 qingling();    //清零
  299.                      for(j=0;j<5;j++)           //密码对比识别
  300.                     {
  301.                        if (mima[j]==ysmima[j])
  302.                        {
  303.                         cnt++;
  304.                        }
  305.                     }
  306.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  307.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  308.             }
  309.                 break;
  310.              case 2:
  311.                    if(shucuo==3)      //输错3次就执行某行动
  312.                    {
  313.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  314.                     PORTB ^= 1<<4;  //某行动
  315.                     status = 0;
  316.                    }
  317.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  318.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  319.              case 11:         //密码设置第一步:输入原密码,正确后闪烁3次,然后开始设置新密码
  320.                if (read_key_driver() ==1 )
  321.             {  
  322.                 qingling();    //清零
  323.                      for(j=0;j<5;j++)           //密码对比识别
  324.                     {
  325.                        if (mima[j]==ysmima[j])
  326.                        {
  327.                         cnt++;
  328.                        }
  329.                     }
  330.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 12;shucuo=0;shangdengcishu = 3;shangdengtime = 50000;guangdengtime = 10000;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  331.                     else  {status = 0;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  332.             }
  333.                 break;                     
  334.              case 12:               //老密码输入对,开始第一次输入新密码
  335.                  if (read_key_driver() ==1 )
  336.                  {   
  337.                     for(j=0;j<5;j++)
  338.                        {
  339.                         ysmima[j]=mima[j];
  340.                        }
  341.                      status = 13;
  342.                  }  
  343.                    break;
  344.              case 13:               //开始第二次输入新密码,并和第一次的对比
  345.                  if (read_key_driver() ==1 )
  346.                  {   
  347.                     for(j=0;j<5;j++)           //密码对比识别
  348.                     {
  349.                        if (mima[j]==ysmima[j])
  350.                        {
  351.                         cnt++;
  352.                        }
  353.                     }
  354.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 14;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  355.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  356.                  }  
  357.                    break;
  358.                case 14:               //开始第三次输入新密码,并和第一次的对比
  359.                  if (read_key_driver() ==1 )
  360.                  {   
  361.                     for(j=0;j<5;j++)           //密码对比识别
  362.                     {
  363.                        if (mima[j]==ysmima[j])
  364.                        {
  365.                         cnt++;
  366.                        }
  367.                     }
  368.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 15;shucuo=0;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  369.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  370.                  }  
  371.                    break;               
  372.                        
  373.                 case 15:        //第三次输对新密码后,开始记录                                                        
  374.                     PORTB = 0x00;     //全亮灯密码进入记录阶段
  375.                     for(j=0;j<5;j++)           //写入新设置密码
  376.                     {
  377.                        #asm("cli")                     
  378.                        while(EECR &(1 <<EEWE));
  379.                        EEAR = j+10;
  380.                        EEDR = mima[j];
  381.                        EECR |=(1 <<EEMWE);
  382.                        EECR |=(1 <<EEWE);
  383.                         ysmima[j] =  mima[j]; //密码立即生效
  384.                        simiao_ok=0;
  385.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  386.                        delay_ms(10);
  387.                        #asm("sei")                       
  388.                         
  389.                     }                  
  390.                     status = 0;                                       
  391.                 break;
  392.                 case 16:
  393.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  394.                    {
  395.                     for(j=0;j<5;j++)           //读出原密码继续使用
  396.                     {
  397.                       #asm("cli")
  398.                       while(EECR &(1 <<EEWE));
  399.                       EEAR = j+10;
  400.                       EECR |=(1<<EERE);
  401.                       ysmima[j]=EEDR;
  402.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  403.                       delay_ms(10);
  404.                       #asm("sei")
  405.                     }
  406.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  407.                     PORTB ^= 1<<4;  //某行动
  408.                     status = 0;
  409.                    }
  410.                   else status = 12;   
  411.                 break;               
  412.          }   
  413.          if (simiao_ok)         //4秒无动作后休眠
  414.          {
  415.           qingling();    //清零
  416.           TIMSK = 0x00;   //关T/C0比较匹配中断
  417.           PORTB ^= 1<<5;       //休眠监测
  418.            //WDTCR=0x18;        //关看门狗
  419.            //WDTCR=0x00;
  420.             WDTCR=(1<<WDTOE)|(1<<WDE);
  421.             WDTCR=(0<<WDE);
  422.            PORTB = 0xFF;     //进入休眠前关所有灯
  423.            GICR = 0x40;   //使能INT0中断
  424.            MCUCR = 0x60; // 睡眠使能,掉电模式
  425.            
  426.            //MCUCSR=(1<<JTD);
  427.            //MCUCSR=(1<<JTD);
  428.            
  429.          
  430.            DDRB = 0x00;
  431.             
  432.           #asm("sleep")      //休眠
  433.           PORTB ^= 1<<6;     //唤醒后监测
  434.          }
  435.         #asm("WDR")   //喂狗
  436.         shangdeng(); //扫描闪灯
  437.          PORTD = 0x7F;                  //恢复端口检测
  438.          DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  439.     }
  440. }

  441. interrupt[EXT_INT0]void ext_int0_isr(void)
  442.   {
  443.    PORTB = 0xFF;
  444.    DDRB = 0xFF;
  445.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  446.    simiao_counter=0;
  447.    PORTB ^= 1<<7;     //中断唤醒监测
  448.    GICR = 0x00;   //禁用INT0中断
  449.     WDTCR=0x08;        //开看门狗约为4s
  450.     WDTCR=0x28;
  451.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  452.   }
复制代码
 楼主| 发表于 2014-4-22 10:54:16 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-22 12:15 编辑

奇怪,为什么开机(包括开机没动休眠后)第一次快速的按动开关,LED灯可以跟随闪动,等再数第二位密码的时候,如果按得快,LED灯闪动就跟不上了呢?到底是程序拖满了它?闪动跟不上,但是实际按动的次数是对的。如何把192行去掉,就正常了,但是不能单独设关灯时间了,程序里其它地方只要有更改过guangdengtime 值的地方,就会出现单击的时候不跟随,也就是单击里的guangdengtime = 0;    //设置关灯时间不生效,
 楼主| 发表于 2014-4-22 12:17:11 | 显示全部楼层
找到原因了,原来是119行里漏输一行:guangdengtime = 0;    //设置关灯时间
 楼主| 发表于 2014-4-22 13:00:47 | 显示全部楼层
现在遇到一个问题:在按键灯长亮的时候,如果我此时短按输入密码,那么第一个按键指示灯看起来没反应,因为此时灯是长亮的,程序应该执行先关长亮灯,延时一会,然后再调用短按闪灯
 楼主| 发表于 2014-4-23 18:40:11 | 显示全部楼层
奇怪,怎么修改这里后,按键就没有反应了呢?只有把PD.2直接对地才行,改回程序后也不行,换芯片也不行,真的是见鬼了。

  1. if (simiao_ok)         //4秒无动作后休眠
  2.          {
  3.           qingling();    //清零
  4.           TIMSK = 0x00;   //关T/C0比较匹配中断
  5.           //PORTB ^= 1<<5;       //休眠监测
  6.            //WDTCR=0x18;        //关看门狗
  7.            //WDTCR=0x00;
  8.             WDTCR=(1<<WDTOE)|(1<<WDE);
  9.             WDTCR=(0<<WDE);
  10.            
  11.            GICR = 0x40;   //使能INT0中断
  12.            MCUCR = 0x60; // 睡眠使能,掉电模式
  13.            
  14.            //MCUCSR=(1<<JTD);
  15.            //MCUCSR=(1<<JTD);
  16.            
  17.          
  18.            PORTA=0xFF;
  19.            DDRA=0x00;
  20.            PORTB = 0xFF;
  21.            DDRB = 0x00;
  22.            PORTC=0xFF;
  23.            DDRC=0x00;
  24.            PORTD = 0x7F;
  25.            DDRD = 0x80;                   // PD7为输出方式,默认输出低电平   
  26.             
  27.           #asm("sleep")      //休眠
  28.           PORTB ^= 1<<6;     //唤醒后监测
  29.          }
复制代码
 楼主| 发表于 2014-4-24 10:10:09 | 显示全部楼层
解决,把G区接PD.2的按键取了就正常了,因为那里是上拉5V的,我记着是没动过那里呢,看来以后出问题得拍照电路板先。
 楼主| 发表于 2014-4-25 03:15:16 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-4-25 03:26 编辑

LED闪灯程序改进了,此时长亮灯时短按可以看到灯闪了,编得真是费劲啊
同时把恢复初始密码的方法改为上电拉低后恢复

  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,kaidengduibi; //第一次开关未完成时,第二次开灯指令的识别
  15. unsigned int shangdengtime,guangdengtime;   //闪灯开的时间,闪灯关的时间
  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=1,kaidengbiaozhi;
  61.      static unsigned int i,j,h;
  62.      if(shangdengcishu >0)  //闪灯次数  类似倒计时程序
  63.         {
  64.           if(kaidengduibi==1)    //开灯比对,有新的开灯指令时为1
  65.           {
  66.             status=0;
  67.           }
  68.           switch (status)
  69.           {
  70.             case 0:
  71.               kaidengduibi=0;    //开灯对比,对比结束
  72.               if(kaidengbiaozhi == 1) //上一次开灯程序未完成标志
  73.               {
  74.                if (++h >= 3000-j)   //按键关灯时间,实现第一次正在开灯,或者正在关灯时,若第二次开灯指令就来了,就先执行关灯
  75.                {
  76.                  j=0;
  77.                  h=0;
  78.                  status=1;
  79.                  i=0;  
  80.                                                    
  81.                }
  82.               }               
  83.               else status=1;
  84.               break;
  85.             case 1:
  86.               qingling();    //清零
  87.               PORTD |=( 1<<7);   //PD7输出高
  88.               PORTD &=~( 1<<2);  //INT0拉低
  89.               DDRD = 0xFF;
  90.               kaidengbiaozhi=1;  //开灯标志,表示开灯任务开始
  91.               PORTD = 0x7F;                  //恢复端口检测
  92.               DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  93.               if (++i >= shangdengtime)   //按键开灯时间
  94.               {
  95.                status=2;
  96.                i=0;
  97.               }            
  98.               break;
  99.             case 2:
  100.               if (++j >= guangdengtime)   //按键关灯时间
  101.                {
  102.                  j=0;
  103.                  status=0;
  104.                  --shangdengcishu ;
  105.                 // kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了                 
  106.                 }
  107.               if(i==3000)  //灭灯时间达到设定值时,把开关标志清零,也就是可以再次接受新的开灯指令了,这样再开灯时就能及时看到亮灯
  108.                {
  109.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了  
  110.                }
  111.               break;
  112.           }              
  113.         }
  114.    }
  115.   
  116. unsigned char read_key_n(void)
  117.   {
  118.     static unsigned char key_state = 0, key_time = 0;
  119.     unsigned char key_press, key_return = 0;
  120.    
  121.     key_press = key_input;                // 读按键I/O电平
  122.     switch (key_state)
  123.       {
  124.         case key_state_0:                // 按键初始态
  125.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  126.             break;
  127.         case key_state_1:                // 按键确认态
  128.             if (!key_press)
  129.             {
  130.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  131.                 key_time = 0;                // 清另按键时间计数器
  132.             }
  133.             else
  134.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  135.             break;
  136.         case key_state_2:
  137.             if (key_press)
  138.             {
  139.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  140.                 key_return = 1;            // 输出"1" ,表示单击
  141.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键成功短按一次
  142.                 shangdengtime = 1500;    //设置闪灯时间
  143.                 guangdengtime = 0;    //设置关灯时间
  144.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  145.                 if (++mimajishu >9)
  146.                  {
  147.                     mimajishu = 0;  
  148.                  }              
  149.             }
  150.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  151.             {
  152.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  153.                 key_time = 0;                // 清按键计数器  
  154.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  155.                 shangdengtime = 1500;    //设置闪灯时间
  156.                 guangdengtime = 0;    //设置关灯时间
  157.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  158.             }  
  159.               qingling();    //清零
  160.             break;
  161.         case key_state_3:
  162.              if (key_press)
  163.             {
  164.               
  165.               key_state = key_state_0; //按键已释放,转换到按键初始态
  166.               cabz = 1;      //长按标志
  167.               PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  168.               key_return = 2;            // 长按超过1秒后输出"2" ,
  169.             }   
  170.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  171.             {
  172.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  173.                 key_time = 0;                // 清按键计数器  
  174.                 key_return = 3;         //长按2秒,进入设置界面
  175.                 PORTB ^= 1<<1;
  176.                 shangdengcishu = 3;    //开长闪灯
  177.                 shangdengtime = 65000;    //设置长闪灯时间
  178.                 guangdengtime = 0;    //设置关灯时间
  179.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  180.             }
  181.             qingling();    //清零   
  182.              break;
  183.         case key_state_4:
  184.             if (key_press)
  185.             {
  186.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  187.             }   
  188.             qingling();    //清零
  189.             break;
  190.      
  191.       }   
  192.     return key_return;
  193.   }  

  194.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  195.    {
  196.      static unsigned char i = 0,aj_state = 0;
  197.      unsigned char key_return = 0;
  198.      #asm("WDR")   //喂狗
  199.      if (key_stime_ok)                // 10ms到,键处理
  200.      {
  201.         key_stime_ok = 0;
  202.         read_key_n();
  203.        switch (aj_state)
  204.        {
  205.         case 0:               
  206.             if (ermiao_ok)
  207.            {
  208.                if(i < 5)    //密码位数设置
  209.                {
  210.                  mima[i] = mimajishu;  //记录第一位密码
  211.                  mimajishu =0;
  212.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  213.                  aj_state = 1;
  214.                  qingling();    //清零
  215.                  i=++i;                  
  216.                  shangdengcishu = i;    //开短闪灯标示刚才输入一位密码成功
  217.                  shangdengtime = 3000;    //设置闪灯时间   
  218.                  guangdengtime = 8000;    //设置关灯时间
  219.                  kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果   
  220.                }   
  221.            }
  222.             break;
  223.         case 1:               
  224.             if (i == 5)  //密码识别位数确认 ,闪2次标示密码输完
  225.             {   
  226.                 i=0;
  227.                 aj_state = 0;
  228.                 key_return = 1;
  229.             }
  230.             else
  231.                  aj_state = 0;   
  232.             break;
  233.        }
  234.         return key_return;
  235.      }
  236.    }
  237.            
  238.   
  239.    
  240. void main(void)
  241. {
  242.     PORTA=0xFF;
  243.     DDRA=0x00;
  244.     PORTB = 0xFF;
  245.     DDRB = 0xFF;
  246.     PORTC=0xFF;
  247.     DDRC=0x00;
  248.     PORTD = 0x7F;
  249.     DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  250.     delay_ms(100);  
  251.     /*上电恢复初始密码*/
  252.     PORTD |=( 1<<7);   //PD7输出高
  253.                   DDRD &=~( 1<<7);  //PD7设置成输入  
  254.                  if(PIND.7 == 0)    //若PD7拉低就把密码恢复出厂设置
  255.                   {
  256.                     shangdengcishu = 5;    //开短闪灯标示刚才输入一位密码成功
  257.                     shangdengtime = 15000;    //设置闪灯时间
  258.                     guangdengtime = 10000;    //设置关灯时间
  259.                     kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  260.                     for(j=0;j<5;j++)           //写入新设置密码
  261.                     {
  262.                        #asm("cli")                     
  263.                        while(EECR &(1 <<EEWE));
  264.                        EEAR = j+10;
  265.                        EEDR = huifu[j]; //恢复默认密码
  266.                        EECR |=(1 <<EEMWE);
  267.                        EECR |=(1 <<EEWE);
  268.                         ysmima[j] =  huifu[j]; //密码立即生效
  269.                        simiao_ok=0;
  270.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  271.                        delay_ms(10);
  272.                        #asm("sei")                    
  273.                     }
  274.                     delay_ms(5000);
  275.                                     
  276.                   }
  277.                   PORTD = 0x7F;
  278.                   DDRD = 0x80;                    // PD7为输出方式,默认输出低电平  
  279.       
  280.      #asm("cli")
  281.       #asm("sei")
  282.      
  283.     for(j=0;j<5;j++)           //读出原密码
  284.     {
  285.     while(EECR &(1 <<EEWE));
  286.     EEAR = j+10;
  287.     EECR |=(1<<EERE);
  288.     ysmima[j]=EEDR;
  289.     delay_ms(10);
  290.     }
  291.   #asm("cli")   
  292. ADCSRA=0x00;
  293. TWCR=0x00;
  294. SPCR=0x00;
  295. ACSR=0x80;
  296. SFIOR=0x00;
  297. UCSRB=0x00;
  298. ACSR=(1<<ACD);

  299.     // T/C0 初始化
  300.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  301.     TCNT0 = 0x00;
  302.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  303.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  304.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  305.      
  306.     #asm("cli")
  307.     #asm("WDR")   
  308.    WDTCR=0x08;        //看门狗约为16.3ms
  309.    WDTCR=0x28;
  310.     #asm("sei")            // 开放全局中断
  311.    
  312.             
  313.     while (1)
  314.     {         
  315.         switch (status)
  316.        {     
  317.              case 0:
  318.              if (key_stime_ok)                // 10ms到,键处理
  319.             {  
  320.                 key_stime_ok = 0;
  321.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码输入处理部分
  322.                  {
  323.                      status = 1;
  324.                  }
  325.                  if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  326.                   {
  327.                      status = 11;                  
  328.                   }
  329.                   
  330.             }
  331.                 break;
  332.              case 1:
  333.                if (read_key_driver() ==1 )
  334.             {  
  335.                 qingling();    //清零
  336.                      for(j=0;j<5;j++)           //密码对比识别
  337.                     {
  338.                        if (mima[j]==ysmima[j])
  339.                        {
  340.                         cnt++;
  341.                        }
  342.                     }
  343.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  344.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  345.             }
  346.                 break;
  347.              case 2:
  348.                    if(shucuo==3)      //输错3次就执行某行动
  349.                    {
  350.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  351.                     PORTB ^= 1<<4;  //某行动
  352.                     status = 0;
  353.                    }
  354.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  355.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  356.              case 11:         //密码设置第一步:输入原密码,正确后闪烁3次,然后开始设置新密码
  357.                if (read_key_driver() ==1 )
  358.             {  
  359.                 qingling();    //清零
  360.                      for(j=0;j<5;j++)           //密码对比识别
  361.                     {
  362.                        if (mima[j]==ysmima[j])
  363.                        {
  364.                         cnt++;
  365.                        }
  366.                     }
  367.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 12;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  368.                     else  {status = 0;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  369.             }
  370.                 break;                     
  371.              case 12:               //老密码输入对,开始第一次输入新密码
  372.                  if (read_key_driver() ==1 )
  373.                  {   
  374.                     for(j=0;j<5;j++)
  375.                        {
  376.                         ysmima[j]=mima[j];
  377.                        }
  378.                      status = 13;
  379.                  }  
  380.                    break;
  381.              case 13:               //开始第二次输入新密码,并和第一次的对比
  382.                  if (read_key_driver() ==1 )
  383.                  {   
  384.                     for(j=0;j<5;j++)           //密码对比识别
  385.                     {
  386.                        if (mima[j]==ysmima[j])
  387.                        {
  388.                         cnt++;
  389.                        }
  390.                     }
  391.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 14;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  392.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  393.                  }  
  394.                    break;
  395.                case 14:               //开始第三次输入新密码,并和第一次的对比
  396.                  if (read_key_driver() ==1 )
  397.                  {   
  398.                     for(j=0;j<5;j++)           //密码对比识别
  399.                     {
  400.                        if (mima[j]==ysmima[j])
  401.                        {
  402.                         cnt++;
  403.                        }
  404.                     }
  405.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 15;shucuo=0;shangdengcishu = 3;shangdengtime = 50000;guangdengtime = 10000;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  406.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  407.                  }  
  408.                    break;               
  409.                        
  410.                 case 15:        //第三次输对新密码后,开始记录                                                        
  411.                     PORTB = 0x00;     //全亮灯密码进入记录阶段
  412.                     for(j=0;j<5;j++)           //写入新设置密码
  413.                     {
  414.                        #asm("cli")                     
  415.                        while(EECR &(1 <<EEWE));
  416.                        EEAR = j+10;
  417.                        EEDR = mima[j];
  418.                        EECR |=(1 <<EEMWE);
  419.                        EECR |=(1 <<EEWE);
  420.                         ysmima[j] =  mima[j]; //密码立即生效
  421.                        simiao_ok=0;
  422.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  423.                        delay_ms(10);
  424.                        #asm("sei")                       
  425.                         
  426.                     }                  
  427.                     status = 0;                                       
  428.                 break;
  429.                 case 16:
  430.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  431.                    {
  432.                     for(j=0;j<5;j++)           //读出原密码继续使用
  433.                     {
  434.                       #asm("cli")
  435.                       while(EECR &(1 <<EEWE));
  436.                       EEAR = j+10;
  437.                       EECR |=(1<<EERE);
  438.                       ysmima[j]=EEDR;
  439.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  440.                       delay_ms(10);
  441.                       #asm("sei")
  442.                     }
  443.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  444.                     PORTB ^= 1<<4;  //某行动
  445.                     status = 0;
  446.                    }
  447.                   else status = 12;   
  448.                 break;               
  449.          }   
  450.          if (simiao_ok)         //4秒无动作后休眠
  451.          {
  452.           qingling();    //清零
  453.           TIMSK = 0x00;   //关T/C0比较匹配中断
  454.           PORTB ^= 1<<5;       //休眠监测
  455.            //WDTCR=0x18;        //关看门狗
  456.            //WDTCR=0x00;
  457.             WDTCR=(1<<WDTOE)|(1<<WDE);
  458.             WDTCR=(0<<WDE);
  459.            PORTB = 0xFF;     //进入休眠前关所有灯
  460.            GICR = 0x40;   //使能INT0中断
  461.            MCUCR = 0x60; // 睡眠使能,掉电模式
  462.            
  463.            //MCUCSR=(1<<JTD);
  464.            //MCUCSR=(1<<JTD);
  465.            
  466.          
  467.            PORTA=0xFF;
  468.            DDRA=0x00;
  469.            PORTB = 0xFF;
  470.            DDRB = 0x00;
  471.            PORTC=0xFF;
  472.            DDRC=0x00;
  473.            //PORTD = 0xFF;
  474.            //DDRD = 0x00;  
  475.             
  476.           #asm("sleep")      //休眠
  477.           PORTB ^= 1<<6;     //唤醒后监测
  478.          }
  479.         #asm("WDR")   //喂狗
  480.         shangdeng(); //扫描闪灯
  481.          
  482.     }
  483. }

  484. interrupt[EXT_INT0]void ext_int0_isr(void)
  485.   {
  486.    PORTB = 0xFF;
  487.    DDRB = 0xFF;
  488.    //PORTD = 0x7F;
  489.    //DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  490.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  491.    simiao_counter=0;
  492.    PORTB ^= 1<<7;     //中断唤醒监测
  493.    GICR = 0x00;   //禁用INT0中断
  494.     WDTCR=0x08;        //开看门狗约为4s
  495.     WDTCR=0x28;
  496.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  497.   }
复制代码
 楼主| 发表于 2014-4-25 08:55:42 | 显示全部楼层
仿真时发现短按闪灯有延迟,再看代码,发现109行和111行有错误,改为以下后正常

  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,kaidengduibi; //第一次开关未完成时,第二次开灯指令的识别
  15. unsigned int shangdengtime,guangdengtime;   //闪灯开的时间,闪灯关的时间
  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=1,kaidengbiaozhi;
  61.      static unsigned int i,j,h;
  62.      if(shangdengcishu >0)  //闪灯次数  类似倒计时程序
  63.         {
  64.           if(kaidengduibi==1)    //开灯比对,有新的开灯指令时为1
  65.           {
  66.             status=0;
  67.           }
  68.           switch (status)
  69.           {
  70.             case 0:
  71.               kaidengduibi=0;    //开灯对比,对比结束
  72.               if(kaidengbiaozhi == 1) //上一次开灯程序未完成标志
  73.               {
  74.                if (++h >= 3000-j)   //按键关灯时间,实现第一次正在开灯,或者正在关灯时,若第二次开灯指令就来了,就先执行关灯
  75.                {
  76.                  j=0;
  77.                  h=0;
  78.                  status=1;
  79.                  i=0;  
  80.                                                    
  81.                }
  82.               }               
  83.               else status=1;
  84.               break;
  85.             case 1:
  86.               qingling();    //清零
  87.               PORTD |=( 1<<7);   //PD7输出高
  88.               PORTD &=~( 1<<2);  //INT0拉低
  89.               DDRD = 0xFF;
  90.               kaidengbiaozhi=1;  //开灯标志,表示开灯任务开始
  91.               PORTD = 0x7F;                  //恢复端口检测
  92.               DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  93.               if (++i >= shangdengtime)   //按键开灯时间
  94.               {
  95.                status=2;
  96.                i=0;
  97.               }            
  98.               break;
  99.             case 2:
  100.               if (++j >= guangdengtime)   //按键关灯时间
  101.                {
  102.                  j=0;
  103.                  status=0;
  104.                  --shangdengcishu ;
  105.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了                 
  106.                 }
  107.               if(j>=3000)  //灭灯时间达到设定值时,把开关标志清零,也就是可以再次接受新的开灯指令了,这样再开灯时就能及时看到亮灯
  108.                {
  109.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了  
  110.                }
  111.               break;
  112.           }              
  113.         }
  114.    }
  115.   
  116. unsigned char read_key_n(void)
  117.   {
  118.     static unsigned char key_state = 0, key_time = 0;
  119.     unsigned char key_press, key_return = 0;
  120.    
  121.     key_press = key_input;                // 读按键I/O电平
  122.     switch (key_state)
  123.       {
  124.         case key_state_0:                // 按键初始态
  125.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  126.             break;
  127.         case key_state_1:                // 按键确认态
  128.             if (!key_press)
  129.             {
  130.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  131.                 key_time = 0;                // 清另按键时间计数器
  132.             }
  133.             else
  134.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  135.             break;
  136.         case key_state_2:
  137.             if (key_press)
  138.             {
  139.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  140.                 key_return = 1;            // 输出"1" ,表示单击
  141.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键成功短按一次
  142.                 shangdengtime = 1500;    //设置闪灯时间
  143.                 guangdengtime = 0;    //设置关灯时间
  144.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  145.                 if (++mimajishu >9)
  146.                  {
  147.                     mimajishu = 0;  
  148.                  }              
  149.             }
  150.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  151.             {
  152.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  153.                 key_time = 0;                // 清按键计数器  
  154.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  155.                 shangdengtime = 1500;    //设置闪灯时间
  156.                 guangdengtime = 0;    //设置关灯时间
  157.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  158.             }  
  159.               qingling();    //清零
  160.             break;
  161.         case key_state_3:
  162.              if (key_press)
  163.             {
  164.               
  165.               key_state = key_state_0; //按键已释放,转换到按键初始态
  166.               cabz = 1;      //长按标志
  167.               PORTB ^= 1<<0;  //PORTB = 0xFE;    //PB0拉低,关门
  168.               key_return = 2;            // 长按超过1秒后输出"2" ,
  169.             }   
  170.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  171.             {
  172.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  173.                 key_time = 0;                // 清按键计数器  
  174.                 key_return = 3;         //长按2秒,进入设置界面
  175.                 PORTB ^= 1<<1;
  176.                 shangdengcishu = 3;    //开长闪灯
  177.                 shangdengtime = 65000;    //设置长闪灯时间
  178.                 guangdengtime = 0;    //设置关灯时间
  179.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  180.             }
  181.             qingling();    //清零   
  182.              break;
  183.         case key_state_4:
  184.             if (key_press)
  185.             {
  186.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  187.             }   
  188.             qingling();    //清零
  189.             break;
  190.      
  191.       }   
  192.     return key_return;
  193.   }  

  194.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  195.    {
  196.      static unsigned char i = 0,aj_state = 0;
  197.      unsigned char key_return = 0;
  198.      #asm("WDR")   //喂狗
  199.      if (key_stime_ok)                // 10ms到,键处理
  200.      {
  201.         key_stime_ok = 0;
  202.         read_key_n();
  203.        switch (aj_state)
  204.        {
  205.         case 0:               
  206.             if (ermiao_ok)
  207.            {
  208.                if(i < 5)    //密码位数设置
  209.                {
  210.                  mima[i] = mimajishu;  //记录第一位密码
  211.                  mimajishu =0;
  212.                  PORTB ^= 1<<2;   //PORTB = 0xFD; //执行开门,PB1拉低     观察第一位密码识别
  213.                  aj_state = 1;
  214.                  qingling();    //清零
  215.                  i=++i;                  
  216.                  shangdengcishu = i;    //开短闪灯标示刚才输入一位密码成功
  217.                  shangdengtime = 3000;    //设置闪灯时间   
  218.                  guangdengtime = 8000;    //设置关灯时间
  219.                  kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果   
  220.                }   
  221.            }
  222.             break;
  223.         case 1:               
  224.             if (i == 5)  //密码识别位数确认 ,闪2次标示密码输完
  225.             {   
  226.                 i=0;
  227.                 aj_state = 0;
  228.                 key_return = 1;
  229.             }
  230.             else
  231.                  aj_state = 0;   
  232.             break;
  233.        }
  234.         return key_return;
  235.      }
  236.    }
  237.            
  238.   
  239.    
  240. void main(void)
  241. {
  242.     PORTA=0xFF;
  243.     DDRA=0x00;
  244.     PORTB = 0xFF;
  245.     DDRB = 0xFF;
  246.     PORTC=0xFF;
  247.     DDRC=0x00;
  248.     PORTD = 0x7F;
  249.     DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  250.     delay_ms(100);  
  251.     /*上电恢复初始密码*/
  252.     PORTD |=( 1<<7);   //PD7输出高
  253.                   DDRD &=~( 1<<7);  //PD7设置成输入  
  254.                  if(PIND.7 == 0)    //若PD7拉低就把密码恢复出厂设置
  255.                   {
  256.                     shangdengcishu = 5;    //开短闪灯标示刚才输入一位密码成功
  257.                     shangdengtime = 15000;    //设置闪灯时间
  258.                     guangdengtime = 10000;    //设置关灯时间
  259.                     kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  260.                     for(j=0;j<5;j++)           //写入新设置密码
  261.                     {
  262.                        #asm("cli")                     
  263.                        while(EECR &(1 <<EEWE));
  264.                        EEAR = j+10;
  265.                        EEDR = huifu[j]; //恢复默认密码
  266.                        EECR |=(1 <<EEMWE);
  267.                        EECR |=(1 <<EEWE);
  268.                         ysmima[j] =  huifu[j]; //密码立即生效
  269.                        simiao_ok=0;
  270.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  271.                        delay_ms(10);
  272.                        #asm("sei")                    
  273.                     }
  274.                     delay_ms(5000);
  275.                                     
  276.                   }
  277.                   PORTD = 0x7F;
  278.                   DDRD = 0x80;                    // PD7为输出方式,默认输出低电平  
  279.       
  280.      #asm("cli")
  281.       #asm("sei")
  282.      
  283.     for(j=0;j<5;j++)           //读出原密码
  284.     {
  285.     while(EECR &(1 <<EEWE));
  286.     EEAR = j+10;
  287.     EECR |=(1<<EERE);
  288.     ysmima[j]=EEDR;
  289.     delay_ms(10);
  290.     }
  291.   #asm("cli")   
  292. ADCSRA=0x00;
  293. TWCR=0x00;
  294. SPCR=0x00;
  295. ACSR=0x80;
  296. SFIOR=0x00;
  297. UCSRB=0x00;
  298. ACSR=(1<<ACD);

  299.     // T/C0 初始化
  300.     TCCR0 = 0x0B;            // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
  301.     TCNT0 = 0x00;
  302.     OCR0 = 0x7C;            // OCR0 = 0x7C(124),(124+1)/62.5=2ms
  303.     TIMSK = 0x02;            // 允许T/C0比较匹配中断
  304.     //mima[1] = 0; mima[0] = 0;    // 设输入密码初值00     
  305.      
  306.     #asm("cli")
  307.     #asm("WDR")   
  308.    WDTCR=0x08;        //看门狗约为16.3ms
  309.    WDTCR=0x28;
  310.     #asm("sei")            // 开放全局中断
  311.    
  312.             
  313.     while (1)
  314.     {         
  315.         switch (status)
  316.        {     
  317.              case 0:
  318.              if (key_stime_ok)                // 10ms到,键处理
  319.             {  
  320.                 key_stime_ok = 0;
  321.                 if (read_key_n() == 1)   //不断扫描按键,如果有长按就关门,若有短按就装到密码输入处理部分
  322.                  {
  323.                      status = 1;
  324.                  }
  325.                  if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  326.                   {
  327.                      status = 11;                  
  328.                   }
  329.                   
  330.             }
  331.                 break;
  332.              case 1:
  333.                if (read_key_driver() ==1 )
  334.             {  
  335.                 qingling();    //清零
  336.                      for(j=0;j<5;j++)           //密码对比识别
  337.                     {
  338.                        if (mima[j]==ysmima[j])
  339.                        {
  340.                         cnt++;
  341.                        }
  342.                     }
  343.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 0;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  344.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  345.             }
  346.                 break;
  347.              case 2:
  348.                    if(shucuo==3)      //输错3次就执行某行动
  349.                    {
  350.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  351.                     PORTB ^= 1<<4;  //某行动
  352.                     status = 0;
  353.                    }
  354.                   else status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  355.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  356.              case 11:         //密码设置第一步:输入原密码,正确后闪烁3次,然后开始设置新密码
  357.                if (read_key_driver() ==1 )
  358.             {  
  359.                 qingling();    //清零
  360.                      for(j=0;j<5;j++)           //密码对比识别
  361.                     {
  362.                        if (mima[j]==ysmima[j])
  363.                        {
  364.                         cnt++;
  365.                        }
  366.                     }
  367.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 12;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  368.                     else  {status = 0;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  369.             }
  370.                 break;                     
  371.              case 12:               //老密码输入对,开始第一次输入新密码
  372.                  if (read_key_driver() ==1 )
  373.                  {   
  374.                     for(j=0;j<5;j++)
  375.                        {
  376.                         ysmima[j]=mima[j];
  377.                        }
  378.                      status = 13;
  379.                  }  
  380.                    break;
  381.              case 13:               //开始第二次输入新密码,并和第一次的对比
  382.                  if (read_key_driver() ==1 )
  383.                  {   
  384.                     for(j=0;j<5;j++)           //密码对比识别
  385.                     {
  386.                        if (mima[j]==ysmima[j])
  387.                        {
  388.                         cnt++;
  389.                        }
  390.                     }
  391.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 14;shucuo=0;shangdengcishu = 1;shangdengtime = 50000;guangdengtime = 0;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  392.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  393.                  }  
  394.                    break;
  395.                case 14:               //开始第三次输入新密码,并和第一次的对比
  396.                  if (read_key_driver() ==1 )
  397.                  {   
  398.                     for(j=0;j<5;j++)           //密码对比识别
  399.                     {
  400.                        if (mima[j]==ysmima[j])
  401.                        {
  402.                         cnt++;
  403.                        }
  404.                     }
  405.                     if (cnt==5){cnt=0;PORTB ^= 1<<3;status = 15;shucuo=0;shangdengcishu = 3;shangdengtime = 50000;guangdengtime = 10000;kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/}        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  406.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  407.                  }  
  408.                    break;               
  409.                        
  410.                 case 15:        //第三次输对新密码后,开始记录                                                        
  411.                     PORTB = 0x00;     //全亮灯密码进入记录阶段
  412.                     for(j=0;j<5;j++)           //写入新设置密码
  413.                     {
  414.                        #asm("cli")                     
  415.                        while(EECR &(1 <<EEWE));
  416.                        EEAR = j+10;
  417.                        EEDR = mima[j];
  418.                        EECR |=(1 <<EEMWE);
  419.                        EECR |=(1 <<EEWE);
  420.                         ysmima[j] =  mima[j]; //密码立即生效
  421.                        simiao_ok=0;
  422.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  423.                        delay_ms(10);
  424.                        #asm("sei")                       
  425.                         
  426.                     }                  
  427.                     status = 0;                                       
  428.                 break;
  429.                 case 16:
  430.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  431.                    {
  432.                     for(j=0;j<5;j++)           //读出原密码继续使用
  433.                     {
  434.                       #asm("cli")
  435.                       while(EECR &(1 <<EEWE));
  436.                       EEAR = j+10;
  437.                       EECR |=(1<<EERE);
  438.                       ysmima[j]=EEDR;
  439.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  440.                       delay_ms(10);
  441.                       #asm("sei")
  442.                     }
  443.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  444.                     PORTB ^= 1<<4;  //某行动
  445.                     status = 0;
  446.                    }
  447.                   else status = 12;   
  448.                 break;               
  449.          }   
  450.          if (simiao_ok)         //4秒无动作后休眠
  451.          {
  452.           qingling();    //清零
  453.           TIMSK = 0x00;   //关T/C0比较匹配中断
  454.           PORTB ^= 1<<5;       //休眠监测
  455.            //WDTCR=0x18;        //关看门狗
  456.            //WDTCR=0x00;
  457.             WDTCR=(1<<WDTOE)|(1<<WDE);
  458.             WDTCR=(0<<WDE);
  459.            PORTB = 0xFF;     //进入休眠前关所有灯
  460.            GICR = 0x40;   //使能INT0中断
  461.            MCUCR = 0x60; // 睡眠使能,掉电模式
  462.            
  463.            //MCUCSR=(1<<JTD);
  464.            //MCUCSR=(1<<JTD);
  465.            
  466.          
  467.            PORTA=0xFF;
  468.            DDRA=0x00;
  469.            PORTB = 0xFF;
  470.            DDRB = 0x00;
  471.            PORTC=0xFF;
  472.            DDRC=0x00;
  473.            //PORTD = 0xFF;
  474.            //DDRD = 0x00;  
  475.             
  476.           #asm("sleep")      //休眠
  477.           PORTB ^= 1<<6;     //唤醒后监测
  478.          }
  479.         #asm("WDR")   //喂狗
  480.         shangdeng(); //扫描闪灯
  481.          
  482.     }
  483. }

  484. interrupt[EXT_INT0]void ext_int0_isr(void)
  485.   {
  486.    PORTB = 0xFF;
  487.    DDRB = 0xFF;
  488.    //PORTD = 0x7F;
  489.    //DDRD = 0x80;                    // PD7为输出方式,默认输出低电平
  490.    TIMSK = 0x02;     // 允许T/C0比较匹配中断
  491.    simiao_counter=0;
  492.    PORTB ^= 1<<7;     //中断唤醒监测
  493.    GICR = 0x00;   //禁用INT0中断
  494.     WDTCR=0x08;        //开看门狗约为4s
  495.     WDTCR=0x28;
  496.     MCUCR = 0x00; // 禁止睡眠使能,在需要休眠时再打开0
  497.   }
复制代码
 楼主| 发表于 2014-4-28 16:14:43 | 显示全部楼层
发现一个现像:这种是能通过编译的/*......*/,但这种就不行/*.../*......*/...*/,也就是注释里再注释就不行了
 楼主| 发表于 2014-5-2 03:19:30 | 显示全部楼层
从官网手册中拷贝过来的代码编译出错



在查了2个多小时后,终于发现是手册里少了个分号



说明我还是不够仔细。

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-4 10:05:05 | 显示全部楼层
为什么这样可以休眠后唤醒:
  1. if (ershimiao_ok)         //20秒无动作后休眠
  2.          {
  3.           shucuo=0;  //2次输错密码,若没有再输入密码,进入休眠就清除记录
  4.           qingling();    //清零
  5.           //PORTB = 11100110;   //11100110进入休眠前关所有灯
  6.           //DDRB = 00100001;  //00100001,PB.0和5配置为输出,其它位为输入
  7.           PORTB |=( 1<<1);   //置位
  8.           PORTB &=~( 1<<0);  //清零
  9.           DDRB = 0x39;
  10.           TIMSK = 0x00;   //关闭T/C0比较匹配中断  
  11.           /*关闭看门狗省电*/
  12.           //#asm("cli") //关闭全局中断
  13.           #asm("WDR")   //喂狗
  14.           //MCUSR = 0x00;           
  15.           //WDTCR |= (1<<WDCE) | (1<<WDE);           
  16.           //WDTCR = 0x00;
  17.           MCUSR &= ~(1<<WDRF);
  18.           WDTCR |= (1<<WDCE) | (1<<WDE);
  19.           WDTCR &= ~(1<<WDE);
  20.           #asm("sei")  // 开放全局中断
  21.           /*使能INT0中断*/
  22.           GIMSK=0x40;
  23.           MCUCR=0x00;
  24.           GIFR=0x40;                     
  25.           MCUCR |= (1<<SM1) | (0<<SM0);  // 掉电模式
  26.           MCUCR |= (1<<SE);   //睡眠使能
  27.           #asm("sleep")      //休眠
  28.           PORTB ^= 1<<5;     //唤醒后监测
  29.          }
  30.         #asm("WDR")   //喂狗
  31.         shangdeng(); //扫描闪灯
复制代码



但下面的这种就不能呢都是PB0输出低,PB1为输入上拉呢
if (ershimiao_ok)         //20秒无动作后休眠
         {
          shucuo=0;  //2次输错密码,若没有再输入密码,进入休眠就清除记录
          qingling();    //清零
          PORTB = 11100110;   //11100110进入休眠前关所有灯
          DDRB = 00100001;  //00100001,PB.0和5配置为输出,其它位为输入
          //PORTB |=( 1<<1);   //置位
          //PORTB &=~( 1<<0);  //清零
         // DDRB = 0x39;
          TIMSK = 0x00;   //关闭T/C0比较匹配中断  
          /*关闭看门狗省电*/
          //#asm("cli") //关闭全局中断
          #asm("WDR")   //喂狗
          //MCUSR = 0x00;           
          //WDTCR |= (1<<WDCE) | (1<<WDE);           
          //WDTCR = 0x00;
          MCUSR &= ~(1<<WDRF);
          WDTCR |= (1<<WDCE) | (1<<WDE);
          WDTCR &= ~(1<<WDE);
          #asm("sei")  // 开放全局中断
          /*使能INT0中断*/
          GIMSK=0x40;
          MCUCR=0x00;
          GIFR=0x40;                     
          MCUCR |= (1<<SM1) | (0<<SM0);  // 掉电模式
          MCUCR |= (1<<SE);   //睡眠使能
          #asm("sleep")      //休眠
          PORTB ^= 1<<5;     //唤醒后监测
         }
        #asm("WDR")   //喂狗
        shangdeng(); //扫描闪灯
 楼主| 发表于 2014-5-4 10:09:21 | 显示全部楼层
这是完整代码,真的是奇怪

  1. #include <tiny85.h>
  2. #include<delay.h>
  3. // Declare your global variables here
  4. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt; //密码计数,录入密码数组,原始密码数组,长按标志                    // 2位密码计数单元
  5. unsigned char ershimiao_counter,ermiao_counter,shucuo_counter,yimiao_counter,key_stime_counter,status,shangdengcishu;        // 时间计数单元,闪灯次数
  6. unsigned char ershimiao_ok,shucuo_ok,ermiao_ok,yimiao_ok,key_stime_ok,kaidengduibi; //第一次开关未完成时,第二次开灯指令的识别
  7. unsigned int shangdengtime,guangdengtime;   //闪灯开的时间,闪灯关的时间
  8. unsigned char huifu[5]={1,2,3,4,5}; //初始密码

  9. // External Interrupt 0 service routine
  10. interrupt [EXT_INT0] void ext_int0_isr(void)
  11. {
  12.   PORTB |=( 1<<1);   //置位
  13.     PORTB &=~( 1<<0);  //清零
  14.     DDRB = 0x39;   
  15.   TIMSK=0x10;     // 允许T/C0比较匹配中断     
  16.   PORTB ^= 1<<5;     //中断唤醒监测
  17.   GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  18.   //GICR = 0x00;   //禁用INT0中断
  19.   WDTCR=0x18;  //开看门狗约为16ms
  20.   WDTCR=0x08;   
  21.   
  22.   MCUCR &=~(1<<SE); // 禁止睡眠使能,在需要休眠时再打开0

  23. }

  24. // Timer 0 output compare A interrupt service routine  , Timer 0 比较匹配中断服务,2ms定时
  25. interrupt [TIM0_COMPA] void timer0_compa_isr(void)
  26. {
  27.   if (++key_stime_counter >=5)
  28.     {
  29.         key_stime_counter = 0;
  30.         key_stime_ok = 1;                // 10ms到
  31.         if (++yimiao_counter >= 100)
  32.         {
  33.             yimiao_counter = 0;
  34.             yimiao_ok = 1;             // 1s到  
  35.             if (++ermiao_counter >= 2)
  36.             {
  37.                 ermiao_counter = 0;
  38.                 ermiao_ok = 1;             // 2s到
  39.                 if (++ershimiao_counter >= 15)
  40.                 {
  41.                  ershimiao_counter = 0;
  42.                  ershimiao_ok = 1;             // 30s到
  43.                  if (++shucuo_counter >= 10)
  44.                   {
  45.                    shucuo_counter = 0;
  46.                    shucuo_ok = 1;             // 300s到
  47.                   }
  48.                 }
  49.             }
  50.         }
  51.     }
  52. }


  53. #define key_input    PINB.1            // 按键输入口兼INTO中断唤醒
  54. #define key_state_0    0
  55. #define key_state_1    1
  56. #define key_state_2    2
  57. #define key_state_3    3
  58. #define key_state_4    4

  59. void qingling(void)   //清零
  60. {
  61.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  62.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  63.       ermiao_counter = 0;
  64.       ermiao_ok = 0;
  65.       ershimiao_counter = 0;
  66.       ershimiao_ok = 0;
  67.       shucuo_counter = 0;
  68.       shucuo_ok = 0;             // 300s到
  69.   }   
  70.   
  71.   void shangdeng(void)   //闪灯
  72.    {
  73.      static unsigned char status=1,kaidengbiaozhi;
  74.      static unsigned int i,j,h;
  75.      if(shangdengcishu >0)  //闪灯次数  类似倒计时程序
  76.         {
  77.           if(kaidengduibi==1)    //开灯比对,有新的开灯指令时为1
  78.           {
  79.             status=0;
  80.           }
  81.           switch (status)
  82.           {
  83.             case 0:
  84.               kaidengduibi=0;    //开灯对比,对比结束
  85.               if(kaidengbiaozhi == 1) //上一次开灯程序未完成标志
  86.               {
  87.                if (++h >= 3000-j)   //按键关灯时间,实现第一次正在开灯,或者正在关灯时,若第二次开灯指令就来了,就先执行关灯
  88.                {
  89.                  j=0;
  90.                  h=0;
  91.                  status=1;
  92.                  i=0;  
  93.                                                    
  94.                }
  95.               }               
  96.               else status=1;
  97.               break;
  98.             case 1:
  99.               
  100.               PORTB |=( 1<<0);   //PD7输出高
  101.               PORTB &=~( 1<<1);  //INT0拉低
  102.               DDRB = 0x3B;
  103.               qingling();    //清零
  104.               kaidengbiaozhi=1;  //开灯标志,表示开灯任务开始               
  105.               if (++i >= shangdengtime)   //按键开灯时间
  106.               {
  107.                status=2;
  108.                i=0;
  109.               }            
  110.               break;
  111.             case 2:
  112.               if (++j >= guangdengtime)   //按键关灯时间
  113.                {
  114.                  j=0;
  115.                  status=0;
  116.                  --shangdengcishu ;
  117.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了                 
  118.                 }
  119.               if(j>=3000)  //灭灯时间达到设定值时,把开关标志清零,也就是可以再次接受新的开灯指令了,这样再开灯时就能及时看到亮灯
  120.                {
  121.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了  
  122.                }
  123.               break;
  124.           }              
  125.         }
  126.    }
  127.   
  128. unsigned char read_key_n(void)
  129.   {
  130.     static unsigned char key_state = 0, key_time = 0;
  131.     unsigned char key_press, key_return = 0;
  132.    
  133.     PORTB |=( 1<<1);   //置位
  134.     PORTB &=~( 1<<0);  //清零
  135.     DDRB = 0x39;
  136.     //PORTB=0x3A;
  137.    //DDRB=0x39;               
  138.     key_press = key_input;                // 读按键I/O电平
  139.     switch (key_state)
  140.       {
  141.         case key_state_0:                // 按键初始态
  142.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  143.             break;
  144.         case key_state_1:                // 按键确认态
  145.             if (!key_press)
  146.             {
  147.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  148.                 key_time = 0;                // 清另按键时间计数器
  149.             }
  150.             else
  151.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  152.             break;
  153.         case key_state_2:
  154.             if (key_press)
  155.             {
  156.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  157.                 key_return = 1;            // 输出"1" ,表示单击
  158.                 key_time = 0;
  159.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键成功短按一次
  160.                 shangdengtime = 3000;    //设置闪灯时间
  161.                 guangdengtime = 0;    //设置关灯时间
  162.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  163.                 if (++mimajishu >9)
  164.                  {
  165.                     mimajishu = 0;  
  166.                  }              
  167.             }
  168.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  169.             {
  170.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  171.                 key_time = 0;                // 清按键计数器
  172.                 key_return = 2;            // 长按超过1秒后输出"2" ,  
  173.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  174.                 shangdengtime = 60000;    //设置闪灯时间
  175.                 guangdengtime = 0;    //设置关灯时间
  176.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  177.             }  
  178.               qingling();    //清零
  179.             break;
  180.         case key_state_3:
  181.              if (key_press)
  182.             {              
  183.                key_state = key_state_0; //按键已释放,转换到按键初始态
  184.                key_time = 0;                // 清按键计数器     
  185.             }   
  186.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  187.             {
  188.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  189.                 key_time = 0;                // 清按键计数器  
  190.                 key_return = 3;         //长按2秒,进入设置界面                 
  191.                 shangdengcishu = 3;    //开长闪灯
  192.                 shangdengtime = 65000;    //设置长闪灯时间
  193.                 guangdengtime = 10000;    //设置关灯时间
  194.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  195.             }
  196.             qingling();    //清零   
  197.              break;
  198.         case key_state_4:
  199.             if (key_press)
  200.             {
  201.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  202.             }   
  203.             qingling();    //清零
  204.             break;
  205.      
  206.       }   
  207.     return key_return;
  208.   }  

  209.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  210.    {
  211.      static unsigned char i = 0,aj_state = 0;
  212.      unsigned char key_return = 0;
  213.      #asm("WDR")   //喂狗
  214.      if (key_stime_ok)                // 10ms到,键处理
  215.      {
  216.         key_stime_ok = 0;
  217.         read_key_n();
  218.        switch (aj_state)
  219.        {
  220.         case 0:               
  221.             if (ermiao_ok)
  222.            {
  223.                if(i < 5)    //密码位数设置
  224.                {
  225.                  mima[i] = mimajishu;  //记录第一位密码
  226.                  mimajishu =0;
  227.                  PORTB ^= 1<<5;   //观察第一位密码识别
  228.                  aj_state = 1;
  229.                  qingling();    //清零
  230.                  i=++i;                  
  231.                  shangdengcishu = i;    //开短闪灯标示刚才输入一位密码成功
  232.                  shangdengtime = 3000;    //设置闪灯时间   
  233.                  guangdengtime = 17000;    //设置关灯时间
  234.                  kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果   
  235.                }   
  236.            }
  237.             break;
  238.         case 1:               
  239.             if (i == 5)  //密码识别位数确认 ,闪2次标示密码输完
  240.             {   
  241.                 i=0;
  242.                 aj_state = 0;
  243.                 key_return = 1;
  244.             }
  245.             else
  246.                  aj_state = 0;   
  247.             break;
  248.        }
  249.         return key_return;
  250.      }
  251.    }


  252. void main(void)
  253. {
  254. // Declare your local variables here

  255. // Crystal Oscillator division factor: 1
  256. #pragma optsize-
  257. CLKPR=0x80;
  258. CLKPR=0x00;
  259. #ifdef _OPTIMIZE_SIZE_
  260. #pragma optsize+
  261. #endif

  262. // Input/Output Ports initialization
  263. // Port B initialization
  264. // Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
  265. // State5=T State4=T State3=T State2=T State1=T State0=0
  266. //PORTB = 0xE6;   //11100110
  267. //DDRB = 0x39;  //00100001,PB.0和5配置为输出,其它位为输入
  268. PORTB=0x3A;
  269. DDRB=0x39;

  270. delay_ms(100);  
  271.     /*上电恢复初始密码*/
  272.     PORTB |=( 1<<0);   //PD7输出高
  273.                   DDRB &=~( 1<<0);  //PD7设置成输入  
  274.                  if(PINB.0 == 0)    //若PD7拉低就把密码恢复出厂设置
  275.                   {
  276.                     shangdengcishu = 5;    //开短闪灯标示刚才输入一位密码成功
  277.                     shangdengtime = 15000;    //设置闪灯时间
  278.                     guangdengtime = 10000;    //设置关灯时间
  279.                     kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  280.                     for(j=0;j<5;j++)           //写入新设置密码
  281.                     {
  282.                        #asm("cli")                     
  283.                        while(EECR &(1 <<EEPE));
  284.                        EECR = (0<<EEPM1)|(0<<EEPM0);
  285.                        EEARL = j+10;
  286.                        EEDR = huifu[j]; //恢复默认密码
  287.                        EECR |=(1 <<EEMPE);
  288.                        EECR |=(1 <<EEPE);
  289.                         ysmima[j] =  huifu[j]; //密码立即生效
  290.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  291.                        delay_ms(10);
  292.                        #asm("sei")                    
  293.                     }
  294.                     //delay_ms(5000);
  295.                                     
  296.                   }
  297.                   //while(PIND.7 == 0) {;}
  298.                   //PORTB = 0xE6;   //11100110
  299.                   //DDRB = 0x39;  //00100001,PB.0和5配置为输出,其它位为输入                    // PD7为输出方式,默认输出低电平
  300.                   PORTB=0x3A;
  301.                   DDRB=0x39;  
  302.       
  303.      #asm("cli")
  304.       #asm("sei")
  305.      
  306.     for(j=0;j<5;j++)           //读出原密码
  307.     {
  308.     while(EECR &(1 <<EEPE));
  309.     EEARL = j+10;
  310.     EECR |=(1<<EERE);
  311.     ysmima[j]=EEDR;
  312.     delay_ms(10);
  313.     }

  314.   #asm("cli")   

  315. // Timer/Counter 0 initialization
  316. // Clock source: System Clock
  317. // Clock value: 125.000 kHz
  318. // Mode: CTC top=OCR0A
  319. // OC0A output: Disconnected
  320. // OC0B output: Disconnected
  321. TCCR0A=0x02;
  322. TCCR0B=0x03;
  323. TCNT0=0x00;
  324. OCR0A=0xF9;
  325. OCR0B=0x00;

  326. // Timer/Counter 1 initialization
  327. // Clock source: System Clock
  328. // Clock value: Timer1 Stopped
  329. // Mode: Normal top=0xFF
  330. // OC1A output: Disconnected
  331. // OC1B output: Disconnected
  332. // Timer1 Overflow Interrupt: Off
  333. // Compare A Match Interrupt: Off
  334. // Compare B Match Interrupt: Off
  335. PLLCSR=0x00;

  336. TCCR1=0x00;
  337. GTCCR=0x00;
  338. TCNT1=0x00;
  339. OCR1A=0x00;
  340. OCR1B=0x00;
  341. OCR1C=0x00;

  342. // External Interrupt(s) initialization
  343. // INT0: On
  344. // INT0 Mode: Low level
  345. // Interrupt on any change on pins PCINT0-5: Off
  346. GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  347. MCUCR=0x00;
  348. GIFR=0x40;

  349. // Timer(s)/Counter(s) Interrupt(s) initialization
  350. TIMSK=0x10;

  351. // Universal Serial Interface initialization
  352. // Mode: Disabled
  353. // Clock source: Register & Counter=no clk.
  354. // USI Counter Overflow Interrupt: Off
  355. USICR=0x00;

  356. // Analog Comparator initialization
  357. // Analog Comparator: Off
  358. ACSR=0x80;
  359. ADCSRB=0x00;
  360. DIDR0=0x00;

  361. // ADC initialization
  362. // ADC disabled
  363. ADCSRA=0x00;

  364. // Watchdog Timer initialization
  365. // Watchdog Timer Prescaler: OSC/2k
  366. // Watchdog Timer interrupt: Off
  367. #pragma optsize-
  368. #asm("wdr")
  369. WDTCR=0x18;
  370. WDTCR=0x08;  
  371. #ifdef _OPTIMIZE_SIZE_
  372. #pragma optsize+
  373. #endif

  374. // Global enable interrupts
  375. #asm("sei")            // 开放全局中断

  376.      while (1)
  377.      {
  378.          switch (status)
  379.        {     
  380.              case 0:            
  381.              if (key_stime_ok)                // 10ms到,键处理
  382.             {  
  383.                 key_stime_ok = 0;
  384.                 switch(read_key_n())
  385.                   {
  386.                        case 0:
  387.                            status = 0;
  388.                        break;
  389.                        case 1:
  390.                            status = 1;
  391.                        break;
  392.                        
  393.                        case 2:
  394.                             PORTB &= ~(1<<3);
  395.                             PORTB |= (1<<4);    //关门
  396.                             DDRB = 0x39;            
  397.                        break;
  398.                   }
  399.               
  400.             }            
  401.                 break;           
  402.              case 1:
  403.                if (read_key_driver() ==1 )
  404.             {  
  405.                 qingling();    //清零
  406.                      for(j=0;j<5;j++)           //密码对比识别
  407.                     {
  408.                        if (mima[j]==ysmima[j])
  409.                        {
  410.                         cnt++;
  411.                        }
  412.                     }
  413.                     if (cnt==5)
  414.                     {
  415.                       cnt=0;
  416.                       //PORTB ^= 1<<3;
  417.                       status = 3;
  418.                       shucuo=0;
  419.                       shangdengcishu = 1;
  420.                       shangdengtime = 50000;
  421.                       guangdengtime = 0;
  422.                       kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  423.                       PORTB &=~(1<<5);
  424.                       PORTB &=~(1<<4);
  425.                       PORTB |=(1<<3);    //开门
  426.                       DDRB = 0x39;   
  427.                     }
  428.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  429.             }
  430.                 break;
  431.              case 2:
  432.                    while(shucuo==3)      //输错3次就锁死300秒
  433.                    {                    
  434.                      #asm("WDR")   //喂狗
  435.                     if(shucuo_ok)
  436.                     {
  437.                       qingling();    //清零
  438.                       status = 0;                     
  439.                       shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  440.                       shangdengcishu = 1;
  441.                       shangdengtime = 50000;
  442.                       guangdengtime = 0;
  443.                       kaidengduibi=1;                     
  444.                     }
  445.                    }
  446.                   status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  447.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  448.              case 3:
  449.                if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  450.                   {
  451.                      status = 12;                  
  452.                   }
  453.                else  if (ermiao_ok) {status = 0;}
  454.                   break;      
  455.               case 12:               //老密码输入对,开始第一次输入新密码
  456.                  if (read_key_driver() ==1 )
  457.                  {   
  458.                     for(j=0;j<5;j++)
  459.                        {
  460.                         ysmima[j]=mima[j];
  461.                        }
  462.                      status = 13;
  463.                  }  
  464.                    break;
  465.              case 13:               //开始第二次输入新密码,并和第一次的对比
  466.                  if (read_key_driver() ==1 )
  467.                  {   
  468.                     for(j=0;j<5;j++)           //密码对比识别
  469.                     {
  470.                        if (mima[j]==ysmima[j])
  471.                        {
  472.                         cnt++;
  473.                        }
  474.                     }
  475.                     if (cnt==5)
  476.                     {
  477.                       cnt=0;
  478.                       //PORTB ^= 1<<3;
  479.                       status = 14;
  480.                       shucuo=0;
  481.                       shangdengcishu = 1;
  482.                       shangdengtime = 50000;
  483.                       guangdengtime = 0;
  484.                       kaidengduibi=1;
  485.                       //mima[1] = 0; mima[0] = 0;
  486.                     }        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  487.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  488.                  }  
  489.                    break;
  490.                case 14:               //开始第三次输入新密码,并和第一次的对比
  491.                  if (read_key_driver() ==1 )
  492.                  {   
  493.                     for(j=0;j<5;j++)           //密码对比识别
  494.                     {
  495.                        if (mima[j]==ysmima[j])
  496.                        {
  497.                         cnt++;
  498.                        }
  499.                     }
  500.                     if (cnt==5)
  501.                     {
  502.                       cnt=0;
  503.                       PORTB ^= 1<<5;  //观察
  504.                       status = 15;
  505.                       shucuo=0;
  506.                       shangdengcishu = 3;
  507.                       shangdengtime = 50000;
  508.                       guangdengtime = 10000;
  509.                       kaidengduibi=1;
  510.                       //mima[1] = 0; mima[0] = 0;
  511.                     }        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  512.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  513.                  }  
  514.                    break;               
  515.                        
  516.                 case 15:        //第三次输对新密码后,开始记录                    
  517.                    shangdengcishu = 1;
  518.                    shangdengtime = 50000;
  519.                    guangdengtime = 0;
  520.                    kaidengduibi=1;
  521.                     for(j=0;j<5;j++)           //写入新设置密码
  522.                     {
  523.                        #asm("cli")                     
  524.                        while(EECR &(1 <<EEPE));
  525.                        EECR = (0<<EEPM1)|(0<<EEPM0);
  526.                        EEARL = j+10;
  527.                        EEDR = mima[j];
  528.                        EECR |=(1 <<EEPM1);
  529.                        EECR |=(1 <<EEPM0);
  530.                         ysmima[j] =  mima[j]; //密码立即生效                     
  531.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  532.                        delay_ms(10);
  533.                        #asm("sei")                       
  534.                         
  535.                     }                  
  536.                     status = 0;                                       
  537.                 break;
  538.                 case 16:
  539.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  540.                    {
  541.                     for(j=0;j<5;j++)           //读出原密码继续使用
  542.                     {
  543.                       #asm("cli")
  544.                       while(EECR &(1 <<EEPE));
  545.                       EEARL = j+10;
  546.                       EECR |=(1<<EERE);
  547.                       ysmima[j]=EEDR;
  548.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  549.                       delay_ms(10);
  550.                       #asm("sei")
  551.                     }
  552.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  553.                     PORTB ^= 1<<5;  //某行动
  554.                     status = 0;
  555.                    }
  556.                   else status = 12;   
  557.                 break;               
  558.          }   
  559.          if (ershimiao_ok)         //20秒无动作后休眠
  560.          {
  561.           shucuo=0;  //2次输错密码,若没有再输入密码,进入休眠就清除记录
  562.           qingling();    //清零
  563.           //PORTB = 11100110;   //11100110进入休眠前关所有灯
  564.           //DDRB = 00100001;  //00100001,PB.0和5配置为输出,其它位为输入
  565.           PORTB |=( 1<<1);   //置位
  566.           PORTB &=~( 1<<0);  //清零
  567.           DDRB = 0x39;
  568.           TIMSK = 0x00;   //关闭T/C0比较匹配中断  
  569.           /*关闭看门狗省电*/
  570.           //#asm("cli") //关闭全局中断
  571.           #asm("WDR")   //喂狗
  572.           //MCUSR = 0x00;           
  573.           //WDTCR |= (1<<WDCE) | (1<<WDE);           
  574.           //WDTCR = 0x00;
  575.           MCUSR &= ~(1<<WDRF);
  576.           WDTCR |= (1<<WDCE) | (1<<WDE);
  577.           WDTCR &= ~(1<<WDE);
  578.           #asm("sei")  // 开放全局中断
  579.           /*使能INT0中断*/
  580.           GIMSK=0x40;
  581.           MCUCR=0x00;
  582.           GIFR=0x40;                     
  583.           MCUCR |= (1<<SM1) | (0<<SM0);  // 掉电模式
  584.           MCUCR |= (1<<SE);   //睡眠使能
  585.           #asm("sleep")      //休眠
  586.           PORTB ^= 1<<5;     //唤醒后监测
  587.          }
  588.         #asm("WDR")   //喂狗
  589.         shangdeng(); //扫描闪灯
  590.      }
  591. }
  592. #include <tiny85.h>
  593. #include<delay.h>
  594. // Declare your global variables here
  595. unsigned char mima[5],ysmima[5],mimajishu,shucuo,j,cnt; //密码计数,录入密码数组,原始密码数组,长按标志                    // 2位密码计数单元
  596. unsigned char ershimiao_counter,ermiao_counter,shucuo_counter,yimiao_counter,key_stime_counter,status,shangdengcishu;        // 时间计数单元,闪灯次数
  597. unsigned char ershimiao_ok,shucuo_ok,ermiao_ok,yimiao_ok,key_stime_ok,kaidengduibi; //第一次开关未完成时,第二次开灯指令的识别
  598. unsigned int shangdengtime,guangdengtime;   //闪灯开的时间,闪灯关的时间
  599. unsigned char huifu[5]={1,2,3,4,5}; //初始密码

  600. // External Interrupt 0 service routine
  601. interrupt [EXT_INT0] void ext_int0_isr(void)
  602. {
  603.   PORTB |=( 1<<1);   //置位
  604.     PORTB &=~( 1<<0);  //清零
  605.     DDRB = 0x39;   
  606.   TIMSK=0x10;     // 允许T/C0比较匹配中断     
  607.   PORTB ^= 1<<5;     //中断唤醒监测
  608.   GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  609.   //GICR = 0x00;   //禁用INT0中断
  610.   WDTCR=0x18;  //开看门狗约为16ms
  611.   WDTCR=0x08;   
  612.   
  613.   MCUCR &=~(1<<SE); // 禁止睡眠使能,在需要休眠时再打开0

  614. }

  615. // Timer 0 output compare A interrupt service routine  , Timer 0 比较匹配中断服务,2ms定时
  616. interrupt [TIM0_COMPA] void timer0_compa_isr(void)
  617. {
  618.   if (++key_stime_counter >=5)
  619.     {
  620.         key_stime_counter = 0;
  621.         key_stime_ok = 1;                // 10ms到
  622.         if (++yimiao_counter >= 100)
  623.         {
  624.             yimiao_counter = 0;
  625.             yimiao_ok = 1;             // 1s到  
  626.             if (++ermiao_counter >= 2)
  627.             {
  628.                 ermiao_counter = 0;
  629.                 ermiao_ok = 1;             // 2s到
  630.                 if (++ershimiao_counter >= 15)
  631.                 {
  632.                  ershimiao_counter = 0;
  633.                  ershimiao_ok = 1;             // 30s到
  634.                  if (++shucuo_counter >= 10)
  635.                   {
  636.                    shucuo_counter = 0;
  637.                    shucuo_ok = 1;             // 300s到
  638.                   }
  639.                 }
  640.             }
  641.         }
  642.     }
  643. }


  644. #define key_input    PINB.1            // 按键输入口兼INTO中断唤醒
  645. #define key_state_0    0
  646. #define key_state_1    1
  647. #define key_state_2    2
  648. #define key_state_3    3
  649. #define key_state_4    4

  650. void qingling(void)   //清零
  651. {
  652.       yimiao_counter = 0; //因为是最后一次按键清零后过了1秒,才开始第一位密码识别的,不清零的话后面第一个10ms过后就会把第二位密码记上了,
  653.       yimiao_ok = 0;       //这会让你没有机会输入第二次密码
  654.       ermiao_counter = 0;
  655.       ermiao_ok = 0;
  656.       ershimiao_counter = 0;
  657.       ershimiao_ok = 0;
  658.       shucuo_counter = 0;
  659.       shucuo_ok = 0;             // 300s到
  660.   }   
  661.   
  662.   void shangdeng(void)   //闪灯
  663.    {
  664.      static unsigned char status=1,kaidengbiaozhi;
  665.      static unsigned int i,j,h;
  666.      if(shangdengcishu >0)  //闪灯次数  类似倒计时程序
  667.         {
  668.           if(kaidengduibi==1)    //开灯比对,有新的开灯指令时为1
  669.           {
  670.             status=0;
  671.           }
  672.           switch (status)
  673.           {
  674.             case 0:
  675.               kaidengduibi=0;    //开灯对比,对比结束
  676.               if(kaidengbiaozhi == 1) //上一次开灯程序未完成标志
  677.               {
  678.                if (++h >= 3000-j)   //按键关灯时间,实现第一次正在开灯,或者正在关灯时,若第二次开灯指令就来了,就先执行关灯
  679.                {
  680.                  j=0;
  681.                  h=0;
  682.                  status=1;
  683.                  i=0;  
  684.                                                    
  685.                }
  686.               }               
  687.               else status=1;
  688.               break;
  689.             case 1:
  690.               
  691.               PORTB |=( 1<<0);   //PD7输出高
  692.               PORTB &=~( 1<<1);  //INT0拉低
  693.               DDRB = 0x3B;
  694.               qingling();    //清零
  695.               kaidengbiaozhi=1;  //开灯标志,表示开灯任务开始               
  696.               if (++i >= shangdengtime)   //按键开灯时间
  697.               {
  698.                status=2;
  699.                i=0;
  700.               }            
  701.               break;
  702.             case 2:
  703.               if (++j >= guangdengtime)   //按键关灯时间
  704.                {
  705.                  j=0;
  706.                  status=0;
  707.                  --shangdengcishu ;
  708.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了                 
  709.                 }
  710.               if(j>=3000)  //灭灯时间达到设定值时,把开关标志清零,也就是可以再次接受新的开灯指令了,这样再开灯时就能及时看到亮灯
  711.                {
  712.                  kaidengbiaozhi=0;  //开灯标志,标示开灯任务结束,准备好第二次开关了  
  713.                }
  714.               break;
  715.           }              
  716.         }
  717.    }
  718.   
  719. unsigned char read_key_n(void)
  720.   {
  721.     static unsigned char key_state = 0, key_time = 0;
  722.     unsigned char key_press, key_return = 0;
  723.    
  724.     PORTB |=( 1<<1);   //置位
  725.     PORTB &=~( 1<<0);  //清零
  726.     DDRB = 0x39;
  727.     //PORTB=0x3A;
  728.    //DDRB=0x39;               
  729.     key_press = key_input;                // 读按键I/O电平
  730.     switch (key_state)
  731.       {
  732.         case key_state_0:                // 按键初始态
  733.             if (!key_press) key_state = key_state_1;    // 键被按下,状态转换到键确认态
  734.             break;
  735.         case key_state_1:                // 按键确认态
  736.             if (!key_press)
  737.             {
  738.                 key_state = key_state_2;    // 按键仍按下,状态转换到计时1
  739.                 key_time = 0;                // 清另按键时间计数器
  740.             }
  741.             else
  742.                 key_state = key_state_0;    // 按键已抬起,转换到按键初始态
  743.             break;
  744.         case key_state_2:
  745.             if (key_press)
  746.             {
  747.                 key_state = key_state_0;    // 按键已释放,转换到按键初始态
  748.                 key_return = 1;            // 输出"1" ,表示单击
  749.                 key_time = 0;
  750.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键成功短按一次
  751.                 shangdengtime = 3000;    //设置闪灯时间
  752.                 guangdengtime = 0;    //设置关灯时间
  753.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  754.                 if (++mimajishu >9)
  755.                  {
  756.                     mimajishu = 0;  
  757.                  }              
  758.             }
  759.             else if (++key_time >= 100)        // 长按1秒按键时间计数
  760.             {
  761.                 key_state = key_state_3;    // 按下时间>1s,状态转换到计时2
  762.                 key_time = 0;                // 清按键计数器
  763.                 key_return = 2;            // 长按超过1秒后输出"2" ,  
  764.                 shangdengcishu = 1;    //开短闪灯 ,告知按下按键已经有1秒 ,此后3秒内松开手就关门
  765.                 shangdengtime = 60000;    //设置闪灯时间
  766.                 guangdengtime = 0;    //设置关灯时间
  767.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  768.             }  
  769.               qingling();    //清零
  770.             break;
  771.         case key_state_3:
  772.              if (key_press)
  773.             {              
  774.                key_state = key_state_0; //按键已释放,转换到按键初始态
  775.                key_time = 0;                // 清按键计数器     
  776.             }   
  777.               else if (++key_time >= 250)        // 长按达到3.5秒按键时间计数
  778.             {
  779.                 key_state = key_state_4;    // 按下时间>3.5s,状态转换到计时2
  780.                 key_time = 0;                // 清按键计数器  
  781.                 key_return = 3;         //长按2秒,进入设置界面                 
  782.                 shangdengcishu = 3;    //开长闪灯
  783.                 shangdengtime = 65000;    //设置长闪灯时间
  784.                 guangdengtime = 10000;    //设置关灯时间
  785.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  786.             }
  787.             qingling();    //清零   
  788.              break;
  789.         case key_state_4:
  790.             if (key_press)
  791.             {
  792.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  793.             }   
  794.             qingling();    //清零
  795.             break;
  796.      
  797.       }   
  798.     return key_return;
  799.   }  

  800.    unsigned char read_key_driver(void)   //按键密码输入记录部分
  801.    {
  802.      static unsigned char i = 0,aj_state = 0;
  803.      unsigned char key_return = 0;
  804.      #asm("WDR")   //喂狗
  805.      if (key_stime_ok)                // 10ms到,键处理
  806.      {
  807.         key_stime_ok = 0;
  808.         read_key_n();
  809.        switch (aj_state)
  810.        {
  811.         case 0:               
  812.             if (ermiao_ok)
  813.            {
  814.                if(i < 5)    //密码位数设置
  815.                {
  816.                  mima[i] = mimajishu;  //记录第一位密码
  817.                  mimajishu =0;
  818.                  PORTB ^= 1<<5;   //观察第一位密码识别
  819.                  aj_state = 1;
  820.                  qingling();    //清零
  821.                  i=++i;                  
  822.                  shangdengcishu = i;    //开短闪灯标示刚才输入一位密码成功
  823.                  shangdengtime = 3000;    //设置闪灯时间   
  824.                  guangdengtime = 17000;    //设置关灯时间
  825.                  kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果   
  826.                }   
  827.            }
  828.             break;
  829.         case 1:               
  830.             if (i == 5)  //密码识别位数确认 ,闪2次标示密码输完
  831.             {   
  832.                 i=0;
  833.                 aj_state = 0;
  834.                 key_return = 1;
  835.             }
  836.             else
  837.                  aj_state = 0;   
  838.             break;
  839.        }
  840.         return key_return;
  841.      }
  842.    }


  843. void main(void)
  844. {
  845. // Declare your local variables here

  846. // Crystal Oscillator division factor: 1
  847. #pragma optsize-
  848. CLKPR=0x80;
  849. CLKPR=0x00;
  850. #ifdef _OPTIMIZE_SIZE_
  851. #pragma optsize+
  852. #endif

  853. // Input/Output Ports initialization
  854. // Port B initialization
  855. // Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
  856. // State5=T State4=T State3=T State2=T State1=T State0=0
  857. //PORTB = 0xE6;   //11100110
  858. //DDRB = 0x39;  //00100001,PB.0和5配置为输出,其它位为输入
  859. PORTB=0x3A;
  860. DDRB=0x39;

  861. delay_ms(100);  
  862.     /*上电恢复初始密码*/
  863.     PORTB |=( 1<<0);   //PD7输出高
  864.                   DDRB &=~( 1<<0);  //PD7设置成输入  
  865.                  if(PINB.0 == 0)    //若PD7拉低就把密码恢复出厂设置
  866.                   {
  867.                     shangdengcishu = 5;    //开短闪灯标示刚才输入一位密码成功
  868.                     shangdengtime = 15000;    //设置闪灯时间
  869.                     guangdengtime = 10000;    //设置关灯时间
  870.                     kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  871.                     for(j=0;j<5;j++)           //写入新设置密码
  872.                     {
  873.                        #asm("cli")                     
  874.                        while(EECR &(1 <<EEPE));
  875.                        EECR = (0<<EEPM1)|(0<<EEPM0);
  876.                        EEARL = j+10;
  877.                        EEDR = huifu[j]; //恢复默认密码
  878.                        EECR |=(1 <<EEMPE);
  879.                        EECR |=(1 <<EEPE);
  880.                         ysmima[j] =  huifu[j]; //密码立即生效
  881.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  882.                        delay_ms(10);
  883.                        #asm("sei")                    
  884.                     }
  885.                     //delay_ms(5000);
  886.                                     
  887.                   }
  888.                   //while(PIND.7 == 0) {;}
  889.                   //PORTB = 0xE6;   //11100110
  890.                   //DDRB = 0x39;  //00100001,PB.0和5配置为输出,其它位为输入                    // PD7为输出方式,默认输出低电平
  891.                   PORTB=0x3A;
  892.                   DDRB=0x39;  
  893.       
  894.      #asm("cli")
  895.       #asm("sei")
  896.      
  897.     for(j=0;j<5;j++)           //读出原密码
  898.     {
  899.     while(EECR &(1 <<EEPE));
  900.     EEARL = j+10;
  901.     EECR |=(1<<EERE);
  902.     ysmima[j]=EEDR;
  903.     delay_ms(10);
  904.     }

  905.   #asm("cli")   

  906. // Timer/Counter 0 initialization
  907. // Clock source: System Clock
  908. // Clock value: 125.000 kHz
  909. // Mode: CTC top=OCR0A
  910. // OC0A output: Disconnected
  911. // OC0B output: Disconnected
  912. TCCR0A=0x02;
  913. TCCR0B=0x03;
  914. TCNT0=0x00;
  915. OCR0A=0xF9;
  916. OCR0B=0x00;

  917. // Timer/Counter 1 initialization
  918. // Clock source: System Clock
  919. // Clock value: Timer1 Stopped
  920. // Mode: Normal top=0xFF
  921. // OC1A output: Disconnected
  922. // OC1B output: Disconnected
  923. // Timer1 Overflow Interrupt: Off
  924. // Compare A Match Interrupt: Off
  925. // Compare B Match Interrupt: Off
  926. PLLCSR=0x00;

  927. TCCR1=0x00;
  928. GTCCR=0x00;
  929. TCNT1=0x00;
  930. OCR1A=0x00;
  931. OCR1B=0x00;
  932. OCR1C=0x00;

  933. // External Interrupt(s) initialization
  934. // INT0: On
  935. // INT0 Mode: Low level
  936. // Interrupt on any change on pins PCINT0-5: Off
  937. GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  938. MCUCR=0x00;
  939. GIFR=0x40;

  940. // Timer(s)/Counter(s) Interrupt(s) initialization
  941. TIMSK=0x10;

  942. // Universal Serial Interface initialization
  943. // Mode: Disabled
  944. // Clock source: Register & Counter=no clk.
  945. // USI Counter Overflow Interrupt: Off
  946. USICR=0x00;

  947. // Analog Comparator initialization
  948. // Analog Comparator: Off
  949. ACSR=0x80;
  950. ADCSRB=0x00;
  951. DIDR0=0x00;

  952. // ADC initialization
  953. // ADC disabled
  954. ADCSRA=0x00;

  955. // Watchdog Timer initialization
  956. // Watchdog Timer Prescaler: OSC/2k
  957. // Watchdog Timer interrupt: Off
  958. #pragma optsize-
  959. #asm("wdr")
  960. WDTCR=0x18;
  961. WDTCR=0x08;  
  962. #ifdef _OPTIMIZE_SIZE_
  963. #pragma optsize+
  964. #endif

  965. // Global enable interrupts
  966. #asm("sei")            // 开放全局中断

  967.      while (1)
  968.      {
  969.          switch (status)
  970.        {     
  971.              case 0:            
  972.              if (key_stime_ok)                // 10ms到,键处理
  973.             {  
  974.                 key_stime_ok = 0;
  975.                 switch(read_key_n())
  976.                   {
  977.                        case 0:
  978.                            status = 0;
  979.                        break;
  980.                        case 1:
  981.                            status = 1;
  982.                        break;
  983.                        
  984.                        case 2:
  985.                             PORTB &= ~(1<<3);
  986.                             PORTB |= (1<<4);    //关门
  987.                             DDRB = 0x39;            
  988.                        break;
  989.                   }
  990.               
  991.             }            
  992.                 break;           
  993.              case 1:
  994.                if (read_key_driver() ==1 )
  995.             {  
  996.                 qingling();    //清零
  997.                      for(j=0;j<5;j++)           //密码对比识别
  998.                     {
  999.                        if (mima[j]==ysmima[j])
  1000.                        {
  1001.                         cnt++;
  1002.                        }
  1003.                     }
  1004.                     if (cnt==5)
  1005.                     {
  1006.                       cnt=0;
  1007.                       //PORTB ^= 1<<3;
  1008.                       status = 3;
  1009.                       shucuo=0;
  1010.                       shangdengcishu = 1;
  1011.                       shangdengtime = 50000;
  1012.                       guangdengtime = 0;
  1013.                       kaidengduibi=1;/*mima[1] = 0; mima[0] = 0;*/        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  1014.                       PORTB &=~(1<<5);
  1015.                       PORTB &=~(1<<4);
  1016.                       PORTB |=(1<<3);    //开门
  1017.                       DDRB = 0x39;   
  1018.                     }
  1019.                     else  {status = 2;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  1020.             }
  1021.                 break;
  1022.              case 2:
  1023.                    while(shucuo==3)      //输错3次就锁死300秒
  1024.                    {                    
  1025.                      #asm("WDR")   //喂狗
  1026.                     if(shucuo_ok)
  1027.                     {
  1028.                       qingling();    //清零
  1029.                       status = 0;                     
  1030.                       shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  1031.                       shangdengcishu = 1;
  1032.                       shangdengtime = 50000;
  1033.                       guangdengtime = 0;
  1034.                       kaidengduibi=1;                     
  1035.                     }
  1036.                    }
  1037.                   status = 0;   //输错3次前继续放回等待输入命令,注意如果之后没有按键转入掉电模式后是否记忆之前输错的次数,以防产生BUG,不然输错两次,
  1038.                   break;              //等转入掉电模式后,又可以唤醒继续输入,这样就惨了!
  1039.              case 3:
  1040.                if (read_key_n() == 3)    //长按3.5秒进入密码设置部分
  1041.                   {
  1042.                      status = 12;                  
  1043.                   }
  1044.                else  if (ermiao_ok) {status = 0;}
  1045.                   break;      
  1046.               case 12:               //老密码输入对,开始第一次输入新密码
  1047.                  if (read_key_driver() ==1 )
  1048.                  {   
  1049.                     for(j=0;j<5;j++)
  1050.                        {
  1051.                         ysmima[j]=mima[j];
  1052.                        }
  1053.                      status = 13;
  1054.                  }  
  1055.                    break;
  1056.              case 13:               //开始第二次输入新密码,并和第一次的对比
  1057.                  if (read_key_driver() ==1 )
  1058.                  {   
  1059.                     for(j=0;j<5;j++)           //密码对比识别
  1060.                     {
  1061.                        if (mima[j]==ysmima[j])
  1062.                        {
  1063.                         cnt++;
  1064.                        }
  1065.                     }
  1066.                     if (cnt==5)
  1067.                     {
  1068.                       cnt=0;
  1069.                       //PORTB ^= 1<<3;
  1070.                       status = 14;
  1071.                       shucuo=0;
  1072.                       shangdengcishu = 1;
  1073.                       shangdengtime = 50000;
  1074.                       guangdengtime = 0;
  1075.                       kaidengduibi=1;
  1076.                       //mima[1] = 0; mima[0] = 0;
  1077.                     }        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  1078.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  1079.                  }  
  1080.                    break;
  1081.                case 14:               //开始第三次输入新密码,并和第一次的对比
  1082.                  if (read_key_driver() ==1 )
  1083.                  {   
  1084.                     for(j=0;j<5;j++)           //密码对比识别
  1085.                     {
  1086.                        if (mima[j]==ysmima[j])
  1087.                        {
  1088.                         cnt++;
  1089.                        }
  1090.                     }
  1091.                     if (cnt==5)
  1092.                     {
  1093.                       cnt=0;
  1094.                       PORTB ^= 1<<5;  //观察
  1095.                       status = 15;
  1096.                       shucuo=0;
  1097.                       shangdengcishu = 3;
  1098.                       shangdengtime = 50000;
  1099.                       guangdengtime = 10000;
  1100.                       kaidengduibi=1;
  1101.                       //mima[1] = 0; mima[0] = 0;
  1102.                     }        //密码输对后PORTB = 0xFD; //执行开门,PB1拉低
  1103.                     else  {status = 16;++shucuo;cnt=0;/*mima[1] = 0; mima[0] = 0;*/}       //即使密码不对,也得清零,不然会影响下一次正确密码的判断
  1104.                  }  
  1105.                    break;               
  1106.                        
  1107.                 case 15:        //第三次输对新密码后,开始记录                    
  1108.                    shangdengcishu = 1;
  1109.                    shangdengtime = 50000;
  1110.                    guangdengtime = 0;
  1111.                    kaidengduibi=1;
  1112.                     for(j=0;j<5;j++)           //写入新设置密码
  1113.                     {
  1114.                        #asm("cli")                     
  1115.                        while(EECR &(1 <<EEPE));
  1116.                        EECR = (0<<EEPM1)|(0<<EEPM0);
  1117.                        EEARL = j+10;
  1118.                        EEDR = mima[j];
  1119.                        EECR |=(1 <<EEPM1);
  1120.                        EECR |=(1 <<EEPM0);
  1121.                         ysmima[j] =  mima[j]; //密码立即生效                     
  1122.                        #asm("WDR")   //喂狗,写得慢,要及时喂狗
  1123.                        delay_ms(10);
  1124.                        #asm("sei")                       
  1125.                         
  1126.                     }                  
  1127.                     status = 0;                                       
  1128.                 break;
  1129.                 case 16:
  1130.                    if(shucuo==3)      //设置密码输错3次,重设密码失败就执行某行动
  1131.                    {
  1132.                     for(j=0;j<5;j++)           //读出原密码继续使用
  1133.                     {
  1134.                       #asm("cli")
  1135.                       while(EECR &(1 <<EEPE));
  1136.                       EEARL = j+10;
  1137.                       EECR |=(1<<EERE);
  1138.                       ysmima[j]=EEDR;
  1139.                       #asm("WDR")   //喂狗,写得慢,要及时喂狗
  1140.                       delay_ms(10);
  1141.                       #asm("sei")
  1142.                     }
  1143.                     shucuo =0 ;   //执行输错后也要清零,不然以后再错就没法执行了
  1144.                     PORTB ^= 1<<5;  //某行动
  1145.                     status = 0;
  1146.                    }
  1147.                   else status = 12;   
  1148.                 break;               
  1149.          }   
  1150.          if (ershimiao_ok)         //20秒无动作后休眠
  1151.          {
  1152.           shucuo=0;  //2次输错密码,若没有再输入密码,进入休眠就清除记录
  1153.           qingling();    //清零
  1154.           //PORTB = 11100110;   //11100110进入休眠前关所有灯
  1155.           //DDRB = 00100001;  //00100001,PB.0和5配置为输出,其它位为输入
  1156.           PORTB |=( 1<<1);   //置位
  1157.           PORTB &=~( 1<<0);  //清零
  1158.           DDRB = 0x39;
  1159.           TIMSK = 0x00;   //关闭T/C0比较匹配中断  
  1160.           /*关闭看门狗省电*/
  1161.           //#asm("cli") //关闭全局中断
  1162.           #asm("WDR")   //喂狗
  1163.           //MCUSR = 0x00;           
  1164.           //WDTCR |= (1<<WDCE) | (1<<WDE);           
  1165.           //WDTCR = 0x00;
  1166.           MCUSR &= ~(1<<WDRF);
  1167.           WDTCR |= (1<<WDCE) | (1<<WDE);
  1168.           WDTCR &= ~(1<<WDE);
  1169.           #asm("sei")  // 开放全局中断
  1170.           /*使能INT0中断*/
  1171.           GIMSK=0x40;
  1172.           MCUCR=0x00;
  1173.           GIFR=0x40;                     
  1174.           MCUCR |= (1<<SM1) | (0<<SM0);  // 掉电模式
  1175.           MCUCR |= (1<<SE);   //睡眠使能
  1176.           #asm("sleep")      //休眠
  1177.           PORTB ^= 1<<5;     //唤醒后监测
  1178.          }
  1179.         #asm("WDR")   //喂狗
  1180.         shangdeng(); //扫描闪灯
  1181.      }
  1182. }
复制代码
 楼主| 发表于 2014-5-6 08:37:51 | 显示全部楼层
为什么在某次编译的时候提示Linker error: the program has no 'main' function,关掉软件再打开就没有提示了,但是点里面的那些括号不在变成黄色的提示。这是怎么回事呢?

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-6 17:32:31 | 显示全部楼层
这个程序为什么PB2会长亮?为什么INT0不能唤醒

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-8 18:44:17 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-8 20:25 编辑

attiny13A和attiny85用CodeWizardAVR编译,INT0死活不能用(ICCV7 for AVR里改为INT0后居然是正常的!),还好PC_INT0可以用,终于调通了(密码还不能记录到片内EEPROM,应该是写程序有问题),这是文件包,休眠电流测试了一下,休眠后串了个5K电阻,测试的压降为2.38毫伏,算下来掉电模式的电流为0.476微安,真的不错啊!接下来INT0死活不能用继续找吧,还要找找BUG和优化代码。还有担心这两个IO 直接引出2米长的线来是否会出问题。唉,太费时间了!

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-8 20:27:37 | 显示全部楼层
搞定密码设定后写入片内EEPROM,原来是那些写相关的位名称不对

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-13 07:51:58 | 显示全部楼层
现在发觉输入密码太慢,准备改成长按按键通过闪灯来识别密码(有泄露密码的可能),到时改成可以随意设置密码位数(6位以内),改之前再保存一次

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-15 07:07:36 | 显示全部楼层
read_key_n(void)中,以下程序如果不注释,仿真的时候居然会运行,
  1. case key_state_3:
  2.              if (key_press)
  3.             {              
  4.                key_state = key_state_0; //按键已释放,转换到按键初始态
  5.                key_time = 0;                // 清按键计数器
  6.                key_return = 5;         //密码录入完成   
  7.             }   
  8.               else if (++key_time >= 50)        // 每0.7秒闪一次计数
  9.             {
  10.                 if (++mimajishu >9)
  11.                  {
  12.                     mimajishu = 0;  
  13.                  }              
  14.                
  15.                 key_time = 0;                // 清按键计数器        
  16.                 shangdengcishu = 1;    //开长闪灯
  17.                 shangdengtime = 3000;    //设置长闪灯时间
  18.                 guangdengtime = 0;    //设置关灯时间
  19.                 kaidengduibi=1;    //判断上一次闪灯是否结束,实现新开灯时能马上看到效果
  20.             }
  21.             
  22.             qingling();    //清零   
  23.              break;
  24.              //以下程序如果不注释,仿真的时候居然会运行
  25.        /* case key_state_4:
  26.             if (key_press)
  27.             {
  28.                 key_state = key_state_0; //按键已释放,转换到按键初始态
  29.             }   
  30.             qingling();    //清零
  31.             break; */     
  32.       }   
  33.     return key_return;
复制代码


本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-19 02:07:35 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-19 02:22 编辑

长按按键来数LED灯闪的次数来输入密码,代码完成,用M16调试的

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-19 04:29:20 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-19 04:30 编辑

移植到tiny85上来了,很不顺利,搞了2个多小时,问题解决了,但是原因不明,难道真的得上TINY的仿真器来找原因吗?

一条奇怪的指令搞定ATTINY85
http://www.amobbs.com/thread-5581468-1-1.html
(出处: amoBBS 阿莫电子论坛)

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-21 14:35:14 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-21 16:56 编辑

现在改成片内128K主频后,下载只能通过高压编程器,ISP没用了,且必须断开PB0接到ISP的线,不然会导致按键灯长亮,也就是进入了恢复密码设置后的那段代码,这个问题让我浪费一天时间。在程序的按键状态机中,不仅那条1毫秒的延时不需要了,而且端口改变之后接着读端口状态之前那条空指令“#asm("nop")      //如果没有这条延时的话,长按按键,闪一次灯就表现出 key_return = 5;的现象,也就是说闪6次后等于输入了6个密码1。”也不需要了。这点手册上没有写吧?看来CPU主频不同,各种怪问题也都来了。通过统计循环次数来闪灯的方法在这里不灵了,定时器的时间是准的呢,怎么怎么长按按键1.7秒后看到闪灯,但之后闪灯间隔由0.7秒变成4秒多?百思不得其解,于是我把闪灯函数改成定时器触发,这样以后改变主频也不用来调里面的参数了。这样一改后所有功能正常了


这是按键和灯接线图

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-21 15:04:03 | 显示全部楼层
不小心输入了一个0,导致编译提示出错Warning: C:\tiny85-128k\tiny85-128k.c(243): expression with possibly no effect和Error: C:\tiny85-128k\tiny85-128k.c(243): ';' expected, but 'P' found

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-23 23:14:07 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-23 23:16 编辑

接上长按键线后测试发现,那条按键后的1毫秒延时必须加上,否则长按按键还是出现2秒闪一次,标示输入的密码是1。初学之路果然充满坑洞。

  1. unsigned char read_key_n(void)
  2.   {
  3.     static unsigned char key_state = 0, key_time = 0;
  4.     unsigned char key_press, key_return = 0;                                                                                                                              
  5.     duankouPORTD |=( 1<<key_LED_fu);   //置位
  6.     duankouPORTD &=~( 1<<key_LED_zheng);  //清零
  7.     duankouDDRD &=~( 1<<key_LED_fu);      
  8.     #asm("nop")      //端口操作后插入空指令能正确读端口     
  9.     delay_ms(1);   // 当时钟为片内8M时,如果没有这条延时的话,长按按键,闪一次灯就表现出 key_return = 5;的现象,也就是说闪6次后等于输入了6个密码1。当时钟为片内128K时,在板上仿真可以不用这条,但当接上5米的线再到按钮时,故障出现,加上这条就OK了。
  10.     key_press = key_input;                // 读按键I/O电平
复制代码

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-24 10:26:01 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-24 10:36 编辑

奇怪,为了提高抗干扰能力,在开、关门后添加100毫秒延时,编译后占用的程序存储量居然减小了

  1. void opendoor(void)   //开门
  2.   {
  3.     duankouPORTD &=~((1<<Monitor_LED)|(1<<close_door));
  4.     duankouPORTD |=(1<<open_door);    //开门
  5.     duankouDDRD |=(1<<open_door)|(1<<close_door);
  6.     delay_ms(100);//防止开继电器干扰单片机
  7.   }
  8. void closedoor(void)   //关门
  9.   {
  10.    duankouPORTD &=~((1<<Monitor_LED)|(1<<open_door));
  11.    duankouPORTD |= (1<<close_door);    //关门
  12.    duankouDDRD |=(1<<open_door)|(1<<close_door);
  13.    delay_ms(100);//防止开继电器干扰单片机
复制代码

本帖子中包含更多资源

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

x
发表于 2014-5-24 17:58:03 | 显示全部楼层
从那里学到的,软件延时100ms能防止继电器干扰单片机?
 楼主| 发表于 2014-5-26 00:05:10 | 显示全部楼层
machao 发表于 2014-5-24 17:58
从那里学到的,软件延时100ms能防止继电器干扰单片机?

马老师问的好啊,是我错了,我应该注明:从某处学来的,还未经证实!以前在本论坛看到过有说继电器通电后延时几十毫秒可以防止继电器通电的电流冲击干扰单片机,具体哪篇我现在都找不到了。实际测试电控门之前,我就加了这么一条写了一片TINY85备用。但从昨天现场的测试结果来看,这片没用上。但昨天的测试我很不满意,原因:原电控器在开门和关门切换之间,有先释放A继电器后再开B继电器的步骤,我的没有,这点之前被我疏忽了,因为继电器在断电的很短时间内会仍然吸合,此时马上开另一组继电器的话,在某些场合可能导致短路。还有在开门的过程中我想马上停止,甚至在关门的过程中我想马上开门,这种情况可以应对某些突发情况,比如开关时电机卡死,关门时突然小猪跑出来等,原控制器上是分别有开门、停止、关门按键的,而现在用一个按键来实现这三个功能的话,我得再修改程序,有了之前的基础,现在感觉改程序轻松多了。初步定为单片机上电初始状态为等待输入密码开门(此时短按可以关门),密码正确后开门,此时若短按按键就停止,再短按按键就关门,再短按按键就停止,再再短按按键就开门,如此循环,直到没有任何操作30秒后(开关门时间为30秒内完成)自动返回初始状态。前几天媳妇的本田自由TODAY摩托车忘记开报警器,被小偷光顾,无奈机头质量太好太牢靠,小偷把机头硬扳歪许多也没有把前轮撇直,害得我第二天费了好大劲才把机头扭回原位。之前从自已的电动车第三次被撬终于被偷走,到半年后在路上找回,我早就想搞车用自动上锁报警喇叭兼断电报警器和无钥匙启动,当然也是用一个按键来操作,看来得抓紧时间了。
 楼主| 发表于 2014-5-26 01:34:01 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-26 01:40 编辑

根据上述改动,做出新的代码了,在马老师AVR仿真板上测试通过。现在做得有点打瞌睡了,以前是改到兴奋的时候就不困了。
现在想起一个问题来了:这个车库门上是里外各装有一个按键的,当在里面输入密码的时候,里面的按钮被人挡着看不见,可外面那颗并联的按钮是没有人遮挡呢,这样还不泄露密码?难道要分别占用两组端口来分别控制?

本帖子中包含更多资源

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

x
发表于 2014-5-27 00:13:54 | 显示全部楼层
1/继电器的控制是通过线圈,它是一个电感。当通断的瞬间会产生一个反相电动势,这个电动势与原电压叠加产生一个瞬间高压,回将驱动三极管击穿。通常在线圈两端并接一个反峰二极管和吸收电容就能很好的抑制掉。这个与延时无关。
2/继电器是机械动作,一次完全导通或断开需要20ms。如果你说断开A,延时100ms后再通B,这是对的,断开A后,延时100ms,A彻底断开了,然后再通B,不会造成电源短路。这个也就是现在的MCU用T/C产生PWM控制电机,带有死区时间设置和产生功能的原因。但这个不是防止干扰单片机,而是防止瞬间电源的短路。
3/你现在要作一个能实际使用的DD,而在实验板上的验证与实际情况差别是非常大的。况且我发现你对实际情况还没有充分的进行分析。比如,系统如何知道现在大门是开的还是关闭的?在关门的过程中,如何知道门已经是关上了?(如果门已经关上了,而系统继续给电机通电的话,此时门已经不能动了,那么电机也可能会烧毁掉,或者门变形了(电机功率很大的情况下)。tiny85只有6个I/O,一个按键、一个LED、一个A继电器,一个B继电器,还有2路作什么用?

=============================================
你应先贴上电路图,把需求和功能描述的准确些。
 楼主| 发表于 2014-5-27 12:48:59 | 显示全部楼层
machao 发表于 2014-5-27 00:13
1/继电器的控制是通过线圈,它是一个电感。当通断的瞬间会产生一个反相电动势,这个电动势与原电压叠加产生 ...

谢谢马老师,我之前没有把使用环境描述清楚,因为觉得原理太简单所以没有画出电路图来。原被控制的电机为杜亚管状电机,内部已经有限位开关,输出为4根线,即:地线、零线、正转(火线)、反转(火线),不管正转还是反转,电机内部顶到限位开关后就自动断电保护电机了。我测试了一下这道卷帘门,开、关门时间各为27秒。根据这一特点,我只要控制板输出30秒后休眠即可。关于如何让系统判断门现在是开还是关,我是设计成让人来判断的,也就是说假设大门为开着的,那么关门的人只要短按按钮就可以关门;假设大门是关着的,那么开门的人就得先输入正确的密码,然后就会马上开门,之后短按就会在停止、关门、停止、开门这样循环,直到没有按按钮30秒后休眠。现在的问题是因为是直接控制原门控器上的继电器,如果此时用遥控器的话就会和密码锁冲突,导致短按密码锁不能关门(原控制器开门后继电器会通电3分钟,只有等3分钟过后才可能用密码锁关门)。所以我现在要把密码锁输出改接到原门控器手动按钮上,输出几十毫秒的低电平(模拟手按按钮)应该就可以了。现在想到的这些问题我都能根据需要来改程序了,可就是那个TINY85的INT0为什么没有反应呢,请马老师再指点一下吧,谢谢!这是原来测试TINY85的INT0的代码:

  1. /*****************************************************
  2. This program was produced by the
  3. CodeWizardAVR V2.05.1b Evaluation
  4. Automatic Program Generator
  5. ?Copyright 1998-2011 Pavel Haiduc, HP InfoTech s.r.l.
  6. http://www.hpinfotech.com

  7. Project :
  8. Version :
  9. Date    : 2014-5-24
  10. Author  : Freeware, for evaluation and non-commercial use only
  11. Company :
  12. Comments:


  13. Chip type               : ATtiny85
  14. AVR Core Clock frequency: 8.000000 MHz
  15. Memory model            : Small
  16. External RAM size       : 0
  17. Data Stack size         : 128
  18. *****************************************************/

  19. #include <tiny85.h>
  20. #include<delay.h>
  21. // External Interrupt 0 service routine
  22. interrupt [EXT_INT0] void ext_int0_isr(void)
  23. {
  24. // Place your code here
  25. GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  26. GIFR=0x40;
  27. PORTB ^= 1<<4;
  28. }

  29. // Declare your global variables here

  30. void main(void)
  31. {
  32. // Declare your local variables here

  33. // Crystal Oscillator division factor: 1
  34. #pragma optsize-
  35. CLKPR=0x80;
  36. CLKPR=0x00;
  37. #ifdef _OPTIMIZE_SIZE_
  38. #pragma optsize+
  39. #endif

  40. // Input/Output Ports initialization
  41. // Port B initialization
  42. // Func5=Out Func4=Out Func3=Out Func2=Out Func1=In Func0=Out
  43. // State5=1 State4=1 State3=1 State2=1 State1=P State0=1
  44. PORTB=0x3F;
  45. DDRB=0x3D;

  46. // Timer/Counter 0 initialization
  47. // Clock source: System Clock
  48. // Clock value: Timer 0 Stopped
  49. // Mode: Normal top=0xFF
  50. // OC0A output: Disconnected
  51. // OC0B output: Disconnected
  52. TCCR0A=0x00;
  53. TCCR0B=0x00;
  54. TCNT0=0x00;
  55. OCR0A=0x00;
  56. OCR0B=0x00;

  57. // Timer/Counter 1 initialization
  58. // Clock source: System Clock
  59. // Clock value: Timer1 Stopped
  60. // Mode: Normal top=0xFF
  61. // OC1A output: Disconnected
  62. // OC1B output: Disconnected
  63. // Timer1 Overflow Interrupt: Off
  64. // Compare A Match Interrupt: Off
  65. // Compare B Match Interrupt: Off
  66. PLLCSR=0x00;

  67. TCCR1=0x00;
  68. GTCCR=0x00;
  69. TCNT1=0x00;
  70. OCR1A=0x00;
  71. OCR1B=0x00;
  72. OCR1C=0x00;

  73. // External Interrupt(s) initialization
  74. // INT0: On
  75. // INT0 Mode: Low level
  76. // Interrupt on any change on pins PCINT0-5: Off
  77. GIMSK=0x40;
  78. MCUCR=0x03;
  79. GIFR=0x40;

  80. // Timer(s)/Counter(s) Interrupt(s) initialization
  81. TIMSK=0x00;

  82. // Universal Serial Interface initialization
  83. // Mode: Disabled
  84. // Clock source: Register & Counter=no clk.
  85. // USI Counter Overflow Interrupt: Off
  86. USICR=0x00;

  87. // Analog Comparator initialization
  88. // Analog Comparator: Off
  89. ACSR=0x80;
  90. ADCSRB=0x00;
  91. DIDR0=0x00;

  92. // ADC initialization
  93. // ADC disabled
  94. ADCSRA=0x00;

  95. // Global enable interrupts
  96. #asm("sei")

  97. while (1)
  98.       {
  99.       // Place your code here
  100.        // Place your code here
  101.       delay_ms(4000);
  102.       PORTB ^= 1<<3;
  103.       GIMSK=0x40;
  104.       }
  105. }
复制代码


这是程序包:

本帖子中包含更多资源

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

x
发表于 2014-5-27 15:42:37 | 显示全部楼层
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.3 Standard
Automatic Program Generator
?Copyright 1998-2011 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 2014-5-27
Author  : PerTic@n
Company : If You Like This Software,Buy It
Comments:


Chip type               : ATtiny85
AVR Core Clock frequency: 8.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/

#include <tiny85.h>

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State5=T State4=T State3=T State2=P State1=T State0=T
PORTB=0x04;
DDRB=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Timer1 Overflow Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
PLLCSR=0x00;

TCCR1=0x00;
GTCCR=0x00;
TCNT1=0x00;
OCR1A=0x00;
OCR1B=0x00;
OCR1C=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=0x40;
MCUCR=0x03;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;

// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      }
}
================================
1/ 这是我用我的CVAVR生成的代码,版本比你用的高。INT0中断设置为MCUCR=0x03时,应该为上升沿触发。我看了TINY85手册,03是上升沿触发,00是低电平触发。你用的CVAVR有问题。

2/你用低电平中断是唤醒CPU吗?如果不是用于唤醒CPU,最好采用边沿触发中断方式。

3/如果是低电平触发中断,那么中断最好这样写:
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
     int delay_pb2 = 0;
      
     // GIMSK=0x00; //禁用INT0中断,等合适的时候再打开=====>这个无用,AVR进中断时自动关闭全局中断响应。
    //  GIFR=0x40;        ======>多于,见下面英文。低电平中断不会将中断标志位值“1”,用不到清楚
    //  PORTB ^= 1<<4;  ====> CVAVR支持位变量操作,这样直观易理解,而且简短。PORTB ^= 1<<4;要3条汇编完成,而下面只要一条
    PORTB.5 = 1                    //LED亮,提示进入中断
    while(delay_pb2 <50000)        等待PB2(INT0)彻底稳定恢复高电平后退出中断
    {
          if (PINB.2)
             ++delay_pb2;
          else
             delay_pb2 = 0;
    }
    PORTB.5=0;   //LED灭,提示退出中断
}


• Bit 6 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt request, INTF0 becomes set (one). If the I-bit in SREG and the INT0 bit in GIMSK are set (one), the MCU will jump to the corresponding Interrupt Vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it.

This flag is always cleared when INT0 is configured as a level interrupt.

4/ INT0的输入是PB2,应该设置成输入方式上拉有效,你初始化设置成输出方式,并输出“1”,那么该引脚是5V输出,你把它拉成低电平触发中断,相当把5V正与地断路,会有大电流从PB2流出,容易将PB2引脚烧毁。
 楼主| 发表于 2014-5-28 02:23:58 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-28 10:23 编辑
machao 发表于 2014-5-27 15:42
/*****************************************************
This program was produced by the
CodeWizardAV ...


    谢谢马老师指点!之前我是先看TINY13A中文版数据手册,以为TINY系列8只脚的引脚功能定义是一样的,后来看TINY85的数据手册只有英文手册,就没有看引脚定义,只是对照寄存器、融丝、EEPROM如何定义,所以之前测试TINY85的INT0时,真正的INT0让我接到了共阳LED灯上,导致我误以为TINY85的INT0不起作用。这实在是我的粗心大意造成。
    1、我选用低电平中断就是为了唤醒CPU
    2、// GIMSK=0x00; //禁用INT0中断,等合适的时候再打开。这条我是为了在密码锁中唤醒后不再用INT0,而把INT0当作普通输入端口而写的。
         //  GIFR=0x40;这条我也看了数据手册,我也觉得没用,但当时实在找不出原因才加上这条试试的。
        PORTB.5 = 1 //LED亮,提示进入中断   这个要用PB5来点灯,应该在融丝里把PB5的复位功能禁用,太麻烦不方法调试我才换成PB4,而我接的是仿真板上A区的共阳LED,输出1时是不亮灯的。
      3、  您举的低电平触发中断写法我看懂了,相当于按键消抖,松开按键后才退出中断程序,不过这个delay_pb2 <50000延时我测试下来非常短,不知道为什么会这样?我甚至还增加了延时,可效果是一样的,真是奇怪
  1. interrupt [EXT_INT0] void ext_int0_isr(void)
  2. {
  3. // Place your code here
  4.     unsigned int delay_pb2 = 0,i;   //定义一个变量   
  5.     PORTB.4 = 0;//LED亮,提示进入中断   
  6.     while(delay_pb2<50000) //等待PB2(INT0)彻底稳定恢复高电平后退出中断
  7.     {
  8.         if (PINB.2)
  9.            {
  10.             for(i = 0;i<1140;i++)         
  11.              {
  12.                ++delay_pb2;
  13.               }               
  14.              delay_pb2 = 0;
  15.            }
  16.          
  17.           else
  18.              delay_pb2 = 0;
  19.     }   
  20.     PORTB.4=1;   //LED灭,提示退出中断
  21. }
复制代码


后来我改成这样就有长延时的效果了
  1. interrupt [EXT_INT0] void ext_int0_isr(void)
  2. {
  3. // Place your code here
  4.     unsigned int delay_pb2 = 1,i,j;   //定义一个变量   
  5.     PORTB.4 = 0;//LED亮,提示进入中断   
  6.     while(delay_pb2) //等待PB2(INT0)彻底稳定恢复高电平后退出中断
  7.     {
  8.         if (PINB.2)
  9.            {
  10.             for(i = 0;i<500;i++)
  11.                 {
  12.                  for(j = 0;j<1140;j++);
  13.                 }
  14.              delay_pb2 = 0;
  15.            }
  16.          
  17.           else
  18.              delay_pb2 = 0;
  19.     }   
  20.     PORTB.4=1;   //LED灭,提示退出中断
  21. }
复制代码

    4、还有那个INT0中断触发方式,如果选任意逻辑电平变化触发中断的话,在以下的代码中,我测试下来发现在PORTB.3 = 0;//亮灯时按一下按键不会马上进入中断程序,而是等PORTB.3 = 1;然后再到PORTB.3 = 0时,才会执行时中断程序;如果在PORTB.3 = 1时按一下按键,一样不会响应中断程序,而是要等PORTB.3 = 0时才响应,想不通啊!然后如果把中断服务程序里的GIMSK=0x00;去掉的话,在 PORTB.3 = 0;//亮灯和PORTB.3 = 1;状态时短按按键都是可以马上响应INT0的。
  1. #include <tiny85.h>
  2. #include<delay.h>
  3. // External Interrupt 0 service routine
  4. interrupt [EXT_INT0] void ext_int0_isr(void)
  5. {
  6. // Place your code here
  7.     unsigned int delay_pb2 = 1,i,j;   //定义一个变量
  8.     GIMSK=0x00; //禁用INT0中断,等合适的时候再打开
  9.     PORTB.4 = 0;//LED亮,提示进入中断   
  10.     while(delay_pb2) //等待PB2(INT0)彻底稳定恢复高电平后退出中断
  11.     {
  12.         if (PINB.2)
  13.            {
  14.             for(i = 0;i<500;i++)
  15.                 {
  16.                  for(j = 0;j<1140;j++);
  17.                 }
  18.              delay_pb2 = 0;
  19.            }
  20.          
  21.           else
  22.              delay_pb2 = 0;
  23.     }      
  24.     PORTB.4=1;   //LED灭,提示退出中断
  25. }
复制代码

主循环是这样的:
  1. while (1)
  2.       {
  3.       // Place your code here
  4.        // Place your code here
  5.       PORTB.3 = 0;//亮灯
  6.       //#asm("nop")      //端口操作后插入空指令能正确读端口
  7.       GIMSK=0x40;//亮灯时开INT0
  8.       delay_ms(4000);
  9.       PORTB.3 = 1;
  10.       delay_ms(4000);  
  11.       }
复制代码
 楼主| 发表于 2014-5-30 17:17:50 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-5-30 17:35 编辑

为了调试方便,把融丝改为62D7,使用片内8M。为了不和遥控器冲突,把控制继电器直接改接到原控制板的三个控制按钮上来实现开门、关门、停止的功能。此时把监视LED端口改接到停止按钮上。为了防止初始状态关门时有意外,添加再短按就停止、再按关门、再按停止如此循环,在此循环中若长按的话依然转入密码输入状态。

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-5-31 07:20:46 | 显示全部楼层
之前密码位数是可以自己在6位以内设定,但是如果是6位以内时,初始状态时输入完密码得等4秒后才能有输出动作。现在改为设为6位以内时,输入完密码马上动作,代价是代码增加186字节。

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-6-3 01:09:52 | 显示全部楼层
今天测试出上电原控制器的停止按钮没有作用,得等输对一次密码后,才能起作用, 现在顺便添加休眠前闪灯
 楼主| 发表于 2014-6-17 03:46:12 | 显示全部楼层
本帖最后由 kdgj8899 于 2014-6-17 03:58 编辑

今天在调试报警器时发现这个密码锁里的一个BUG,实践中还没发现问题,但理论上分析出问题了,就是原休眠程序中没有status = 0这条,按理应该唤醒后会继续跑密码输对后的循环。之前只是想着密码输对开门,然后30秒后休眠,忘记了休眠后唤醒程序是接着跑呢,先上修改后的程序

本帖子中包含更多资源

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

x
 楼主| 发表于 2014-6-21 00:46:51 | 显示全部楼层
找到为什么之前没出问题的原因了,原来我己经在PC-INT0中断里添加status = 0这条了。
 楼主| 发表于 2014-8-14 00:11:37 | 显示全部楼层
昨天在大门边做氩弧焊作业,后来发现这个单片机密码老输不对,做恢复密码的操作不起作用(可以休眠,原控制板功能也正常),看来单片机被远程烧掉了。以前在票据打印机旁边做氩弧焊作业,同样烧掉一台票据打印机。看来这个氩弧焊太强大了。
 楼主| 发表于 2015-3-10 09:59:12 | 显示全部楼层
这个单按钮接线有2米长,其中大部分是在铝合金型材中,但是经过半年的测试,我发现单片机容易受干扰,看来得改在按钮上直接做个发射编码,然后在控制盒里再解码,这样控制才可靠。得抽时间学编解码了。
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 公安备案:44190002001997(交互式论坛) 工信部备案:粤ICP备09047143号 )

GMT+8, 2019-9-18 04:02

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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