ADC 同步规则双ADC多通道采集

ADC 同步规则双ADC多通道采集

#include "bsp_adc.h"
#include <stdio.h>

// 定义一个数组用于存储 ADC 转换后的值,这里准备存储两个 ADC 转换结果
uint32_t adc_value[2];

// 定时器配置函数,用于配置定时器产生触发 ADC 转换的信号
void timer_config(void)
{
    // 定义定时器输出比较参数结构体
    timer_oc_parameter_struct timer_ocintpara;
    // 定义定时器参数结构体
    timer_parameter_struct timer_initpara;

    // TIMER1 配置
    // 初始化定时器参数结构体为默认值
    timer_struct_para_init(&timer_initpara);
    // 设置定时器预分频器,这里将定时器时钟频率分频为原来的 5400 分之一
    timer_initpara.prescaler = 5399;
    // 设置定时器对齐模式为边沿对齐模式
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    // 设置定时器计数方向为向上计数
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    // 设置定时器周期,计数到 9999 后产生更新事件
    timer_initpara.period = 9999;
    // 设置定时器时钟分频因子为 1
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    // 设置重复计数器值为 0
    timer_initpara.repetitioncounter = 0;
    // 根据上述配置初始化 TIMER1
    timer_init(TIMER1, &timer_initpara);

    // CH0 配置为 PWM 模式 1
    // 初始化定时器输出比较参数结构体为默认值
    timer_channel_output_struct_para_init(&timer_ocintpara);
    // 设置输出比较极性为高电平有效
    timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    // 使能定时器通道输出
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    // 根据上述配置初始化 TIMER1 的通道 1
    timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocintpara);

    // 设置 TIMER1 通道 1 的脉冲值,用于控制 PWM 占空比
    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 3999);
    // 设置 TIMER1 通道 1 的输出模式为 PWM 模式 1
    timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    // 禁用 TIMER1 通道 1 的输出比较影子寄存器
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);
}

// ADC 初始化函数,调用多个子函数完成 ADC 的初始化工作
void adc_init()
{
    // 配置 ADC 系统时钟
    adc_rcu_config();
    // 配置 ADC 相关的 GPIO 引脚
    adc_gpio_config();
    // 配置定时器
    timer_config();
    // 配置 ADC 的 DMA 功能
    adc_dma_config();
    // 配置 ADC 本身的参数
    adc_config();
}

// 配置 ADC 系统时钟的函数
void adc_rcu_config(void)
{
    // 使能 GPIOA 时钟,因为 ADC 引脚连接在 GPIOA 上
    rcu_periph_clock_enable(RCU_GPIOA);
    // 使能 ADC0 时钟
    rcu_periph_clock_enable(RCU_ADC0);
    // 使能 ADC1 时钟
    rcu_periph_clock_enable(RCU_ADC1);
    // 使能 DMA0 时钟,用于 ADC 数据的 DMA 传输
    rcu_periph_clock_enable(RCU_DMA0);
    // 使能定时器 1 时钟,用于触发 ADC 转换
    rcu_periph_clock_enable(RCU_TIMER1);
    // 配置 ADC 时钟,将 APB2 时钟分频为原来的 8 分之一作为 ADC 时钟
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
}

// 配置 ADC 相关 GPIO 引脚的函数
void adc_gpio_config(void)
{
    // 将 GPIOA 的引脚 4 和 5 配置为模拟输入模式,速度为 50MHz
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_5);
}

