📄 dtmfgenerator.c
字号:
#include <p18cxxx.h>
//************************************************************
// 初始化CPU系统时钟为内部RC=8MHz,经过4倍频PLL,FOSC=32MHz
//************************************************************
void Initize_PIC18_OSCillator(void)
{
OSCCON=0x70;//选择内部8MHz的主振荡器
OSCTUNE=0x40;//使能4xPLL--->Fosc=32MHz
}
//************************************************************
// 初始化使用到的I/O端口的方向与初始电平函数
//************************************************************
void Initize_PIC18_Port(void)
{
ADCON1|=0x0F;//配置RA0..5,RE0..3全部为数字I/O口
TRISE=0;//配置RE0..3口为输出方向
LATE=0;//RE端口的输出电平全为0
TRISD=0;//配置RD0..7口为输出方向
LATD=0;//RD端口的输出电平全为0
TRISCbits.TRISC1=0;//配置RC1端口为输出方向
LATCbits.LATC1=0;//RC1口的输出电平为0
INTCON2bits.RBPU=0;//启用RB端口的内部弱上拉功能
TRISB=0xFF;//RB0..7口为输入方向
PORTB=0xFF;//RB0..7的引脚电平全为高电平
}
//************************************************************
// 初始化TMR0为定时1mS,FOSC=32MHz,预分频为1:256
//************************************************************
void Initize_PIC18_TMR0(void)
{
T0CONbits.TMR0ON=0;//TMR0停止工作
T0CONbits.T08BIT=1;//选择8位的定时/计数器
T0CONbits.T0CS=0;//选择内部CLKO时钟源作为定时
T0CONbits.PSA=0;//选择预分频器 T0CONbits.TMR0ON=0
T0CONbits.T0PS2=1;//预分频比为1:256 T0CONbits.T0BIT=1
T0CONbits.T0PS1=1; // T0CONbits.T0CS=0
T0CONbits.T0PS0=1; // T0CONbits.PSA=0
TMR0L=256-32;//装入定时1mS的初值 T0CONbits.TOPS2=1;T0CONbits.T0PS1=1;T0CONbits.T0PS0=1
T0CONbits.TMR0ON=1;//开始定时工作 T0CON=0x47;
}
//************************************************************
// 初始化TMR2,FOSC=32MHz
//************************************************************
void Initize_PIC18_TMR2(void)
{
T2CON=0x00;//配置TMR2的预分频为1:1,后分频为1:1
T2CONbits.TMR2ON=1;//启动TMR2开始工作
}
//************************************************************
// 初始化CCP模块为PWM模式,PWM周期为31.2KHz,FOSC=32MHz
//************************************************************
void Initize_PIC18_CCP(void)
{
PR2=0xFF;//F=FOSC/((PR2+1)*4*N)=31.2KHz
CCPR1L=0x00;//占空比为0
CCP1CON=0x0F;//配置CCP模块工作于PWM模式
}
//************************************************************
// 初始化PIC18单片机的中断系统
//************************************************************
void Initize_PIC18_Interrupt(void)
{
INTCONbits.TMR0IF=0;//清TMR0溢出中断标志 INTCONbits.TMR0IF=0 INTCONbits.TMR0IE=1 INTCONbits.TMR0IP=0 外部中断寄存器
INTCONbits.TMR0IE=1;//允许TMR0溢出中断响应
INTCON2bits.TMR0IP=0;//设置TMR0为低中断优先级
PIR1bits.TMR2IF=0;//清TMR2匹配中断标志 PIR1bits.TMR2IF=0 PIRbits.TMR2IE=1 IRP1bits.TMR2IP=1 外设中断寄存器
PIE1bits.TMR2IE=1;//允许TMR2匹配中断响应
IPR1bits.TMR2IP=1;//设置TMR2为高中断优先级
RCONbits.IPEN=1;//允许中断嵌套 RCONbits.IPEN=1 INTCONbits.GEIE=1 INTCONbits.PEIE =1 允许所有低优先级中断
INTCONbits.GIE=1;//CPU开中断
INTCONbits.PEIE=1;//CPU响应第二梯队中断
}
//************************************************************
// 高优先级中断和低优先级中断函数声明
//************************************************************
void PIC18F_High_isr (void);
void PIC18F_Low_isr (void);
#pragma code high_vector_section=0x08
void high_vector (void)
{
_asm goto PIC18F_High_isr _endasm
}
#pragma code low_vector_section=0x18
void low_vector (void)
{
_asm goto PIC18F_Low_isr _endasm
}
#pragma code
//************************************************************
// LED数码管显示代码定义及相关变量及缓冲区的定义
//************************************************************
const unsigned char LEDDATA[]=
{
0x3F,0x06,0x5B,0x4F, //0,1,2,3,
0x66,0x6D,0x7D,0x07, //4,5,6,7,
0x7F,0x6F,0x77,0X7C, //8,9,A,b,
0x39,0x5E,0x79,0x71, //C,d,E,F,
0x00,0x40,
};
unsigned char LEDBuffer[8];
unsigned char LEDScanPointer;
#define LED8PORT LATD
#define LEDBPORT LATE
//************************************************************
// 正弦波量化表定义,量化系数为128
//************************************************************
const unsigned char auc_SinParam[128]=
{
64 ,67 ,70 ,73 ,76 ,79 ,82 ,85 ,
88 ,91 ,94 ,96 ,99 ,102,104,106,
109,111,113,115,117,118,120,121,
123,124,125,126,126,127,127,127,
127,127,127,127,126,126,125,124,
123,121,120,118,117,115,113,111,
109,106,104,102,99 ,96 ,94 ,91 ,
88 ,85 ,82 ,79 ,76 ,73 ,70 ,67 ,
64 ,60 ,57 ,54 ,51 ,48 ,45 ,42 ,
39 ,36 ,33 ,31 ,28 ,25 ,23 ,21 ,
18 ,16 ,14 ,12 ,10 ,9 ,7 ,6 ,
4 ,3 ,2 ,1 ,1 ,0 ,0 ,0 ,
0 ,0 ,0 ,0 ,1 ,1 ,2 ,3 ,
4 ,6 ,7 ,9 ,10 ,12 ,14 ,16 ,
18 ,21 ,23 ,25 ,28 ,31 ,33 ,36 ,
39 ,42 ,45 ,48 ,51 ,54 ,57 ,60 ,
};
//************************************************************
// 量化DTMF的高频群和低频群正弦信号的XSW步长
//************************************************************
const unsigned char auc_frequencyH[4]=
{
107,96 ,
87 ,79 ,
};
const unsigned char auc_frequencyL[4]=
{
61 ,56 ,
50 ,46 ,
};
//************************************************************
// 定义相关DTMF全局变量
//************************************************************
unsigned char x_SWa = 0x00; //高频群步长变量
unsigned char x_SWb = 0x00; //低频群步长变量
unsigned int i_CurSinValA = 0; //
unsigned int i_CurSinValB = 0; //
unsigned int i_TmpSinValA; //
unsigned int i_TmpSinValB; //
//************************************************************
//延时函数Delay()
//************************************************************
void Delay(unsigned int t)
{
while(t--);
}
//************************************************************
// 按键代码表
//************************************************************
//键盘0-9及A-F排列代码表
const unsigned char KEYCODE[]=
{
0x7e,0xbe,0xde,0xee,//
0x7d,0xbd,0xdd,0xed,
0x7b,0xbb,0xdb,0xeb,
0x77,0xb7,0xd7,0xe7,
};
//************************************************************
// 主程序入口main()函数
//************************************************************
void main(void)
{
unsigned char KeyTemp;
unsigned char Key;
unsigned char i;
Initize_PIC18_OSCillator();
Initize_PIC18_Port();
Initize_PIC18_TMR0();
Initize_PIC18_TMR0();
Initize_PIC18_TMR2();
Initize_PIC18_CCP();
Initize_PIC18_Interrupt();
while(1)
{
//******************************************************
TRISB = 0x0F;//置PORTB的高4位为输出,低4位为输入
PORTB = 0x0F;//PORTB的高4位输出全为0
if((PORTB & 0x0F)!=0x0F)//判断是否有键按下
{
Delay(1000);//延时,消除按键抖动
if((PORTB & 0x0F)!=0x0F)//再判断是否真得有键按下
{
KeyTemp=PORTB & 0x0F;//保存当前按键的状态
Key=KeyTemp;//将当前列结果存储到变量
i=0;
//列的最低位是否为0,以及四个列全检查完毕
while((Key & 0x01)&&(i<4))
{
i++;//如果当前列不为低电平,指向中一列
Key>>=1;//右移一位
}
//找到之后读取该列低频群的步长给x_SWb变量
if(i<4)x_SWb=auc_frequencyL[i];
else x_SWb=0;
TRISB = 0xF0;//置PORTB的高4位为输入,低4位为输出
PORTB = 0xF0;//PORTB的低4位输出全为0
Delay(1000);//延时,消除按键的抖动
KeyTemp|=(PORTB & 0xF0);//读取当前按键的状态
Key=KeyTemp;//将当前行结果存储到变量
Key>>=4;//将行线内容移到低四位上
i=0;
//行的最低位是否为0,以及四个行全检查完毕
while((Key & 0x01)&&(i<4))
{
i++;//如果当前行不为低电平,指向中一行
Key>>=1;//右移一位
}
//找到之后读取该行高频群的步长给x_SWa变量
if(i<4)x_SWa=auc_frequencyH[i];
else x_SWa=0;
Key=0;
//将两次读取的按键状态与按键排列的代码表比较,
//找到相匹配的按键数值
while(KeyTemp!=KEYCODE[Key])Key++;
//将LEDBuffer显示缓冲区的内容整体左移一个单元
for(i=sizeof(LEDBuffer)-1;i>0;i--)
LEDBuffer[i]=LEDBuffer[i-1];
//将最新按下的按键号码送到LEDBuffer[0]缓冲区单元
LEDBuffer[0]=Key;
while((PORTB & 0xF0)!=0xF0);//等待按键释放
}
}
//******************************************************
}
}
//************************************************************
// 高优先中断服务程序入口函数void PIC18F_High_isr(void)
//************************************************************
void PIC18F_High_isr(void)
{
if(1==PIR1bits.TMR2IF)//TMR2与PR2的内容相匹配,产生TMR2溢出
{
PIR1bits.TMR2IF=0;//清TMR2溢出中断标志位
//根据所得的步长重新计算正弦取表指针
i_CurSinValA+=x_SWa;
i_CurSinValB+=x_SWb;
//重新规格化临时取表指针
i_TmpSinValA=(char)(((i_CurSinValA+4) >> 3)&(0x007F));
i_TmpSinValB=(char)(((i_CurSinValB+4) >> 3)&(0x007F));
//计算PWM的值:高频群值 + 3/4低频群值
CCPR1L=(auc_SinParam[i_TmpSinValA]+
(auc_SinParam[i_TmpSinValB]-
(auc_SinParam[i_TmpSinValB]>>2)));
}
}
//************************************************************
// 低优先中断服务程序入口函数void PIC18F_Low_isr(void)
//************************************************************
void PIC18F_Low_isr(void)
{
if(1==INTCONbits.TMR0IF)//TMR0定时1ms溢出了
{
INTCONbits.TMR0IF=0;//清TMR0溢出中断标志位
TMR0L=256-32;//重新装入初值
//根据扫描指针对应的显示缓冲区的内容的显示代码送到PD端口
LED8PORT=LEDDATA[LEDBuffer[LEDScanPointer]];
//将当前扫描指针送到RE端口由HC138进行译码选通当前的LED数码管
LEDBPORT=LEDScanPointer;
LEDScanPointer++;//扫描指针加1
//如果显示缓冲区的内容全部送完,则清扫描指针重新开始新的扫描
if(sizeof(LEDBuffer)==LEDScanPointer)LEDScanPointer=0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -