当前位置:   article > 正文

STM32嵌入式系统中的ADC数据采集与电压转换实战指南_单片机嵌入式内数据采集与导出

单片机嵌入式内数据采集与导出

目录

引言

第一部分:准备工作

1. 硬件选择:

2.开发环境搭建:

3. 基础知识复习:

第二部分:硬件连接

1. 电源与地连接:

2. 模拟输入配置:

3. 参考电压设置:

第三部分:软件配置

1. 初始化ADC模块:

2. 中断处理:

3. 数据采集函数编写:

第四部分:数据处理与电压输出

1. 数据校准:

2. 电压计算:

3. 输出接口配置:

第五部分:实战演练

1. 示例代码分析:

ADC.C文件

ADC.h文件

主函数main

注意事项

结语


引言

在现代电子工程领域,嵌入式系统扮演着至关重要的角色。STM32微控制器,作为嵌入式系统中的明星产品,其内置的ADC模块为我们提供了从现实世界获取模拟信号的能力。本文将带领读者一步步了解如何在STM32上实现高效的数据采集,并将这些数据转换为电压输出,以便进一步处理或显示。

第一部分:准备工作

1. 硬件选择:

首先,我们需要选择合适的STM32微控制器,考虑到ADC通道数量、分辨率以及性能需求。

2.开发环境搭建:

安装并配置STM32CubeIDE或其他集成开发环境(IDE),准备进行软件开发。

3. 基础知识复习:

ADC的工作原理,理解分辨率、采样速率和转换时间等关键概念。ADC的分辨率决定了ADC能够区分的最小电压变化。例如,一个12位的ADC可以区分1/4096的电压变化。

下图为ADC的工作原理

第二部分:硬件连接

1. 电源与地连接:

确保微控制器的电源稳定,正确连接VDD和VSS。

2. 模拟输入配置:

将待测量的模拟信号连接到ADC输入通道,注意避免干扰。

3. 参考电压设置:

配置外部或内部参考电压源,这是ADC转换的基准。ADC能够测量的电压范围,一般情况下,ADC引脚的输入电压是从0至VDD,如果有REF引脚,一般是0至Vref,也有0至2Vref的情况。

第三部分:软件配置

1. 初始化ADC模块:

在此之前需要建立一个变量用于存放转换后的数据

  1. void ADC_init(void)
  2. {
  3. GPIO_InitTypeDef gpio_info;
  4. ADC_CommonInitTypeDef adc_common_info;
  5. ADC_InitTypeDef adc_Init_info;
  6. NVIC_InitTypeDef NVIC_InitStructure;
  7. //初始化ADC
  8. //1.初始化引脚 PC3
  9. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
  10. gpio_info.GPIO_Mode = GPIO_Mode_AN;
  11. gpio_info.GPIO_OType = GPIO_OType_PP;
  12. gpio_info.GPIO_Pin = GPIO_Pin_3;
  13. gpio_info.GPIO_PuPd = GPIO_PuPd_NOPULL;
  14. gpio_info.GPIO_Speed = GPIO_High_Speed;
  15. GPIO_Init(GPIOC,&gpio_info);
  16. //初始化ADC时钟
  17. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  18. //2.初始化ADC common
  19. adc_common_info.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //不适用DMA
  20. adc_common_info.ADC_Mode = ADC_Mode_Independent; //独立模式
  21. adc_common_info.ADC_Prescaler = ADC_Prescaler_Div6;
  22. adc_common_info.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;
  23. ADC_CommonInit(&adc_common_info);
  24. //3.初始
  25. adc_Init_info.ADC_ContinuousConvMode = ENABLE;//使用连续转换模式,mcu会自动进行多次转换
  26. adc_Init_info.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
  27. adc_Init_info.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//外部触发源
  28. adc_Init_info.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//不使用外部触发源
  29. adc_Init_info.ADC_NbrOfConversion = 1;//只转换PC3一个通道,所以写1
  30. adc_Init_info.ADC_Resolution = ADC_Resolution_12b;
  31. adc_Init_info.ADC_ScanConvMode = DISABLE;//只有一个采集通道不用扫描
  32. ADC_Init(ADC1,&adc_Init_info);
  33. //4,配置转换通道
  34. //PC3引脚对应
  35. ADC_RegularChannelConfig(ADC1 ,ADC_Channel_13,1,ADC_SampleTime_56Cycles);
  36. //5.开启中断,这样当ADC转换完成之后能立即通知用户
  37. ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
  38. //5.1配置中断优先级
  39. NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn; //PA0 对应的是EXTI0_IRQn
  40. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  41. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//主优先级
  42. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级
  43. NVIC_Init(&NVIC_InitStructure);
  44. //6.使能ADC
  45. ADC_Cmd(ADC1 ,ENABLE);
  46. //7.启动开始进行转换
  47. ADC_SoftwareStartConv(ADC1);
  48. }

2. 中断处理

如果需要,设置中断服务程序,以便在转换完成后及时处理数据。

  1. void ADC_IRQHandler()
  2. {
  3. //判断是不是ADC1转换完成中断
  4. if(ADC_GetITStatus(ADC1 ,ADC_IT_EOC)==SET)
  5. {
  6. //读取ADC转换得到的数值
  7. adc_value = ADC_GetConversionValue(ADC1);
  8. //清除中断标志
  9. ADC_ClearITPendingBit(ADC1,ADC_IT_EOC );
  10. }
  11. }

