stm32f103 adc单通道+dma传输

                                                                基于stm32f103的adc采集+dma传输实验

一.adc配置:设置规则序列

typedef struct
{
uint32_t ADC_Mode;     //  adc模式位(具体参考不完全手册)
FunctionalState ADC_ScanConvMode;   //   
用来设置是否开启扫描模式(disable关闭,ENABLE开启扫描)
FunctionalState ADC_ContinuousConvMode;  //  用来设置是否开启连续转换模式(disable关闭,ENABLE开启扫描)
uint32_t ADC_ExternalTrigConv;    //  用来设置启动规则转换组转换的外部事件,软件触发选ADC_ExternalTrigConv_None 即可
uint32_t ADC_DataAlign;   // 数据对其方式(左对齐,右对齐)
uint8_t ADC_NbrOfChannel;   // 设置规则序列长度 (在多通道扫描模式下需要给每个通道设置执行顺序这个顺序就是根据规则序列表里面排列的通道顺序来执行的因此我们要设置这个表里面有多少个通道)

}ADC_InitTypeDef;

adc配置流程:

1.使能io时钟和adc时钟(不用使能端口复用功能,adc挂载在APB2总线下,只有在其他总线下的外外设才需要端口复用)

2.设置adc时钟分配因子以确定adc工作时钟频率。

3.重置adc寄存器。

4.初始化adc结构体参数。(ADC_Init())

5.使能adc。

6.开启复位校准。

7.开启ad校准。

最后一步

8.为通道设置采样时间(如果是多通道则需要配置每个通道的采样优先级即:规则序列表)

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)

注意:转换时间=采样事件+12.5周期

若ADC_CLOCK=14M,采样时间1.5周期那么转换时间为1m即是1us(ADC_CLOCK最高频率不能超过14m一般设置6分频即72M/6=12M)。

二.dma配置步骤:

typedef struct
{
uint32_t DMA_PeripheralBaseAddr;       //dma外设地址(u32类型例如:(u32)&(ADC1->DR)) 
uint32_t DMA_MemoryBaseAddr;          //内存地址(u32类型例如:(u32)a(数组名)
uint32_t DMA_DIR;       //  传输方向(内存--外设,外设---内存,内存---内存)
uint32_t DMA_BufferSize;  //一次传输数据量的大小
uint32_t DMA_PeripheralInc;  //传输数据的时候外设地址是不变还是递增
uint32_t DMA_MemoryInc;    //传输数据的时候内存地址是不变还是递增
uint32_t DMA_PeripheralDataSize;  //外设的的数据长度是为字节传输(8bits),半字传输 (16bits)还是字传输 (32bits)
uint32_t DMA_MemoryDataSize;   //内存的的数据长度是为字节传输(8bits),半字传输 (16bits)还是字传输 (32bits)
uint32_t DMA_Mode;     //设置 DMA 模式是否循环采集(可选单词采集和循环采集)
uint32_t DMA_Priority;   //各个通道优先级
uint32_t DMA_M2M;    //是 否 是 存 储 器 到 存 储 器 模 式 传 输 ,
}DMA_InitTypeDef;

注意 :DMA_MemoryDataSize和DMA_PeripheralDataSize库函数设置的时候两个的值不同。

例如:#define DMA_PeripheralDataSize_Word        ((uint32_t)0x00000200)

#define DMA_MemoryDataSize_Word            ((uint32_t)0x00000800)

dma配置步骤:

1.使能相应时钟

2.将dma相应通道寄存器值设置为缺省值

3.初始化结构体参数

4.初始化dma

5.使能dma

到这里已经配置完dma最后一步:

6.使能相应外设dma(例如:ADC_DMACmd(ADC1,ENABLE);只用使能一次)

完整代码:

