OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3031|回复: 5

STM32F1 ADC多通道连续采集 采用DMA结果只传递一个数据

[复制链接]

1

主题

5

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2020-5-15
在线时间
7 小时
发表于 2020-6-29 15:37:46 | 显示全部楼层 |阅读模式
10金钱
采用PA1 PA2 PA3 3通道ADC连续扫描模式,DMA传输数据,通过串口打印3个口的电压值,结果只初始化的时候DMA传递了一个数据过来,只有第一个口有一个数据,电压原本为1.67V,结果被除以50,现串口显示0.38左右,其他数据均未采集,一共设置的是150次。。。反复琢么两天也没想明白,请教各位大能帮忙!!帮忙找找有什么毛病,这是寄存器版本的,

#include "sys.h"
#include "delay.h"
#include "LED.h"
#include "usart.h"

#define N  50
#define M  3

void filter(void);
void ADC_Init(void);                                 //ADC通道初始化
void DMA_Init(DMA_Channel_TypeDef*DMA_CHx);//配置DMA1_CHx

vu16 ADC_Value[N][M];//用来存放ADC转换结果,也是DMA的目标地址 define a N line and M row
u16 filterADC[M];//用来存放平均值
int main(void)
{
    float V1;
        float V2;
        float V3;
       
        Stm32_Clock_Init(9);        //系统时钟设置
        delay_init(72);                            //延时初始化
    uart_init(72,115200);
        LED_Init();                                  //初始化与LED连接的硬件接口

        ADC_Init();
    DMA_Init(DMA1_Channel1);
               
        while(1)
        {               
               
                delay_ms(10);
                        filter();
                                       
                V1=filterADC[0]*3.3/4095;printf("V1=%f\r\n",V1);
                                V2=filterADC[1]*3.3/4095;printf("V2=%f\r\n",V2);
                                V3=filterADC[2]*3.3/4095;printf("V3=%f\r\n\r\n\r\n",V3);

                           delay_ms(500);
                           LED0=!LED0;               
       
        }

}
void filter(void)
{
        vu32 sum=0;                //必须初始化为0,否则初值将保持上次调用值。
        vu8 i=0,j=0;
        for(i=0;i<M;i++)                //M row
        {
                for(j=0;j<N;j++)        //N line
                {
                        sum+=ADC_Value[j][i];
                }
                filterADC[i]=sum/N;
                sum=0;
        }       
}

          
//初始化ADC1
//以规则通道为例
//开启ADC1通道1 ADC1通道2 ADC1通道3        开启连续扫描模式         使能DMA                                                                                                                          

