求助!!!!!!!!!ADC采集信号误差很大

2019-10-11 15:14发布

本帖最后由 ruby 于 2017-3-18 16:10 编辑

我用DMA+ADC方式采集单路1KHZ的正弦信号,发现采集后的信号质量很差,我用的是函数发生器产生的信号,信号本身应该没问题,参考电源用示波器看了也没问题,用的是买的开发板,电路应该也没问题,是我程序本身有问题吗?我的程序如下:
#include "stm32f10x_lib.h"
#include "sys.h"
#include "delay.h"
#define USART1_DR_Base  0x40013804  
#define ADC1_DR_Address 0x4001244C //0x40012400+0x4C

//#define DMA1_MEM_ADD    (u32)ADC_Buf
//#define DMA1_MEM_SIZE    (u32)sizeof(ADC_Buf)
u16 ADC_Buf[2000];
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx);//配置DMA1_CHx
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);//使能DMA1_CHx
void MYDMA_GOnes(DMA_Channel_TypeDef*DMA_CHx); //执行一次DMA   
void  adc_init(void) ;
void  USART_Initaize(u32 pclk2,u32 bound);
void  Uart1_PutChar(u8 ch);
void Uart1_PutString(u8 *Buf, u8 Len);
//主函数的内容
int main(void)
{     
    u16 times=0;
    u16 t;
    u32 temp =0;
    u16 adcx;
    u8 table[4];
    u8 *p;
    p= table;
    Stm32_Clock_Init(9);//88M
    delay_init(72);     //延迟初始化
    USART_Initaize(72,9600); //设置波特率
    adc_init();
      while (1)
    {
        if(DMA1->ISR&(1<<1)) //传输完成了
        {  
      /×××××××××××××××
        把通过DMA传输过来的2000个数据取出并用串口输出
    /
            for(times=0;times<2000;times++)
            {
             temp=ADC_Buf[times];
             adcx=temp*330/4096;;               
             table[0]=adcx / 100 + 0x30;
             table[1]='.';
             table[2]=adcx % 100/10 + 0x30;
             table[3]= adcx %10 + 0x30;
             Uart1_PutString(p,4);
             Uart1_PutString(" ",2);
             temp =0;
            }
            
            DMA1->IFCR|=1<<1;
            MYDMA_GOnes(DMA1_Channel1);
        }
                                 
    }  
               
}  
   
void  adc_init(void)
{     
    RCC->APB2ENR|=1<<2;    //使能PORTA时钟
    GPIOA->CRL&=0XFFFFFFF0;//PA.0 anolog输入  
    RCC->APB2ENR|=1<<9;    //ADC1时钟使能
    __nop();
    __nop();      
    RCC->APB2RSTR|=1<<9;   //ADC1复位
    RCC->APB2RSTR&=~(1<<9);//复位结束
    RCC->CFGR|=3<<14;      //SYSCLK/DIV2=88M/8=11Mhz 得到ADC采样为43.65Khz   
  
    ADC1->CR1&=0XF0FFFF;   //独立工作模式
    ADC1->CR1|=1<<8;       //扫描模式  
    ADC1->CR2|=1<<1;       //连续转换模式
    ADC1->CR2|=0x000E0000; //软件控制转换,bit21控制
    ADC1->CR2|=1<<20;      //使用外部触发(SWSTART)!!!
    ADC1->CR2&=~(1<<11);   //右对齐

    ADC1->SQR1&=0xFFF0FFFF;//一个转换在规则序列中
    ADC1->SQR3&=0XFFFFFFE0;//规则序列1=通道0
    ADC1->SQR3|=0;     
    ADC1->SMPR2|=0X07;     //通道0的转换时间为239.5+12.5个ADC时钟周期
    ADC1->CR2|=1<<0;       //开启ADC转换器,第一次唤醒ADC转换器
    ADC1->CR2|=1<<3;       //使能复位校准
    while(ADC1->CR2&1<<3); //等待校准结束      
    ADC1->CR2|=1<<2;       //开启AD校准   
    while(ADC1->CR2&1<<2); //等待校准结束   
    ADC1->CR2|=1<<8;    //开启ADC,DMA转换

    MYDMA_Config(DMA1_Channel1);//配置DMA通道1
    MYDMA_Enable(DMA1_Channel1);//开启DMA通道1  
    ADC1->CR2|=1<<0;    //开启AD转换
}

