打印
[STM32F1]

STM32通过DMA采集多通道AD

[复制链接]
2433|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
734774645|  楼主 | 2016-3-23 10:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
环境
     主机:XP
     开发环境:MDK4.23
     MCU:STM32F103CBT6

说明:

通过脚PA1,PA2采集AD。每路AD采集10次。



#include "ad_driver.h"

//全局变量
//AD采样存放空间
__IO uint16_t ADCConvertedValue[20];

//函数
//初始化AD
void init_ad(void)
{
        ADC_InitTypeDef ADC_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
         GPIO_InitTypeDef GPIO_InitStructure;

        //---------------------充电AD初始化--------------------
        //启动DMA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        //启动ADC1时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

        //采样脚设置
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        //DMA1通道1配置
        DMA_DeInit(DMA1_Channel1);
        //外设地址
        DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
        //内存地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;
        //dma传输方向单向
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        //设置DMA在传输时缓冲区的长度
        DMA_InitStructure.DMA_BufferSize = 20;
        //设置DMA的外设递增模式,一个外设
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        //设置DMA的内存递增模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        //外设数据字长
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        //内存数据字长
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        //设置DMA的传输模式:连续不断的循环模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        //设置DMA的优先级别
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        //设置DMA的2个memory中的变量互相访问
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        
        //使能通道1
        DMA_Cmd(DMA1_Channel1, ENABLE);

        //ADC1配置
        //独立工作模式
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        //扫描方式
        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_InitStructure.ADC_NbrOfChannel = 2;
        ADC_Init(ADC1, &ADC_InitStructure);
        
        //规则模式通道配置
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1 , 1, ADC_SampleTime_239Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2 , 2, ADC_SampleTime_239Cycles5);
        
        //使能ADC1的DMA
        ADC_DMACmd(ADC1, ENABLE);
        
        //使能ADC1
        ADC_Cmd(ADC1, ENABLE);
        
        //使能ADC1复位校准寄存器  
        ADC_ResetCalibration(ADC1);
        //检查校准寄存器是否复位完毕
        while(ADC_GetResetCalibrationStatus(ADC1));
        
        //开始校准
        ADC_StartCalibration(ADC1);
        //检测是否校准完毕
        while(ADC_GetCalibrationStatus(ADC1));
         
        //开启ADC1的软件转换
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

//获得充电电压
float voltage_charge(void)
{
         uint8_t i = 0;
        uint16_t sum = 0;
        float v = 0;

        //取得10次充电电压平均值
        for (i = 0;i < 10;i++)
        {
                 sum += ADCConvertedValue[i * 2];
        }
        sum /= 10;
        //变换成电压值
        v = 0.002991 * sum;

        return v;
}

//获得放电电压
float voltage_discharge(void)
{
         uint8_t i = 0;
        uint16_t sum = 0;
        float v = 0;

        //取得10次充电电压平均值
        for (i = 0;i < 10;i++)
        {
                 sum += ADCConvertedValue[i * 2 + 1];
        }
        sum /= 10;
        //变换成电压值
        v = 0.002991 * sum;

        return v;
}


沙发
734774645|  楼主 | 2016-3-23 10:24 | 只看该作者
stm32f103 adc1 与DMA的结合方式应用实例

#define     ADC1_Chanel0    0   
#define     ADC1_Chanel1    1   
#define     ADC1_Chanel2    2   
#define     ADC1_Chanel3    3   
#define     ADC1_Chanel4    4   
#define     ADC1_Chanel5    5   
#define     ADC1_Chanel6    6   
#define     ADC1_Chanel7    7   
#define     ADC1_Chanel8    8   
#define     ADC1_Chanel9    9   
#define     ADC1_Chanel10   10  
#define     ADC1_Chanel11   11  
#define     ADC1_Chanel12   12  
#define     ADC1_Chanel13   13  
#define     ADC1_Chanel14   14  
#define     ADC1_Chanel15   15  
#define     ADC1_Chanel16   16  

//====AD开启通道个数======================
#define     ADC_ENB_NUM     1