void  ADC_Init(void)
{   
        //先初始化IO口

        RCC->APB2ENR|=1<<2;    //使能PORTA口时钟
    RCC->APB2ENR|=1<<9;    //ADC1时钟使能

        RCC->CFGR&=~(3<<14);   //分频因子清零       
        //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
        //否则将导致ADC准确度下降!
        RCC->CFGR|=2<<14;   //ADC 分频系数为6 adcclock为12M        
        GPIOA->CRL&=0XFFFF000F;//PA1 PA2 PA3 anolog输入

        RCC->APB2RSTR|=1<<9;   //ADC1复位
        RCC->APB2RSTR&=~(1<<9);//复位结束
                  
        ADC1->CR1&=0XF0FFFF;   //工作模式清零
        ADC1->CR1|=0<<16;      //独立工作模式
        ADC1->CR1&=1<<8;    //扫描模式       
        ADC1->CR2&=1<<1;    //连续转换模式
        ADC1->CR2&=~(7<<17);          
        ADC1->CR2|=7<<17;           //不使用外部触发模式  
        ADC1->CR2&=~(1<<11);   //右对齐       
    ADC1->SQR1&=0xFF0FFFFF;
        ADC1->SQR1|=2<<20;     //3个转换在规则序列中 也就是只转换规则序列1~3

    ADC1->SMPR2&=~(7<<(3*1));   //通道1采样时间清空          
        ADC1->SMPR2|=7<<(3*1); //通道1  239.5周期,提高采样时间可以提高精确度
    ADC1->SQR3&=~(0X0000001F<<(5*0));//规则序列1 ADC1通道1
        ADC1->SQR3|=1<<(5*0);       

    ADC1->SMPR2&=~(7<<(3*2));   //通道2采样时间清空          
        ADC1->SMPR2|=7<<(3*2); //通道2  239.5周期,提高采样时间可以提高精确度
    ADC1->SQR3&=~(0X0000001F<<(5*1));//规则序列1 ADC1通道1
        ADC1->SQR3|=2<<(5*1);       

    ADC1->SMPR2&=~(7<<(3*3));   //通道3采样时间清空          
        ADC1->SMPR2|=7<<(3*3); //通道3  239.5周期,提高采样时间可以提高精确度
    ADC1->SQR3&=~(0X0000001F<<(5*2));//规则序列1 ADC1通道1
        ADC1->SQR3|=3<<(5*2);

    ADC1->CR2|=1<<8;        //使能DMA
    ADC1->CR2|=1<<0;           //开启AD转换器         

    ADC1->CR2|=1<<3;       //使能复位校准  
        while(ADC1->CR2&1<<3); //等待复位结束                          
    //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。                  
        ADC1->CR2|=1<<2;        //开启AD校准          
        while(ADC1->CR2&1<<2);  //等待校准结束
        //该位由软件设置以开始校准,并在校准结束时由硬件清除       

        ADC1->CR2|=1<<20;      //使用SWSTART触发         必须使用一个事件来触发
        ADC1->CR2|=1<<22;       //启动规则转换通道        
}                                  
                    
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/16位数据宽度/存储器增量模式
//DMA_CHxMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量  
void DMA_Init(DMA_Channel_TypeDef*DMA_CHx)
{
        RCC->AHBENR|=1<<0;                        //开启DMA1时钟
        delay_ms(5);                                //等待DMA时钟稳定
    DMA_CHx->CCR&=~0x0001;
    DMA_CHx->CCR=0;
        DMA_CHx->CPAR=0;                 
        DMA_CHx->CMAR=0;        
        DMA_CHx->CNDTR=0;                   
        DMA1->IFCR=0x0000000F;
       
        DMA_CHx->CPAR=(u32)&ADC1->DR; //DMA1 外设地址
        DMA_CHx->CMAR=(u32)&ADC_Value; //DMA1,存储器地址
        DMA_CHx->CNDTR=N*M;                //DMA1,传输数据量

        DMA_CHx->CCR|=0<<4;                  //从外设读 DIR数据传输方向
        DMA_CHx->CCR|=1<<5;                  //循环模式 CIRC=1
        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|=3<<12;                 //高优先级
        DMA_CHx->CCR|=0<<14;            //非存储器到存储器模式                         

    DMA_CHx->CCR|=1<<0;          //开启DMA传输

}


最佳答案

查看完整内容[请看2#楼]

论坛有多通道的采集 参照下:http://www.openedv.com/forum.php?mod=viewthread&tid=276626
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

31

主题

2183

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
14433
金钱
14433
注册时间
2018-8-3
在线时间
1157 小时
发表于 2020-6-29 15:37:47 | 显示全部楼层
回复

使用道具 举报

1

主题

5

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2020-5-15
在线时间
7 小时
 楼主| 发表于 2020-6-30 08:07:32 | 显示全部楼层
楼上说的那个帖子例程我看了,库函数版本的程序都好用了,可是就是寄存器版本的程序不好使,库函数本身也是操作的寄存器啊,为什么寄存器的就没好用呢,
//通过串口实时打印PA1 PA2 PA3口电压值。
//每个通道采集50次

#include "pbdata.h"

void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
void ADC1_Configuration(void);
void DMA_Configuration(void);

vu16 AD_Value[N][M];        //用来存放ADC转换结果,也是DMA的目标地址 define a N line and M row array
vu16 filterAD[M];                        //滤波后AD值

int fputc(int ch,FILE *f)
{
        USART_SendData(USART1,(u8)ch);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
        return ch;
}

int main(void)
{
        RCC_Configuration();       
        GPIO_Configuration();
        USART_Configuration();
        ADC1_Configuration();
        DMA_Configuration();
         
        while(1)
        {       
                delay_ms(10);                //延时,防止第一次上电或复位时,ADC没有转换完成
                filter();
                printf("V1=%f\r\n",filterAD[0]*3.3/4095);
                printf("V2=%f\r\n",filterAD[1]*3.3/4095);
                printf("V3=%f\r\n",filterAD[2]*3.3/4095);
                printf("\r\n");
                delay_ms(1000);                
        }       
}
void filter(void)
{
        vu32 sum=0;                //必须初始化为0,否则初值将保持上次调用值。
        vu8 i=0,j=0;
        for(i=0;i<M;i++)                //M row
        {
                for(j=0;j<N;j++)        //N line
                {
                        sum+=AD_Value[j][i];
                }
                filterAD[i]=sum/N;
                sum=0;
        }       
}
void RCC_Configuration(void)
{
    SystemInit();//72m
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //GPIOA
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);        //USART
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);                //AFIO

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);                //ADC
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);                                                //12M  最大14M
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                 //使能DMA传输
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;       

        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA,&GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA,&GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;//ADin: POT PA1 PA2 PA3 K3 K4
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;                //模拟输入
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
}


