本文主要实现基于LM401模组,,测试ADC低功耗采集,详细解析代码基于计算方式
对于小白理解ADC有更详细的理解
【LM401】ADC采集代码解读
硬件基于易智联的LM401
的LoRa模组,用的 LM401-pro-kit
开发板,开发板资料以及参考资料如下:
【STM32WLE5之lora:5、易智联LM40评估板ADC定时采集上报】
1. 单片机ADC与DAC简单理解
-
ADC:模数转换,单片机的IO口接一个传感器,传感器输出模拟值,单片机读取模拟量转化为数字量。( 单片机输入模拟值,转化为数字值)
-
DAC:数模转换,给单片机数字值,从单片机的IO口输出模拟信号量。( 单片机IO口输出模拟信号量)
2. 模组ADC通道介绍
12位DAC、2Msps 低功耗采样保持电路 ,12通道,采用 16-bit 硬件过采样,转化范围1.62—3.6V,给出部分引脚,具体查看手册
PB1 — ADC_IN5 PB2 — ADC_IN4
PB3 — ADC_IN2 PB4 — ADC_IN3
PB13 — ADC_IN0 PB14 — ADC_IN1
其中三个通道说明:
#define ADC_CHANNEL_VREFINT (LL_ADC_CHANNEL_VREFINT) // 内部参考电压
#define ADC_CHANNEL_TEMPSENSOR (LL_ADC_CHANNEL_TEMPSENSOR) // MCU 内部温度,精确度不高 1度左右
#define ADC_CHANNEL_VBAT (LL_ADC_CHANNEL_VBAT) // 外部连接电压值
3. ADC初始化
void MX_ADC_Init(void)
{
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 时钟分频数
hadc.Init.Resolution = ADC_RESOLUTION_12B; // 分辨率为 12bit
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 一般选择右对齐
hadc.Init.ScanConvMode = ADC_SCAN_DISABLE; // 单通道(单次)或者多通道(扫描)模式选择,扫描的话就是序列的形式
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 单一转换结束
hadc.Init.LowPowerAutoWait = DISABLE; // 低功耗
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.NbrOfConversion = 1;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE; // 不使用 DMA
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.OversamplingMode = ENABLE; //使能过采样
hadc.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16; // ,16倍过采样
hadc.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_4;
hadc.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
hadc.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
4. 采集值的计算
比如,demo中通过PA11引脚读取ADC的值,读取后的计算方式:
注意::计算时用的12位分辨率,和ADC初始化设置的分辨率要对应
bat_v = SYS_GetBatteryLevel(); // 获取内部参考电压
-> ADC_ReadChannels(ADC_CHANNEL_VREFINT);
temp = GetADC_PA11();
pa11_v = __LL_ADC_CALC_DATA_TO_VOLTAGE(bat_v, temp,ADC_RESOLUTION_12B); // 将PA11的ADC转换成电压,单位mV 通过这个函数计算出实际电压值,单位是 mV
/// @brief 将采集到的模拟电压值转换为实际电压值,计算结果单位是 mV
/// @param 参数1:ADC转换环境的参考电压值
/// 参数2:采集到的模拟电压值
/// 参数3:AD芯片分辨率(本系列可可以是6 8 10 12)
#define __HAL_ADC_CALC_DATA_TO_VOLTAGE(__VREFANALOG_VOLTAGE__,\
__ADC_DATA__,\
__ADC_RESOLUTION__) \
__LL_ADC_CALC_DATA_TO_VOLTAGE((__VREFANALOG_VOLTAGE__),\
(__ADC_DATA__),\
(__ADC_RESOLUTION__))
( V R E F / 2 n ) ∗ A d c D a t a (VREF/2^n)*AdcData (VREF/2n)∗AdcData
5.测试结果
测试 PB4
和 PB3
两路ADC,分别将PB3
直接接地,PB4
接3.3v
,测试过程代码
说明:本例 参考电压为 3.3v 用的12位ADC
#define VREF_MV (3300UL)
#define ADC_MAX_RESULT ((1 << 12)-1) // 12 bit ADC
uint16_t batteryLevel = SYS_GetBatteryLevel(); // 获取系统的参考电压 单位 mv(3300mv)
APP_PRINTF("batteryLevel= %d \r\n",batteryLevel);
uint16_t ADC_PB3_Value = GetADC_PB3_Value();
uint16_t ADC_PB4_Value = GetADC_PB4_Value();
APP_PRINTF("ADC_PB3_Value= %d \r\n", ADC_PB3_Value);
APP_PRINTF("ADC_PB4_Value= %d \r\n ",ADC_PB4_Value);
APP_PRINTF("*********************************** \r\n ");
APP_PRINTF("ADC_PB3_Value= %d \r\n",(ADC_PB3_Value * VREF_MV) / ADC_MAX_RESULT);
APP_PRINTF("ADC_PB4_Value= %d \r\n ",(ADC_PB4_Value * VREF_MV) / ADC_MAX_RESULT);
打印信息如下: