ADC实验(单通道 ADC 采集实验)(单通道 ADC 采集(DMA 读取)实验 )

单通道 ADC 采集实验

本实验我们来学习单通道 ADC 采集实验。本实验使用规则组单通道的单次转换模式,并 且通过软件触发,即由 ADC_CR2 寄存器的 SWSTART 位启动。下面先带大家来了解本实验要 配置的寄存器。 

ADC 寄存器

⚫ ADC 控制寄存器 1(ADC_CR1)

 SCAN 位用于选择是否使用扫描模式。本实验我们使用单通道采集,所以没必要选择扫描 模式,该位置 0 即可。

DUALMOD[3:0]位用来设置 ADC 的操作模式,我们的例程中 ADC 相关的实验都是使用独 立模式,所以设置为 0000 即可。

⚫ ADC 控制寄存器 2(ADC_CR2)

该寄存器我们针对性的介绍一些位:ADON 位用于打开或关闭 AD 转换器,还可以用于触 发 ADC 转换。CONT 位用于设置单次转换模式还是连续转换模式,本实验我们使用单次转换 模式,所以 CONT 位置 0 即可。CAL 位用于开启 AD 校准。RSTCAL 位用于判断校准寄存器是 否已初始化。ALIGN 用于设置数据对齐,我们使用右对齐,所以该位置 0。EXTSEL[2:0]位用 于选择规则组启动转换的外部事件触发源,本实验使用的是软件触发(SWSTART),所以这三 个位置为 111。EXTTRIG 位必须置 1,EXTSEL[2:0]位才能选择软件触发(SWSTART),别漏了 这步,否则设置软件触发会不成功。SWSTART 位用于启动一次规则组通道的转换,即软件触发转换。

⚫ ADC 采样事件寄存器 1(ADC_SMPR1)

 ⚫ ADC 采样事件寄存器 2(ADC_SMPR2)

 ADC 采样时间设置需要由两个寄存器设置,ADC_SMPR1 和 ADC_SMPR1,分别设置通道 10~17 和通道 0~9 的采样时间,每个通道用 3 个位设置。可以看出 ADC 的每个通道的采样时间 是支持单独设置的。

一般每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降 低 ADC 的转换速率,看大家怎么衡量选择了。本实验中,我们设置采样时间是 239.5 个周期。 结合前面介绍过的转换时间公式:TCONV = 采样时间 + 12.5 个周期

以及例程中,PCLK2 的时钟是 72MHz,经过 ADC 时钟预分频器的 6 分频后,ADC 时钟 频率为 12MHz。代入上式可得到:TCONV = 239.5 + 12.5 个 ADC 时钟周期 = ( 1 12000000) ∗ 252 s = 21us

由上式可得,ADC 的转换时间是 21us。

⚫ ADC 规则序列寄存器 1

ADC 规则序列寄存器共有 3 个,这几个寄存器的功能都差不多,这里我们仅介绍一下 ADC 规则序列寄存器 1(ADC_SQR1)。

L[3:0]用于设置规则组序列的长度,取值范围:0~15,表示规则组的长度是 1~16。本实验 只用了 1 个输入通道,所以 L[3:0]位设置为 0000 即可。

SQ13[4:0]~SQ16[4:0]位设置规则组序列的第 13~16 个转换编号,第 1~12 个转换编号的设 置请查看 ADC_SQR2 和 ADC_SQR3 寄存器。

本实验我们使用单通道,ADC1 通道 1,所以规则组序列里只有一个输入通道,我们将 ADC_SQR3 寄存器的 SQ1[4:0]位的值设置为 1 即可。

⚫ ADC 规则数据寄存器(ADC_DR)

 在规则序列中 AD 转换结果都将被存在这个寄存器里面,而注入通道的转换结果被保存在 ADC_JDRx 里面。该寄存器的数据可以通过 ADC_CR2 的 ALIGN 位设置左对齐还是右对齐。 在读取数据的时候要注意。 

⚫ ADC 状态寄存器(ADC_SR)

