7.基于STM32CubeMx实现ADC转化

方式一:软件启动ADC转换

CubeMx上操作:

1.G431开发板上PB12接的模拟输入,内部是使用的ADC1_In11,所以CubeMx选择ADC1,下拉选择IN11通道Single End;其它不用动;

2.主程序:

         HAL_ADC_Start(&hadc1);
        if(HAL_ADC_PollForConversion (&hadc1,200)==HAL_OK)
        {
            uint32_t val=HAL_ADC_GetValue(&hadc1);
            uint32_t Volt=val*3300;
            Volt>>=12;
            char str[22];
            sprintf(str,"Volt:%d%d%d%dmv",Volt/1000,Volt%1000/100,Volt%100/10,Volt%10);
            LCD_DisplayStringLine(Line1,(uint8_t *)str);
        }

方式二:定时器启动ADC转换

1.CubeMx上任然选择通道11,外部触发源External Trigger Conver Source选择Time3 Trigger Out event,跳变沿选择上跳沿,NVIC中启动ADC中断,优先级为1。

2.时钟树HCLK设置100MHz,APB1/2定时器时钟频率50MHz,时钟源选择内部时钟,分频系数49999,Count Period设置为500,定时500ms,Disable主从模式,触发事件选择Update Event,这样ADC1在TIM3的TRGO信号的每个上跳沿启动一次ADC转换,转换周期由TIM3的定时周期决定。无需开启TIM3的全局中断。

3.程序部分

主函数:

HAL_ADC_Start_IT(&hadc1);//以中断方式启动ADC

HAL_TIM_Base_Start(&hadc1);//启动定时器TIM3

重写回调函数:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(hadc->Instance==ADC1)
{
    uint32_t val=HAL_ADC_GetValue(hadc);
    uint32_t Volt=3300*val;
    Volt=Volt>>12;
    //此时Volt就是电压值,参考电压为3.3v;
}
}

方法三:同一ADC多通道转换

1.在对应引脚选择ADC1_INx,如将PB12选择为ADC1_IN11,PB11选择为ADC_14.
2.配置定时器TIM3,定时500ms,触发事件选择Update Event;
3.将ADC1的IN11和IN14选择为单端,勾选Vbat电池电压,参考电压;
4.Number of Conversion选择4,ADD DMA,循环模式,数据宽度为字。然后才能Enable DMA Continuous Mode;
5.外部触发源选择Timer3 Trigger Out Event,然后将4个Rank选择你要的四个通道,开启ADC中断,DMA不用开中断。
6.main.c中:

	HAL_ADC_Start_DMA(&hadc1,DataBuffer,4);//以DMA方式启动
	HAL_TIM_Base_Start(&htim3);
	
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)//转换结束回调函数
{
	uint8_t i=0;
	for(i=0;i<4;i++)//数组的前四位存放的是对应电压值.
	{
sprintf(str,"ADC1:%d%d%d%dmv",DataBuffer[i]/1000,DataBuffer[i]%1000/100,DataBuffer[i]%100/10,DataBuffer[i]%10);
	switch(i)
	{
		case 0:LCD_DisplayStringLine (Line5,(uint8_t *)str);break;
		case 1:LCD_DisplayStringLine (Line6,(uint8_t *)str);break;
		case 2:LCD_DisplayStringLine (Line7,(uint8_t *)str);break;
		case 3:LCD_DisplayStringLine (Line8,(uint8_t *)str);break;	
	}}}

实例三:多ADC同步转换

使用ADC1测量PB12电压,ADC2测量PB15电压。多重ADC模式只能采用DMA数据传输。

1.为ADC1选择通道IN11,在ADC_Common_Setting组里有几个参数用于多ADC模式:
    Mode:选择Dual regular simultaneous mode only,也就是ADC1和ADC2规则同步转换模式
    DMA Access Mode:DMA访问模式,这里选择DMA access mode 2或者DMA access mode enable
