STM32 ADC多通道规则采样和注入采样

2024-05-18 18:32

本文主要是介绍STM32 ADC多通道规则采样和注入采样,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


layout: post
tags: [STM32]
comments: true

文章目录

    • layout: post tags: [STM32] comments: true
    • 什么是ADC?
    • STM32 ADC的特性
    • 采样模式
    • 采样时间
    • 代码实现

什么是ADC?

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

STM32 ADC的特性

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

  • 12 bit分辨率,量化到0-4096的范围;
  • 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
  • 单次和连续转换模式
  • 从通道0到通道n的自动扫描模式
  • 自校准
  • 带内嵌数据一致性的数据对齐
  • 采样间隔可以按通道分别编程
  • 规则转换和注入转换均有外部触发选项
  • 间断模式
    本文只讨论规则采样和注入采样,并给出具体的代码实现,更多细节还需要参考《STM32参考手册》

采样模式

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

触发源可以是外部信号,也可以是定时器的触发信号;标准库中注入模式的触发信号如下所示;
在这里插入图片描述
注入组的外部触发信号

/** @defgroup ADC_external_trigger_sources_for_injected_channels_conversion * @{*/#define ADC_ExternalTrigInjecConv_T2_TRGO           ((uint32_t)0x00002000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigInjecConv_T2_CC1            ((uint32_t)0x00003000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigInjecConv_T3_CC4            ((uint32_t)0x00004000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigInjecConv_T4_TRGO           ((uint32_t)0x00005000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigInjecConv_Ext_IT15_TIM8_CC4 ((uint32_t)0x00006000) /*!< For ADC1 and ADC2 */#define ADC_ExternalTrigInjecConv_T1_TRGO           ((uint32_t)0x00000000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigInjecConv_T1_CC4            ((uint32_t)0x00001000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigInjecConv_None              ((uint32_t)0x00007000) /*!< For ADC1, ADC2 and ADC3 */#define ADC_ExternalTrigInjecConv_T4_CC3            ((uint32_t)0x00002000) /*!< For ADC3 only */
#define ADC_ExternalTrigInjecConv_T8_CC2            ((uint32_t)0x00003000) /*!< For ADC3 only */
#define ADC_ExternalTrigInjecConv_T8_CC4            ((uint32_t)0x00004000) /*!< For ADC3 only */
#define ADC_ExternalTrigInjecConv_T5_TRGO           ((uint32_t)0x00005000) /*!< For ADC3 only */
#define ADC_ExternalTrigInjecConv_T5_CC4            ((uint32_t)0x00006000) /*!< For ADC3 only */

规则组的外部触发信号

#define ADC_ExternalTrigConv_T1_CC1                ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T1_CC2                ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T2_CC2                ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T3_TRGO               ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T4_CC4                ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO    ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */#define ADC_ExternalTrigConv_T1_CC3                ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */#define ADC_ExternalTrigConv_T3_CC1                ((uint32_t)0x00000000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T2_CC3                ((uint32_t)0x00020000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T8_CC1                ((uint32_t)0x00060000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T8_TRGO               ((uint32_t)0x00080000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T5_CC1                ((uint32_t)0x000A0000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T5_CC3                ((uint32_t)0x000C0000) /*!< For ADC3 only */

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

采样时间

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

#define ADC_SampleTime_1Cycles5                    ((uint8_t)0x00)
#define ADC_SampleTime_7Cycles5                    ((uint8_t)0x01)
#define ADC_SampleTime_13Cycles5                   ((uint8_t)0x02)
#define ADC_SampleTime_28Cycles5                   ((uint8_t)0x03)
#define ADC_SampleTime_41Cycles5                   ((uint8_t)0x04)
#define ADC_SampleTime_55Cycles5                   ((uint8_t)0x05)
#define ADC_SampleTime_71Cycles5                   ((uint8_t)0x06)
#define ADC_SampleTime_239Cycles5                  ((uint8_t)0x07)

TCONV = 采样时间+ 12.5个周期

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

#ifndef CURRENT_H
#define CURRENT_H
#include <stdint.h>#define RES_IA	1024	//采样电阻A
#define RES_IB	1024	//采样电阻B/*** Ia--->PA0/ADC0*	|------------>PA2/ADC2* Ib--->PA1/ADC1*	|------------>PA3/ADC3*/void cur_fbk_init(void);uint16_t cur_fbk_get_Ia(void);
uint16_t cur_fbk_get_Ia_avl(uint8_t sample_times);
uint16_t cur_fbk_get_Ib(void);
uint16_t cur_fbk_get_Ib_avl(uint8_t sample_times);uint16_t get_inject_ia(void);
uint16_t get_inject_ib(void);int16_t cur_fbk_get_theta(void);#endif

current.c

