layout: post

tags: [STM32]

comments: true

什么是ADC?

Analog to Digital Converter,将模拟信号转换成数字的模数转换器,后面可能还会接触到DAC,恰恰相反,是将数字信号转换成模拟信号。具体的原理可以自行找搜索引擎,可以得到更好的答案。

STM32 ADC的特性

参考手册给出ADC的功能十分丰富,具体如下:

  • 12 bit分辨率,量化到0-4096的范围;
  • 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
  • 单次和连续转换模式
  • 从通道0到通道n的自动扫描模式
  • 自校准
  • 带内嵌数据一致性的数据对齐
  • 采样间隔可以按通道分别编程
  • 规则转换和注入转换均有外部触发选项
  • 间断模式

    本文只讨论规则采样和注入采样,并给出具体的代码实现,更多细节还需要参考《STM32参考手册》

采样模式

  • 规则采样:相当于软件触发采样,可以在程序里主动调用规则采样去读取具体的ADC值,同样
  • 注入采样:相当于中断,所以需要具体的触发源,比如外部的信号可以触发注入采样,ADC转换成功之后,便会触发ADC中断,在中断服务子程序中,就可以读取ADC值;

触发源可以是外部信号,也可以是定时器的触发信号;标准库中注入模式的触发信号如下所示;



注入组的外部触发信号

  1. /** @defgroup ADC_external_trigger_sources_for_injected_channels_conversion
  2. * @{
  3. */
  4. #define ADC_ExternalTrigInjecConv_T2_TRGO ((uint32_t)0x00002000) /*!< For ADC1 and ADC2 */
  5. #define ADC_ExternalTrigInjecConv_T2_CC1 ((uint32_t)0x00003000) /*!< For ADC1 and ADC2 */
  6. #define ADC_ExternalTrigInjecConv_T3_CC4 ((uint32_t)0x00004000) /*!< For ADC1 and ADC2 */
  7. #define ADC_ExternalTrigInjecConv_T4_TRGO ((uint32_t)0x00005000) /*!< For ADC1 and ADC2 */
  8. #define ADC_ExternalTrigInjecConv_Ext_IT15_TIM8_CC4 ((uint32_t)0x00006000) /*!< For ADC1 and ADC2 */
  9. #define ADC_ExternalTrigInjecConv_T1_TRGO ((uint32_t)0x00000000) /*!< For ADC1, ADC2 and ADC3 */
  10. #define ADC_ExternalTrigInjecConv_T1_CC4 ((uint32_t)0x00001000) /*!< For ADC1, ADC2 and ADC3 */
  11. #define ADC_ExternalTrigInjecConv_None ((uint32_t)0x00007000) /*!< For ADC1, ADC2 and ADC3 */
  12. #define ADC_ExternalTrigInjecConv_T4_CC3 ((uint32_t)0x00002000) /*!< For ADC3 only */
  13. #define ADC_ExternalTrigInjecConv_T8_CC2 ((uint32_t)0x00003000) /*!< For ADC3 only */
  14. #define ADC_ExternalTrigInjecConv_T8_CC4 ((uint32_t)0x00004000) /*!< For ADC3 only */
  15. #define ADC_ExternalTrigInjecConv_T5_TRGO ((uint32_t)0x00005000) /*!< For ADC3 only */
  16. #define ADC_ExternalTrigInjecConv_T5_CC4 ((uint32_t)0x00006000) /*!< For ADC3 only */

规则组的外部触发信号

  1. #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
  2. #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
  3. #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
  4. #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
  5. #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
  6. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
  7. #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
  8. #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */
  9. #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) /*!< For ADC3 only */
  10. #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) /*!< For ADC3 only */
  11. #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) /*!< For ADC3 only */
  12. #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) /*!< For ADC3 only */
  13. #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) /*!< For ADC3 only */
  14. #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) /*!< For ADC3 only */

从参考手册中可以看到ADC的框架,注入通道转换成功之后,标志位JEOC使能,然后JEOCIE中断位被使能,最终触发ADC中断;

采样时间