//获得ADC值
u16 get_adc(void)   
{      
    ADC1->CR2|=1<<22;       //启动规则转换通道
    while(!(ADC1->SR&1<<1));//等待转换结束     
    return ADC1->DR; //返回ADC值      
}

//DMA1各通道配置
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx)
{
    RCC->AHBENR|=1<<0;//开启DMA1时钟
    __nop();                    //等待DMA1时钟稳定
    __nop();                    //经测试最少2个nop
    __nop();
    DMA_CHx->CPAR=ADC1_DR_Address;//DMA1 外设地址 ADC1_DR_Address
    DMA_CHx->CMAR=(u32)ADC_Buf ;   //DMA1,ADC 存储器地址
    DMA_CHx->CNDTR=(u32)sizeof(ADC_Buf) ;  //DMA1,传输数量
    DMA_CHx->CCR=0X00000000;//复位
    DMA_CHx->CCR|=0<<4;  //从外设器件读数据
    DMA_CHx->CCR|=0<<5;  //非循环模式
    DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
    DMA_CHx->CCR|=1<<7;  //存储器增量模式
    DMA_CHx->CCR|=1<<8;  //外设数据宽度为16位
    DMA_CHx->CCR|=1<<10; //存储器数据宽度为16位
    DMA_CHx->CCR|=1<<13; //高优先级
    DMA_CHx->CCR|=0<<14; //·非存储器到存储器模式
}
//开启DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
    DMA_CHx->CCR|=1<<0;  //开启DMA传输
}   
//开启一次DMA传输
//单次DMA转换后,必须把DMA关闭,再次启动,才能实现第二次DMA传输
void MYDMA_GOnes(DMA_Channel_TypeDef*DMA_CHx)
{   
    DMA_CHx->CCR&=~(1<<0);  //关闭DMA传输
    DMA_CHx->CNDTR=(u32)sizeof(ADC_Buf) ;  //DMA1传输数量
    DMA_CHx->CCR|=1<<0;  //开启DMA传输
}

void  USART_Initaize(u32 pclk2,u32 bound)
{
    float temp;
    u16 mantissa;
    u16 fraction;      
    temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
    mantissa=temp;                 //得到整数部分
    fraction=(temp-mantissa)*16; //得到小数部分
    mantissa<<=4;
    mantissa+=fraction;
    RCC->APB2ENR|=1<<2;   //使能PORTA时钟
    RCC->APB2ENR|=1<<14;  //使能串口时钟
    GPIOA->CRH&=0XFFFFF00F;
    GPIOA->CRH|=0X000008B0;//IO状态设置
         
    RCC->APB2RSTR|=1<<14;   //复位串口
    RCC->APB2RSTR&=~(1<<14);//停止复位            
    //波特率设置
     USART1->BRR=mantissa; //波特率设置  
    USART1->CR1|=0X200C;  //1位停止,无校检位
#ifdef EN_USART1_RX          //如果使能了接收
    //使能接收中断
    USART1->CR1|=1<<8;    //PE中断使能
    USART1->CR1|=1<<5;    //接收缓冲区非空中断使能           
    MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
void  Uart1_PutChar(u8 ch)
{   
    USART1->DR = (u8) ch;  
    while((USART1->SR&0X40)==0);//循环发送直到发送完成   
}

void Uart1_PutString(u8 *Buf, u8 Len)
{
    u8 i;
    for(i= 0; i<Len; i++)
    {
        Uart1_PutChar(*Buf++);
    }
}








友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。