【ADC模拟信号采集(未完成)】

ADC

是将模拟信号转化为数字量的芯片,模拟信号指电压信号,不管是什么传感器,如温度,电流,光敏,都是转换为电压值的测量。

STM32G474-ADC

在这里插入图片描述
实际上这里是H7的,只不过端口数量不一样,其他该有的都有
①VREF+电压
②ADC双时钟域架构:主时钟是正常工作时的,频率较高,辅助时钟可以用于低功耗状态下提供时钟,他们的分频系数不一样,但出自同一个系统时钟,所以是同步的。这很重要。
③输入通道:被测量的电压输入,差分的,但我们这里用的是单端的,另外一个接地就行。
④转换序列
⑤触发源:可选,注入和规则
⑥转换时间:软件配置对应寄存器,我们调hal库吧
⑦参考电压
⑧ADC核心:逐次逼近
⑨数据寄存器
⑩中断:中断线左侧的白色框是触发中断的事件
⑪通道预选控制信号:通道预选控制信号的主要作用是告诉ADC当前需要处理哪个通道的模拟信号。在ADC系统中,可能有多个模拟信号源,每个信号源都连接到一个不同的ADC通道上。通过改变通道预选控制信号,可以选择不同的通道进行模数转换。可以软件设置。
我把G474的也发出来,结构差不多
在这里插入图片描述

分类

并联比较型和逐次逼近型,前者转化速度快,成本高,后者相反。
在stm32芯片里用的是后者,注意要检测的电压一定不能大于adc的参考电压。

转换序列

规则通道和注入通道基本区别
规则通道多达16个通道,而注入通道只有4个通道。
每个注入通道均有一个用于储存转换结果的注入数据寄存器,而所有规则通道均共用一个规则数据寄存器。
注入通道可以中断规则通道的转换,然后再恢复规则通道的转换。

监测电机工作时的电压、电流等信息

ADC配置

void adc_init(void)
{
    g_adc_handle.Instance = ADC_ADCX;										/*ADC1*/
    g_adc_handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;            /* 4分频,ADCCLK = SYSCLK/4 = 170/4 = 42.5Mhz 用于调整ADC模块时钟频率*/
    g_adc_handle.Init.Resolution = ADC_RESOLUTION_12B;                      /* 12位模式,设置ADC的分辨率为12位。这意味着ADC将输入信号转换为12位的数字值 */
    g_adc_handle.Init.GainCompensation = 0;                                 /* 不需要增益补偿。在某些ADC中,增益补偿用于校正ADC的增益误差。*/
    g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;                      /* 右对齐,这意味着ADC转换结果的最低有效位(LSB)位于最低位 */
    g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;                      /* 非扫描模式,在扫描模式下,ADC会连续转换多个通道。禁用此模式意味着ADC只会转换一个指定的通道。 */
    g_adc_handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;                   /* 单通道转换结束标志,设置转换结束(EOC)标志的触发条件为单通道转换结束。 */
    g_adc_handle.Init.LowPowerAutoWait = DISABLE;                           /* 禁用低功耗延迟模式,这有助于减少ADC的功耗,但可能会增加转换的延迟。*/
    g_adc_handle.Init.ContinuousConvMode = ENABLE;                          /* 使能连续转换,在此模式下,ADC会连续进行转换,而无需在每次转换后重新触发。*/
    g_adc_handle.Init.NbrOfConversion = 1;                                  /* 1个转换在规则序列中 也就是只转换规则序列1,由于禁用了扫描模式,这实际上意味着ADC只会转换一个通道。*/
    g_adc_handle.Init.DiscontinuousConvMode = DISABLE;                      /* 禁止不连续采样模式,这通常与扫描模式一起使用,用于在不同的通道组之间进行不连续的采样。 */
    g_adc_handle.Init.NbrOfDiscConversion = 0;                              /* 不连续采样通道数为0 ,由于禁用了不连续采样模式,此设置实际上没有作用。*/
    g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;                /* 软件触发,这意味着你需要通过软件命令来启动ADC的转换。 */
    g_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
    g_adc_handle.Init.DMAContinuousRequests = DISABLE;                      /* 关闭DMA请求,这意味着ADC不会通过DMA连续地传输数据到内存。 */
    g_adc_handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;                   /* 数据溢出时覆盖ADC数据,如果ADC的转换结果没有及时读取,新的转换结果会覆盖旧的结果。*/
    g_adc_handle.Init.OversamplingMode = DISABLE;                           /* 禁用过采样功能 ,过采样可以提高ADC的分辨率和信噪比。*/
    HAL_ADC_Init(&g_adc_handle);                                            /* 初始化,句柄 */
    
    HAL_ADCEx_Calibration_Start(&g_adc_handle, ADC_SINGLE_ENDED);           /* 以单端模式运行ADC校准 */
}

GPIO以及中断配置代码

/**
 * @brief       ADC底层驱动,引脚配置,时钟使能
                此函数会被HAL_ADC_Init()调用
 * @param       hadc:ADC句柄
 * @retval      无
 */
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
    if(hadc->Instance == ADC_ADCX)
    {
        GPIO_InitTypeDef gpio_init_struct;
        ADC_ADCX_CHY_CLK_ENABLE();          /* 使能ADCx时钟 */
        ADC_ADCX_CHY_GPIO_CLK_ENABLE();     /* 开启GPIO时钟 */

        /* AD采集引脚模式设置,模拟输入 */
        gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN;
        gpio_init_struct.Mode = GPIO_MODE_ANALOG;
        gpio_init_struct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct);
    }
}