该寄存器保存了 ADC 转换时的各种状态。本实验我们通过 EOC 位的状态来判断 ADC 转 换是否完成,如果查询到 EOC 位被硬件置 1,就可以从 ADC_DR 寄存器中读取转换结果,否 则需要等待转换完成。

 单通道ADC采集实验配置步骤

 

 相关HAL库函数介绍

 关键结构体介绍

 使用 ADC1 采集通道 1(PA1)上面的电压,并在 LCD 模块上面显示 ADC 规则数据寄存 器 12 位的转换值以及将该值换算成电压后的电压值。使用短路帽将 ADC 和 RV1 排针连接,使 得 PA1 连接到电位器上,然后将 ADC 采集到的数据和转换后的电压值在 TFTLCD 屏中显示。 用户可以通过调节电位器的旋钮改变电压值。LED0 闪烁,提示程序运行。

有的朋友可能还想测试其它地方的电压值,我们还可以通过杜邦线,一端接到 ADC 排针 上,另外一端就接你要测试的电压点。一定要保证测试点的电压在 0~3.3V 的电压范围,否则可 能烧坏我们的 ADC,甚至是整个主控芯片。

代码

#include "./BSP/ADC/adc.h"
#include "./SYSTEM/delay/delay.h"

ADC_HandleTypeDef g_adc_handle;/* ADC句柄 */

/* ADC单通道 */
void adc_init(void)
{
    ADC_ChannelConfTypeDef adc_ch_conf = {0};
    
    g_adc_handle.Instance = ADC1;/* 选择ADC1 */
    g_adc_handle.Init.ContinuousConvMode = DISABLE;/* 关闭连续转换模式 */
    g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;/* 数据对齐方式:右对齐 */
    g_adc_handle.Init.DiscontinuousConvMode = DISABLE;/* 禁止规则通道组间断模式 */
    g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;/* 触发转换方式:软件触发 */
    g_adc_handle.Init.NbrOfConversion = 1;/* 赋值范围是1~16,本实验用到1个规则通道序列 */
    g_adc_handle.Init.NbrOfDiscConversion = 0;/* 配置间断模式的规则通道个数,禁止规则通道组间断模式后,此参数忽略 */
    g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;/* 非扫描模式,仅用到一个通道 */
    HAL_ADC_Init(&g_adc_handle);/* 初始化 */
    
    HAL_ADCEx_Calibration_Start(&g_adc_handle);/* 校准ADC */
    
    adc_ch_conf.Channel = ADC_CHANNEL_1;/* 通道1 */
    adc_ch_conf.Rank = ADC_REGULAR_RANK_1;/* 序列1 */
    adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;/* 采样时间239.5个ADC时钟周期 */
    HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);/* 通道配置 */
}

/* ADC Msp底层函数初始化 */
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
        GPIO_InitTypeDef gpio_init_struct = {0};
        
        __HAL_RCC_GPIOA_CLK_ENABLE();/* 开启GPIOA时钟 */
        __HAL_RCC_ADC1_CLK_ENABLE();/* 使能ADC1时钟 */
        
        /* 设置ADC时钟 */
        adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;/* ADC外设时钟 */
        adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;/* 分频因子6时钟为72M/6=12MHz */
        HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);/* 设置ADC时钟 */
        
        /* 设置ADC采集通道对应IO引脚工作模式 */
        gpio_init_struct.Pin = GPIO_PIN_1;/* ADC通道IO引脚 */
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;/* 模拟 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
    }
}

/* 获得ADC转换后结果的函数 */
uint32_t adc_get_result(void)
{
    HAL_ADC_Start(&g_adc_handle);/* 开启ADC转换 */
    HAL_ADC_PollForConversion(&g_adc_handle, 10);/* 轮询转换(等待转换完成) */
    return (uint16_t)HAL_ADC_GetValue(&g_adc_handle);/* 返回最近一次ADC1规则组的转换结果 */
}

/* 获取通道1的转换值,取times次,然后平均 */
uint32_t adc_get_result_average(uint8_t times)
{
    uint32_t temp_val = 0;
    uint8_t t;
    
    for(t = 0; t < times; t++)/* 获取times次数据 */
    {
        temp_val += adc_get_result();
        delay_ms(5);
    }
    
    return (temp_val / times);/* 返回平均值 */
}
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"