标准库中对于采样周期的定义;

  1. #define ADC_SampleTime_1Cycles5 ((uint8_t)0x00)
  2. #define ADC_SampleTime_7Cycles5 ((uint8_t)0x01)
  3. #define ADC_SampleTime_13Cycles5 ((uint8_t)0x02)
  4. #define ADC_SampleTime_28Cycles5 ((uint8_t)0x03)
  5. #define ADC_SampleTime_41Cycles5 ((uint8_t)0x04)
  6. #define ADC_SampleTime_55Cycles5 ((uint8_t)0x05)
  7. #define ADC_SampleTime_71Cycles5 ((uint8_t)0x06)
  8. #define ADC_SampleTime_239Cycles5 ((uint8_t)0x07)

TCONV = 采样时间+ 12.5个周期

  1. ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);

ADCCLK=14MHz,采样时间为1.5周期(ADC_SampleTime_1Cycles5)

采样时间TCONV = 1.5 + 12.5 = 14周期 = 1μs

代码实现

基于ST标准库V3.5,实现了ADC规则采样和注入采样两种模式;

current.h

  1. #ifndef CURRENT_H
  2. #define CURRENT_H
  3. #include <stdint.h>
  4. #define RES_IA 1024 //采样电阻A
  5. #define RES_IB 1024 //采样电阻B
  6. /**
  7. * Ia--->PA0/ADC0
  8. * |------------>PA2/ADC2
  9. * Ib--->PA1/ADC1
  10. * |------------>PA3/ADC3
  11. */
  12. void cur_fbk_init(void);
  13. uint16_t cur_fbk_get_Ia(void);
  14. uint16_t cur_fbk_get_Ia_avl(uint8_t sample_times);
  15. uint16_t cur_fbk_get_Ib(void);
  16. uint16_t cur_fbk_get_Ib_avl(uint8_t sample_times);
  17. uint16_t get_inject_ia(void);
  18. uint16_t get_inject_ib(void);
  19. int16_t cur_fbk_get_theta(void);
  20. #endif