2.因为只有一个通道,所以将Scan Conversion Mode 设置为Disable,
多重ADC只能使用DMA方式传输数据,所以DMA Continue Request设置为enabled,
在Adc1界面中进行DMA设置。
3.ADC2选择通道15,其它参数和ADC1一样,但不要开启ADC1全局中断,只开DMA1中断。不要为ADC2配置DMA,也不要为ADC2开启全局中断。因为会自动打开DMA中断
4.有一个小问题是,有些版本会出现,ADC2 的DMA Continuous Requests只能选择Diabled,但是应该设置为Enabled,如果为ADC2配置DMA流,才会出现Enabled选项,但是在双重ADC模式下,ADC2不能配置DMA流,否则不能实现双重ADC同步模式了,在CubeMx中不能更改,那就去生成的初始函数MX_ADC2_Init()中修改
5.主程序:
   	HAL_TIM_Base_Start(&htim3);
	HAL_ADCEx_MultiModeStart_DMA(&hadc1,DataBuffer,1); 
	HAL_ADCEx_MultiModeStart_DMA(&hadc2,DataBuffer,1);
	 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	uint32_t Data=DataBuffer[0];//ADC1和ADC2的数据
	uint16_t ADC1Data=Data&0x0000ffff;//低16位为ADC1的数据
	uint16_t ADC2Data=(Data&0xffff0000)>>16;//高16位为ADC2的数据
	ADC1Data=3300*ADC1Data/4096;
	ADC2Data=3300*ADC2Data/4096;
		sprintf(str,"ADC1:%d%d%d%dmv",ADC1Data/1000,ADC1Data%1000/100,ADC1Data%100/10,ADC1Data%10);		
		LCD_DisplayStringLine (Line5,(uint8_t *)str);
	  sprintf(str,"ADC2:%d%d%d%dmv",ADC2Data/1000,ADC2Data%1000/100,ADC2Data%100/10,ADC2Data%10);		
		LCD_DisplayStringLine (Line6,(uint8_t *)str);
}

