单片机ADC实验
·
单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
原理图:


一、单通道ADC采集实验:
主函数
int main(void)
{
uint16_t adcx;
float temp;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为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_CH3_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH3_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
while (1)
{
adcx = adc_get_result_average(ADC_ADCX_CHY, 10); /* 获取ADC通道的转换值,10次取平均 */
lcd_show_xnum(134, 110, adcx, 5, 16, 0, BLUE); /* 显示ADC采样后的平均值 */
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及引脚 定义 */
#define ADC_ADCX_CHY_GPIO_PORT GPIOA
#define ADC_ADCX_CHY_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CHY ADC_CHANNEL_3
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
/******************************************************************************************/
void adc_init(void)
{
g_adc_handle.Instance = ADC_ADCX;
g_adc_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_handle.Init.ScanConvMode = DISABLE; /* 非扫描模式 */
g_adc_handle.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
g_adc_handle.Init.NbrOfConversion = 1; /* 本实验只使用到一个规则序列 */
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_handle.Init.NbrOfDiscConversion = 0; /* 不连续采样通道数为0 */
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
g_adc_handle.Init.DMAContinuousRequests = DISABLE; /* 关闭DMA请求 */
HAL_ADC_Init(&g_adc_handle); /* 初始化ADC */
}
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时钟 */
gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN; /* ADC采集对应IO */
gpio_init_struct.Mode = GPIO_MODE_ANALOG; /* 模拟输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct); /* 初始化IO */
}
}
void adc_channel_set(ADC_HandleTypeDef *adc_handle, uint32_t ch, uint32_t rank, uint32_t stime)
{
ADC_ChannelConfTypeDef adc_channel; /* 配置对应ADC通道 */
adc_channel.Channel = ch; /* ADC通道 */
adc_channel.Rank = rank; /* 设置采样序列 */
adc_channel.SamplingTime = stime; /* 设置采样时间 */
HAL_ADC_ConfigChannel( adc_handle, &adc_channel);
}
uint32_t adc_get_result(uint32_t ch)
{
adc_channel_set(&g_adc_handle , ch, 1, ADC_SAMPLETIME_480CYCLES); /* 设置通道,序列和采样时间 */
HAL_ADC_Start(&g_adc_handle); /* 开启ADC */
HAL_ADC_PollForConversion(&g_adc_handle, 10); /* 轮询转换 */
return (uint16_t)HAL_ADC_GetValue(&g_adc_handle); /* 返回最近一次ADC1规则组的转换结果 */
}
uint32_t adc_get_result_average(uint32_t ch, uint8_t times)
{
uint32_t temp_val = 0;
uint8_t t;
for (t = 0; t < times; t++) /* 获取times次数据 */
{
temp_val += adc_get_result(ch); /* 累加 */
delay_ms(5);
}
return temp_val / times; /* 返回平均值 */
}
测试结果:
PA3悬空时,读出电压为0.5V

PA3接GND时,接近0V

接3.3V