void USART_Configuration(void)
{
    USART_InitTypeDef  USART_InitStructure;

        USART_InitStructure.USART_BaudRate=9600;
        USART_InitStructure.USART_WordLength=USART_WordLength_8b;
        USART_InitStructure.USART_StopBits=USART_StopBits_1;
        USART_InitStructure.USART_Parity=USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

        USART_Init(USART1,&USART_InitStructure);
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
        USART_Cmd(USART1,ENABLE);
        USART_ClearFlag(USART1,USART_FLAG_TC);
}

void ADC1_Configuration(void)
{
        ADC_InitTypeDef  ADC_InitStructure;

        ADC_DeInit(ADC1);                                                                                                                                                        //将外设 ADC1 的全部寄存器重设为缺省值
        ADC_StructInit(&ADC_InitStructure);
       
        ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;                        //ADC1 ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode=ENABLE;                                                //工作在单通道模式(还是扫描模式:多通道模式)
        ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;                        //模数转换工作在单次模式(还是连续模式)
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel=M;                                                                        //顺序进行转换的通道数
        ADC_Init(ADC1, &ADC_InitStructure);                                                                         //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
       
        //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
        //ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
       
        ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);//选择ADC1通道1-PA1
        ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_239Cycles5);//选择ADC1通道2-PA2
        ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_239Cycles5);//选择ADC1通道3-PA3
       
       
        ADC_DMACmd(ADC1, ENABLE);                                // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
        ADC_Cmd(ADC1, ENABLE);                                         //使能指定的ADC1
               
        ADC_ResetCalibration(ADC1);                                                                                //重置校准器
        while(ADC_GetResetCalibrationStatus(ADC1));                //获取校准状态
        ADC_StartCalibration(ADC1);                                                                                //开始指定ADC的校准状态
        while(ADC_GetCalibrationStatus(ADC1));                                //获取指定ADC的校准程序
                 
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);                                //使能软件启动规则组转换功能  

}
void DMA_Configuration(void)
{   
        DMA_InitTypeDef DMA_InitStructure;  
        DMA_DeInit(DMA1_Channel1);                                                                                                                                                 //将DMA的通道1寄存器重设为缺省值  
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;                 //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;                                 //DMA内存基地址  
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                 //内存作为数据传输的目的地 外设作为数据传输的来源
        DMA_InitStructure.DMA_BufferSize = M*N;                                                                                                 //DMA通道的DMA缓存的大小  
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                         //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度为16位  
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                 //内存数据宽度为16位  
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                                                 //工作在循环缓存模式,当传输完一次后,重新接着传送,永不停息。
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                         //DMA通道 x拥有高优先级  
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                         //DMA通道x没有设置为内存到内存传输  
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);                                                                         //根据DMA_InitStruct中指定的参数初始化DMA的通道
        DMA_Cmd(DMA1_Channel1, ENABLE);                                                                                                                         //启动DMA通道
}
回复

使用道具 举报

1

主题

5

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2020-5-15
在线时间
7 小时
 楼主| 发表于 2020-7-1 08:05:22 | 显示全部楼层
困惑了好长时间,原子哥能能帮忙看看么
回复

使用道具 举报

1

主题

5

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2020-5-15
在线时间
7 小时
 楼主| 发表于 2020-7-7 14:48:14 | 显示全部楼层
自己解决一下吧,找到问题了,ADC连续转换语句写错了 ADC1->CR2&=1<<1;    //连续转换模式,&应该改成|
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2020-6-11
在线时间
12 小时
发表于 2020-7-21 19:30:12 | 显示全部楼层
欧阳诗诗0926 发表于 2020-7-7 14:48
自己解决一下吧,找到问题了,ADC连续转换语句写错了 ADC1->CR2&=1

加油                     
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-30 00:22

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表