int main(void)
{
    uint16_t adcx;
    float temp;
    
    HAL_Init();                         /* 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 传口初始化 */
    
    led_init();                         /* LED初始化 */
    lcd_init();                         /* LCD初始化 */
    adc_init();                         /* ADC初始化 */
    
    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "ADC TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH1_VAL:", BLUE);
    lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
    
    while(1)
    {
        adcx = adc_get_result_average(10);/* 获取通道1的转换值,10次取平均 */
        lcd_show_xnum(134, 110, adcx, 5, 16, 0, BLUE);      /* 显示ADCC采样后的原始值 */
        
        temp = (float)adcx * (3.3 / 4096);/* 获取计算后的带小数的实际电压值,比如3.1111 */
        adcx = temp;/* 赋值整数部分给adcx变量,因为adcx为u16整形 */
        lcd_show_xnum(134, 130, adcx, 1, 16, 0, BLUE);/* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
        
        temp -=adcx;/* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
        temp *= 1000;/* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
        lcd_show_xnum(150, 130, temp, 3, 16, 0X80, BLUE);   /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
        
        LED0_TOGGLE();
        delay_ms(100);
    }
}

单通道 ADC 采集(DMA 读取)实验 

 本实验我们来学习单通道 ADC 采集(DMA 读取)实验。本实验使用规则组单通道的连续 转换模式,并且通过软件触发,即由 ADC_CR2 寄存器的 SWSTART 位启动。由于使用连续转 换模式,所以使用 DMA 读取转换结果的方式。下面先带大家来了解本实验要配置的寄存器。

ADC&DMA 寄存器

⚫ ADC 配置寄存器(ADC_CR2)

DMA 位用于配置使用 DMA 模式,本实验该位置 1。在单通道 ADC 采集实验中,默认设 置为 0,即不使用 DMA 模式,规则组转换的结果存储在 ADC_DR 寄存器,然后通过手动读取 ADC_DR 寄存器的方式得到转换结果。本实验我们使用 ADC 的连续转换模式,并通过 DMA 读 取转换结果,这样 DMA 就会自动在 ADC_DR 寄存器中读取转换结果。 

CONT 位用于设置单次转换模式还是连续转换模式,本实验我们使用连续转换模式,所以 CONT 位置 1 即可。

⚫ DMA 通道 x 外设地址寄存器(DMA_CPARx)(x = 1…7)

该寄存器存放的是 DMA 通道 x 外设地址。本实验,我们需要通过 DMA 读取 ADC 转换后 存放在 ADC 规则数据寄存器 (ADC_DR) 的结果数据。所以我们需要给 DMA_CPARx 寄存器 写入 ADC_DR 寄存器的地址。这样配置后,DMA 就会从 ADC_DR 寄存器的地址读取 ADC 的 转换后的数据到某个内存空间。这个内存空间地址需要我们通过DMA_CMARx寄存器来设置, 比如定义一个变量,把这个变量的地址值写入该寄存器。

注意:DMA_CPARx 寄存器受到写保护,只有 DMA_CCRx 寄存器中的 EN 为“0”时才可 以写入,即先要禁止通道开启才可以写入。

⚫ DMA 通道 x 存储器地址寄存器(DMA_CMARx)(x = 1…7)

 ⚫ DMA 通道 x 传输数量寄存器(DMA_CNDTRx)(x = 1…7)

单通道 ADC 采集(DMA 读取)配置步骤 

 代码

#include "./BSP/ADC/adc.h"

DMA_HandleTypeDef g_dma_adc_handle;/* 定义要搬运ADC数据的DMA句柄 */
ADC_HandleTypeDef g_adc_dma_handle;/* 定义ADC(DMA读取)句柄 */

uint8_t g_adc_dma_sta;/* DMA传输状态标志, 0,未完成; 1, 已完成 */

/* ADC DMA读取 初始化函数 */
void adc_dma_init(uint32_t mar)
{
    ADC_ChannelConfTypeDef adc_ch_conf = {0};
    
    __HAL_RCC_DMA1_CLK_ENABLE();/* DMA1时钟使能 */
    
    g_dma_adc_handle.Instance = DMA1_Channel1;/* 设置DMA通道 */
    g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;/* 从外设到存储器模式 */
    g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;/* 存储器数据长度:16位 */
    g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE;/* 存储器增量模式 */
    g_dma_adc_handle.Init.Mode = DMA_NORMAL;/* 外设流控模式 */
    g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;/* 外设数据长度:16位 */
    g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE;/* 外设非增量模式 */
    g_dma_adc_handle.Init.Priority = DMA_PRIORITY_HIGH;/* 高等优先级 */
    HAL_DMA_Init(&g_dma_adc_handle);
    
    __HAL_LINKDMA(&g_adc_dma_handle, DMA_Handle, g_dma_adc_handle);/* 将DMA与adc联系起来 */
    
    g_adc_dma_handle.Instance = ADC1;/* 选择ADC1 */
    g_adc_dma_handle.Init.ContinuousConvMode = ENABLE;/* 打开连续转换模式 */
    g_adc_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;/* 数据对齐方式:右对齐 */
    g_adc_dma_handle.Init.DiscontinuousConvMode = DISABLE;/* 禁止规则通道组间断模式 */
    g_adc_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;/* 触发转换方式:软件触发 */
    g_adc_dma_handle.Init.NbrOfConversion = 1;/* 赋值范围是1~16,本实验用到1个规则通道序列 */
    g_adc_dma_handle.Init.NbrOfDiscConversion = 0;/* 配置间断模式的规则通道个数,禁止规则通道组间断模式后,此参数忽略 */
    g_adc_dma_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;/* 非扫描模式,仅用到一个通道 */
    HAL_ADC_Init(&g_adc_dma_handle);/* 初始化 */
    
    HAL_ADCEx_Calibration_Start(&g_adc_dma_handle);/* 校准ADC */
    
    adc_ch_conf.Channel = ADC_CHANNEL_1;/* 通道1 */
    adc_ch_conf.Rank = ADC_REGULAR_RANK_1;/* 序列1 */
    adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;/* 采样时间239.5个ADC时钟周期 */
    HAL_ADC_ConfigChannel(&g_adc_dma_handle, &adc_ch_conf);/* 通道配置 */
    
    HAL_DMA_Start_IT(&g_dma_adc_handle, (uint32_t)&ADC1->DR, mar, 0);/* 启动DMA,并开启中断 */
    HAL_ADC_Start_DMA(&g_adc_dma_handle, &mar, 0);/* 开启ADC,通过DMA传输结果 */
}

/* ADC Msp底层函数初始化 */
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
        GPIO_InitTypeDef gpio_init_struct = {0};
        
        __HAL_RCC_GPIOA_CLK_ENABLE();/* 开启GPIOA时钟 */
        __HAL_RCC_ADC1_CLK_ENABLE();/* 使能ADC1时钟 */
        
        /* 设置ADC时钟 */
        adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;/* ADC外设时钟 */
        adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;/* 分频因子6时钟为72M/6=12MHz */
        HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);/* 设置ADC时钟 */
        
        /* 设置ADC采集通道对应IO引脚工作模式 */
        gpio_init_struct.Pin = GPIO_PIN_1;/* ADC通道IO引脚 */
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;/* 模拟 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
        
        /* 配置DMA数据流请求中断优先级 */
        HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 3);
        HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
    }
}