int DMA_Config(DMA_Channel_TypeDef* CHx,u32 PBaseAddr,u32 MBaseAddr,u32 buffsize)
{
    
    DMA_InitTypeDef DMA_InitStruct;
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    
    DMA_DeInit(CHx);
    
    DMA_InitStruct.DMA_PeripheralBaseAddr=PBaseAddr; //外设基地址
    DMA_InitStruct.DMA_MemoryBaseAddr=MBaseAddr;          //内存寄存器
    DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;  //数据传输方向  外设到内存
    DMA_InitStruct.DMA_BufferSize=32;              //通道缓存大小
    DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //外设寄存器地址不递增
    DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Disable;          //关闭内存寄存器地址递增
    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
    DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;      //内存数据宽度

    DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;                    //循环传输模式
    DMA_InitStruct.DMA_Priority=DMA_Priority_High;             //优先级
    DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;                    //不开启内存到内存
    
    DMA_Init(CHx ,&DMA_InitStruct);  //初始化DMA
    //USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
    DMA_Cmd(CHx ,ENABLE);
    return 1;
}

void Adc_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    ADC_InitTypeDef ADC_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);//使能时钟
    //配置GPIOA_5口模拟输入
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    //ADC时钟分频因子
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    //重置ADC寄存器
    ADC_DeInit(ADC1);  
    ADC_InitStruct.ADC_Mode= ADC_Mode_Independent;//独立模式
    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None ; //无外部触发
    ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;  //enable开启连续扫描
    ADC_InitStruct.ADC_NbrOfChannel=1;  //规则转换通道数目
    ADC_InitStruct.ADC_ScanConvMode=DISABLE;  //DISABLE单通道模式,enable多通道扫描模式
    ADC_Init(ADC1,&ADC_InitStruct);
    ADC_Cmd(ADC1,ENABLE);  //使能adc
    ADC_ResetCalibration(ADC1);//开启复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);  //开启ad校准
    while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_Adc(u8 ch1,u8 ch2)
{
    u16 count=0;
    ADC_RegularChannelConfig(ADC1,ch1,1,ADC_SampleTime_239Cycles5);
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
    {
        count++;
        if(count==60000)
            break;
    }
    return ADC_GetConversionValue(ADC1);  //返回adc数据寄存器器的值

 

注意:由于将 DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
    DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;      //内存数据宽度

改为: DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
    DMA_InitStruct.DMA_MemoryDataSize=
DMA_PeripheralDataSize_HalfWord;      //内存数据宽度

这样接收到的数据只有8位也就是最大值255

注意:在DMA传输过程中使用内存地址递增模式,循环传输时到传输到数组结尾时返回的位置是传入的地址处,而不是数组首地址。

例如:

int a[10];

 DMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)(&a[1]),(u32)buffsize);  //dma初始化注意此时传入的地址是a+1

当dma传输数据到a[10]后继续从a[1]地址处继续传输,而不是从数组首地址a[0]处。。。

 

 

ADC(Analog-to-Digital Converter)是模拟信号转换为数字信号的设备,而DMA(Direct Memory Access)则是一种数据传输方式。ADC单通道DMA是一种通过DMA传输数据的方式,用于将ADC采样到的模拟信号转换为数字信号并直接传输到内存中,而不需要CPU的干预。 在ADC单通道DMA模式下,ADC会不断采样模拟信号,并将采样到的数据存储到缓冲区中。当缓冲区满时,ADC会触发DMA传输请求,将数据通过DMA直接传输到内存中的指定地址。传输完成后,DMA会产生中断信号通知CPU,以便CPU进行后续的处理。 ADC单通道DMA的优势在于减少了CPU的负担,提高了数据传输的效率。由于ADC采样的速度相对较慢,如果每次采样都需要CPU的介入来处理数据传输,将会浪费CPU资源并降低系统的响应速度。而使用DMA进行数据传输,可以让CPU在数据传输过程中进行其他任务,提高系统的并发性。 此外,使用DMA进行数据传输还能减少数据传输的延迟。由于DMA是直接从ADC缓冲区中读取数据并传输到内存中,数据传输过程中不需要等待CPU的响应,数据的传输速度更快,能够及时地将数据存储到内存中。 综上所述,ADC单通道DMA是一种通过DMA方式进行数据传输的方法,具有减轻CPU负担、提高数据传输效率和降低传输延迟等优势。在实际应用中,可以根据系统的需求选择合适的ADC采样率和DMA传输模式,以便实现高效的数据采集和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值