OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 121|回复: 0

《M144Z-M3最小系统板使用指南——STM32F103版》第三十三章 单通道ADC采集实验

[复制链接]

1051

主题

1062

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4367
金钱
4367
注册时间
2019-5-8
在线时间
1193 小时
发表于 2024-4-26 17:02:03 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2024-4-25 11:32 编辑

第三十三章 单通道ADC采集实验

1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板

2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boar ... _mini_sysboard.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32技术交流QQ群:725095144

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

本章介绍使用STM32F103模数转换器(ADC)进行带通道的电压采集。通过本章的学习,读者将学习到单通道ADC的使用。
本章分为如下几个小节:
33.1 硬件设计
33.2 程序设计
33.3 下载验证

33.1 硬件设计
33.1.1 例程功能
1. LCD上不断刷新显示PA1引脚输入电压采样的数字量和模拟量。
2. LED0闪烁,提示程序正在运行

33.1.2 硬件资源
1. LED
       LED0 - PB5
2. 正点原子2.8/3.5/4.3/7/10寸TFTLCD模块
3. ADC2
       Channel1 - PA1

33.1.3 原理图
本章实验使用的ADC1为STM32F103的片上资源,因此没有对应的连接原理图。

33.2 程序设计
33.2.1 HAL库的ADC驱动
本章实验将使用ADC1的通道1(PA1引脚)采集外部输入电压的模拟量,并将其转换为数字量,其具体的步骤如下:
①:初始化ADC
②:配置ADC通道
③:开启ADC
④:ADC轮询转换
⑤:获取ADC值
在HAL库中对应的驱动函数如下:
①:初始化ADC
该函数用于初始化ADC,其函数原型如下所示:
  1. HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc);
复制代码
该函数的形参描述,如下表所示:
QQ截图20240425112911.png
表33.2.1.1 函数HAL_ADC_Init()形参描述
该函数的返回值描述,如下表所示:
QQ截图20240425112921.png
表33.2.1.2 函数HAL_ADC_Init()返回值描述
该函数需要传入ADC的句柄指针,该句柄中就包含了ADC的初始化配置参数结构体,该结构体的定义如下所示:
  1. typedef struct
  2. {
  3.     uint32_t DataAlign;                     /* 数据对齐方式 */
  4.     uint32_t ScanConvMode;                  /* 扫描模式 */
  5.    FunctionalState ContinuousConvMode;     /* 连续转换 */
  6.     uint32_t NbrOfConversion;               /* 规则序列 */
  7.    FunctionalState DiscontinuousConvMode; /* 不连续采样模式  */
  8.     uint32_tNbrOfDiscConversion;           /* 不连续采样序列 */
  9.     uint32_t ExternalTrigConv;              /* 外部触发转换 */
  10. }ADC_InitTypeDef;
复制代码
该函数的使用示例,如下所示:
  1. #include "stm32f1xx_hal.h"
  2. void example_fun(void)
  3. {
  4.    ADC_HandleTypeDef adc_handle = {0};
  5.    
  6.     /* 初始化ADC */
  7.    adc_handle.Instance = ADC1;
  8.    adc_handle.Init.DataAlign =ADC_DATAALIGN_RIGHT;
  9.    adc_handle.Init.ScanConvMode = DISABLE;
  10.    adc_handle.Init.ContinuousConvMode= DISABLE;
  11.    adc_handle.Init.NbrOfConversion= 1;
  12.    adc_handle.Init.DiscontinuousConvMode= DISABLE;
  13.    adc_handle.Init.NbrOfDiscConversion= 1;
  14.    adc_handle.Init.ExternalTrigConv=ADC_SOFTWARE_START;
  15.    HAL_ADC_Init(&adc_handle);
  16. }
复制代码
②:配置ADC通道
该函数用于配置ADC通道,其函数原型如下所示:
  1. HAL_StatusTypeDef HAL_ADC_ConfigChannel(   ADC_HandleTypeDef* hadc,
  2.                                              ADC_ChannelConfTypeDef* sConfig);
复制代码
该函数的形参描述,如下表所示:
QQ截图20240425112934.png
表33.2.1.3 函数HAL_ADC_ConfigChannel()形参描述
该函数的返回值描述,如下表所示:
QQ截图20240425112943.png
表33.2.1.4 函数HAL_ADC_ConfigChannel()返回值描述
该函数使用ADC_ChannelConfTypeDef类型结构体指针传入了ADC通道的配置参数,该结构体的定义如下所示:
  1. typedef struct
  2. {
  3.     uint32_t Channel;       /* 通道 */
  4.     uint32_t Rank;          /* 规则组中的序号 */
  5.     uint32_t SamplingTime;  /* 采样时间 */
  6. }ADC_ChannelConfTypeDef;
