利用DMA0存储ADC采样结果,4路模拟输入,扫描采样,完成40次采样产生中断。然后再通过DMA1把数据用UART1发出去。程序运行后很快就出现Target halted,就运行结束了。但是发现串口有收到数据,但是不是每一次执行都会收到,通常是执行两次,会收到一些数据,不过是乱码。我实际4个模拟通道什么都没有接,原理上是不是采样都为0啊?附上程序,请大神帮忙看看!
//-------------------------------------------------------------------------------//
// 外部晶振4MHZ N 8 1 9600
#include "p33FJ128MC706.h"
_FOSCSEL(IESO_OFF&FNOSC_PRIPLL); // 使用外部晶振XT
_FOSC(FCKSM_CSDCMD&OSCIOFNC_OFF&POSCMD_XT); //禁止时钟切换,OSCO为时钟输出,XT晶振模式
_FWDT(FWDTEN_OFF); // 关闭开门狗
_FICD(JTAGEN_OFF & ICS_PGD1)
void config_AD(void);
void config_TMR3(void);
void config_DMA0(void);
void config_DMA1(void);
void config_U1UART(void);
void config_INT(void);
void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void);
#define LL 10
unsigned int AN2[LL],AN3[LL],AN4[LL],AN5[LL];
volatile unsigned int *P;
unsigned int AA __attribute__((space(dma),address(0x4000))); //为了获取首地址
int main(void)
{ //外接4MHz晶振,通过PLL得到总振荡频率40MHz,Fcy=20MHz,Tcy=50ns
CLKDIVbits.PLLPRE=0; // N1=2,此输出为4MHz/2=2MHz,符合0.8~8.0MHz的要求
PLLFBDbits.PLLDIV=78; // M=80,此输出为2MHz*80=160MHz,符合100~200MHz的要求
CLKDIVbits.PLLPOST=0b01; // N2=4,此输出为160MHz/4=40MHz,符合12.5~80MHz的要求
while(OSCCONbits.COSC!=0b011); // 等待时钟稳定
RCONbits.SWDTEN=0; // 禁止WDT
config_AD();
config_TMR3();
config_DMA0();
config_DMA1();
config_U1UART();
config_INT;
while(1);
{
Delay(10);
}
}
//总中断设置
void config_INT(void)
{ SRbits.IPL=4; //CPU中断优先级=4
CORCONbits.IPL3=0; //CPU中断优先级<7
INTCON1bits.NSTDIS=1; //禁止嵌套中断
INTCON2bits.ALTIVT=0; //使用标准中断向量
}
//配置AD
void config_AD(void)
{ //引脚设置
AD1CON1bits.ADON = 0;
AD1PCFGL=0xFFC3; // AN2、AN3、AN4、AN5为模拟口
//AD1CON1
AD1CON1bits.ADSIDL=1; // A/D模块休眠不工作
AD1CON1bits.ADDMABM = 1; // DMA按照ADC转换顺序来存放
AD1CON1bits.AD12B = 1; // 12-bitA/D
AD1CON1bits.FORM = 0b00; // 转换结果:整数
AD1CON1bits.SSRC = 2; // Timer3触发A/D
AD1CON1bits.ASAM = 1; // 转换结束后立即开始采样
AD1CON1bits.SIMSAM = 0; // 按顺序依次采样多个通道
//AD1CON2
AD1CON2bits.VCFG = 0b000; // 参考电压为电源电压
AD1CON2bits.CSCNA = 1; // 扫描采样多路开关A的CH0+输入
AD1CON2bits.CHPS = 0; // 选择转换CH0
AD1CON2bits.BUFM = 0; // 总是从起始地址开始填充缓冲区
AD1CON2bits.SMPI=0b0011; // 完成4次采样
AD1CON2bits.ALTS=0; // 只用A开关
//AD1CON3
AD1CON3bits.ADRC = 0; // ADC时钟由系统时钟产生
AD1CON3bits.ADCS = 3; // Tad=4Tcy=4*50=200ns
//AD1CHS0:A/D 输入通道0选择寄存器
AD1CHS0bits.CH0SA = 0; // 通道0的同向输入为AN0
AD1CHS0bits.CH0NA = 0; // 通道0的反向输入为Vref-
//AD1CHS123:A/D 输入通道1、2、3选择寄存器
AD1CHS123bits.CH123SA = 0; // CH1的同向输入为AN0,CH2的同向输入为AN1,CH3的同向输入为AN2,
AD1CHS123bits.CH123NA = 0; // CH1、CH2、CH3的反向输入为Vref-,
//AD1CSSH/AD1CSSL:A/D 输入扫描选择寄存器
AD1CSSL = 0x003C; // 扫描AN2, AN3, AN4, AN5
AD1CON4bits.DMABL = 3; // Each buffer contains 8 words
IFS0bits.AD1IF = 0; // 清除A/D中断标志位
IEC0bits.AD1IE = 0; // 不使能A/D中断
AD1CON1bits.ADON = 1; // 使能A/D模块
}
//配置TMR3
void config_TMR3(void)
{
TMR3 = 0x0000;
PR3 = 2499; // Trigger ADC1 every 125usec
IFS0bits.T3IF = 0; // Clear Timer 3 interrupt
IEC0bits.T3IE = 0; // Disable Timer 3 interrupt
T3CONbits.TON = 1; // Start Timer 3
}
//配置DMA0:把ADC结果自动放入DMA RAM
void config_DMA0(void)
{
DMA0REQbits.IRQSEL=13; // ADC1触发DMA
DMA0CONbits.SIZE=0; //字模式
DMA0CONbits.DIR=0; //DMA方向为外设到RAM
DMA0CONbits.HALF=0; //整块传输,即结束后产生中断
DMA0CONbits.AMODE = 0; // 带后递增间接寻址模式
DMA0CONbits.MODE = 1; // 禁止单数据块乒乓模式
DMA0STA=__builtin_dmaoffset(&AA); //获得DMA0的寄存器起始地址
DMA0PAD=(volatile unsigned int)&ADC1BUF0;//将ADC结果地址告诉DMA RAM的数组
DMA0CNT=LL*4-1; // 每完成40次采样/转换操作产生中断
IFS0bits.DMA0IF = 0; // 清除中断标志
IEC0bits.DMA0IE = 1; // 允许DMA 中断
IPC1bits.DMA0IP = 6; // DMA中断优先级为6
DMA0CONbits.CHEN = 1; // 使能 DMA0 通道
}
//配置DMA1:把DMA0放在DMA RAM中的数据用UART1发送出去
void config_DMA1(void)
{
DMA1REQbits.IRQSEL=12; //UART1发送,首次需手动发送一个数
DMA1CONbits.SIZE=1; //字节模式
DMA1CONbits.DIR=1; //DMA方向为RAM到外设
DMA1CONbits.HALF=0; //整块传输,即结束后产生中断
DMA1CONbits.AMODE = 0b00; // 带后递增间接寻址模式
DMA1CONbits.MODE = 0b01; // 禁止乒乓模式 ,单次模式
DMA1STA=DMA0STA; //获得DMA0的寄存器起始地址
DMA1PAD=(volatile unsigned int)&U1TXREG;
DMA1CNT=LL*4-1; // 40次发送后中断
DMA1CONbits.CHEN = 0; // 先不使能 DMA0 通道
_DMA1IE=1;
_DMA1IP=6;
}
//配置UART
void config_U1UART(void) //串口初始化
{ //U1MODE
U1MODEbits.USIDL = 1; //休眠关闭串口
U1MODEbits.IREN = 0; //IrDA编码器关闭
U1MODEbits.RTSMD = 1; // 引脚处于单工模式
U1MODEbits.UEN = 0; //使能U1TX,U1RX
U1MODEbits.WAKE = 0; //禁止启动位唤醒
U1MODEbits.LPBACK = 0; //禁止环回模式
U1MODEbits.ABAUD = 0; // 自动波特率禁止
U1MODEbits.URXINV = 0; //U1RX空闲状态是0
U1MODEbits.BRGH = 0; //标准模式
U1MODEbits.PDSEL = 0; // N , 8, 1
U1MODEbits.STSEL = 0; // 1个停止位
//U1STA
U1STAbits.UTXISEL1 = 0;
U1STAbits.UTXISEL0 = 0; // 发送一个数据中断
U1STAbits.UTXINV = 0; //IrDA编码的UxTX空闲状态为0
U1STAbits.UTXBRK = 0; //禁止或已完成同步间隔字符的发送
U1STAbits.URXISEL = 0b00; //收到一个数即中断
U1STAbits.ADDEN = 0; //禁止地址检测模式
U1BRG =129; // Fcy=20MHZ N 8 1 波特率9600 = 129;
IPC3bits.U1TXIP=6; //TX中断优先级=6
IEC0bits.U1TXIE = 1; // 允许发送中断
U1MODEbits.UARTEN = 1; // 串口使能
U1STAbits.UTXEN = 1; // 发送使能
}
//两次中断时间间隔为5ms(0.125*40=5ms),每个AD通道的数据个数为10个
void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void)
{
IFS0bits.DMA0IF = 0; // 清除中断标志
/* unsigned char i;
for(i=0;i<LL;i++) //共40个数据
{
AN2=*P++;
AN3=*P++;
AN4=*P++;
AN5=*P++;
}*/
U1TXREG=0; //异步串行发送触发DMA第一次需手动发送一个数
DMA1STA=DMA0STA; //DMA1的DMA RAM首地址与DMA0的相同
DMA1CONbits.CHEN=1; //打开DMA1模块,传送次数完成后自动关闭模块
DMA1REQbits.FORCE=1; //手动触发DMA1模块
}
void Delay(unsigned int i) //延时程序
{
unsigned int j;
for(;i>0;i--)
{
Nop();
for(j=0;j<255;j++)
{
Nop();
ClrWdt();
}
}
}
|