#define  ADC_CYC_Cycles5     ADC_SampleTime_55Cycles5  //设置AD转换速率



uint16_t AD_Value[ADC_ENB_NUM] ; //DMA存储数据的区域

#define ADC1_DR_Address    ((uint32_t)0x4001244C)    //ADC1数据寄存器的基地址


//*************************************
// 函数名称:ADC1_Config
// 函数功能:adc1 初始化配置
// 入口参数:无
// 出口参数:无
// 返 回 值:无
//***************************************/
void ADC1_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;
     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);     //使能ADC
    /* DMA1 channel1 configuration ----------------------------------------------*/
     
    RCC_ADCCLKConfig(RCC_PCLK2_Div6) ; //ADC时钟分频 72/6 = 12M
         
    /* ADC1 configuration ------------------------------------------------------*/
     
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //独立的转换模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;          //开启扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;   //开启连续转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC外部开关,关闭状态
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   //对齐方式,ADC为12位中,右对齐方式
    ADC_InitStructure.ADC_NbrOfChannel = ADC_ENB_NUM;    //开启通道数,1个
    ADC_Init(ADC1, &ADC_InitStructure);
     
    /* ADC1 regular channel9 configuration */
    //ADC通道组,第9个通道 采样顺序1,转换时间  
    ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_CYC_Cycles5);
      
//  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_55Cycles5);  

     
    ADC_DMACmd(ADC1, ENABLE);     //ADC命令,使能
    ADC_Cmd(ADC1, ENABLE);  //开启ADC1
    ADC_ResetCalibration(ADC1);   //重新校准
    while(ADC_GetResetCalibrationStatus(ADC1));  //等待重新校准完成
    ADC_StartCalibration(ADC1);     //开始校准
    while(ADC_GetCalibrationStatus(ADC1));     //等待校准完成
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //连续转换开始,ADC通过DMA方式不断的更新RAM区。
    //  ADC_TempSensorVrefintCmd(ENABLE);
}

//*************************************
// 函数名称:DMA_Config_ADC1
// 函数功能:DMA 初始化配置
// 入口参数:无
// 出口参数:无
// 返 回 值:无
//***************************************/
void DMA_Config_ADC1(void)
{
    DMA_InitTypeDef DMA_InitStructure;
     
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);       //使能DMA时钟
    DMA_DeInit(DMA1_Channel1);        //开启DMA1的第一通道
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //DMA对应的外设基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value[0];//内存存储基地址 自己开僻的数组
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//DMA的转换模式为SRC模式,由外设搬移到内存
    DMA_InitStructure.DMA_BufferSize = Num_Adc_Chanel; //DMA缓存大小,N个
    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;  //DMA搬移数据尺寸,HalfWord就是为16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;   //转换模式,循环缓存模式。
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA优先级高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;          //M2M模式禁用
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);         
     
    /* Enable DMA1 channel1 */
    DMA_Cmd(DMA1_Channel1, ENABLE);
}
//===ADC GPIO 初始化=======
void ADC1_GPIOInit(void)
{
//-----------PB---------------------------------
    //VR 端口 PB1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;  //管脚1
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //50M时钟速度
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            //输入模式
    GPIO_Init(GPIOB, &GPIO_InitStructure);  

}


//====实例应用=======

    //ADC1初始化设置
    ADC1_GPIOInit() ;
    ADC1_Config() ;
    DMA_Config_ADC1() ; //dma设置

//--主程序-----
void mian(void)
{
    while(1)
    {
        while(!F_10MS);
        F_10MS = 0 ;

        Tmp = AD_Value[0] ; //在缓存区中 读取AD结果

    }
         
}


使用特权

评论回复
板凳
ZHOU@JIE| | 2016-8-15 13:55 | 只看该作者
734774645 发表于 2016-3-23 10:24
stm32f103 adc1 与DMA的结合方式应用实例

楼主这个代码main函数里少东西吧?上传的时候出问题了?没在dma中断里处理数据?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

196

主题

3436

帖子

14

粉丝