重学STM32---(五)ADC

  这两天把外部中断和ADC看了下,个人感觉外部中断不是很难,也就没有把记下来了,毕竟写这个挺浪费时间。ADC是比较复杂的,如果想让完全自由的运用ADC必须经过多次实践可能才可以。由于已经学过库函数,也就打算自己看数据手册写了一个简单的寄存器版的ADC,期间也遇到了很多问题,幸好都解决了。

  把这次学习的重点都记下来,以后再看不知是什么感觉O(∩_∩)O哈哈~

1. 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。

2. 通过设置ADC_CR2寄存器的ADON位可给ADC上电。当第一次设置ADON位时,它将ADC从断
电状态下唤醒

      

3.AD转换模式:单次转换和连续转换    (单次转换模式下,ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位)

                 (在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换,在同一寄存器设置)

4.扫描模式:

此模式用来扫描一组模拟通道。
  扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置,ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。 
  如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到SRAM中。而注入通道转换的数据总是存储在ADC_JDRx寄存器中。

5.可编程的通道采样时间:
  

  ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。
总转换时间如下计算: 
TCONV = 采样时间+ 12.5个周期

6.双ADC模式:(同步注入模式 ,同步规则模式 ,快速交叉模式 ,慢速交叉模式,交替触发模式,独立模式)

在双ADC模式里,根据ADC1_CR1寄存器中DUALMOD[2:0]位所选的模式,转换的启动可以是ADC1主和ADC2从的交替触发或同步触发。

注意: 在双ADC模式里,当转换配置成由外部事件触发时,用户必须将其设置成仅触发主ADC,从ADC设置成软件触发,这样可以防止意外的触发从转换。但是,主和从ADC的外部触发必须同时被激活。

在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。

配置一个简单ADC程序的步骤:(单通道)

0.开启对应的IO口时钟和ADC时钟,在RCC_CFGR寄存器中给ADC分频,使之不超过14M...

1.在ADC_CR1寄存器中:设置独立模式(DUALMOD[3:0]:双模式选择 ),不使用扫描模式,允许产生EOC中断...其余默认就行

2.在ADC_CR2寄存器中:位SWSTART(开始转换规则通道,要转换时设置1),不用外部事件启动转换,位EXTSEL[2:0](选择启动规则通道组转换的外部事件,选择       111,软件触发),数据右对齐(左右随意),不使用DMA模式,单次转换模式,位ADON(开/关A/D转换器 )

3.ADC_SMPRx(ADC采样时间寄存器):自己看实际情况设置就行(总转换时间如下计算:TCONV = 采样时间+ 12.5个周期)

4.ADC_SQR1寄存器:默认0就行了(因为就一个通道)

5.在中断服务函数中检查ADC_SR寄存器中EOC位,为1时用软件清除,然后进行下一步

6.在ADC_DR寄存器中读数据

注意:初始化ADC时要校准,在ADC_CR2寄存器中设置校准

 

程序:

学习库函数写了一个时常要修改数据的结构体,这样重写另一个ADC也就方便了许多,只要修改结构体的值就行   但我这个还不是很好

adc.h

#ifndef _ADC_H_
#define _ADC_H_

typedef enum
{
disable = 0,
enable = !disable
}STATE;

typedef struct
{
  unsigned int ADC_ModeSel;             //双模式选择
  STATE ADC_ScanModeSel;            //是否开启扫描模式
  unsigned int ADC_ExternalTrigConv;       //外部触发方式
  unsigned int ADC_DatdAlign;            //数据对齐方式
  STATE ADC_DMAEN;                //是否使用DMA
  STATE ADC_ContinuousCon;            //是否连续转换
  unsigned char ADC_NumRegularchan;      //规则转换通道个数
}ADC_STRUCT;

extern ADC_STRUCT ADC_STRUCTInit ;

unsigned short Get_Value(unsigned char ch);
void Adc1_Chan1_Init();

#endif

adc.c

#include "adc.h"
#include "stm32f10x.h"
#include "delay.h"

ADC_STRUCT ADC_STRUCTInit =
{
  0x0,            //独立模式
  disable,          //不开启扫描模式
  0x000E0000,       //软件触发方式
  0x00000000,        //右对齐
  disable,          //不使用DMA
  disable,          //单次转换
  1              //1个通道
};

void Adc1_Chan1_Init()
{
RCC->APB2ENR |= 1 << 9;        //开启ADC1时钟
RCC->APB2ENR |= 1 << 2;        //开启GPIOA时钟

GPIOA->CRL &= ~(0xf << 4);       //模拟输入

RCC->APB2RSTR |= 1<<9;        // ADC时钟复位
RCC->APB2RSTR &= ~(1<<9);

RCC->CFGR &= 0x0000C000;          //ADC_APB2 6分频 72M/6 = 12M
RCC->CFGR |= 0x00008000;

ADC1->CR1 = 0x00F0FFFF;

ADC1->CR1 |= ADC_STRUCTInit.ADC_ModeSel << 16;          //独立模式

ADC1->CR1 |= ADC_STRUCTInit.ADC_ScanModeSel << 8;         //关闭扫描模式

ADC1->CR2 |= ADC_STRUCTInit.ADC_ExternalTrigConv |                    //软件触发

        ADC_STRUCTInit.ADC_DatdAlign            |           //右对齐 

        ADC_STRUCTInit.ADC_DMAEN <<  8      |                        //  不使用DMA                                     ADC_STRUCTInit.ADC_ContinuousCon <<1;             //单次转换

ADC1->CR2 |= 1 << 20;       //使用外部事件启动转换(必须,这里也郁闷了半天)

ADC1->SMPR2 |= 3 << 3;       //采样时间,

ADC1->CR2 |= 0x1;          //开启ADC (数据手册写错了,必须在校准之前开启ADC,害了我郁闷了半天)

ADC1->CR2 |= 1 << 3;
while (ADC1->CR2 & 1<<3); //复位校准

ADC1->CR2 |= 1 << 2;
while (ADC1->CR2 & 1<<2); //AD校准

}

u16 Get_Value(u8 ch)
{
u16 value;
ADC1->SQR3 &= 0xffffffe0; //
ADC1->SQR3 |= ch;

ADC1->CR2 |= 1<<22; // 开启规则转换
while(!(ADC1->SR & 1<<1));//等待转换结束
value = ADC1->DR ; //读取转换值,清零转换结束状态位
return value ;
}

可以连续采集n次,求平均值提高精确度

http://www.chuxue123.com/forum.php?mod=viewthread&tid=9765&highlight=ADC

时间: 2025-01-01 23:07:11

重学STM32---(五)ADC的相关文章

STM32之ADC+步骤小技巧(英文)

神通广大的各位互联网的网友们.大家早上中午晚上好好好.今早起来很准时的收到了两条10086的扣月租的信息.心痛不已.怀着这心情.又开始了STM32的研究.早上做了计算机控制的PID实验,又让我想起了飞思卡尔的电磁小车..曾经的电感电压采集让我心碎的多少次.又让我开心了多少次.但已经成为过去.(软件和硬件都会影响),呵呵.估计有人已经猜到我接下来要介绍什么了.在你们面前.我已无秘密.额.其实标题也直接"表白"了.看到标题,别吓到哈.并不是要用英文写.至于原因是什么.请往下看: 好吧.言归

重学ps_1

1,选取 打开图片->点击选取工具->ctrl+c->ctrl+n->ctrl+v 2,去除图片背景 打开你要去除背景的图片->在图层面板中->双击图层把图层改为0层->用魔棒点击背景->然后点击delete键->最后将图片存储为png格式 如果存为jpg他会默认添加背景 3,改变图片上文字的颜色 打开要改变的图片->选择快速工具->在你要改变的文字上点击一下->然后在点击油漆桶工具->在选择你想要改变的颜色->然后点击文

重学html

html是描述网页结构的标记语言. 1.html中标记是由尖括号和标记名组成,例如:<h1>,一个元素是指开始标记.闭合标记和他们之间的内容组成,例如:<h1>北京</h1> 2.很多时候,我们用html创建的网页在浏览器中运行的时候,会利用浏览器自带的默认样式来表现结构. 3.css级联样式表,用来描述如何表现内容. <style type="text/css">   <!--type告诉浏览器你所使用的样式的种类--> &

重学线代——声明篇

为啥重学线代呢? 1.当初学得模棱两可,时间长了啥也没剩下 2.越来越发现线代很流弊,很有用(不只是线代,各门数学都有此感触) 3.比较巧合地在网络上发现了个很好的线代教学资源 4.假期浪费了太可惜了 你这堆博客要写点啥呢? 课程笔记.个人领悟.无知吐槽.等等等等 你还想说点啥么? 没了 哦 恩

重学C++ (1)

写在开头的话:这学期没有写太多的代码,终于把中英文两篇论文弄完了,趁着中间的空隙,想想找工作的处境.自己也定了自己的方向.不管学什么语言吧,每个语言都有自己的优势和使用的群体.只要自己是良马,终会有伯乐赏识. 定的标题为“重学C++” 本人之前使用C++基本上用作算法编写,MFC界面的学习编写,集成OpencV进行图像处理的项目开发或者论文实验 总的来说,能处理基本问题.但是远不能达到灵活的地步.所以下载了两本书<effective C++>和<effective STL>我希望能

STM32 F4 ADC DMA Temperature Sensor

STM32 F4 ADC DMA Temperature Sensor Goal: detecting temperature variations using a temperature sensor, ADC with DMA and TIM3 as a trigger (ADC sampling frequency = TIM3 trigger frequency). Note: Using TIM3 as a trigger is suited for monitoring temper

C#&amp;java重学笔记(函数)

C#部分  1.写在函数定义的()中的关键字: a.params关键字:用来满足函数的参数为数组时,而数组的长度不固定的情况.且该关键字只能用来修饰数组型参数.这样一修饰,就达成了类似JavaScript函数书写参数的特点. b.ref关键字:让参数按引用传递,类似于C中的传指针参数.比如经典的数值交换函数,你传形参和传指针的结果应该知道,加了ref关键字就相当于传指针.注意:ref只接收变量做参数,你字面量怎么弄指针?而且该变量必须初始化!     c.out关键字:功能和ref一样,区别在于

Java集合类简单总结(重学)

java集合类简介(重学) 一.Collection(集合).Map接口两者应该是平行关系吧. 1.Map介绍 Map是以键值(key-value)对来存放的,2个值.通过key来找到value(例:姓名-电话,通过姓名得到电话),通过Map创建的对象key都 不可以重复. 它的两个常用子类:HashMap类和HashTable类. HashMap类:无序存放的,key不允许重复 HashTable类:无序存放,key不允许重复 key值可通过Map的方法keyset获取全部的key值,返回是个

C#&amp;java重学笔记(面向对象)

C#部分 1.C#有一个internal关键字,指字段可以同一个程序集中访问,出了程序集不行.还有一个protected internal(没有先后之分)修饰词,指只能在同一个程序集中的子类访问 2.abstract和virtual修饰词: abstract用来修饰类和方法,表 抽象.抽象类中的方法可以不抽象,但是抽象方法所在的类必抽象.且抽象方法不得被实现,即不能用{}表示函数体.而且抽象类只有被继承才能体现它的作用,同时子类必须override父类的抽象方法!      virtual用来修