复制代码
该函数的使用示例,如下所示:
  1. #include "stm32f1xx_hal.h"
  2. void example_fun(void)
  3. {
  4.    ADC_ChannelConfTypeDef config = {0};
  5.    
  6.     /* 配置ADC通道 */
  7.    config.Channel = ADC_CHANNEL_0;
  8.    config.Rank = 1;
  9.    config.SamplingTime =ADC_SAMPLETIME_3CYCLES;
  10.    HAL_ADC_ConfigChannel(&adc_handle, &config);
  11. }
复制代码
③:开启ADC
该函数用于开启ADC,其函数原型如下所示:
  1. HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);
复制代码
该函数的形参描述,如下表所示:
QQ截图20240425112953.png
表33.2.1.5 函数HAL_ADC_Start()形参描述
该函数的返回值描述,如下表所示:
QQ截图20240425113003.png
表33.2.1.6 函数HAL_ADC_Start()返回值描述
该函数的使用示例,如下所示:
  1. #include "stm32f1xx_hal.h"
  2. void example_fun(void)
  3. {
  4.     /* 开启ADC */
  5.    HAL_ADC_Start(&adc_handle);
  6. }
复制代码
④:ADC轮询转换
该函数用于ADC轮询转换,其函数原型如下所示:
  1. HAL_StatusTypeDef HAL_ADC_PollForConversion(   ADC_HandleTypeDef* hadc,
  2.                                                  uint32_t Timeout);
复制代码
该函数的形参描述,如下表所示:
QQ截图20240425113013.png
表33.2.1.7 函数HAL_ADC_PollForConversion()形参描述
该函数的返回值描述,如下表所示:
QQ截图20240425113021.png
表33.2.1.8 函数HAL_ADC_PollForConversion()返回值描述
该函数的使用示例,如下所示:
  1. #include "stm32f1xx_hal.h"
  2. void example_fun(void)
  3. {
  4.     /* ADC轮询转换 */
  5.    HAL_ADC_PollForConversion(&adc_handle, HAL_MAX_DELAY);
  6. }
复制代码
⑤:获取ADC
该函数用于获取ADC值,其函数原型如下所示:
  1. uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);
复制代码
该函数的形参描述,如下表所示:
QQ截图20240425113030.png
表33.2.1.9 函数HAL_ADC_GetValue()形参描述
该函数的返回值描述,如下表所示:
QQ截图20240425113037.png
表33.2.1.10 函数HAL_ADC_GetValue()返回值描述
该函数的使用示例,如下所示:
  1. #include"stm32f1xx_hal.h"
  2. void example_fun(void)
  3. {
  4.     uint32_t value;
  5.    
  6.     value = HAL_ADC_GetValue(&adc_handle);
  7.    
  8.     /* Do something.*/
  9. }
复制代码

33.2.2ADC驱动
本章实验的ADC驱动主要负责向应用层提供ADC的初始化和获取ADC转换结果的函数。本章实验中,ADC的驱动代码包括adc.c和adc.h两个文件。
ADC驱动中,对ADC、GPIO的相关宏定义,如下所示:
  1. #define ADC_ADCX    ADC2
  2. #define ADC_ADCX_CLK_ENABLE()          \
  3.     do {                                \
  4.          __HAL_RCC_ADC2_CLK_ENABLE();   \
  5.     }while (0)
  6. #define ADC_ADCX_CHY           ADC_CHANNEL_1
  7. #define ADC_ADCX_CHY_GPIO_PORT GPIOA
  8. #define ADC_ADCX_CHY_GPIO_PIN  GPIO_PIN_1
  9. #define ADC_ADCX_CHY_GPIO_CLK_ENABLE() \
  10.     do {                                \
  11.          __HAL_RCC_GPIOA_CLK_ENABLE();  \
  12.     }while (0)
  13. ADC驱动中,ADC的初始化函数,如下所示:
  14. /**
  15. *@brief   初始化ADC
  16. *@param   无
  17. *@retval  无
  18. */
  19. void adc_init(void)
  20. {
  21.     /* 配置ADC */
  22.    g_adc_handle.Instance = ADC_ADCX;
  23.    g_adc_handle.Init.DataAlign =ADC_DATAALIGN_RIGHT;
  24.    g_adc_handle.Init.ScanConvMode = DISABLE;
  25.    g_adc_handle.Init.ContinuousConvMode= DISABLE;
  26.    g_adc_handle.Init.NbrOfConversion= 1;
  27.    g_adc_handle.Init.DiscontinuousConvMode= DISABLE;
  28.    g_adc_handle.Init.NbrOfDiscConversion= 1;
  29.    g_adc_handle.Init.ExternalTrigConv=ADC_SOFTWARE_START;
  30.    HAL_ADC_Init(&g_adc_handle);
  31. }