二、但通道ADC采集(使用DMA)
主函数
int main(void)
{
uint16_t i, adcx;
uint32_t sum;
float temp;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为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_CH3_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH3_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); /* 显示ADC采样后的原始值 */
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及引脚 定义 */
#define ADC_ADCX_CHY_GPIO_PORT GPIOA
#define ADC_ADCX_CHY_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CHY ADC_CHANNEL_3
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
/* ADC单通道/多通道 DMA采集 DMA及通道 定义 */
#define ADC_ADCX_DMASx DMA2_Stream4
#define ADC_ADCX_DMASx_Chanel DMA_CHANNEL_0
#define ADC_ADCX_DMASx_IRQn DMA2_Stream4_IRQn
#define ADC_ADCX_DMASx_IRQHandler DMA2_Stream4_IRQHandler
#define ADC_ADCX_DMASx_IS_TC() ( __HAL_DMA_GET_FLAG(&g_dma_adc_handle, DMA_FLAG_TCIF0_4) ) /* 判断DMA2 Stream4传输完成标志, 这是一个假函数形式,
* 不能当函数使用, 只能用在if等语句里面
*/
#define ADC_ADCX_DMASx_CLR_TC() do{ __HAL_DMA_CLEAR_FLAG(&g_dma_adc_handle, DMA_FLAG_TCIF0_4); }while(0) /* 清除DMA2 Stream4传输完成标志 */
/******************************************************************************************/
void adc_dma_init(uint32_t mar)
{
GPIO_InitTypeDef gpio_init_struct;
ADC_ChannelConfTypeDef adc_ch_conf = {0};
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
ADC_ADCX_CHY_GPIO_CLK_ENABLE(); /* 开启GPIO时钟 */
if ((uint32_t)ADC_ADCX_DMASx > (uint32_t)DMA2) /* 大于DMA2的基地址, 则为DMA2的数据流通道了 */
{
__HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2时钟使能 */
}
else
{
__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1时钟使能 */
}
/* 设置AD采集通道对应IO引脚工作模式 */
gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct);
/* 初始化DMA */
g_dma_adc_handle.Instance = ADC_ADCX_DMASx; /* 设置DMA数据流 */
g_dma_adc_handle.Init.Channel = DMA_CHANNEL_0; /* 设置DMA通道 */
g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 从外设到存储器模式 */
g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设非增量模式 */
g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE; /* 存储器增量模式 */
g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */
g_dma_adc_handle.Init.Mode = DMA_NORMAL; /* 外设流控模式 */
g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM; /* 中等优先级 */
HAL_DMA_Init(&g_dma_adc_handle);
g_adc_dma_handle.Instance = ADC_ADCX;
g_adc_dma_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_dma_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_dma_handle.Init.ScanConvMode = DISABLE; /* 非扫描模式 */
g_adc_dma_handle.Init.ContinuousConvMode = ENABLE; /* 开启连续转换 */
g_adc_dma_handle.Init.NbrOfConversion = 1; /* 本实验用到1个规则通道序列 */
g_adc_dma_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_dma_handle.Init.NbrOfDiscConversion = 0; /* 不连续采样通道数为0 */
g_adc_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_dma_handle.Init.DMAContinuousRequests = ENABLE; /* 开启DMA请求 */
HAL_ADC_Init(&g_adc_dma_handle); /* 初始化ADC */
__HAL_LINKDMA(&g_adc_dma_handle, DMA_Handle, g_dma_adc_handle); /* 把ADC和DMA连接起来 */
/* 配置ADC通道 */
adc_ch_conf.Channel = ADC_ADCX_CHY; /* 通道 */
adc_ch_conf.Rank = 1; /* 序列 */
adc_ch_conf.SamplingTime = ADC_SAMPLETIME_480CYCLES; /* 采样时间 */
HAL_ADC_ConfigChannel(&g_adc_dma_handle, &adc_ch_conf); /* 通道配置 */
/* 配置DMA数据流请求中断优先级 */
HAL_NVIC_SetPriority(ADC_ADCX_DMASx_IRQn, 3, 3);
HAL_NVIC_EnableIRQ(ADC_ADCX_DMASx_IRQn);
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传输结果 */
}
void adc_dma_enable(uint16_t cndtr)
{
__HAL_ADC_DISABLE(&g_adc_dma_handle); /* 先关闭ADC */
__HAL_DMA_DISABLE(&g_dma_adc_handle); /* 关闭DMA传输 */
g_dma_adc_handle.Instance->NDTR = cndtr; /* 重设DMA传输数据量 */
__HAL_DMA_ENABLE(&g_dma_adc_handle); /* 开启DMA传输 */
__HAL_ADC_ENABLE(&g_adc_dma_handle); /* 重新启动ADC */
ADC_ADCX->CR2 |= 1 << 30; /* 启动规则转换通道 */
}
void ADC_ADCX_DMASx_IRQHandler(void)
{
if (ADC_ADCX_DMASx_IS_TC())
{
g_adc_dma_sta = 1; /* 标记DMA传输完成 */
ADC_ADCX_DMASx_CLR_TC(); /* 清除DMA2 数据流4 传输完成中断 */
}
}
测试结果:

三、多通道ADC采集
主函数
int main(void)
{
uint16_t i,j,adcx;
uint32_t sum;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为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_CH3_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH3_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
lcd_show_string(30, 150, 200, 16, 16, "ADC1_CH4_VAL:", BLUE);
lcd_show_string(30, 170, 200, 16, 16, "ADC1_CH4_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
lcd_show_string(30, 190, 200, 16, 16, "ADC1_CH5_VAL:", BLUE);
lcd_show_string(30, 210, 200, 16, 16, "ADC1_CH5_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
while (1)
{
if(g_adc_flag == 1)
{
for(j = 0; j<3; j++)
{
sum = 0; /* 清零 */
for (i = 0; i < 10; i++) /* 每个通道采集了10次数据,进行10次累加 */
{
sum += g_adc_value[(3 * i) + j]; /* 相同通道的转换数据累加 */
}
adcx = sum / (10); /* 取平均值 */
lcd_show_xnum(134, 110+(j*40), g_adc_value[j], 5, 16, 0, BLUE); /* 显示ADCC采样后的原始值 */
g_adc_u_value[j] = (float)g_adc_value[j] * 3.3f /4096;
adcx = g_adc_u_value[j];
lcd_show_xnum(134, 130+(j*40), adcx, 1, 16, 0, BLUE); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
g_adc_u_value[j] -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
g_adc_u_value[j] *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
lcd_show_xnum(150, 130+(j*40), g_adc_u_value[j], 3, 16, 0X80, BLUE); /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
}
g_adc_flag = 0; /* 清除标志位以便下次接收 */
HAL_ADC_Start_IT(&g_adc_handle); /* 当三次都转换完成之后重新开启下一次的转换 */
}
LED0_TOGGLE();
delay_ms(100);
}
}
配置
/* ADC及引脚 定义 */
#define ADC_ADCX_CH3_GPIO_PORT GPIOA
#define ADC_ADCX_CH3_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX_CH4_GPIO_PORT GPIOA
#define ADC_ADCX_CH4_GPIO_PIN GPIO_PIN_4
#define ADC_ADCX_CH4_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX_CH5_GPIO_PORT GPIOA
#define ADC_ADCX_CH5_GPIO_PIN GPIO_PIN_5
#define ADC_ADCX_CH5_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CH3 ADC_CHANNEL_3
#define ADC_ADCX_CH4 ADC_CHANNEL_4
#define ADC_ADCX_CH5 ADC_CHANNEL_5
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
void adc_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
ADC_ChannelConfTypeDef adc_ch_conf;
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
ADC_ADCX_CH3_GPIO_CLK_ENABLE(); /* 开启通道3的GPIO时钟 */
ADC_ADCX_CH4_GPIO_CLK_ENABLE(); /* 开启通道4的GPIO时钟 */
ADC_ADCX_CH5_GPIO_CLK_ENABLE(); /* 开启通道5的GPIO时钟 */
/* AD采集引脚模式设置,模拟输入 */
gpio_init_struct.Pin = ADC_ADCX_CH3_GPIO_PIN|ADC_ADCX_CH4_GPIO_PIN|ADC_ADCX_CH5_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ADC_ADCX_CH3_GPIO_PORT, &gpio_init_struct);
g_adc_handle.Instance = ADC_ADCX;
g_adc_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_handle.Init.ScanConvMode = ENABLE; /* 非扫描模式 */
g_adc_handle.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
g_adc_handle.Init.NbrOfConversion = 3; /* 本实验用到3个规则通道序列 */
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_handle.Init.NbrOfDiscConversion = 0; /* 不连续采样通道数为0 */
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
g_adc_handle.Init.DMAContinuousRequests = DISABLE; /* 关闭DMA请求 */
g_adc_handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
HAL_ADC_Init(&g_adc_handle); /* 初始化 */
adc_ch_conf.Channel = ADC_CHANNEL_3; /* ADC通道3 */
adc_ch_conf.Rank = 1;
adc_ch_conf.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);
adc_ch_conf.Channel = ADC_CHANNEL_4; /* ADC通道4 */
adc_ch_conf.Rank = 2;
HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);
adc_ch_conf.Channel = ADC_CHANNEL_5; /* ADC通道5 */
adc_ch_conf.Rank = 3;
HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);
HAL_NVIC_SetPriority(ADC_IRQn, 2, 2); /* 抢占优先级2,子优先级2 */
HAL_NVIC_EnableIRQ(ADC_IRQn);
HAL_ADC_Start_IT(&g_adc_handle); /* 开启ADC中断 */
}
void ADC_IRQHandler(void)
{
g_adc_value[g_timer++] = HAL_ADC_GetValue(&g_adc_handle)&0xFFF; /* 依次存储3个通道的原始值 */
if(g_timer == 3)
{
g_timer = 0;
g_adc_flag = 1;
}
}
测试结果:

四、多通道ADC采集(使用DMA)
主函数
int main(void)
{
uint16_t i,adcx;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
adc_nch_dma_init(); /* ADC DMA初始化 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "ADC 3CH DMA TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH3_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH3_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
lcd_show_string(30, 150, 200, 16, 16, "ADC1_CH4_VAL:", BLUE);
lcd_show_string(30, 170, 200, 16, 16, "ADC1_CH4_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
lcd_show_string(30, 190, 200, 16, 16, "ADC1_CH5_VAL:", BLUE);
lcd_show_string(30, 210, 200, 16, 16, "ADC1_CH5_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
while (1)
{
for(i = 0; i<3; i++)
{
lcd_show_xnum(134, 110+(i*40), adc[i], 5, 16, 0, BLUE); /* 显示ADC采样后的平均值 */
g_adc_u_value[i] = (float)adc[i] * 3.3f /4096; /* 计算电压值 */
adcx = g_adc_u_value[i];
lcd_show_xnum(134, 130+(i*40), adcx, 1, 16, 0, BLUE); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
g_adc_u_value[i] -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
g_adc_u_value[i] *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数 */
lcd_show_xnum(150, 130+(i*40), g_adc_u_value[i], 3, 16, 0X80, BLUE); /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
}
LED1_TOGGLE();
delay_ms(100);
}
}
配置
/* ADC及引脚 定义 */
#define ADC_ADCX_CH3_GPIO_PORT GPIOA
#define ADC_ADCX_CH3_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX_CH4_GPIO_PORT GPIOA
#define ADC_ADCX_CH4_GPIO_PIN GPIO_PIN_4
#define ADC_ADCX_CH4_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX_CH5_GPIO_PORT GPIOA
#define ADC_ADCX_CH5_GPIO_PIN GPIO_PIN_5
#define ADC_ADCX_CH5_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CH3 ADC_CHANNEL_3 /* 通道Y, 0 <= Y <= 17 */
#define ADC_ADCX_CH4 ADC_CHANNEL_4
#define ADC_ADCX_CH5 ADC_CHANNEL_5
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
#define ADC_CH_NUM 3 /* 需要转换的通道数目 */
#define ADC_COLL 1000 /* 单采集次数 */
#define ADC_SUM ADC_CH_NUM * ADC_COLL /* 总采集次数 */
/* ADC单通道/多通道 DMA采集 DMA及通道 定义*/
#define ADC_ADCX_DMASx DMA2_Stream4 /* DMA2数据流4 */
#define ADC_ADCX_DMASx_Chanel DMA_CHANNEL_0 /* DMA通道0 */
#define ADC_ADCX_DMASx_IRQn DMA2_Stream4_IRQn
#define ADC_ADCX_DMASx_IRQHandler DMA2_Stream4_IRQHandler
#define ADC_ADCX_DMASx_IS_TC() ( __HAL_DMA_GET_FLAG(&g_dma_nch_adc_handle, DMA_FLAG_TCIF0_4) ) /* 判断DMA2 Stream4传输完成标志, 这是一个假函数形式,
* 不能当函数使用, 只能用在if等语句里面
*/
#define ADC_ADCX_DMASx_CLR_TC() do{ __HAL_DMA_CLEAR_FLAG(&g_dma_nch_adc_handle, DMA_FLAG_TCIF0_4); }while(0) /* 清除DMA2 Stream4传输完成标志 */
void adc_nch_dma_init(void)
{
GPIO_InitTypeDef gpio_init_struct = {0};
ADC_ChannelConfTypeDef sConfig = {0};
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
ADC_ADCX_CH3_GPIO_CLK_ENABLE(); /* 开启GPIO时钟 */
ADC_ADCX_CH4_GPIO_CLK_ENABLE();
ADC_ADCX_CH5_GPIO_CLK_ENABLE();
if ((uint32_t)ADC_ADCX_DMASx > (uint32_t)DMA2) /* 大于DMA2基地址,则为DMA2的数据流通道了 */
{
__HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2时钟使能 */
}
else
{
__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1时钟使能 */
}
/* 设置ADC1通道3~5对应的IO口模拟输入 */
gpio_init_struct.Pin = ADC_ADCX_CH3_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(ADC_ADCX_CH3_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ADC_ADCX_CH4_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH4_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = ADC_ADCX_CH5_GPIO_PIN;
HAL_GPIO_Init(ADC_ADCX_CH5_GPIO_PORT, &gpio_init_struct);
/* DMA配置 */
g_dma_nch_adc_handle.Instance = ADC_ADCX_DMASx; /* 设置DMAx */
g_dma_nch_adc_handle.Init.Channel = DMA_CHANNEL_0; /* 设置DMA通道 */
g_dma_nch_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 外设到存储器模式 */
g_dma_nch_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设非增量模式 */
g_dma_nch_adc_handle.Init.MemInc = DMA_MINC_ENABLE; /* 存储器增量模式 */
g_dma_nch_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
g_dma_nch_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */
g_dma_nch_adc_handle.Init.Mode = DMA_NORMAL; /* 外设流控模式 */
g_dma_nch_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM; /* 中等优先级 */
HAL_DMA_Init(&g_dma_nch_adc_handle);
__HAL_LINKDMA(&g_adc_nch_dma_handle,DMA_Handle,g_dma_nch_adc_handle); /* 将DMA与adc联系起来 */
g_adc_nch_dma_handle.Instance = ADC_ADCX;
g_adc_nch_dma_handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_nch_dma_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_nch_dma_handle.Init.ScanConvMode = ENABLE; /* 使能扫描模式 */
g_adc_nch_dma_handle.Init.ContinuousConvMode = ENABLE; /* 使能连续转换 */
g_adc_nch_dma_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止规则通道组间断模式 */
g_adc_nch_dma_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
g_adc_nch_dma_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_nch_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_nch_dma_handle.Init.NbrOfConversion = ADC_CH_NUM; /* 本实验用到3个规则通道序列 */
g_adc_nch_dma_handle.Init.DMAContinuousRequests = ENABLE; /* 开启DMA连续转换 */
HAL_ADC_Init(&g_adc_nch_dma_handle);
sConfig.Channel = ADC_ADCX_CH3;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig); /* 配置ADC通道3 */
sConfig.Channel = ADC_ADCX_CH4;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig); /* 配置ADC通道4 */
sConfig.Channel = ADC_ADCX_CH5;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&g_adc_nch_dma_handle, &sConfig); /* 配置ADC通道5 */
/* 配置中断 */
HAL_NVIC_SetPriority(ADC_ADCX_DMASx_IRQn, 2, 1);
HAL_NVIC_EnableIRQ(ADC_ADCX_DMASx_IRQn);
/* 开启ADC,使用DMA读取 */
HAL_ADC_Start_DMA(&g_adc_nch_dma_handle,(uint32_t *)g_adc_value,ADC_SUM);
}
void ADC_ADCX_DMASx_IRQHandler(void)
{
HAL_DMA_IRQHandler(&g_dma_nch_adc_handle);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
HAL_ADC_Stop_DMA(hadc); /* 关闭DMA传输 */
adc[0] = adc_get_result_average(0); /* 计算ADC平均值 */
adc[1] = adc_get_result_average(1);
adc[2] = adc_get_result_average(2);
HAL_ADC_Start_DMA(&g_adc_nch_dma_handle, (uint32_t*)&g_adc_value, ADC_SUM);
}
uint32_t adc_get_result_average(uint8_t ch)
{
uint32_t temp_val = 0;
uint16_t t;
for (t = ch; t < ADC_SUM; t += ADC_CH_NUM ) /* 获取ADC_SUM次数据 */
{
temp_val += g_adc_value[t];
}
return temp_val / ADC_COLL; /* 返回平均值 */
}
测试结果:

