⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 基于AVR单片机的程近期电话交换机源程序,可实现一拖四(一外线,四内线).
💻 C
字号:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/delay.h>

#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long

#define relay_s	 PORTD|= 0x01	//继电器吸合, 接到外线
#define relay_c  PORTD&=~0x01		//继电器释放, 内线互打

#define PH1_s    PORTC|= 0x20		//接通#1
#define PH1_c    PORTC&=~0x20		//断开#1
#define PH2_s    PORTB|= 0x20		//接通#2
#define PH2_c    PORTB&=~0x20		//断开#2
#define PH3_s    PORTB|= 0x08		//接通#3
#define PH3_c    PORTB&=~0x08		//断开#3
#define PH4_s    PORTB|= 0x02		//接通#4
#define PH4_c    PORTB&=~0x02		//断开#4

#define RG1_s	 PH1_c, PORTC|= 0x10		//振铃#1开
#define RG1_c	 PORTC&=~0x10, PH1_s		//振铃#1关
#define RG2_s	 PH2_c, PORTB|= 0x10		//振铃#2开
#define RG2_c	 PORTB&=~0x10, PH2_s		//振铃#2关
#define RG3_s	 PH3_c, PORTB|= 0x04		//振铃#3开
#define RG3_c	 PORTB&=~0x04, PH3_s		//振铃#3关
#define RG4_s	 PH4_c, PORTB|= 0x01		//振铃#4开
#define RG4_c	 PORTB&=~0x01, PH4_s		//振铃#4关

#define GATE     20				//听筒拿起通门槛电压( 50 为 0.125V)

#define L1_s     PORTB|= 0x40		//L1 on
#define L1_c     PORTB&=~0x40		//L1 off
#define L1_i	 PORTB^= 0x40		//L1 inver
#define L2_s	 PORTB|= 0x80		//L2 on
#define L2_c     PORTB&=~0x80		//L2 off

#define  CPU_CRYSTAL    (8.00) 	//CPU Ck

#define  dy(us)\
  _delay_loop_2((uint)((us)*CPU_CRYSTAL/4))
  
volatile uchar adcou=240;				//adc 转换计数器
volatile uint  adadd=0;				//adc 累加值
volatile uchar hu[4]={0,0,0,0};		//听筒合起标志
volatile uchar ringflag[4]={0,0,0,0};	//正在响铃标志
volatile uchar decode[10]={0};	    //最近十次解码结果
volatile uchar lms=0;					//LED点亮时间计数器
volatile uint  ringtime=400;			//响铃时间计数器, 当ringtime>400时,铃响, tingtime<=400时,铃不响
volatile uchar L_flash=0;				//LED1闪烁标志, =1时闪烁

volatile uchar ringcou=0;				//外线振铃计数器
volatile uint  ringcoutime=0;			//外线振铃时间计数器
volatile uchar out_ringflag=0;		//外线振铃标志

  
void delay(uint t)		//delay t mS
{
 while(t--)
   dy(980);
} 


void s_ini(void)
{
 OSCCAL= 0xBF;
 PORTB = 0x2A;
 DDRB  = 0xff;
 PORTC = 0x20;
 DDRC  = 0x30;
 PORTD = 0x00;
 DDRD  = 0x01;
 
 MCUCR = 0x0E;		//INT1 raising edg cause intterupt, INT0 falling edg
 GICR  = 0xC0;		//enable INT1,INT0
 
 ADCSRA= 0xED;		//enabel ADC, enable interrupt, ADCck=fck/128
 ADMUX = 0xc0;		//CH0
 
 TCCR2 = 0x0f;
 OCR2  = 77;		//timer for 10mS
 TIMSK = 0x80;		//enable intterrupt 
 
  
 UCSRB = 0x00; 		//serial port setting
 UCSRA = 0x00;
 UCSRC = 0x80 | 0x06;
 UBRRL = 51; 		//set baud rate lo		   baud rate=9600, fck=8.00MHz
 UBRRH = 0x00; 		//set baud rate hi
 UCSRB = 0x08;      //enable to sent receive and 8 bits per bits//*/
 
 sei();  
}

SIGNAL(SIG_ADC)		//adc interrupt
{
 uint tmp;
 if(((ringtime<395)&&(ringtime>375))||((ringtime<270)&&(ringtime>250))
	||((ringtime<145)&&(ringtime>125)) || ((ringtime<20)&&(ringtime>0)))	//铃响期间不进行摘机检测
   {
    adadd+=ADC;		//
    adcou--;
	
    if(adcou==0)		//完成ADC0,切换到ADC3
      {
       adcou=240;
	 
       ADMUX=0xC3;
	    if((adadd/50)>GATE)	//取结果
	       hu[3]=1;
	    else
	       hu[3]=0;
	   }
    else if(adcou==230)	//开始记录ADC3
       {
	    adadd=0;
	   }
     else if(adcou==180)	//完成ADC3,切换到ADC2
       {
	    ADMUX=0xc2;
	    if((adadd/50)>GATE)	//取结果
	       hu[0]=1;
	    else 
	       hu[0]=0;	    
	   }
     else if(adcou==170)	//开始记录ADC2
      {
	    adadd=0;
	   }
     else if(adcou==120)	//完成ADC2, 切换到ADC1
      {
	   ADMUX=0xc1;
	   if((adadd/50)>GATE)		//取结果
	       hu[1]=1;
       else 
          hu[1]=0; 
	   }
     else if(adcou==110)	//开始记录ADC1
       {
	    adadd=0;
	   }
     else if(adcou==60)	//完成ADC1, 切换到ADC0
       {
	    ADMUX=0xc0;
	    if((adadd/50)>GATE)
	       hu[2]=1;
	    else
	       hu[2]=0;
	   }
     else if(adcou==50)	//开始记录ADC0
       {
	    adadd=0;
	   }
  }
 else
   tmp=ADC;		
}

