在STM32G030xx的HAL库中使用DMA采集ADC多通达数据并开启DMA开启全满和半满中断
例程说明
- 芯片型号STM32G030C8T6
- 使用DMA1 CH1采集ADC1数据
- 使用DMA分时采集ADC多通道数据并开启DMA开启全满和半满中断
硬件连接
| 信号名称 |
ADC通道 |
描述 |
| ADC_CH_INTER_VREF |
ADC_CHANNEL_VREFINT |
内部参考电压 |
| ADC_CH_NTC_TEMP |
ADC_CHANNEL_1 |
NTC温度检测 |
| ADC_CH_ENV_GRAY |
ADC_CHANNEL_9 |
环境光敏电阻 |
| ADC_CH_TXHV |
ADC_CHANNEL_10 |
发射高压 |
| ADC_CH_APDHV |
ADC_CHANNEL_15 |
接收高压 |
| ADC_CH_BAT |
ADC_CHANNEL_16 |
电池电压 |
一、ADC和DMA初始化
c
复制代码
#define NTC_TEMP_ADC_Pin GPIO_PIN_1
#define NTC_TEMP_ADC_GPIO_Port GPIOA
#define GRAY_ADC_Pin GPIO_PIN_1
#define GRAY_ADC_GPIO_Port GPIOB
#define TXHV_ADC_Pin GPIO_PIN_2
#define TXHV_ADC_GPIO_Port GPIOB
#define APDHV_ADC_Pin GPIO_PIN_11
#define APDHV_ADC_GPIO_Port GPIOB
#define VBAT_ADC_Pin GPIO_PIN_12
#define VBAT_ADC_GPIO_Port GPIOB
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.LowPowerAutoPowerOff = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;
hadc1.Init.OversamplingMode = DISABLE;
hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
__HAL_RCC_ADC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = NTC_TEMP_ADC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(NTC_TEMP_ADC_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = VBAT_ADC_Pin|GRAY_ADC_Pin|TXHV_ADC_Pin|APDHV_ADC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
__HAL_DMA_CLEAR_FLAG(&hdma_adc1, DMA_FLAG_HT1);
__HAL_DMA_CLEAR_FLAG(&hdma_adc1, DMA_FLAG_TC1);
__HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_HT);
__HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TC);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
__HAL_RCC_ADC_CLK_DISABLE();
HAL_GPIO_DeInit(NTC_TEMP_ADC_GPIO_Port, NTC_TEMP_ADC_Pin);
HAL_GPIO_DeInit(GPIOB, VBAT_ADC_Pin|GRAY_ADC_Pin|TXHV_ADC_Pin|APDHV_ADC_Pin);
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
}
void MX_DMA_Init(void)
{
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
二、中断函数
c
复制代码
void DMA1_Channel1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_adc1);
}
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef * hadc)
{
if (hadc->Instance == ADC1)
{
pADCDMA->State = ADC_DMA_MEM_STA_HFULL;
__HAL_DMA_CLEAR_FLAG(&hdma_adc1, DMA_FLAG_HT1);
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef * hadc)
{
if (hadc->Instance == ADC1)
{
pADCDMA->State = ADC_DMA_MEM_STA_AFULL;
__HAL_DMA_CLEAR_FLAG(&hdma_adc1, DMA_FLAG_TC1);
}
}
三、初始化接收数据缓存
c
复制代码
#define ADC_DMA_MEM_STA_NONE (0)
#define ADC_DMA_MEM_STA_HFULL (1)
#define ADC_DMA_MEM_STA_AFULL (2)
#define ADC_DMA_MEM_SIZE (32)
typedef enum
{
ADC_CH_NTC_TEMP = ADC_CHANNEL_1,
ADC_CH_ENV_GRAY = ADC_CHANNEL_9,
ADC_CH_APDHV = ADC_CHANNEL_15,
ADC_CH_TXHV = ADC_CHANNEL_10,
ADC_CH_BAT = ADC_CHANNEL_16,
ADC_CH_INTER_VBAT = ADC_CHANNEL_VBAT,
ADC_CH_INTER_VREF = ADC_CHANNEL_VREFINT,
ADC_CH_INTER_TEMP = ADC_CHANNEL_TEMPSENSOR,
}ADC_CH_ENUM;
typedef struct
{
volatile u8 State;
u16 * pMem;
}ADC_DMA_Transfer_TypeDef;
static ADC_DMA_Transfer_TypeDef ADC_DMA_TypeDef = {0};
ADC_DMA_Transfer_TypeDef * pADCDMA = &ADC_DMA_TypeDef;
static u16 ADC_DMA_MEM[ADC_DMA_MEM_SIZE] = {0};
void vInit_ADC_DMA_Memory(void)
{
pADCDMA = &ADC_DMA_TypeDef;
pADCDMA->State = ADC_DMA_MEM_STA_AFULL;
pADCDMA->pMem = ADC_DMA_MEM;
}
四、停止及等待DMA
c
复制代码
static void vStop_ADC_DMA(void)
{
HAL_ADC_Stop_DMA(&hadc1);
HAL_DMA_Abort(&hdma_adc1);
HAL_ADC_Stop(&hadc1);
}
static u8 xWait_ADC_DMA(void)
{
u32 overTime = 0x2FFFF;
pADCDMA->State = ADC_DMA_MEM_STA_NONE;
while (pADCDMA->State != ADC_DMA_MEM_STA_AFULL)
{
if (overTime-- < 10)
{
return 1;
}
}
overTime = 0x2FFFF;
while (pADCDMA->State == ADC_DMA_MEM_STA_AFULL)
{
if (overTime-- < 10)
{
return 2;
}
}
overTime = 0x2FFFF;
while (pADCDMA->State != ADC_DMA_MEM_STA_AFULL)
{
if (overTime-- < 10)
{
return 3;
}
}
return 0;
}
五、设置ADC采样通道
c
复制代码
static u8 xSet_Sampling_Channel(u32 channel, u32 memSize)
{
ADC_ChannelConfTypeDef sConfig = {0};
vStop_ADC_DMA();
CLEAR_BIT(ADC1->CHSELR, ADC_CHANNEL_ID_BITFIELD_MASK);
sConfig.Channel = channel;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
return 1;
}
if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
{
return 2;
}
if (HAL_ADC_Start_DMA(&hadc1, (u32 *)pADCDMA->pMem, memSize) != HAL_OK)
{
return 3;
}
return 0;
}
六、获取通道ADC值
c
复制代码
static u16 xGet_Channel_Value(u32 channel)
{
u8 res = 0;
if (xSet_Sampling_Channel(channel, ADC_DMA_MEM_SIZE))
{
res = 0;
goto GET_CHX_VALUE_ERROR;
}
if (xWait_ADC_DMA())
{
res = 1;
goto GET_CHX_VALUE_ERROR;
}
if (xWait_ADC_DMA())
{
res = 2;
goto GET_CHX_VALUE_ERROR;
}
vStop_ADC_DMA();
if((channel == ADC_CHANNEL_VBAT) || (channel == ADC_CHANNEL_VREFINT) || (channel == ADC_CHANNEL_TEMPSENSOR))
{
LL_ADC_SetCommonPathInternalCh(ADC1_COMMON, LL_ADC_PATH_INTERNAL_NONE);
}
BubbleSort_u16(pADCDMA->pMem, ADC_DMA_MEM_SIZE);
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("Channel:%08X Min:%u Max:%u ABS:%u\r\n", channel, pADCDMA->pMem[0], pADCDMA->pMem[ADC_DMA_MEM_SIZE - 1], (pADCDMA->pMem[ADC_DMA_MEM_SIZE - 1] - pADCDMA->pMem[0]));
#endif
return Average_u16(pADCDMA->pMem, ADC_DMA_MEM_SIZE, (ADC_DMA_MEM_SIZE >> 2));
GET_CHX_VALUE_ERROR:
vStop_ADC_DMA();
return res;
}
七、采集各通道数据
c
复制代码
//内部参考电压
void vGet_Inter_Vref(void)
{
u32 value = 0, cali = 0;
cali = *(u16 *)(ADDR_VREFCALI);
LL_ADC_SetCommonPathInternalCh(ADC1_COMMON, LL_ADC_PATH_INTERNAL_VREFINT);
vNopDelayMS(10);
value = xGet_Channel_Value(ADC_CH_INTER_VREF);
LL_ADC_SetCommonPathInternalCh(ADC1_COMMON, LL_ADC_PATH_INTERNAL_NONE);
pAppSysPar->VRefInt = (cali * 3000) / value;
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("Inter_Vref......cali:%-5u value:%-5u VRefInt:%umV\r\n\r\n", cali, value, pAppSysPar->VRefInt);
#endif
}
//电池电压
u16 xGetBatVal(void)
{
u64 vol = 0, adc = 0;
adc = xGet_Channel_Value(ADC_CH_BAT);
vol = ((adc * pAppSysPar->VRefInt * 151) / (4095 * 51));
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("GetBatVol......REF:%-5u ADC:%-5u VBAT:%umV\r\n\r\n", pAppSysPar->VRefInt, (u16)(adc&0xFFFF), (u16)(vol&0xFFFF));
#endif
return (u16)vol;
}
//接收高压
u16 usGetAPDHV(void)
{
u64 adc = 0, vol = 0;
adc = xGet_Channel_Value(ADC_CH_APDHV);
vol = (adc * pAppSysPar->VRefInt * 2239) / (39 * 4095);
vol = (vol + 50) / 100;
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("GetAPDHV......REF:%-5u ADC:%-5u APDHV(0.1V):%u\r\n\r\n", pAppSysPar->VRefInt, (u16)(adc&0xFFFF), (u16)(vol&0xFFFF));
#endif
return (u16)vol;
}
// 发射高压
u16 usGetTXHV(void)
{
u64 adc = 0, vol = 0;
adc = xGet_Channel_Value(ADC_CH_TXHV);
vol = (adc * pAppSysPar->VRefInt * 2239) / (39 * 4095);
vol = (vol + 50) / 100;
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("GetTXHV......REF:%-5u ADC:%-5u TXHV(0.1V):%u\r\n\r\n", pAppSysPar->VRefInt, (u16)(adc&0xFFFF), (u16)(vol&0xFFFF));
#endif
return (u16)vol;
}
// 光敏电阻
u16 usGetGray(void)
{
u64 adc = 0, vol = 0;
adc = xGet_Channel_Value(ADC_CH_ENV_GRAY);
vol = (adc * pAppSysPar->VRefInt / 4095);
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("GetGray......REF:%-5u ADC:%-5u Vol(mV):%u\r\n\r\n", pAppSysPar->VRefInt, (u16)(adc&0xFFFF), (u16)(vol&0xFFFF));
#endif
return (u16)vol;
}
// NTC温度
s16 ssGetNTC(void)
{
u32 adc = 0, vol = 0;
s16 temper = 0;
s8 cp = 0;
adc = xGet_Channel_Value(ADC_CH_NTC_TEMP);
vol = (adc * pAppSysPar->VRefInt / 4095);
temper = GetTemeratureFromTab(vol);
cp = (s8)(0.035019888f * temper - 18.91695514f);
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("GetNTC......REF:%-5u ADC:%-5u NTC(0.1C):%d CP:%d ", pAppSysPar->VRefInt, (u16)(adc&0xFFFF), temper, cp);
#endif
if (cp < -27) cp = -27;
if (cp > 6) cp = 6;
temper = temper - cp;
#if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
dprintf("RNTC:%d\r\n\r\n", temper);
#endif
return temper;
}
八、测试结果
c
复制代码
static void xsuper_test(void)
{
InitVref();
xGetBatVal();
ssGetNTC();
usGetAPDHV();
usGetTXHV();
usGetGray();
TimerStart(xsuper_test, 6000);
dprintf("\r\n\r\n");
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
TimerStart(xsuper_test, 3000);
while (1)
{
SoftTimerHandler();
}
}