3. 数据采集函数编写:

创建一个函数,用于启动ADC转换并读取转换后的数据。

  1. uint16_t ADC_GetValue(void)
  2. {
  3. return adc_value;
  4. }

第四部分:数据处理与电压输出

1. 数据校准:

对采集到的数据进行校准,消除系统误差。

2. 电压计算:

根据ADC的分辨率和参考电压,将数字值转换为实际电压值。本文采用12位ADC

DCV = (ADC_GetValue() * 3.3f) / 4096.0f; // 4096是12位ADC的最大数值

3. 输出接口配置:

选择适当的输出接口,如USART、LCD或DAC,将电压数据显示或输出。

第五部分:实战演练

1. 示例代码分析:

ADC.C文件
  1. uint16_t adc_value = 0;//保存ADC转换得到的数据
  2. void ADC_IRQHandler()
  3. {
  4. //判断是不是ADC1转换完成中断
  5. if(ADC_GetITStatus(ADC1 ,ADC_IT_EOC)==SET)
  6. {
  7. //读取ADC转换得到的数值
  8. adc_value = ADC_GetConversionValue(ADC1);
  9. //清除中断标志
  10. ADC_ClearITPendingBit(ADC1,ADC_IT_EOC );
  11. }
  12. }
  13. uint16_t ADC_GetValue(void)
  14. {
  15. return adc_value;
  16. }
  17. void ADC_init(void)
  18. {
  19. GPIO_InitTypeDef gpio_info;
  20. ADC_CommonInitTypeDef adc_common_info;
  21. ADC_InitTypeDef adc_Init_info;
  22. NVIC_InitTypeDef NVIC_InitStructure;
  23. //初始化ADC
  24. //1.初始化引脚 PC3
  25. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
  26. gpio_info.GPIO_Mode = GPIO_Mode_AN;
  27. gpio_info.GPIO_OType = GPIO_OType_PP;
  28. gpio_info.GPIO_Pin = GPIO_Pin_3;
  29. gpio_info.GPIO_PuPd = GPIO_PuPd_NOPULL;
  30. gpio_info.GPIO_Speed = GPIO_High_Speed;
  31. GPIO_Init(GPIOC,&gpio_info);
  32. //初始化ADC时钟
  33. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  34. //2.初始化ADC common
  35. adc_common_info.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //不适用DMA
  36. adc_common_info.ADC_Mode = ADC_Mode_Independent; //独立模式
  37. adc_common_info.ADC_Prescaler = ADC_Prescaler_Div6;
  38. adc_common_info.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;
  39. ADC_CommonInit(&adc_common_info);
  40. //3.初始
  41. adc_Init_info.ADC_ContinuousConvMode = ENABLE;//使用连续转换模式,mcu会自动进行多次转换
  42. adc_Init_info.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
  43. adc_Init_info.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//外部触发源
  44. adc_Init_info.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//不使用外部触发源
  45. adc_Init_info.ADC_NbrOfConversion = 1;//只转换PC3一个通道,所以写1
  46. adc_Init_info.ADC_Resolution = ADC_Resolution_12b;
  47. adc_Init_info.ADC_ScanConvMode = DISABLE;//只有一个采集通道不用扫描
  48. ADC_Init(ADC1,&adc_Init_info);
  49. //4,配置转换通道
  50. //PC3引脚对应
  51. ADC_RegularChannelConfig(ADC1 ,ADC_Channel_13,1,ADC_SampleTime_56Cycles);
  52. //5.开启中断,这样当ADC转换完成之后能立即通知用户
  53. ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
  54. //5.1配置中断优先级
  55. NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn; //PA0 对应的是EXTI0_IRQn
  56. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  57. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//主优先级
  58. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级
  59. NVIC_Init(&NVIC_InitStructure);
  60. //6.使能ADC
  61. ADC_Cmd(ADC1 ,ENABLE);
  62. //7.启动开始进行转换
  63. ADC_SoftwareStartConv(ADC1);
  64. }
ADC.h文件
  1. #ifndef _ADC_H_
  2. #define _ADC_H_
  3. #include "stm32F4xx.h"
  4. uint16_t ADC_GetValue(void);
  5. void ADC_init(void);
  6. #endif
主函数main
  1. int main(void)
  2. {
  3. GPIO_InitTypeDef gpio_info;
  4. Delay_init();
  5. ADC_init();
  6. ADC_GetValue();
  7. UART_Init(115200);
  8. USART_Cmd(USART1,ENABLE);
  9. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE);
  10. while(1)
  11. {
  12. float DVC=ADC_GetValue();
  13. printf( "%.2f\r\n",DVC/4096*3.3);
  14. Delay_ms (100);
  15. }
  16. }

注意事项

- 确保参考电压稳定且准确,因为它直接影响到电压转换的准确性。
- 如果输入电压超出ADC的规定范围,可能需要使用外部电路(如运算放大器和分压器)来调整电压水平。
- 在某些应用中,可能还需要考虑ADC的线性误差、温漂和噪声等因素,以提高测量的精度。

结语

通过本文的指导,相信读者已经对STM32嵌入式系统中的ADC数据采集与电压输出有了深入的理解。实践是检验真理的唯一标准,建议读者动手实验,不断优化自己的设计。未来,随着技术的进步和应用场景的拓展,我们期待看到更多创新的应用案例。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号