复制代码
从上面的代码中可以看出,初始化ADC就是调用函数HAL_ADC_Init()来初始化ADC。
ADC驱动中,配置ADC通道的函数,如下所示:
  1. /**
  2. *@brief   设置ADC通道
  3. *@param   adc_handle: ADC句柄
  4. *@param   channel: ADC通道
  5. *@param   rank: 规则采样的编号
  6. *@param   sampling_time: 采样时间
  7. *@retval  无
  8. */
  9. voidadc_channel_set(  ADC_HandleTypeDef *adc_handle,
  10.                          uint32_t channel,
  11.                          uint32_t rank,
  12.                          uint32_t sampling_time)
  13. {
  14.    ADC_ChannelConfTypeDef adc_channel_conf_struct = {0};
  15.    
  16.     /* 配置ADC通道 */
  17.    adc_channel_conf_struct.Channel = channel;
  18.    adc_channel_conf_struct.Rank = rank;
  19.    adc_channel_conf_struct.SamplingTime = sampling_time;
  20.    HAL_ADC_ConfigChannel(adc_handle, &adc_channel_conf_struct);
  21. }
  22. ADC驱动中,获取ADC转换结果的函数,如下所示:
  23. /**
  24. *@brief   获取ADC结果
  25. *@param   channel: ADC通道
  26. *@retval  ADC结果
  27. */
  28. uint16_t adc_get_result(uint32_t channel)
  29. {
  30.     uint16_t result;
  31.    
  32.    adc_channel_set(&g_adc_handle, channel, 1,ADC_SAMPLETIME_480CYCLES);
  33.    HAL_ADC_Start(&g_adc_handle);
  34.    HAL_ADC_PollForConversion(&g_adc_handle, HAL_MAX_DELAY);
  35.    result =HAL_ADC_GetValue(&g_adc_handle);
  36.    
  37.     return result;
  38. }
  39. /**
  40. *@brief   均值滤波获取ADC结果
  41. *@param   channel: ADC通道
  42. *@param   times: 均值滤波的原始数据个数
  43. *@retval  ADC结果
  44. */
  45. uint16_t adc_get_result_average(uint32_t channel, uint8_t times)
  46. {
  47.     uint32_t sum_result = 0;
  48.     uint8_t index;
  49.     uint16_t result;
  50.    
  51.     for (index=0; index<times; index++)
  52.     {
  53.          sum_result += adc_get_result(channel);
  54.     }
  55.    
  56.    result = sum_result / times;
  57.    
  58.     return result;
  59. }
复制代码
以上两个函数都是用于获取ADC转换结果的函数,其中函数adc_get_result()会配置并开启ADC指定通道的规则通道转换,并等待其转换结束后,读取其转换的1次结果;而函数adc_get_result_averagr()则是多次调用啊含糊adc_get_result()获取多次ADC的转换结果,然后进行均值滤波。

33.2.3 实验应用代码
本章实验的应用代码,如下所示:
  1. int main(void)
  2. {
  3.     uint16_t adc_result;
  4.     uint16_t voltage;
  5.    
  6.    HAL_Init();                         /* 初始化HAL库 */
  7.    sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置时钟,72MHz */
  8.    delay_init(72);                     /* 初始化延时 */
  9.    usart_init(115200);                 /* 初始化串口 */
  10.    led_init();                         /* 初始化LED */
  11.    lcd_init();                         /* 初始化LCD */
  12.    adc_init();                         /* 初始化ADC */
  13.    
  14.    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  15.    lcd_show_string(30, 70, 200, 16, 16, "ADCTEST", RED);
  16.    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  17.    
  18.    lcd_show_string(30, 110, 200, 16, 16, "ADC2_CH1_VAL:0", BLUE);
  19.    lcd_show_string(30, 130, 200, 16, 16, "ADC2_CH1_VOL:0.000V", BLUE);
  20.    
  21.     while (1)
  22.     {
  23.          /* 均值滤波获取ADC结果 */
  24.          adc_result = adc_get_result_average(ADC_ADCX_CHY, 10);
  25.          lcd_show_xnum(134, 110, adc_result, 5, 16, 0, BLUE);
  26.          
  27.          /* 计算实际电压值(扩大1000倍) */
  28.          voltage = (adc_result * 3300) / 4095;
  29.          lcd_show_xnum(134, 130, voltage / 1000, 1, 16, 0, BLUE);
  30.          lcd_show_xnum(150, 130, voltage % 1000, 3, 16, 0x80, BLUE);
  31.          
  32.          LED0_TOGGLE();
  33.          
  34.          delay_ms(100);
  35.     }
  36. }
复制代码
从上面的代码中可以看出,在进行完包括ADC的所有初始化工作后,便不断地获取ADC2通道1进行10次转换后经过均值滤波后的结果,并将该原始值显示在LCD上,同时还通过该电压的原始值计算出了电压的模拟量,并在LCD上进行显示。

33.3 下载验证
在完成编译和烧录操作后,可以看到LCD上实时刷新显示着ADC2通道1(PA1引脚)采集到电压的数字量和模拟量,此时可以通过杜邦线给PA1引脚接入不同的电压值(注意共地,且输入电压不能超过3.3V,否则可能损坏开发板),可以看到LCD上显示的电压数字量和模拟量也随之改变。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-16 05:54

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表