/* 使能一次 ADC DMA传输函数 */
void adc_dma_enable(uint16_t cndtr)
{
    /* 寄存器方式 */
//    ADC1->CR2 &= ~(1 << 0);/* 先关闭ADC */
//    DMA1_Channel1->CCR &= ~(1 << 0); /* 关闭DMA传输 */
//    
//    while(DMA1_Channel1->CCR & (1 << 0));/* 确保DMA可以被设置 */
//    DMA1_Channel1->CNDTR = cndtr;/* DMA传输数据量 */
//    
//    DMA1_Channel1->CCR |= (1 << 0);/* 开启DMA传输 */
//    ADC1->CR2 |= (1 << 0);/* 重新启动ADC */
//    
//    ADC1->CR2 |= (1 << 22);/* 启动规则转换通道 */
    
    /* HAL库方式 */
    __HAL_ADC_DISABLE(&g_adc_dma_handle);/* 先关闭ADC */
    __HAL_DMA_DISABLE(&g_dma_adc_handle);/* 关闭DMA传输 */
    
    while(DMA1_Channel1->CCR & (1 << 0));/* 确保DMA可以被设置 */
    DMA1_Channel1->CNDTR = cndtr;/* DMA传输数据量 */
    
    __HAL_DMA_ENABLE(&g_dma_adc_handle);/* 开启DMA传输 */
    __HAL_ADC_ENABLE(&g_adc_dma_handle);/* 重新启动ADC */
    
    HAL_ADC_Start(&g_adc_dma_handle);/* 启动规则转换通道 */
}