14.2.1 常规通道
分组   函数名 功能描述
初始化和配置
HAL_ADC_Init() ADC的初始化,设置ADC的总体参数
HAL_ADC_MspInit() ADC初始化的MSP弱函数,在
HAL_ADC_Init()里被调用
HAL_ADC_ConfigChannel() ADC常规通道配置,一次配置一个通道
HAL_ADC_AnalogWDGConfig() 模拟看门狗配置
HAL_ADC_GetState() 返回ADC当前状态
HAL_ADC_GetError() 返回ADC的错误码
软件启动转换
HAL_ADC_Start() 启动ADC,并开始常规通道的转换
HAL_ADC_Stop() 停止常规通道的转换,并停止ADC
HAL_ADC_PollForConversion() 轮询方式等待ADC常规通道转换完成
HAL_ADC_GetValue() 读取常规通道转换结果寄存器的数据
中断方式转换
HAL_ADC_Start_IT() 开启中断,开始ADC常规通道的转换
HAL_ADC_Stop_IT() 关闭中断,停止ADC常规通道的转换
HAL_ADC_IRQHandler() ADC中断ISR函数里调用的ADC中断通用处理函数
DMA方式转换
HAL_ADC_Start_DMA() 开启ADC的DMA请求,开始ADC常规通道的转换
HAL_ADC_Stop_DMA() 停止ADC的DMA请求,停止ADC常规通道的转换
软件启动转换
其中,参数hadc是ADC外设对象指针,Timeout是超时等待时间,单位是节拍数。结构体DMA_HandleTypeDef定义DMA流对象,包含大量函数指针,用于指向DMA流中断的具体回调函数。
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); //软件启动转换
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); //停止转换
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); //读取转换结果寄存器的32位数据
中断方式转换
启动和停止中断方式ADC转换的函数:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);
ADC有4个中断事件源,中断事件类型的宏定义如下:
#define ADC_IT_EOC ((uint32_t)ADC_CR1_EOCIE) //规则通道转换结束(EOC)事件
#define ADC_IT_AWD ((uint32_t)ADC_CR1_AWDIE) //模拟看门狗触发事件
#define ADC_IT_JEOC ((uint32_t)ADC_CR1_JEOCIE) //注入通道转换结束事件
#define ADC_IT_OVR ((uint32_t)ADC_CR1_OVRIE) //数据溢出事件,即转换结果未被及时读出ADC的中断事件类型和对应的回调函数
中断事件类型 中断事件 回调函数
ADC_IT_EOC 规则通道转换结束(EOC)事件 HAL_ADC_ConvCpltCallback()
ADC_IT_AWD 模拟看门狗触发事件 HAL_ADC_LevelOutOfWindowCallback()
ADC_IT_JEOC 注入通道转换结束事件HAL_ADCEx_InjectedConvCpltCallback()
ADC_IT_OVR数据溢出事件,即数据寄存器内的数据未被及时读出HAL_ADC_ErrorCallback()
DMA方式转换
ADC只有一个DMA请求,方向是外设到存储器。
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc);其中,参数hadc的ADC外设对象指针;参数pData是uint32_t类型缓存区指针,因为ADC转换结果寄存器是32位的,所以DMA数据宽度是32位;参数Length是缓存区长度,单位是字(4个字节)
DMA流中断事件类型和关联的回调函数
DMA中断事件类型 DMA中断事件类型 关联的回调函数名称
DMA_IT_TC 传输完成中断 HAL_ADC_ConvCpltCallback()
DMA_IT_HT 传输半完成中断 HAL_ADC_ConvHalfCpltCallback()
DMA_IT_TE 传输错误中断 HAL_ADC_ErrorCallback()
注入通道
分组 函数名 功能描述
通道配置 HAL_ADCEx_InjectedConfigChannel() 注入通道配置
软件启动转换
HAL_ADCEx_InjectedStart() 软件方式启动注入通道的转换
HAL_ADCEx_InjectedStop() 软件方式停止注入通道的转换
HAL_ADCEx_InjectedPollForConversion() 查询注入通道转换是否完成
HAL_ADCEx_InjectedGetValue() 读取注入通道的转换结果数据寄存器
中断方式转换
HAL_ADCEx_InjectedStart_IT() 开启注入通道的中断方式转换
HAL_ADCEx_InjectedStop_IT() 停止注入通道的中断方式转换
HAL_ADCEx_InjectedConvCpltCallback() 注入通道转换结束中断事件(ADC_IT_JEOC)的回调函数
ADC的注入通道相关函数
14.2.3 多重ADC
多重ADC就是两个或三个ADC同步或交错使用
函数名 功能描述
HAL_ADCEx_MultiModeConfigChannel() 多重模式的通道配置
HAL_ADCEx_MultiModeStart_DMA() 以DMA方式启动多重ADC
HAL_ADCEx_MultiModeStop_DMA() 停止多重ADC的DMA方式传输
HAL_ADCEx_MultiModeGetValue() 停止多重ADC后,读取最后一次转换结果数据
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是基于STM32CubeMX和HAL库实现ADC采样的步骤: 1. 打开STM32CubeMX,选择你的芯片型号,在“Pinout”窗口中配置ADC输入端口。 2. 在“Configuration”窗口中选择ADC和DMA。启用ADC的DMA模式,以便能够在ADC转换完成后自动将数据传输到内存中。 3. 配置ADC的采样时间,分辨率和转换模式等参数。 4. 在代码中初始化ADC和DMA,并启动ADC转换。 下面是一个简单的代码示例,演示如何使用STM32CubeMX和HAL库实现ADC采样: ``` #include "stm32f4xx_hal.h" ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; uint16_t adc_buf[10]; void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.NbrOfDiscConversion = 0; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DMAContinuousRequests = ENABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } } void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(adcHandle->Instance==ADC1) { /* ADC1 clock enable */ __HAL_RCC_ADC1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**ADC1 GPIO Configuration PA0/WKUP ------> ADC1_IN0 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* ADC1 DMA Init */ /* ADC1 Init */ hdma_adc1.Instance = DMA2_Stream0; hdma_adc1.Init.Channel = DMA_CHANNEL_0; 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_LOW; hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1); } } void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) { if(adcHandle->Instance==ADC1) { /* Peripheral clock disable */ __HAL_RCC_ADC1_CLK_DISABLE(); /**ADC1 GPIO Configuration PA0/WKUP ------> ADC1_IN0 */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0); /* ADC1 DMA DeInit */ HAL_DMA_DeInit(adcHandle->DMA_Handle); } } int main(void) { HAL_Init(); MX_ADC1_Init(); MX_DMA_Init(); HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, 10); while (1) { // 处理ADC采样数据 } } ``` 在上面的代码中,我们使用了ADC1_IN0作为采样输入端口,开启了DMA模式,并使用了ADC_SAMPLETIME_480CYCLES的采样时间和ADC_RESOLUTION_12B的分辨率。ADC将会连续采样10个数据,并使用DMA传输到内存中。在main函数中,我们使用HAL_ADC_Start_DMA启动ADC转换。最后,我们可以在while循环中处理采样数据。 这只是一个简单的例子,你可以根据实际需求修改代码。同时也需要注意,每个芯片的ADC和DMA配置略有不同,需要根据芯片手册进行配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值