SIGNAL(SIG_OUTPUT_COMPARE2)		//time 2 compare interrupt  for display 10mS
{
 if(ringcoutime)		//外线振铃计时器
    {
	 ringcoutime--;
	 if(ringcoutime==0)		//时间到
	    {
	     ringcou=0;
		 out_ringflag=0;
		}
	}
	
 ringtime--;
 if(ringtime==0)
   {
    ringtime=500;
   }
 if((ringtime==500)||(ringtime==440))	//内线振铃,响0.4S,停0.2S, 响0.4S 停4S
   {
    if(ringflag[0])		//查标志位,看是否需要响铃
	    RG1_s;
    if(ringflag[1])
	    RG2_s;
	if(ringflag[2])
	    RG3_s;
	if(ringflag[3])
	    RG4_s;
   }
 else if((ringtime==460)||(ringtime==400))	//关闭所有振铃
    {
	 if(ringflag[0])		//只有启动了的振铃才关, 
	    RG1_c;
     if(ringflag[1])
	    RG2_c;
	 if(ringflag[2])
	    RG3_c;
	 if(ringflag[3])
	    RG4_c;
    }
 if(out_ringflag)		//外线振铃标志
    {
	 if(ringtime==500)		//#1响铃
	    {
		 RG1_s;
		}
	 else if(ringtime==400)	//#1关闭响铃
	    {
		 RG1_c;
		}
     else if(ringtime==375)	//#2响铃
	    {
		 RG2_s;
		}
	 else if(ringtime==275)	//#2关闭响铃
	    {
		 RG2_c;
		}
	 else if(ringtime==250)	//#3响铃
	    {
		 RG3_s;
		}
	 else if(ringtime==150)	//#3关闭响铃
	    {
		 RG3_c;
		}
	 else if(ringtime==125)	//#4响铃
	    {
		 RG4_s;
		}
	 else if(ringtime==25)		//#4关闭响铃
	    {
		 RG4_c;
		}
	}
 
 
 
 if(L_flash==0)			//L2 flash	电源指示
     {
	  if(ringtime%100==0)
	      L2_s;
	  else if(ringtime%100==80)
	      L2_c;
     }		
 else if(L_flash==1)		//LED flash fast
    {
	 if((ringtime%15)==0)
	     L1_i;
    }  
 else if(L_flash==2)	//LED flash slow
     {
	  if((ringtime%50)==0)
	     L1_i;
	 }
 if(lms)
   {
    lms--;
	if(lms==0)
	   L1_c;		//time up turn off led
   }
} 

SIGNAL(SIG_INTERRUPT0)		//外线振铃
{
 if(ringcou<10)
     ringcou++;
	 
 ringcoutime=500;			//设定为5S
}


SIGNAL(SIG_INTERRUPT1)		//DTMF decode sussess cause this interrup
{
  uchar i;
  lms=12;			//turn on led for 120mS
  L1_s;
  for(i=9;i;i--)		//保存最近十次解码结果
    {
	 decode[i]=decode[i-1];
	}
  decode[0]=PIND>>4;	//读解码结果
  
}	

void clr_decode(void)	//解码数组全部填0
{
 uchar i;
 for(i=0;i<10;i++)
   decode[i]=0;
}

//检测哪个分机拿起了听筒, 但不检测num 号机, 
uchar test_hu(uchar num)  //若num为0则检查所有分机, 无返回0, 有返回分机号1-4
{
 uchar i;
 for(i=0;i<4;i++)	//检测有没有分机拿起
  {
    if(hu[i]&&((i+1)!=num))
     {
	   return(i+1);
     }			  
  }
 return 0;		//返回分机号
}

void lock(uchar num)	//封锁除num外的分机, 分机号为0则不取消封锁
{
 if(num==0)		//取消封锁
    {
     PH1_s;
	 PH2_s;
	 PH3_s;
	 PH4_s;
	}
 else if(num==1)	//封锁2,3,4
   {
    PH2_c;
	PH3_c;
	PH4_c;
   }
 else if(num==2)	//封锁1,3,4
   {
    PH1_c;
	PH3_c;
	PH4_c;
   }
 else if(num==3)	//封锁1,2,4
   {
    PH1_c;
	PH2_c;
	PH4_c;
   } 
 else if(num==4)	//封锁1,2,3
   {
    PH1_c;
	PH2_c;
	PH3_c;
   }
}

