基于HAL库,实现最简单ADC采集。
第一步,使用CubeMX配置时钟。
然后是adc的配置:
将,稍微修改一下风格,并手写头文件和源文件。
adc.h很简单,就不说了。
- #ifndef __ADC_H
- #define __ADC_H
- #include "sys.h"
- void MY_ADC_Init(void); //ADC通道初始化
- u16 Get_Adc(void); //获得某个通道值
- #endif
复制代码
其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。
- #include "adc.h"
- #include "delay.h"
- ADC_HandleTypeDef ADC1_Handler; //ADC句柄
- ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄
- //初始化ADC
- void MY_ADC_Init(void)
- {
- ADC1_Handler.Instance = ADC1;
- ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
- ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
- ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式
- ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换
- ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
- ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
- ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列1
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0
- ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
- ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断
- HAL_ADC_Init(&ADC1_Handler); //初始化
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5
- ADC1_ChanConf.Rank = 1; //1个序列
- ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间
- ADC1_ChanConf.Offset = 0;
- HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
- }
- //ADC底层驱动,引脚配置,时钟使能
- //此函数会被HAL_ADC_Init()调用
- //hadc:ADC句柄
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
- {
- GPIO_InitTypeDef GPIO_Initure;
- __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
- __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
- GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
- GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);
- }
- //获得ADC值
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
- //返回值:转换结果
- u16 Get_Adc()
- {
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
- HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
- }
复制代码
main.c中,主函数初始化之后,直接读取adc的值,并打印。
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "adc.h"
- int main(void)
- {
- u16 adcx;
- Cache_Enable(); //打开L1-Cache
- HAL_Init(); //初始化HAL库
- Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
- delay_init(216); //延时初始化
- uart_init(115200); //串口初始化
- MY_ADC_Init(); //初始化ADC1通道5
-
- while (1)
- {
- adcx = Get_Adc(); //获取通道5的转换值,20次取平均
- printf("%d\r\n", adcx);
- delay_ms(250);
- }
- }
复制代码
如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:
- //获得ADC值
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
- //返回值:转换结果
- u16 Get_Adc(u32 ch)
- {
- ADC_ChannelConfTypeDef ADC1_ChanConf;
- ADC1_ChanConf.Channel=ch; //通道
- ADC1_ChanConf.Rank=1; //1个序列
- ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
- ADC1_ChanConf.Offset=0;
- HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
-
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
-
- HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换
- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
- }
复制代码
|