#include "current.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_rcc.h"
#include <stdint.h>#if 1
#define IA_CHANNEL_DRI ADC_Channel_0
#define IB_CHANNEL_DRI ADC_Channel_1
#else
#define IA_CHANNEL_DRI ADC_Channel_2
#define IB_CHANNEL_DRI ADC_Channel_3
#endifvolatile uint16_t Ia_val = 0;
volatile uint16_t Ib_val = 0;static void cur_fbk_irq_init(void){NVIC_InitTypeDef NVIC_InitStructure;/* Configure and enable ADC interrupt */NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}static void cur_fbk_adc_init(void){ADC_DeInit(ADC1);ADC_InitTypeDef ADC_InitStructure;/* ADC1 configuration ------------------------------------------------------*/ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfChannel = 2;/* Set injected sequencer length */ADC_InjectedSequencerLengthConfig(ADC1, 2);/* ADC1 injected channel Configuration */ ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5);ADC_InjectedChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_71Cycles5);//ADC_InjectedChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_71Cycles5);//ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_71Cycles5);	/* ADC1 injected external trigger configuration *///ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_CC4);ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None);//ADC_SetInjectedOffset(ADC1, ADC_InjectedChannel_1,2048);//ADC_SetInjectedOffset(ADC1, ADC_InjectedChannel_2,2048);/* Enable automatic injected conversion start after regular one */ADC_AutoInjectedConvCmd(ADC1, ENABLE);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 external trigger */ ADC_ExternalTrigConvCmd(ADC1, ENABLE);ADC_Init(ADC1, &ADC_InitStructure);ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1)){/**TODOtimeout_detect*/}ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1)){/**TODOtimeout_detect*/}ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);
}static void cur_fbk_rcc_init(void){/* ADCCLK = PCLK2/6 */RCC_ADCCLKConfig(RCC_PCLK2_Div6); /* Enable peripheral clocks ------------------------------------------------*//* Enable DMA1 and DMA2 clocks *///RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_DMA2, ENABLE);/* Enable ADC1 and GPIOA clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
}static void cur_fbk_pin_init(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);		}static uint16_t cur_fbk_get_ad_val(uint8_t channel){ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5 );ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能软件转换功能//等待转换结束/*EOC:转换结束位 (End of conversion)该位由硬件在(规则或注入)通道组转换结束时设置,由软件清除或由读取ADC_DR时清除0:转换未完成;1:转换完成。 		*/while((ADC1->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC){}//while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )){}return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
}void cur_fbk_init(void){cur_fbk_rcc_init();cur_fbk_pin_init();cur_fbk_irq_init();cur_fbk_adc_init();
}uint16_t cur_fbk_get_Ia_avl(uint8_t sample_times){uint32_t Ia_sum = 0;int8_t i;for(; i < sample_times; i++){Ia_sum+=cur_fbk_get_Ia();}return (uint16_t)(Ia_sum/sample_times);
}uint16_t cur_fbk_get_Ib_avl(uint8_t sample_times){uint32_t Ib_sum = 0;int8_t i = 0;for(;i < sample_times; i++){Ib_sum+=cur_fbk_get_Ib();}return (uint16_t)(Ib_sum/sample_times);
}uint16_t cur_fbk_get_Ia(void){return cur_fbk_get_ad_val(IA_CHANNEL_DRI);
}uint16_t cur_fbk_get_Ib(void){return cur_fbk_get_ad_val(IB_CHANNEL_DRI);
}int16_t cur_fbk_get_theta(void){return 0;
}/******************************************************************************/
/*            STM32F10x Peripherals Interrupt Handlers                        */
/******************************************************************************//*** @brief  This function handles ADC1 and ADC2 global interrupts requests.* @param  None* @retval None*/
void ADC1_2_IRQHandler(void)
{Ia_val = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1);Ib_val = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_2);/* Clear ADC1 JEOC pending interrupt bit */ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);
}uint16_t get_inject_ia(void){return Ia_val;
}uint16_t get_inject_ib(void){return Ib_val;
}

这篇关于STM32 ADC多通道规则采样和注入采样的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/995650

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

Adblock Plus官方规则Easylist China说明与反馈贴(2015.12.15)

-------------------------------特别说明--------------------------------------- 视频广告问题:因Adblock Plus的局限,存在以下现象,优酷、搜狐、17173黑屏并倒数;乐视、爱奇艺播放广告。因为这些视频网站的Flash播放器被植入了检测代码,而Adblock Plus无法修改播放器。 如需同时使用ads

PHP防止SQL注入详解及防范

SQL 注入是PHP应用中最常见的漏洞之一。事实上令人惊奇的是,开发者要同时犯两个错误才会引发一个SQL注入漏洞。 一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)。这两个重要的步骤缺一不可,需要同时加以特别关注以减少程序错误。 对于攻击者来说,进行SQL注入攻击需要思考和试验,对数据库方案进行有根有据的推理非常有必要(当然假设攻击者看不到你的

PHP防止SQL注入的方法(2)

如果用户输入的是直接插入到一个SQL语句中的查询,应用程序会很容易受到SQL注入,例如下面的例子: $unsafe_variable = $_POST['user_input'];mysql_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')"); 这是因为用户可以输入类似VALUE”); DROP TA

PHP防止SQL注入的方法(1)

(1)mysql_real_escape_string – 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count(*) as ctr from users where username ='".mysql_real_escape_string($username)."' and password='". mysql_r