int main(void)
{
 uchar i;
 uchar num=0;		//num # 分机拿起
 uchar num1=0;
 uchar calln=0;		//被叫机号
 
 s_ini();
 
 for(;;)
   {
    num=test_hu(0);	//检查哪个分机拿起
	
	if(num)		//有分机拿起
	    {
		  L_flash=3;
		  L2_s;
	      lock(num);		//封锁除num外的分机
		 // UDR=num;
	
		  while(num==test_hu(0))		//直到放下听筒
		    {
			 if((decode[1]==8)&&(decode[0]>0&&decode[0]<5
			                   &&decode[0]!=num))	//拨号条件, 不能打自己
			     {
				  calln=decode[0];		//保存被叫机号
				  *(ringflag+(calln-1))=1;			//响铃
				  L_flash=1;				//LED闪烁
				  while((num==test_hu(calln))&&(calln != test_hu(num)))	//等等被叫接电话或主叫放下听筒
				      {
					   }
				  *(ringflag+(calln-1))=0;//停止响铃
				  
				  clr_decode();		//清除解码阵列
	
				  if(calln==test_hu(num))		//被叫接电话
				       {
					    L_flash=2;			//LED慢速闪烁
						while(test_hu(0))	//等待通话完毕
						   {				//在这里加入多方通话功能
						   }
						L_flash=3;
						L1_c;
					   }
				  if(num!=test_hu(calln))		//主叫放下电话
				      {
					   L_flash=3;				//停止LED闪烁
					   L1_c;
					  }
				  clr_decode();		//清除解码阵列
				}
			  if(decode[0]==9)		//打外线条件
			     {
				  delay(100);		//延时, 不让'9'拨出去
				  relay_s;			// 接通外线
				  delay(100);
				  while(test_hu(0))//等待听筒放下
				    {				//在这里加入多方通话功能
					 if((decode[2]==11)&&(decode[1]==8)&&
					        (decode[0]>0&&decode[0]<5&&decode[0]!=num))//拨号条件, 不能打自己
					   {
					      calln=decode[0];		    //保存被叫机号
						  *(ringflag+(calln-1))=1;	//响铃
				          L_flash=1;				//LED闪烁
						   while((num==test_hu(calln))&&(calln != test_hu(num)))	//等等被叫接电话或主叫放下听筒
				               {
					            }
				           *(ringflag+(calln-1))=0;//停止响铃
				           if(calln==test_hu(num))	//被叫接电话
				              {
					            L_flash=2;			//LED慢速闪烁
						      }
				           clr_decode();		   //清除解码阵列
						}
					}
				 L1_c;
				 relay_c;			//返回内线
				 clr_decode();		//清除解码阵列
				 }
			}
		  L2_c;
		  L_flash=0;		  
		  lock(0);		//解除封锁	  
	   }
	else			//没分机拿起
	   {
	    if(ringcou>5)				//有外线电话
		   {
		    L1_s;					//点亮L1
			out_ringflag=1;
			num1=0;
			while(num1==0&&ringcou>5)			//等等有人接电话
			  {
			    num1=test_hu(0);		//等待num1接到了电话			  
			  }
			L1_c;  
			if(num1)		//有人接电话
				{
				 L_flash=3;
				 L2_s;
				 out_ringflag=0;	//清除标志
				 RG1_c;RG2_c;RG3_c;RG4_c;	//取消所有响铃
				 
				 lock(num1);		//封锁其它机
				 relay_s;			//接到外线,和对方通话
				 while(test_hu(0))//等待听筒放下
				    {				//在这里加入多方通话功能
					  if((decode[2]==11)&&(decode[1]==8)&&
					        (decode[0]>0&&decode[0]<5&&decode[0]!=num1))//拨号条件, 不能打自己
					   {
					      calln=decode[0];		    //保存被叫机号
						  *(ringflag+(calln-1))=1;	//响铃
				          L_flash=1;				//LED闪烁
						   while((num1==test_hu(calln))&&(calln != test_hu(num1)))	//等等被叫接电话或主叫放下听筒
				               {
					            }
				           *(ringflag+(calln-1))=0;//停止响铃
				           if(calln==test_hu(num1))	//被叫接电话
				              {
					            L_flash=2;			//LED慢速闪烁
						      }
				           clr_decode();		   //清除解码阵列
						}
					 
					}
					
				 relay_c;			//	返回内线
				 lock(0);			//解除封锁
				}
			else		//主叫放下听筒
			    {
				 out_ringflag=0;	//清除标志
				 RG1_c;RG2_c;RG3_c;RG4_c;	//取消所有响铃
				}
			ringcou=0;
			ringcoutime=0;
			L1_c;
			L2_c;
			L_flash=0;			//LED flash
		   }			
	   }
   }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -