📄 main.c
字号:
/*********************
电话遥控开关测试程序
文件名:main.c
MCU :ATMEGA8
时 钟 : 外部4MHz
芯艺 2005-01-21
*********************/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define uchar unsigned char
#define uint unsigned int
#define LIGHT_BIT PB1 //控制灯引脚位
#define LED_BIT PC0 //发光管引脚位
#define TEL_BIT PB2 //摘机控制引脚位
#define SET_LED PORTC|=_BV(PC0)
#define CLR_LED PORTC&=~_BV(PC0)
#define OPEN_LIGHT PORTB|=_BV(PB1)
#define CLOSE_LIGHT PORTB&=~_BV(PB1)
// C 调各音频码
const uchar g_aMusicTab[] ={0,238,225,220,200,189,179,168,159,150,142,134,126, \
118,112,108,100,94,89,84,79,75,71,67,63, \
59,56,53,50,47,44,42,39,37,35,33,31};
// "生日快乐" 曲码
const uchar g_aMusic[] PROGMEM = { 20,02,00,01,20,01,22,04,20,04,25,04,24,04,00,04,
20,02,00,01,20,01,22,04,20,04,27,04,25,04,00,04,
20,02,00,01,20,01,32,04,29,04,25,04,24,04,22,04,
30,02,00,01,30,01,29,04,25,04,27,04,25,04,00,04,
20,02,00,01,20,01,22,04,20,04,25,04,24,04,00,04,
20,02,00,01,20,01,22,04,20,04,27,04,25,04,00,04,
20,02,00,01,20,01,32,04,29,04,25,04,24,04,22,04,
30,02,00,01,30,01,29,04,25,04,27,04,25,04,00,04,
00,00};
uchar g_flag=0;//判断是否有DTMF码接收到的全局标记
//误差不会太大的延时1ms函数
void DelayMs(uint ms)
{
uint i;
for(i=0;i<ms;i++)
_delay_loop_2(4 *250);
}
//外部中断0,MT8870接收到了一个DTMF码
SIGNAL(SIG_INTERRUPT0)
{
uchar tmp;
PORTB|=_BV(PB0); //TOE置位,MT8870数据输出允许
tmp++;
tmp=PIND;
tmp>>=4;
g_flag=tmp;
PORTB&=~_BV(PB0);//TOE清零,MT8870数据输出禁止
}
//T/C2 比较匹配中断
SIGNAL(SIG_OUTPUT_COMPARE2)
{
static uchar flag=0;
if(flag)
PORTC|=_BV(PC5);
else
PORTC&=~_BV(PC5);
flag=!flag;
}
//检测一次振铃信号
//铃流信号通过硬件整形后在PD3口输入低电平
//无铃流信号时PD3保持高
void PassPlus(void)
{
while(1)
{
if(PIND&_BV(PD3))
{
DelayMs(1);
continue;
}
else
{
DelayMs(100);//延时消抖
if((PIND&_BV(PD3))==0)
break;
}
}
while(1)
{
if((PIND&_BV(PD3))==0)
{
DelayMs(1);
continue;
}
else
{
DelayMs(100);//延时消抖
if((PIND&_BV(PD3)))
break;
}
}
}
//提示音输出函数,num 提示音响数,frq:提示音频率
void Beep(uchar num,uint frq)
{
uchar i;
TCCR2=_BV(WGM21)|_BV(CS21)|_BV(CS20); //CTC 模式 32分频
OCR2=62500/frq;
TIMSK=_BV(OCIE2); //比较匹配中断允许
for(i=0;i<num;i++)
{
DelayMs(500);
cli();
PORTC&=~_BV(PC5);
DelayMs(500);
sei();
}
TCCR2=0;
TIMSK=0;
PORTC&=~_BV(PC5);//关闭音乐信号
sei();
}
//结合T/C2中断程序 从PC5播放音乐,调用之前总中断必须允许
void PlayMusic(void)
{
int i=0;
uchar msc[2];
TCCR2=_BV(WGM21)|_BV(CS21)|_BV(CS20); //CTC 模式 32分频
OCR2=0XFF;
TIMSK=_BV(OCIE2); //比较匹配中断允许
while(1)
{
msc[0]=pgm_read_byte(g_aMusic+i++);
msc[1]=pgm_read_byte(g_aMusic+i++);
if(msc[1]==0)
break;
//调整频率
cli();
if(msc[0]==0)//如果是休止符
{
PORTC&=~_BV(PC5);
DelayMs(187*msc[1]);
continue;
}
TCNT2=0;
OCR2=g_aMusicTab[msc[0]];
sei();
//按节拍延时
DelayMs(187*msc[1]);
}
//关闭T/C2
TCCR2=0;
TIMSK=0;
PORTC&=~_BV(PC5);//关闭音乐信号
sei();
}
int main(void)
{
uchar i;
uint j;
DelayMs(1000);
PORTC=0;
PORTB=0;
PORTD=0;
DDRD=0;
DDRC=_BV(LED_BIT)|_BV(PC5);
DDRB=_BV(LIGHT_BIT)|_BV(TEL_BIT)|_BV(PB0);//PB0为MT8870输出允许引脚
MCUCR=_BV(ISC00)|_BV(ISC01);//INT0在MT8870 STD脚上升沿触发
GICR=_BV(INT0); //外部中断0允许
SET_LED; //发光管亮
while(1)
{
for(i=0;i<2;i++)
{
PassPlus();
}
PORTB=_BV(TEL_BIT);//摘机
sei();//总中断允许
Beep(3,1000);//摘机提示
for(j=0;j<3000;j++) //约半分钟无按键自动挂机
{
if(g_flag) //有DTMF码收到
{
j=0;
switch(g_flag)
{
case 8: //'1'键
PORTB|=_BV(LIGHT_BIT);//开灯
Beep(2,500);
break;
case 4: //'2'键
PORTB&=~_BV(LIGHT_BIT);//关灯
Beep(2,1000);
break;
case 2: //'4'键
PlayMusic(); //播放音乐
DelayMs(1000);
Beep(2,300); //结束提示
break;
case 0x0c: //'3'键
j=3000; //退出挂机
break;
default:
break;
}
g_flag=0;
}
//
if(j%100==0)
{
if(PORTC&_BV(LED_BIT))
CLR_LED;
else
SET_LED;
}
DelayMs(10);
}
SET_LED;
PORTB&=~_BV(TEL_BIT);//挂机
cli();
}
}//main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -