定时器TIM触发ADC采样,DMA搬运到内存(外部触发)

TIM+ADC+DMA原理
一般情况下,当我们需要进行采样的时候,需要用到ADC。例如:需要对某个信号进行定时采样(也就是隔一段时间,比如说2ms)。

本文提供的解决方案是:使用ADC的定时器触发ADC单次转换的功能,然后使用DMA进行数据的搬运!

这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能(即采样速率),然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换完成中断,这样每次转换完成就会产生中断。

主要需要解决的一个问题:定时器触发ADC采样,如何实现?

定时器触发ADC采样,是属于外部触发转换的一种方式。在《STM32中文参考手册》中,找到了关于这部分的内容:

配合上ADC外设的框图:

可以看出,STM32的ADC1和ADC2用于规则通道的外部触发可以有以上6个事件信号,本文使用TIM2_CH2触发ADC1。

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //使用外部触发模式
ADC_ExternalTrigConvCmd(ADC1, ENABLE); //设置外部触发模式使能
1
2
对于ADC的配置不太熟悉的,可以参考博文:【STM32】ADC的基本原理、寄存器(超基础、详细版)、
【STM32】ADC库函数、一般步骤详解(实例:内部温度传感器实验)

同时注意一下外部触发的触发条件:当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换。

如何有上升沿呢?定时器配置为PWM输出模式,这是重点。通过调用TIM_OC2Init(Tim2, & TIM_OCInitStructure),完成对TIM2_CH2的PWM配置。

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 1000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
TIM_OC2Init(TIM2, & TIM_OCInitStructure); //初始化外设TIM2_CH2

对于PWM的配置不太熟悉的,可以参考博文:【STM32】通用定时器的PWM输出(实例:PWM输出)、【STM32】通用定时器的基本原理(实例:定时器中断)

其次,就是DMA将采样的数据由ADC1外设搬运到内存中。

配置DMA的外设地址和内存地址,并设置方向为从外设到内存即可。

可以看到ADC1可以作为DMA1的外设请求信号,那么ADC1的地址在哪里呢?

根据ADC1寄存器组的起始地址,找到偏移值:

最终得到ADC1_DR_Address=0x4001244C。

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC1地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向(从外设到内存)
1
2
3
对于DMA的配置不太熟悉的,可以参考博文:STM32】DMA基本原理、寄存器、库函数(DMA一般步骤)

STM32全部源码
本文采用的外设为:TIM2_CH2外部触发PA6(ADC1_CH6)采样,通过DMA1搬运到内存。

#include “adc.h”

volatile uint16_t ADC_ConvertedValue; //ADC采样的数据
#define ADC1_DR_Address ((u32)0x4001244C) //ADC1的地址

//TIM2配置,arr为重加载值,psc为预分频系数
void TIM2_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 		//时钟使能

//定时器TIM2初始化
TIM_TimeBaseStructure.TIM_Period = arr; 		//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; 			//设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 		//设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 		//TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);			//根据指定的参数初始化TIMx的时间基数单位

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;		//选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;		//比较输出使能
TIM_OCInitStructure.TIM_Pulse = 1000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;		//输出极性:TIM输出比较极性低
TIM_OC2Init(TIM2, & TIM_OCInitStructure);		//初始化外设TIM2_CH2

TIM_Cmd(TIM2, ENABLE); 			//使能TIMx
TIM_CtrlPWMOutputs(TIM2, ENABLE); 

}

//DMA1配置
void DMA1_Init()
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);	  			//使能ADC1通道时钟

//DMA1初始化
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;				//ADC1地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; 		//内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 				//方向(从外设到内存)
DMA_InitStructure.DMA_BufferSize = 1; 						//传输内容的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 		//外设地址固定
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 			//内存地址固定
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;    //内存数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; 		//DMA模式:循环传输
DMA_InitStructure.DMA_Priority = DMA_Priority_High ; 		//优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   		//禁止内存到内存的传输
DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //配置DMA1

DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);		//使能传输完成中断

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

DMA_Cmd(DMA1_Channel1,ENABLE);

}

//GPIO配置,PA6
void GPIO_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	  //使能GPIOA时钟

//PA6 作为模拟通道输入引脚   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);  

}

void Adc_Init(){
ADC_InitTypeDef ADC_InitStructure;

TIM2_Init(30000,7199);		//72000000/7200=10000Hz,每3s采集一次
DMA1_Init();
GPIO_Init();

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	  //使能ADC1通道时钟

//ADC1初始化
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 			//独立ADC模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;  			//关闭扫描方式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;			//关闭连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   	//使用外部触发模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 			//采集数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; 			//要转换的通道数目
ADC_Init(ADC1, &ADC_InitStructure);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);				//配置ADC时钟,为PCLK2的6分频,即12Hz
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_239Cycles5);		//配置ADC1通道6为239.5个采样周期 

//使能ADC、DMA
ADC_DMACmd(ADC1,ENABLE);
ADC_Cmd(ADC1,ENABLE);

ADC_ResetCalibration(ADC1);				//复位校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));				//等待校准寄存器复位完成

ADC_StartCalibration(ADC1);				//ADC校准
while(ADC_GetCalibrationStatus(ADC1));				//等待校准完成

ADC_ExternalTrigConvCmd(ADC1, ENABLE);		//设置外部触发模式使能

}

//中断处理函数
void DMA1_Channel1_IRQHandler(void)
原文链接:https://blog.csdn.net/qq_38410730/article/details/89921413@TOC

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

2014-01-07 2014-01-09 2014-01-11 2014-01-13 2014-01-15 2014-01-17 2014-01-19 2014-01-21 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值