深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商
QLdsPIC3]音频编码解码[C30+dsPIC30F6014A]
//实验功能:熟悉dsPIC芯片的DC1模块功能和音频编解码芯片SI3000的使用
//软件规划:
// 1。音频信号从J10(MIC IN)进去,编码后送dsPIC控制器,dsPIC接收直接送回SI3000解码从J11(SPK OUT)输出
// 2。DCI采用中断接收数据
// 3。SI3000工作在SLAVE从模式(由dsPIC提供SCK)
//硬件规划:
// 1。拨码开关S10全部置ON
// 2。跳线J9全部跳到SLAVE边
// 3。音频输入接到J10(MIC IN)
// 4。音频输出接到J11(SPK OUT)
#include //dsPIC30F6014标准头文件
_FOSC(0x0ffe5); //4倍频晶振,Failsafe 时钟关闭
_FWDT(WDT_OFF); //关闭看门狗定时器
_FBORPOR(PBOR_OFF & MCLR_EN); //掉电复位禁止,MCLR复位使能。
_FGS(CODE_PROT_OFF); //代码保护禁止
#define SAMPLE_RATE 7200L
#define FRAMECLKRATE (SAMPLE_RATE*256L) //SCK频率使用1.8432M
#define CLOCK_FREQ (1L*10000000L) // 采用 4x PLL..PIC 指令频率 (Fosc*4/4)
#define CMD_STAGE0 0 //正常模式
#define CMD_STAGE1 1 //设置lsb告诉解码器下一个控制字是命令
#define CMD_STAGE2 2 //把带命令的字节放到输出缓冲
#define CMD_STAGE3 3 //设置帧模式
#define CMD_STAGE4 4 //回复正常帧模式
#define PROC_BLOCK_SIZE 144 //数据处理块大小
#define QUEUE_SIZE (PROC_BLOCK_SIZE*2) //Rx和Tx队列的大小,必须为处理缓冲大小的2倍
unsigned int* pActiveRxBuf;
unsigned int* pActiveTxBuf;
unsigned char __attribute__((address(0x900))) CmdStage;
static volatile unsigned int CodecCmd;
static volatile char ClkAdjTrig;
static int TxQue[QUEUE_SIZE];
static int RxQue[QUEUE_SIZE];
static volatile unsigned int TxQTail;
static volatile unsigned int RxQHead;
void InitCodec(void);
void WriteCodecCtrl( unsigned char adr, unsigned char parm );
void AdjustClock( char shift );
unsigned char ReadCodecCtrl( unsigned char adr );
//***************延时程序***************************
void TimeDelay(unsigned char x)
{
unsigned char i;
for(i=0;i<x;i++);
}
//************把数据放到接收缓冲的子程序************
inline void PutRxQue(int data)
{
RxQue[RxQHead++] = data;
if(RxQHead==QUEUE_SIZE) RxQHead = 0;
}
//***********从接收缓冲获取数据的子程序***************
inline int GetTxQue(void)
{
static int tmp;
tmp = RxQue[TxQTail++]&0xFFFE; //接收到数据送回解码输出
if(TxQTail==QUEUE_SIZE) TxQTail = 0;
return tmp;
}
//DCI中断服务子程序
void __attribute__((__interrupt__)) _DCIInterrupt(void)
{
int tmp;
switch( CmdStage )
{
case CMD_STAGE0:
TXBUF0 = GetTxQue();
TXBUF1 = GetTxQue();
TXBUF2 = GetTxQue();
TXBUF3 = GetTxQue();
PutRxQue(RXBUF0);
PutRxQue(RXBUF1);
PutRxQue(RXBUF2);
tmp = RXBUF3; //调整时钟的相位
if(ClkAdjTrig > 0) //如果需要插入采样
PutRxQue(tmp);
if(ClkAdjTrig >= 0) //如果不须,则跳过
PutRxQue(tmp);
ClkAdjTrig = 0;
break;
case CMD_STAGE1:
TXBUF0 = GetTxQue();
TXBUF1 = GetTxQue();
TXBUF2 = GetTxQue();
TXBUF3 = GetTxQue() | 1; //告诉编码解码器下一个值是命令
PutRxQue(RXBUF0);
PutRxQue(RXBUF1);
PutRxQue(RXBUF2);
PutRxQue(RXBUF3);
CmdStage = CMD_STAGE2;
break;
case CMD_STAGE2:
TXBUF0 = CodecCmd; //插入编码解码器命令
TXBUF1 = GetTxQue(); //取采样数据
TXBUF2 = 0x0000; //写虚拟值
TXBUF3 = 0x0000; //写虚拟值
PutRxQue(RXBUF0);
PutRxQue(RXBUF1);
PutRxQue(RXBUF2);
PutRxQue(RXBUF3);
CmdStage = CMD_STAGE3;
break;
case CMD_STAGE3:
TXBUF0 = GetTxQue();
TXBUF1 = GetTxQue();
TXBUF2 = GetTxQue();
TXBUF3 = GetTxQue();
PutRxQue(RXBUF0);
PutRxQue(RXBUF1);
PutRxQue(RXBUF2);
PutRxQue(RXBUF3);
DCICON2=0XF6FF; //设置DCI缓冲长度为2
CmdStage = CMD_STAGE4;
break;
case CMD_STAGE4:
TXBUF0 = GetTxQue();
TXBUF1 = GetTxQue();
TXBUF2 = GetTxQue();
TXBUF3 = GetTxQue();
CodecCmd = RXBUF0;
PutRxQue(RXBUF1);
DCICON2=0XFFFF; //设置DCI缓冲长度为4
CmdStage = CMD_STAGE0;
break;
}
IFS2bits.DCIIF = 0; // 清DCI中断标志
}
//**************初始化DCI和编码解码器*******************
void InitCodec(void)
{
int i;
for(i=0; i {
RxQue[i] = 0;
TxQue[i] = 0xffff;
}
TxQTail = 0;
RxQHead = 0;
CmdStage = CMD_STAGE0;
CodecCmd = 0;
ClkAdjTrig = 0;
TRISFbits.TRISF6 = 1; //编码解码器(Codec)引脚为输入
IFS2bits.DCIIF = 0;
IEC2bits.DCIIE=1;
IPC10bits.DCIIP=7;
DCICON1=0X8040; // 配置DCI模块用于传送16位数据且工作在多通道模式
DCICON2=0XFFFF;
DCICON3=( CLOCK_FREQ / ( 2 * FRAMECLKRATE) ) - 1;
TSCON=1;
RSCON=1;
LATFbits.LATF6 = 0; //复位编码解码器
TRISFbits.TRISF6 = 0;
TimeDelay(200);
TRISFbits.TRISF6 = 1; //编码解码器设为输入
TimeDelay(1);
WriteCodecCtrl( 3, 0); //SI3000寄存器3
WriteCodecCtrl( 4, 19); //SI3000寄存器4
WriteCodecCtrl( 1,0X18 ); //SI3000寄存器1
WriteCodecCtrl( 2, 0); //SI3000寄存器2
WriteCodecCtrl( 5, 2); //SI3000寄存器5
WriteCodecCtrl( 6, 0X5E ); //SI3000寄存器6
WriteCodecCtrl( 7, 0X5F ); //SI3000寄存器7
WriteCodecCtrl( 9, 0); //SI3000寄存器9
}
//*************写命令到编码解码器子程序**********************
void WriteCodecCtrl( unsigned char adr, unsigned char parm )
{
CodecCmd = (unsigned int)adr;
CodecCmd = (CodecCmd<<8) & 0x1F00; //SI3000寄存器的5位地址
CodecCmd += (unsigned int)parm; //待写入的数据
CmdStage = CMD_STAGE1;
while( CmdStage != CMD_STAGE0 ){}
}
//*************从编码解码器读命令子程序**********************
unsigned char ReadCodecCtrl( unsigned char adr )
{
CodecCmd = (unsigned int)adr;
CodecCmd = (CodecCmd<<8) & 0x1F00;
CodecCmd |= 0x2000; //读功能
CmdStage = CMD_STAGE1;
while( CmdStage != CMD_STAGE0 ){}
return CodecCmd&0x00FF;
}
//**********************主函数*******************************
int main(void)
{
TRISG=0X1000;
InitCodec();
while(1);
}