/*!
    \brief      configure the DMA peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
#if 1
// 配置 ADC 的 DMA 功能的函数
void adc_dma_config(void)
{
    // 定义 DMA 参数结构体
    dma_parameter_struct dma_data_parameter;

    // 对 DMA0 的通道 0 进行去初始化操作
    dma_deinit(DMA0, DMA_CH0);

    // 初始化 DMA 为单次数据传输模式
    // 设置 DMA 外设地址为 ADC0 的数据寄存器地址
    dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
    // 禁用外设地址自增
    dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    // 设置 DMA 内存地址为存储 ADC 转换结果的数组地址
    dma_data_parameter.memory_addr = (uint32_t)(adc_value);
    // 使能内存地址自增
    dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    // 设置外设数据宽度为 32 位
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
    // 设置内存数据宽度为 32 位
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT;
    // 设置 DMA 传输方向为从外设到内存
    dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
    // 设置 DMA 传输的数据数量为 1
    dma_data_parameter.number = 1;
    // 设置 DMA 通道优先级为高
    dma_data_parameter.priority = DMA_PRIORITY_HIGH;
    // 根据上述配置初始化 DMA0 的通道 0
    dma_init(DMA0, DMA_CH0, &dma_data_parameter);

    // 使能 DMA0 通道 0 的循环模式
    dma_circulation_enable(DMA0, DMA_CH0);

    // 使能 DMA0 的通道 0
    dma_channel_enable(DMA0, DMA_CH0);
}

/*!
    \brief      configure the ADC peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
// 配置 ADC 本身参数的函数
void adc_config(void)
{
    // 对 ADC0 和 ADC1 进行复位操作
    adc_deinit(ADC0);
    adc_deinit(ADC1);

    // 使能 ADC0 和 ADC1 的扫描模式
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);
    // 配置 ADC0 的规则通道触发源为 TIMER1 的通道 1
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T1_CH1);
    // 配置 ADC1 的规则通道不使用外部触发
    adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
    // 配置 ADC0 和 ADC1 的数据对齐方式为右对齐
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
    // 配置 ADC 为双规则并行模式
    adc_mode_config(ADC_DAUL_REGULAL_PARALLEL);
    // 配置 ADC0 和 ADC1 的规则通道长度为 1
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);
    adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 1);

    // 配置 ADC0 的规则通道 0 为通道 4,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);
    // 配置 ADC1 的规则通道 0 为通道 5,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);

    // 使能 ADC0 和 ADC1 的规则通道外部触发
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
    adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);

    // 使能 ADC0
    adc_enable(ADC0);
    // 延时 1ms 等待 ADC 稳定
    delay_1ms(1);
    // 对 ADC0 进行校准
    adc_calibration_enable(ADC0);
    // 使能 ADC1
    adc_enable(ADC1);
    // 延时 1ms 等待 ADC 稳定
    delay_1ms(1);
    // 对 ADC1 进行校准
    adc_calibration_enable(ADC1);

    // 使能 ADC0 的 DMA 功能
    adc_dma_mode_enable(ADC0);
}

#else
// 另一种 DMA 配置方式
void adc_dma_config(void)
{
    // 定义 DMA 参数结构体
    dma_parameter_struct dma_data_parameter;

    // 对 DMA0 的通道 0 进行去初始化操作
    dma_deinit(DMA0, DMA_CH0);

    // 初始化 DMA 数据传输模式
    // 设置 DMA 外设地址为 ADC0 的数据寄存器地址
    dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
    // 禁用外设地址自增
    dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    // 设置 DMA 内存地址为存储 ADC 转换结果的数组地址
    dma_data_parameter.memory_addr = (uint32_t)(&adc_value);
    // 使能内存地址自增
    dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    // 设置外设数据宽度为 32 位
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
    // 设置内存数据宽度为 32 位
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT;
    // 设置 DMA 传输方向为从外设到内存
    dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
    // 设置 DMA 传输的数据数量为 2
    dma_data_parameter.number = 2;
    // 设置 DMA 通道优先级为高
    dma_data_parameter.priority = DMA_PRIORITY_HIGH;
    // 根据上述配置初始化 DMA0 的通道 0
    dma_init(DMA0, DMA_CH0, &dma_data_parameter);

    // 使能 DMA0 通道 0 的循环模式
    dma_circulation_enable(DMA0, DMA_CH0);

    // 使能 DMA0 的通道 0
    dma_channel_enable(DMA0, DMA_CH0);
}

// 另一种 ADC 配置方式
void adc_config(void)
{
    // 对 ADC0 和 ADC1 进行复位操作
    adc_deinit(ADC0);
    adc_deinit(ADC1);
    // 配置 ADC 为双规则并行模式
    adc_mode_config(ADC_DAUL_REGULAL_PARALLEL);
    // 使能 ADC0 和 ADC1 的扫描模式
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);

    // 配置 ADC0 和 ADC1 的数据对齐方式为右对齐
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); 
    adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
    // 配置 ADC0 和 ADC1 的规则通道长度为 2
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2); 
    adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 2); 

    // 配置 ADC0 的规则通道 0 为通道 4,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5); 
    // 配置 ADC0 的规则通道 1 为通道 5,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);
    // 配置 ADC1 的规则通道 0 为通道 5,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);
    // 配置 ADC1 的规则通道 1 为通道 4,采样时间为 55.5 个 ADC 时钟周期
    adc_regular_channel_config(ADC1, 1, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);

    // 配置 ADC0 的规则通道触发源为 TIMER1 的通道 1
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T1_CH1); 
    // 配置 ADC1 的规则通道不使用外部触发
    adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE); 
    // 使能 ADC0 和 ADC1 的规则通道外部触发
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE); 
    adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);

    // 使能 ADC0
    adc_enable(ADC0);
    // 对 ADC0 进行校准
    adc_calibration_enable(ADC0); 
    // 使能 ADC1
    adc_enable(ADC1);
    // 延时 1ms 等待 ADC 稳定
    delay_1ms(1);
    // 对 ADC1 进行校准
    adc_calibration_enable(ADC1);

    // 使能 ADC0 的 DMA 功能
    adc_dma_mode_enable(ADC0); 
}
#endif

// 计算功率并进行比较的函数
void calculate_power_and_compare()
{
    // 定义电压、电流和功率变量
    float voltage1, current1, power1;
    float voltage2, current2, power2;

    // 定义存储高 16 位和低 16 位数据的变量
    uint16_t h_raw, l_raw;

    // 提取 adc_value[0] 的高 16 位数据
    h_raw = (uint16_t)((adc_value[0]) >> 16);
    // 提取 adc_value[0] 的低 16 位数据
    l_raw = (uint16_t)((adc_value[0]) & 0xffff);

    // 根据 ADC 转换结果计算电压值,假设参考电压为 3.3V,放大倍数为 3
    voltage1 = ((h_raw * 3.3) / 4096) * 3;
    // 根据 ADC 转换结果计算电流值,假设参考电压为 3.3V,放大倍数为 2
    current1 = ((l_raw * 3.3) / 4096) * 2; 
    // 对电流值进行处理,减去偏移量并除以灵敏度
    current1 = (current1 - 1.65) / 0.132;
    // 计算功率
    power1 = voltage1 * current1;

    // printf("value0:%x,  high: %x low:%x\n", adc_value[0], h_raw, l_raw);

    // 以下代码被注释掉,可用于处理 adc_value[1] 的数据
    // h_raw = (uint16_t)((adc_value[1]) >> 16);
    // l_raw = (uint16_t)((adc_value[1]) & 0xffff);

    // voltage2 = ((h_raw * 3.3) / 4096) * 3;
    // current2 = ((l_raw * 3.3) / 4096) * 2; 
    // current2 = (current2 - 1.65) / 0.132;  
    // power2 = voltage2 * current2;

    // printf("value1:%x,  high: %x low:%x\n", adc_value[1], h_raw, l_raw);

    // 输出计算结果
    printf("Voltage: %f V, Current: %f A, Power: %f W\n", voltage1, current1, power1);
    // printf("adc_value[1] - Voltage

这是测量两个io的电压,如果使用 “另一种 DMA 配置方式和ADC配置”是双通道采集数据,但是这里面有一个误区,

也就是adc_value[0]:

高16bit是ADC1(ADC_CHANNEL_5采集)

低16bit是ADC0(ADC_CHANNEL_4采集)

adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);

adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);

注意:adc_value[1]的高16bit是ADC1(ADC_CHANNEL_4采集),

低16bit是ADC0(ADC_CHANNEL_5采集)

adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);

adc_regular_channel_config(ADC1, 1, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);

因为 规则不变,只是ADC0采集的通道变了,所以

	l_raw = (uint16_t)((adc_value[1]) >> 16);
    // 提取 adc_value[1] 的低 16 位数据,来自 ADC0(ADC_CHANNEL_5 采集)
    h_raw = (uint16_t)((adc_value[1]) & 0xffff);

    voltage2 = ((h_raw * 3.3) / 4096) * 3;
    current2 = ((l_raw * 3.3) / 4096) * 2; 
    current2 = (current2 - 1.65) / 0.132;
    power2 = voltage2 * current2;

TIMER1​ 的通道 1 产生触发信号时,ADC0​ 开始对配置的通道(ADC_CHANNEL_4​ 和 ADC_CHANNEL_5​)进行采样和转换。转换完成后,转换结果会被存储在 ADC0​ 的数据寄存器中。由于 ADC0​ 的 DMA 功能已被使能,DMA 会自动将数据寄存器中的数据读取出来,并按照配置的内存地址和数据宽度,将数据传输到 adc_value​ 数组中。具体来说:

  • adc_value[0]​ 的高 16 位存储 ADC1​ 对 ADC_CHANNEL_5​ 的采样结果,低 16 位存储 ADC0​ 对 ADC_CHANNEL_4​ 的采样结果。
  • adc_value[1]​ 的高 16 位存储 ADC1​ 对 ADC_CHANNEL_4​ 的采样结果,低 16 位存储 ADC0​ 对 ADC_CHANNEL_5​ 的采样结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值