打印
[RISC-V MCU 应用开发]

二十九、CH32V103应用教程——ADC(单通道DMA读取方式)

[复制链接]
4449|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
RISCVLAR|  楼主 | 2020-12-22 19:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 RISCVLAR 于 2020-12-23 14:49 编辑

CH32V103应用教程——ADC(单通道DMA读取方式)

关于ADC,前面第十章已经对其基础配置和应用进行过讲解。但ADC功能繁多,它有多达18个通道,可测量16个外部和2个内部信号源,且各通道的A/D转换可以单次、连续、扫描或间断模式执行。其还可模拟看门狗监测通道电压,并具有自动校准功能。本章以及接下几章将对ADC各功能进行一一讲解和应用。本章将进行ADC单通道DMA读取方式的应用。

1、ADC简介及相关函数介绍
CH32V103开发板 ADC模块包含一个12位的逐次逼近型的模拟数字转换器,可测量16个外部信号源和2个内部信号源,各个通道的AD转换可以实现单次、连续、扫描或间断模式执行。AD转换结果以左对齐或右对齐的方式存储在16位数据寄存器(ADC_RDATAR)中。ADC模拟看门狗特性允许应用程序检测输入电压是否在用户定义的阀值范围内。

ADC主要特性如下:
● 12位分辨率,支持16个外部通道和2个内部信号源采样
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
● 单次和连续转换模式
● 从通道0到通道n的自动扫描模式
● 自动校准功能
● 数据对齐模式:左对齐、右对齐
● 采样间隔可以按通道分别编程
● 规则转换和注入转换均有外部触发选项
● 间断模式
● ADC转换时间:时钟为72MHz为1.17μs
● ADC输入范围:0≤VIN≤VDDA
● 规则通道转换期间有DMA请求产生。

ADC的规则通道转换支持DMA功能。规则通道转换的值储存在一个仅有的数据寄存器ADC_RDATAR中,为防止连续转换多个规则通道时,没有及时取走 ADC_RDATAR 寄存器中的数据,可以开启ADC的DMA功能。硬件会在规则通道的转换结束时(ADC状态寄存器EOC位置位)产生 DMA请求,并将转换的数据从ADC_RDATAR寄存器传输到用户指定的目的地址。

对DMA控制器模块的通道配置完成后,ADC控制寄存器2(ADC_CTLR2)的DMA位置 1,开启ADC的DMA功能。
注:注入组转换不支持DMA功能。

本章仅进行ADC单通道DMA读取方式应用,关于多通道DMA读取方式应用,将会在下章进行介绍。

关于ADC具体信息,可参考CH32V103应用手册.关于ADC库函数,在第十章节已进行过介绍,在此不再赘述。

2、硬件设计
本章教程通过ADC1通道1读取开发板3.3V引脚和GND引脚ADC值,并通过串口调试助手打印显示出来。其中ADC1通道1对应PA1引脚,在进行使用测试时只需用杜邦线将PA1引脚与3.3V 引脚和GND引脚连接即可。

3软件设计
本章主要进行ADC单通道DMA读取方式的应用,DMA的数据传输方式为外设到存储器,本章教程在ADC和DMA基础上进行,关于ADC和DMA基本介绍以及应用,可参考前面相关章节。ADC单通道DMA读取方式应用程序具体如下:
adc.h文件
#ifndef __ADC_H
#define __ADC_H

#include "ch32v10x_conf.h"

void adc_Init(void);

void DMA_Tx_Init(void);

void ADC_DMA_CONF(void);

#endif
adc.h文件主要进行函数的声明;
adc.c文件
#include "adc.h"

u16 ADC_ConvertedValue;

//ADC对应GPIO初始化配置以及ADC初始化配置
void adc_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能GPIOA时钟和ADC1时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //GPIO模式为模拟输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //配置ADC为独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;      //设置单通道关闭扫描模式,多通道可设置为开启扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //设置开启连续转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //设置转换不是由外部触发启动,由软件触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //设置ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;                //规则转换的ADC通道的数目
    ADC_Init(ADC1, &ADC_InitStructure);                    //根据ADC_InitStructure中指定的参数初始化ADC1寄存器

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC时钟分频为6分频,72/6=12MHz

    ADC_Cmd(ADC1, ENABLE);      //使能ADC1

    ADC_ResetCalibration(ADC1); //重置ADC1校准寄存器。

    while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束

    ADC_StartCalibration(ADC1); //开启AD校准

    while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}

//ADC DMA模式配置
void DMA_Tx_Init( void )
{
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE ); //使能开启DMA时钟

    DMA_DeInit(DMA1_Channel1); //复位DMA控制器

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->RDATAR;  //配置外设地址为ADC数据寄存器地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;//配置存储器地址为读取ADC值地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;              //配置数据源为外设,即DMA传输方式为外设到存储器
    DMA_InitStructure.DMA_BufferSize = 1;                           //设置DMA数据缓冲区大小,此处设置为1
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA外设递增模式关闭
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;        //设置DMA存储器递增模式关闭
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //设置外设数据大小为半字,即两个字节
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         //设置存储器数据大小为半字,即两个字节
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;    //设置DMA模式为循环传输模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA传输通道优先级为高,当使用一 DMA通道时,优先级设置不影响
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;       //因为此DMA传输方式为外设到存储器,因此禁用存储器到存储器传输方式
    DMA_Init( DMA1_Channel1, &DMA_InitStructure );     //初始化DMA

    DMA_Cmd(DMA1_Channel1 , ENABLE); //使能DMA
}