current.c

  1. #include "current.h"
  2. #include "stm32f10x.h"
  3. #include "stm32f10x_gpio.h"
  4. #include "stm32f10x_adc.h"
  5. #include "stm32f10x_rcc.h"
  6. #include <stdint.h>
  7. #if 1
  8. #define IA_CHANNEL_DRI ADC_Channel_0
  9. #define IB_CHANNEL_DRI ADC_Channel_1
  10. #else
  11. #define IA_CHANNEL_DRI ADC_Channel_2
  12. #define IB_CHANNEL_DRI ADC_Channel_3
  13. #endif
  14. volatile uint16_t Ia_val = 0;
  15. volatile uint16_t Ib_val = 0;
  16. static void cur_fbk_irq_init(void){
  17. NVIC_InitTypeDef NVIC_InitStructure;
  18. /* Configure and enable ADC interrupt */
  19. NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
  20. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  21. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  22. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  23. NVIC_Init(&NVIC_InitStructure);
  24. }
  25. static void cur_fbk_adc_init(void){
  26. ADC_DeInit(ADC1);
  27. ADC_InitTypeDef ADC_InitStructure;
  28. /* ADC1 configuration ------------------------------------------------------*/
  29. ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  30. ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  31. ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  32. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  33. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  34. ADC_InitStructure.ADC_NbrOfChannel = 2;
  35. /* Set injected sequencer length */
  36. ADC_InjectedSequencerLengthConfig(ADC1, 2);
  37. /* ADC1 injected channel Configuration */
  38. ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5);
  39. ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_71Cycles5);
  40. //ADC_InjectedChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_71Cycles5);
  41. //ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_71Cycles5);
  42. /* ADC1 injected external trigger configuration */
  43. //ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_CC4);
  44. ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None);
  45. //ADC_SetInjectedOffset(ADC1, ADC_InjectedChannel_1,2048);
  46. //ADC_SetInjectedOffset(ADC1, ADC_InjectedChannel_2,2048);
  47. /* Enable automatic injected conversion start after regular one */
  48. ADC_AutoInjectedConvCmd(ADC1, ENABLE);
  49. /* Enable ADC1 DMA */
  50. ADC_DMACmd(ADC1, ENABLE);
  51. /* Enable ADC1 external trigger */
  52. ADC_ExternalTrigConvCmd(ADC1, ENABLE);
  53. ADC_Init(ADC1, &ADC_InitStructure);
  54. ADC_Cmd(ADC1, ENABLE);
  55. ADC_ResetCalibration(ADC1);
  56. while(ADC_GetResetCalibrationStatus(ADC1)){
  57. /**
  58. TODO
  59. timeout_detect
  60. */
  61. }
  62. ADC_StartCalibration(ADC1);
  63. while(ADC_GetCalibrationStatus(ADC1)){
  64. /**
  65. TODO
  66. timeout_detect
  67. */
  68. }
  69. ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);
  70. }
  71. static void cur_fbk_rcc_init(void){
  72. /* ADCCLK = PCLK2/6 */
  73. RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  74. /* Enable peripheral clocks ------------------------------------------------*/
  75. /* Enable DMA1 and DMA2 clocks */
  76. //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_DMA2, ENABLE);
  77. /* Enable ADC1 and GPIOA clocks */
  78. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
  79. }
  80. static void cur_fbk_pin_init(void){
  81. GPIO_InitTypeDef GPIO_InitStructure;
  82. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  83. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  84. GPIO_Init(GPIOA, &GPIO_InitStructure);
  85. }
  86. static uint16_t cur_fbk_get_ad_val(uint8_t channel){
  87. ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5 );
  88. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能软件转换功能
  89. //等待转换结束
  90. /*
  91. EOC:转换结束位 (End of conversion)
  92. 该位由硬件在(规则或注入)通道组转换结束时设置,由软件清除或由读取ADC_DR时清除
  93. 0:转换未完成;
  94. 1:转换完成。
  95. */
  96. while((ADC1->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC){}
  97. //while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )){}
  98. return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
  99. }
  100. void cur_fbk_init(void){
  101. cur_fbk_rcc_init();
  102. cur_fbk_pin_init();
  103. cur_fbk_irq_init();
  104. cur_fbk_adc_init();
  105. }
  106. uint16_t cur_fbk_get_Ia_avl(uint8_t sample_times){
  107. uint32_t Ia_sum = 0;
  108. int8_t i;
  109. for(; i < sample_times; i++){
  110. Ia_sum+=cur_fbk_get_Ia();
  111. }
  112. return (uint16_t)(Ia_sum/sample_times);
  113. }
  114. uint16_t cur_fbk_get_Ib_avl(uint8_t sample_times){
  115. uint32_t Ib_sum = 0;
  116. int8_t i = 0;
  117. for(;i < sample_times; i++){
  118. Ib_sum+=cur_fbk_get_Ib();
  119. }
  120. return (uint16_t)(Ib_sum/sample_times);
  121. }
  122. uint16_t cur_fbk_get_Ia(void){
  123. return cur_fbk_get_ad_val(IA_CHANNEL_DRI);
  124. }
  125. uint16_t cur_fbk_get_Ib(void){
  126. return cur_fbk_get_ad_val(IB_CHANNEL_DRI);
  127. }
  128. int16_t cur_fbk_get_theta(void){
  129. return 0;
  130. }
  131. /******************************************************************************/
  132. /* STM32F10x Peripherals Interrupt Handlers */
  133. /******************************************************************************/
  134. /**
  135. * @brief This function handles ADC1 and ADC2 global interrupts requests.
  136. * @param None
  137. * @retval None
  138. */
  139. void ADC1_2_IRQHandler(void)
  140. {
  141. Ia_val = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);
  142. Ib_val = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);
  143. /* Clear ADC1 JEOC pending interrupt bit */
  144. ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);
  145. }
  146. uint16_t get_inject_ia(void){
  147. return Ia_val;
  148. }
  149. uint16_t get_inject_ib(void){
  150. return Ib_val;
  151. }