五、内部温度传感器实验
主函数
int main(void)
{
short temp;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
adc_temperature_init(); /* 初始化ADC内部温度传感器采集 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "Temperature TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 120, 200, 16, 16, "TEMPERATE: 00.00C", BLUE);
while (1)
{
temp = adc_get_temperature(); /* 得到温度值 */
if (temp < 0)
{
temp = -temp;
lcd_show_string(30 + 10 * 8, 120, 16, 16, 16, "-", BLUE); /* 显示负号 */
}
else
{
lcd_show_string(30 + 10 * 8, 120, 16, 16, 16, " ", BLUE); /* 无符号 */
}
lcd_show_xnum(30 + 11 * 8, 120, (temp / 100), 2, 16, 0, BLUE); /* 显示整数部分 */
lcd_show_xnum(30 + 14 * 8, 120, (temp % 100), 2, 16, 0X80, BLUE); /* 显示小数部分 */
LED0_TOGGLE(); /* LED0闪烁,提示程序运行 */
delay_ms(250);
}
}
配置
/* ADC 定义 */
#define ADC_ADCX ADC1
#define ADC_TEMPSENSOR_CHX ADC_CHANNEL_TEMPSENSOR /* 内部温度传感器专用通道 */
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
void adc_temperature_init(void)
{
ADC_ChannelConfTypeDef adc_ch_conf = {0};
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
g_adc_handle.Instance = ADC_ADCX;
g_adc_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_handle.Init.ScanConvMode = DISABLE; /* 非扫描模式 */
g_adc_handle.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
g_adc_handle.Init.NbrOfConversion = 1; /* 本实验用到1个规则通道序列 */
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_handle.Init.NbrOfDiscConversion = 0; /* 不连续采样通道数为0 */
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
g_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* 使用软件触发 */
g_adc_handle.Init.DMAContinuousRequests = DISABLE; /* 关闭DMA请求 */
HAL_ADC_Init(&g_adc_handle); /* 初始化ADC */
/* 配置ADC通道 */
adc_ch_conf.Channel = ADC_TEMPSENSOR_CHX; /* ADC通道 */
adc_ch_conf.Rank = 1; /* 序列 */
adc_ch_conf.SamplingTime = ADC_SAMPLETIME_480CYCLES; /* 采样时间 */
HAL_ADC_ConfigChannel(&g_adc_handle,&adc_ch_conf); /* 通道配置 */
}
uint32_t adc_get_result(uint32_t ch)
{
HAL_ADC_Start(&g_adc_handle); /* 开启ADC */
HAL_ADC_PollForConversion(&g_adc_handle, 0xFFFF); /* 轮询转换 */
return (uint16_t)HAL_ADC_GetValue(&g_adc_handle); /* 返回转换结果 */
}
uint32_t adc_get_result_average(uint32_t ch, uint8_t times)
{
uint32_t temp_val = 0;
uint8_t t;
for (t = 0; t < times; t++) /* 获取times次数据 */
{
temp_val += adc_get_result(ch);
delay_ms(5);
}
return temp_val / times; /* 返回平均值 */
}
short adc_get_temperature(void)
{
uint32_t adcx;
short result;
double temperature;
adcx = adc_get_result_average(ADC_TEMPSENSOR_CHX, 20); /* 读取内部温度传感器通道,20次取平均 */
temperature = (float)adcx * (3.3 / 4096); /* 转化为电压值 */
temperature = (temperature - 0.76) / 0.0025 + 25; /* 计算温度 */
result = temperature *= 100; /* 扩大100倍 */
return result;
}
测试结果:

