单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:8135|回复:3

单片机检测交流电掉电程序(数码分段开关)

[复制链接]
ID:262发表于 2014-2-20 22:02|显示全部楼层
灯饰配件中有一种控制器叫数码分段开关,基本工作原理是利用墙壁开关通断电来实现对多种负载的轮流亮灭,这其中就涉及到单片机如何检测交流电掉电。首先,要把交流电的同步信号提取出来,形成单片机能识别的低压信号,一般有2中方法,一种是直接利用电阻分压法,把同步信号提取(适合非隔离型电路)。另外一种方法是利用光耦提取隔离的交流信号。2种方法如下所示:

psb(285).jpeg
光耦隔离取样电路

psb(286).jpeg

电阻分压取样电路

所取得的交流信号如下图:
psb(287).jpeg

本程序实现的功能是,第一次打开关,L1亮,L2灭,第二次打开关,L1灭,L2亮,第三次打开关,L1,L2全亮,第四次打开关,L1,L2全灭,如此循环。那么,单片机检测交流电掉电,每隔一定时间检测一次交流信号输入口,如果是低电平,开始计时,如果12MS-15MS之后,还是低电平,说明交流电被断过一次电,此时要做出相应的控制动作。所用单片机为PIC16F676,RA5上的脚作为交流检测脚。RC2,RC3作为负载输出控制端。程序如下:

#include<pic.h>
__CONFIG(0X1B4);
#define uchar unsigned char//宏定义,相当于uchar=unsigned char
#define uint unsigned int//宏定义,相当于uint=unsigned  int




uint key2_time_cnt;//按键去抖计数器
uchar key2_lock;//按键有效标志
uchar key2_num_s;//功能散转变量
uchar key2_touch_s_flag;//交流断电信号有效标志
uint shuzi;//时标计数变量
uchar SYS1MS;//时标开关标志

void PORT_init()
{
ANSEL=0X00;//普通端口设置
CMCON=0X07;//比较器关闭
TRISA=0b00110100;
TRISC=0b00110000;
PORTC=0X00;
PORTA=0X00;
T0CS=0;//定时器内部时钟选择
;
T0IF=0;//定时器中断标志清零
T0IE=1;//定时器中断使能
GIE=1;//全局中断使能
TMR0=9;//定时器初值为零
}

void key_scan2()
{
if(RA5==1)//如果RA5上按键没有按下
{
   key2_lock=0;//2号键标志清零
   key2_time_cnt=0;//去抖计数器清零
   if(key2_touch_s_flag==1)//如果交流断电信号有效
   {
    
     key2_touch_s_flag=0;//清交流信号标志
     key2_num_s++;//功能号开始自加
     if(key2_num_s>3)key2_num_s=0;//一共4种功能
   }

}
else if(key2_lock==0)//如果有键第一次按下
{
   key2_time_cnt++;//去抖计数器开始计数
   if(key2_time_cnt>149)//当计数器值大于149,说明低电平持续的时间大于10MS,而交流电高低电平的持续时间是8——10MS,这就表示交流电被断电了。
   {
     key2_touch_s_flag=1;//交流断电有效,标志置一。
     key2_time_cnt=0;//清去抖动计数器
     key2_lock=1;//自锁标志置1,避免一直触发
    
   }
}
}

void key_service2()
{

switch(key2_num_s)
{
   case 0:
       RC2=1;
   RC3=0;
   RA0=0;
   RA1=0;
       //key2_num_s=0;
       break;
   case 1:
     RC2=0;
   RC3=1;
   RA0=0;
   RA1=0;
       //key2_num_s=0;
       break;
   case 2:
       RC2=1;
   RC3=1;
   RA0=0;
   RA1=0;
     // key2_num_s=0;
       break;
   case 3:
     RC2=0;
   RC3=0;
   RA0=0;
   RA1=0;
       //key2_num_s=0;
       break;
   }
  
}

void main()
{
PORT_init();
while(1)
{
if(SYS1MS==1)
{
SYS1MS=0;
key_scan2();
}
key_service2();
}
}
void interrupt isr()//定时器0中断函数
{
     if((T0IE&T0IF)==1)//判断定时器中断
   {  
     T0IF=0;//清定时器中断标志
         T0IE=0;//关定时器中断
         TMR0=9;//从9加到256所用时间是250US
         shuzi++;
         if(shuzi==4)
         {
           shuzi=0;
           SYS1MS=1;
         }
        
        
         T0IE=1;//开定时器中断
   }
}



本程序对于断电检测使用了
if()
{
第一区
}
else if()
{
第二区
}

       一开始,信号高电平阶段,在第一区,要把各种标志清零,同时,要判断断电标志是否有效,这样做的目的是为了消除,交流电断电瞬间单片机会出现误动作(闪灯) ,如果作为一般按键检测的话,这里做判断,并且做出相应的按键有效处理,实际上是,等待按键松手后才做有效的处理。当有低电平到来时,实际上 else if(key2_lock==0)这语句等同于else if((!RA5)&&(!key2_lock)),RA5为低,同时按键标志没有被置1,确定上面2个条件同时成立,说明RA5端口起码是低电平了,但不一定是断电了。在第二区,然后让去抖动计数器key2_time_cnt自加,当计数器大于149时候,认为断电了(因为在一个周期内交流电低电平持续时间大概是100,所以要适当加宽低电平判断范围,)此时要马上把断电有效标志key2_touch_s_flag置1。
     对于交流电断电检测功能函数key2_scan()在整个程序的位置,第一,可以直接放到定时器中断里面,每250US执行一次。第二,可以利用定时器设定一个时标比如1MS的时标,主程序中,根据时标来执行key2_scan()函数。最好不要直接放在主循环中,这样会漏掉按键检测的某个档位。
       以上就是数码分段器的基本控制程序。单片机交流检测是本程序的难点。




ID:59566发表于 2014-3-10 14:06|显示全部楼层
写得很有水平
ID:61875发表于 2014-11-10 16:11|显示全部楼层
谢谢楼主的奉献学习了。
ID:77667发表于 2015-4-21 22:18|显示全部楼层
如果都是自己做的就很厉害

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网