STM32 ADC多通道规则采样和注入采样的更多相关文章

  1. 【stm32】ADC的规则通道和注入通道混合使用

    之前完成了规则通道DMA的数据传输了,不过平时在使用ADC的时候可能就会遇到很多情况,不可能就这样简单的按规则通道来采样,DMA存储,使用数据的:可能有时候会需要立刻采样,那样我们就需要利用到注入通道 ...

  2. STM32 ADC多通道转换DMA模式与非DMA模式两种方法(HAL库)

    一.非DMA模式(转) 说明:这个是自己刚做的时候百度出来的,不是我自己做出来的,因为感觉有用就保存下来做学习用,原文链接:https://blog.csdn.net/qq_24815615/arti ...

  3. STM32—ADC多通道采集电压

    文章目录 ADC详解 程序说明 函数主体 引脚配置 ADC和DMA配置 主函数 ADC详解 前面的博客中详细介绍了STM32中ADC的相关信息,这篇博客是对ADC内容的一个总结提升,ADC的详细介绍: ...

  4. STM32 ADC多通道转换

    描述:用ADC连续采集11路模拟信号,并由DMA传输到内存.ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ.在每次转换结束后,由DMA循环将转换的数据传输到内存中.ADC可以连续采集N ...

  5. STM32 双ADC同步规则采样

      最近需要用到两个ADC对电压电流进行同步采样,看了一下STM32的ADC介绍,发现STM32最多有3个独立ADC,有在双AD模式下可以进行同步测量,正好满足我的要求.参考官方给的例子在结合自己的需 ...

  6. Hi3518EV200平台ADC多通道采样

    Hi3518EV200平台ADC多通道采样流程 Hi3518EV200 ADC 本文针对Hi3518EV200平台处理器,通过ADC单次采样方式,实现对多通道(1~4通道)ADC进行采样控制.本文仅仅 ...

  7. STM32 ADC 采样 频率的确定

    一 STM32 ADC 采样频率的确定 1.       : 先看一些资料,确定一下ADC 的时钟: (1),由时钟控制器提供的ADCCLK 时钟和PCLK2(APB2 时钟)同步.CLK 控制器为A ...

  8. stm32中adc的常规通道和注入通道的区别

    STM32的每个ADC模块通过内部的模拟多路开关,可以切换到不同的输入通道并进行转换.STM32特别地加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换. 有2种划 ...

  9. STM32—ADC详解

    文章目录 一.ADC简介 二.ADC功能框图讲解 1.电压输入范围 2.输入通道 3.转换顺序 4.触发源 5.转换时间 6.数据寄存器 7.中断 8.电压转换 三.初始化结构体 四.单通道电压采集 ...

随机推荐

  1. ADO.NET 事务控制

    在ADO.NET 中,可以使用Connection 和Transaction 对象来控制事务.若要执行事务,请执行下列操作: 1.调用Connection 对象的BeginTransaction 方法 ...

  2. stand up meeting 1/12/2016

    part 组员                工作              工作耗时/h 明日计划 工作耗时/h    UI 冯晓云  UI测试和调整:页面跳转调整    3 查漏补缺,扫除UI b ...

  3. A Bug's Life POJ - 2492 (种类或带权并查集)

    这个题目的写法有很多,用二分图染色也可以写,思路很好想,这里我们用关于并查集的两种写法来做. 题目大意:输入x,y表示x和y交配,然后判断是否有同性恋. 1 带权并查集: 我们可以用边的权值来表示一种 ...

  4. win10下cuda安装以及利用anaconda安装pytorch-gpu过程

    安装环境:win10+2070super 1.Cuda的下载安装及配置 (1)测试本机独立显卡是否支持CUDA的安装,点击此处查询显卡是否在列表中. (2)查看自己是否能右键找到NVIDA控制面板,如 ...

  5. OkHttp 优雅封装 OkHttps 之 回调线程魔变

    第一篇:OkHttp 优雅封装 HttpUtils 之 气海雪山初探 第二篇:OkHttp 优雅封装 HttpUtils 之 上传下载解密 简介 HttpUtils 从 v2.3.0 之后便重命名了, ...

  6. Redis Linux安装+配置

    1.进入指定目录,下载资源(也可本地下载后复制到指定目录) wget http://download.redis.io/releases/redis-5.0.5.tar.gz 2.解压到指定目录 ta ...

  7. Python之学会测试,让开发更加高效(一)

      前几天,听了公司某位大佬关于编程心得的体会,其中讲到了"测试驱动开发",感觉自己的测试技能薄弱,因此,写下这篇文章,希望对测试能有个入门.这段时间,笔者也体会到了测试的价值,一 ...

  8. jeecg ant design vue一级菜单跳到外部页面——例如跳到百度

    需求:点击首页跳到百度新打开的页面 找到SideMenu.vue   对应的inde.js找到renderMenuItem 函数.加一个判断 if(menu.meta.url=='https://ww ...

  9. thinkphp5.1+layui2.x 时间戳转换为日期格式

    layui.use(['table','util'],function(){ var table = layui.table,form = layui.form; table.render({ ele ...

  10. 讲讲python中函数的参数

    python中函数的参数 形参:定义函数时代表函数的形式参数 实参:调用函数时传入的实际参数 列如: def f(x,y): # x,y形参 print(x, y) f(1, 2) # 1, 2 实参 ...