六、定时器触发ADC采集
主函数
int main(void)
{
uint16_t adcx;
float temp;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
adc_dma_init(); /* ADC DMA初始化 */
gtim_timx_int_init(10000-1,8400-1); /* 10K Hz计数频率,1s溢出一次 */
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_CH3_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, 16, "ADC1_CH3_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */
while (1)
{
if(g_adc_dma_sta == 1)
{
adcx = g_adc_value[0]; /* 默认只使用一个ADC通道 */
/* 显示结果 */
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采集完成状态标志 */
}
LED0_TOGGLE();
delay_ms(100);
}
}
配置
/* ADC及引脚 定义 */
#define ADC_ADCX_CHY_GPIO_PORT GPIOA
#define ADC_ADCX_CHY_GPIO_PIN GPIO_PIN_3
#define ADC_ADCX_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CHY ADC_CHANNEL_3
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE(); }while(0) /* ADC1 时钟使能 */
#define ADC_CH_NUM 1 /* 需要转换的通道数目 */
/* ADC单通道/多通道 DMA采集 DMA及通道 定义 */
#define ADC_ADCX_DMASx DMA2_Stream4
#define ADC_ADCX_DMASx_Chanel DMA_CHANNEL_0
#define ADC_ADCX_DMASx_IRQn DMA2_Stream4_IRQn
#define ADC_ADCX_DMASx_IRQHandler DMA2_Stream4_IRQHandler
#define ADC_ADCX_DMASx_IS_TC() ( __HAL_DMA_GET_FLAG(&g_dma_adc_handle, DMA_FLAG_TCIF0_4) ) /* 判断DMA2 Stream4传输完成标志, 这是一个假函数形式,
* 不能当函数使用, 只能用在if等语句里面
*/
#define ADC_ADCX_DMASx_CLR_TC() do{ __HAL_DMA_CLEAR_FLAG(&g_dma_adc_handle, DMA_FLAG_TCIF0_4); }while(0) /* 清除DMA2 Stream4传输完成标志 */
/* 通用定时器 定义 */
#define GTIM_TIMX_INT TIM3
#define GTIM_TIMX_INT_IRQn TIM3_IRQn
#define GTIM_TIMX_INT_IRQHandler TIM3_IRQHandler
#define GTIM_TIMX_INT_CLK_ENABLE() do{ __HAL_RCC_TIM3_CLK_ENABLE(); }while(0) /* TIM3 时钟使能 */
void adc_dma_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
ADC_ChannelConfTypeDef adc_ch_conf = {0};
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能ADCx时钟 */
ADC_ADCX_CHY_GPIO_CLK_ENABLE(); /* 开启GPIO时钟 */
if ((uint32_t)ADC_ADCX_DMASx > (uint32_t)DMA2) /* 大于DMA2的基地址, 则为DMA2的数据流通道了 */
{
__HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2时钟使能 */
}
else
{
__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1时钟使能 */
}
/* 设置AD采集通道对应IO引脚工作模式 */
gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct);
/* 初始化DMA */
g_dma_adc_handle.Instance = ADC_ADCX_DMASx; /* 设置DMA数据流 */
g_dma_adc_handle.Init.Channel = DMA_CHANNEL_0; /* 设置DMA通道 */
g_dma_adc_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; /* 从外设到存储器模式 */
g_dma_adc_handle.Init.PeriphInc = DMA_PINC_DISABLE; /* 外设非增量模式 */
g_dma_adc_handle.Init.MemInc = DMA_MINC_ENABLE; /* 存储器增量模式 */
g_dma_adc_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据长度:16位 */
g_dma_adc_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /* 存储器数据长度:16位 */
g_dma_adc_handle.Init.Mode = DMA_CIRCULAR; /* 循环模式 */
g_dma_adc_handle.Init.Priority = DMA_PRIORITY_MEDIUM; /* 中等优先级 */
HAL_DMA_Init(&g_dma_adc_handle);
__HAL_LINKDMA(&g_adc_dma_handle,DMA_Handle,g_dma_adc_handle);
g_adc_dma_handle.Instance = ADC_ADCX;
g_adc_dma_handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* 4分频,21Mhz */
g_adc_dma_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 12位模式 */
g_adc_dma_handle.Init.ScanConvMode = DISABLE; /* 非扫描模式 */
g_adc_dma_handle.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
g_adc_dma_handle.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
g_adc_dma_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; /* 触发源 */
g_adc_dma_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; /* 定时器触发 */
g_adc_dma_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
g_adc_dma_handle.Init.NbrOfConversion = 1; /* 本实验用到1个规则通道序列 */
g_adc_dma_handle.Init.DMAContinuousRequests = ENABLE; /* 开启DMA请求 */
HAL_ADC_Init(&g_adc_dma_handle);
/* 配置ADC通道 */
adc_ch_conf.Channel = ADC_ADCX_CHY; /* 通道 */
adc_ch_conf.Rank = 1; /* 序列 */
adc_ch_conf.SamplingTime = ADC_SAMPLETIME_480CYCLES; /* 采样时间 */
HAL_ADC_ConfigChannel(&g_adc_dma_handle, &adc_ch_conf); /* 通道配置 */
/* 配置DMA数据流请求中断优先级 */
HAL_NVIC_SetPriority(ADC_ADCX_DMASx_IRQn, 3, 3);
HAL_NVIC_EnableIRQ(ADC_ADCX_DMASx_IRQn);
HAL_ADC_Start_DMA(&g_adc_dma_handle,(uint32_t *)g_adc_value,1);
__HAL_DMA_ENABLE_IT(&g_dma_adc_handle, DMA_IT_TC); /* 使能传输完成中断 */
}
void adc_dma_enable(uint16_t cndtr)
{
__HAL_ADC_DISABLE(&g_adc_dma_handle); /* 先关闭ADC */
__HAL_DMA_DISABLE(&g_dma_adc_handle); /* 关闭DMA传输 */
g_dma_adc_handle.Instance->NDTR = cndtr; /* 重设DMA传输数据量 */
__HAL_DMA_ENABLE(&g_dma_adc_handle); /* 开启DMA传输 */
__HAL_ADC_ENABLE(&g_adc_dma_handle); /* 重新启动ADC */
ADC_ADCX->CR2 |= 1 << 30; /* 启动规则转换通道 */
}
void ADC_ADCX_DMASx_IRQHandler(void)
{
if (ADC_ADCX_DMASx_IS_TC())
{
g_adc_dma_sta = 1; /* 标记DMA传输完成 */
ADC_ADCX_DMASx_CLR_TC(); /* 清除DMA2 数据流4 传输完成中断 */
}
}
void gtim_timx_int_init(uint16_t arr, uint16_t psc)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
GTIM_TIMX_INT_CLK_ENABLE(); /* 使能TIMx时钟 */
g_timx_handle.Instance = GTIM_TIMX_INT; /* 通用定时器x */
g_timx_handle.Init.Prescaler = psc; /* 预分频系数 */
g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
g_timx_handle.Init.Period = arr; /* 自动装载值 */
HAL_TIM_Base_Init(&g_timx_handle);
/* 定时器中断触发ADC采集配置 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; /* 每次更新事件触发一次转换 */
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&g_timx_handle, &sMasterConfig);
HAL_NVIC_SetPriority(GTIM_TIMX_INT_IRQn, 1, 3); /* 设置中断优先级,抢占优先级1,子优先级3 */
HAL_NVIC_EnableIRQ(GTIM_TIMX_INT_IRQn); /* 开启ITMx中断 */
HAL_TIM_Base_Start_IT(&g_timx_handle); /* 使能定时器x和定时器x更新中断 */
}
void GTIM_TIMX_INT_IRQHandler(void)
{
__HAL_TIM_CLEAR_IT(&g_timx_handle, TIM_IT_UPDATE); /* 清除标志位,不做其他处理 */
}
测试结果:

在ADC DMA和定时器中断里增加打印

更多推荐



所有评论(0)