/* ADC DMA读取中断服务函数 */
void DMA1_Channel1_IRQHandler(void)
{
    if(DMA1->ISR & (1 << 1))
    {
        g_adc_dma_sta = 1;/* 标记DMA传输完成 */
        DMA1->IFCR |= (1 << 1);/* 清除DMA1 数据流 传输完成中断 */
    }
}

第一部分使能 ADC、DMA 和 GPIO 的时钟。

第二部分配置 ADC 时钟预分频系数为 6,得到 ADC 的输入时钟频率是 12MHz。

第三部分是设置 ADC 采集通道对应 IO 引脚工作模式。

第四部分初始化 DMA,并通过__HAL_LINKDMA 宏定义将 DMA 相关的配置关联到 ADC 的句柄中。

第五部分是初始化 ADC,并校准 ADC。

第六部分是配置 ADC 通道。

第七部分是配置 DMA 数据流请求中断优先级,并使能该中断。

第八部分是启动 DMA 并开启 DMA 中断,以及启动 ADC 并通过 DMA 传输转换结果。 

该函数我们使用寄存器来操作,防止用 HAL 库相关宏操作会对其它参数进行修改,同时也 是为了兼容后面的实验。HAL_DMA_Start_IT 函数已经配置好了 DMA 传输的源地址和目标地 址,本函数只需要调用 ADC_ADCX_DMACx->CNDTR = cndtr;语句给 DMA_CNDTRx 寄存器 写入要传输的数据量,然后启动 DMA 就可以传输了。

在该函数里,通过判断 DMA 传输完成标志位是否是 1,是 1 就给 g_adc_dma_sta 变量赋 值为 1,标记 DMA 传输完成,最后清除 DMA 的传输完成标志位。

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"

#define ADC_DMA_BUF_SIZE        100         /* ADC DMA采集 BUF大小 */
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];   /* ADC DMA BUF */

extern uint8_t g_adc_dma_sta;               /* DMA传输状态标志, 0,未完成; 1, 已完成 */

int main(void)
{
    uint16_t i;
    uint16_t adcx;
    uint32_t sum;
    float temp;
    
    HAL_Init();                         /* 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 传口初始化 */
    
    led_init();                         /* LED初始化 */
    lcd_init();                         /* LCD初始化 */
    
    adc_dma_init((uint32_t)&g_adc_dma_buf); /* 初始化ADC DMA采集 */

    lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30,  70, 200, 16, 16, "ADC DMA TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH1_VAL:", BLUE);
    lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */

    adc_dma_enable(ADC_DMA_BUF_SIZE);   /* 启动ADC DMA采集 */
    
    while(1)
    {
        if (g_adc_dma_sta == 1)
        {
            /* 计算DMA 采集到的ADC数据的平均值 */
            sum = 0;

            for (i = 0; i < ADC_DMA_BUF_SIZE; i++)   /* 累加 */
            {
                sum += g_adc_dma_buf[i];
            }

            adcx = sum / ADC_DMA_BUF_SIZE;           /* 取平均值 */

            /* 显示结果 */
            lcd_show_xnum(134, 110, adcx, 4, 16, 0, BLUE);      /* 显示ADCC采样后的原始值 */

            temp = (float)adcx * (3.3 / 4096);                  /* 获取计算后的带小数的实际电压值,比如3.1111 */
            adcx = temp;                                        /* 赋值整数部分给adcx变量,因为adcx为u16整形 */
            lcd_show_xnum(134, 130, adcx, 1, 16, 0, BLUE);      /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */

            temp -= adcx;                                       /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
            temp *= 1000;                                       /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
            lcd_show_xnum(150, 130, temp, 3, 16, 0X80, BLUE);   /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */

            g_adc_dma_sta = 0;                                  /* 清除DMA采集完成状态标志 */
            adc_dma_enable(ADC_DMA_BUF_SIZE);                   /* 启动下一次ADC DMA采集 */
        }

        LED0_TOGGLE();
        delay_ms(100);
    }
}

此部分代码,和单通道 ADC 采集实验十分相似,只是这里使能了 DMA 传输数据,DMA 传输的数据存放在 g_adc_dma_buf 数组里,这里我们对数组的数据取平均值,减少误差。在 LCD 屏显示结果的处理和单通道 ADC 采集实验一样。首先在液晶固定位置显示了小数点,先计算 出整数部分在小数点前面显示,然后计算出小数部分,在小数点后面显示。这样就能在液晶上 面显示转换结果的整数和小数部分。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值