void ADC_DMA_CONF(void)
{
    adc_Init();

    DMA_Tx_Init();

    //配置 ADC通道转换顺序为1,第一个转换,采样时间为55.5个时钟周期
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);

    //使能ADC DMA请求
    ADC_DMACmd(ADC1, ENABLE);

    //由于没有采用外部触发,所以使用软件触发ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
adc.c文件主要进行ADC1通道1对应GPIO引脚PA1的初始化配置、ADC初始化配置、DMA外设到存储器传输方式初始化配置以及ADC单通道DMA读取方式综合配置。其中。adc_Init函数主要进行ADC对应GPIO初始化配置以及ADC初始化配置,其与第十章ADC应用配置步骤类似,在此不再过多介绍,需要注意的是,此处设置开启ADC连续转换模式,具体如下:
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //设置开启连续转换模式
DMA_Tx_Init函数主要进行ADC DMA模式配置,其具体配置步骤与第二十八章DMA外设到存储器步骤类似,具体做如下修改:
对外设地址和存储器地址进行修改,外设地址修改为ADC数据寄存器:
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->RDATAR;  //配置外设地址为ADC数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;//配置存储器地址为读取ADC值地址
对DMA数据缓冲区大小进行修改,此处缓冲区大小修改为1:
DMA_InitStructure.DMA_BufferSize = 1;                           //设置DMA数据缓冲区大小,此处设置为1
对DMA存储器递增模式以及外设数据大小和存储器数据大小进行修改,具体如下:
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;        //设置DMA存储器递增模式关闭
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //设置外设数据大小为半字,即两个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         //设置存储器数据大小为半字,即两个字节
对DMA模式进行修改,设置DMA模式为循环传输模式,具体如下:
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;    //设置DMA模式为循环传输模式
ADC_DMA_CONF函数主要进行ADC单通道DMA读取方式综合配置,主要进行ADC和DMA的初始化以及使能ADC DMA请求,具体程序如下:
void ADC_DMA_CONF(void)
{
    adc_Init();

    DMA_Tx_Init();

    //配置 ADC通道转换顺序为1,第一个转换,采样时间为55.5个时钟周期
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);

    //使能ADC DMA请求
    ADC_DMACmd(ADC1, ENABLE);

    //由于没有采用外部触发,所以使用软件触发ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
main.c文件
int main(void)
{
    Delay_Init();
        USART_Printf_Init(115200);
    ADC_DMA_CONF();

        printf("SystemClk:%d\r\n",SystemCoreClock);
    printf("ADC单通道DMA读取测试\r\n");

    while (1)
    {

        printf("\r\n The current AD value = %d \r\n", ADC_ConvertedValue);

        Delay_Ms(500);
    }
}
main.c文件主要进行函数初始化以及打印输出ADC值。

4下载验证
将编译好的程序下载到开发板并复位,使用杜邦线将PA1引脚与3.3V引脚连接起来,串口显示如下:
使用杜邦线将PA1引脚与GND引脚连接起来,串口显示如下:


28、ADC-DMA读取单通道.rar

480.96 KB

使用特权

评论回复

相关帖子

沙发
ShuXS| | 2021-11-3 20:32 | 只看该作者
谢谢

使用特权

评论回复
板凳
uiint| | 2021-11-4 19:51 | 只看该作者
这个多通道转换不用DMA可以吗   

使用特权

评论回复
地板
hellosdc| | 2021-11-4 19:51 | 只看该作者
最大的转换速度是多少?           

使用特权

评论回复
5
mituzu| | 2021-11-4 19:51 | 只看该作者
用DMA有中断吗?        

使用特权

评论回复
6
suzhanhua| | 2021-11-4 19:52 | 只看该作者
ADC功能繁多,直接转换即可。     

使用特权

评论回复
7
xietingfeng| | 2021-11-4 19:52 | 只看该作者
单通道DMA和多通道DMA有什么区别呢   

使用特权

评论回复
8
isseed| | 2021-11-4 19:52 | 只看该作者
ADC的中断是怎么配置?        

使用特权

评论回复
9
wangdezhi| | 2021-11-4 19:52 | 只看该作者
CH32V103比stm32f103强多了。      

使用特权

评论回复
10
biechedan| | 2021-11-4 19:53 | 只看该作者
单次、连续、扫描或间断模式混乱了。   

使用特权

评论回复
11
chenci2013| | 2021-11-4 19:53 | 只看该作者
期待版主把所有的模式都讲一遍。           

使用特权

评论回复
12
gygp| | 2021-11-4 19:53 | 只看该作者
ADC和DAC配合着用。   

使用特权

评论回复
13
updownq| | 2022-11-3 20:26 | 只看该作者
这个不同通道之间会有干扰怎么解决的?

使用特权

评论回复
14
nomomy| | 2022-11-3 20:41 | 只看该作者
这个dma如何产生中断?是转换完成以后吗?

使用特权

评论回复
15
mattlincoln| | 2022-11-3 20:59 | 只看该作者
ADC功能繁多,研究起来还是比较繁多一些。

使用特权

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

本版积分规则

132

主题

293

帖子

37

粉丝