ADC工作参数设置

/**
 * @brief       设置ADC通道采样时间
 * @param       adcx : adc句柄指针,ADC_HandleTypeDef
 * @param       ch   : 通道号, ADC_CHANNEL_0~ADC_CHANNEL_17
 * @param       stime: 采样时间  0~7, 对应关系为:
 *   @arg       ADC_SAMPLETIME_2CYCLES_5,  2.5个ADC时钟周期        ADC_SAMPLETIME_6CYCLES_5, 6.5个ADC时钟周期
 *   @arg       ADC_SAMPLETIME_12CYCLES_5, 12.5个ADC时钟周期       ADC_SAMPLETIME_24CYCLES_5, 24.5个ADC时钟周期
 *   @arg       ADC_SAMPLETIME_47CYCLES_5, 47.5个ADC时钟周期       ADC_SAMPLETIME_92CYCLES_5, 92.5个ADC时钟周期
 *   @arg       ADC_SAMPLETIME_247CYCLES_5 , 247.5个ADC时钟周期    ADC_SAMPLETIME_640CYCLES_5,640.5个ADC时钟周期
 * @param       rank: 多通道采集时需要设置的采集编号,
                假设你定义channel1的rank=1,channel2的rank=2,
                那么对应你在DMA缓存空间的变量数组AdcDMA[0] 就是通道1的转换结果,AdcDMA[1]就是通道2的转换结果。 
                单通道设置为 ADC_REGULAR_RANK_1
 *   @arg       编号1~16:ADC_REGULAR_RANK_1~ADC_REGULAR_RANK_16
 * @retval      无
 */
void adc_channel_set(ADC_HandleTypeDef *adc_handle, uint32_t ch, uint32_t rank, uint32_t stime)
{
    /* 配置对应ADC通道 */
    ADC_ChannelConfTypeDef adc_channel;
    adc_channel.Channel = ch;                           /* 设置ADCX对通道ch */
    adc_channel.Rank = rank;                            /* 设置采样序列 */
    adc_channel.SamplingTime = stime;                   /* 设置采样时间 */
    adc_channel.SingleDiff = ADC_SINGLE_ENDED;          /* 单端输入模式 */
    HAL_ADC_ConfigChannel( adc_handle, &adc_channel );   
}

电压检测

直接使用 ADC 采集 VBUS 的电压,再根据公式:POWER= 25 * VBUS,即可算出电源电压。

代码讲解
    /* init_adc_val存储电流测量对应的参考电压ADC值,这里进行滤波 */
    init_adc_val = g_adc_val[2];                /* 取出第一次得到的值 */
    for(t=0;t<1000;t++)
    {
        init_adc_val += g_adc_val[2];           /* 现在的值和上一次存储的值相加 */
        init_adc_val /= 2;                      /* 取平均值 */
        delay_ms(1);
    }

这里是main里抓取参考电压的方法,测1000次,取平均值,不管是电压,电流,还是温度,都是检测电压值,所以都会用到去电压平均值的方法。

电压计算
 if(t % 20 == 0)
        {
        	/* 电压计算公式:
			* V_POWER = V_BUS * 25
			* ADC 值转换为电压值:电压=ADC 值*3.3/4096
			* 整合公式可以得出电压 V_POWER= ADC 值 *(3.3f * 25 / 4096)
			*/
			#define ADC2VBUS (float)(3.3f * 25 / 4096)
            printf("Valtage:%.1fV \r\n",    g_adc_val[0]*ADC2VBUS);  /* 打印电压值 */   
        }

电流检测

由于 STM32 内部 ADC 并不能直接对电流进行采集,所以我们需要先把电流的信号转换为电压的信号
我们在 H 桥的回路中串接一个 20mR 的采样电阻。

这样就可以得到一个采样电压 I-V = 0.02R * 实际电流 I,但是这个采样电压太小了,直接用 ADC 进行采集的话偏差较大,我们需要对它进行差分放大。差分放大倍数= 12 /(1+1)=6 倍,参考电压为 1.27V,由此可得输出电压Iout(即 CURT点的电压)=6 * 0.02R * 实际电流 I + 1.27V。

我们只需要采集 Iout 的电压,再根据公式:实际电流 I=(输出电压 Iout-1.27)/0.12A,即可算出实际电流。
在这里插入图片描述

代码分析
/* 电流计算公式:
* I=(最终输出电压-初始参考电压)/(6*0.02)A
* ADC 值转换为电压值:电压=ADC 值*3.3/4096,这里电压单位为 V,我们换算成
mV,4096/1000=4.096,后面就直接算出为 mA
* 整合公式可以得出电流 I= (当前 ADC 值-初始参考 ADC 值)* (3.3 / 4.096 / 0.12)
*/
#define ADC2CURT (float)(3.3f / 4.096f / 0.12f)
printf("Current:%.1fmA \r\n\r\n",   abs(g_adc_val[2]-init_adc_val)*ADC2CURT); /* 打印电流值 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值