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

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

       好吧、言归正传:STM32的ADC模块,请容许我用如此通俗的语言:普通话  来介绍STM32ADC模块的特点ui

      一、1MHz转换速率、12位转换结果(12位、记住这个12位哈、由于2^12=4096 ,也请记住4096哈es5

           STM32F103系列:在56MHz时转换时间为:1μsspa

                                    在72MHz时转换时间为:1.17μs3d

      二、转换范围:0~3.6V  (3.6v---->当你须要将采集的数据用电压来显示的话:设你采集的数据为:x[0~4095],此时的计算公式就为:(x / 4096) * 3.6)code

      三、ADC供电要求:2.4V~3.6 V(可千万别接到 5V 的石榴裙子底下呀blog

      四、ADC输入范围:VREF-≤ VIN ≤VREF+ (VREF+和VREF-只有LQFP100封装才有)事件

      五、双重模式(带2个ADC的设备): 8种转换模式图片

      六、最多有18个通道:16个外部通道ip

                                   2个内部通道:链接到温度传感器和内部参考电压(VREFINT = 1.2V)

      ......(略,请看参考手册哈,因为篇幅,就不过多的列出来了、、说到略、让我想起了月光宝盒诸葛亮的:略懂略懂、、其实我也是略懂略懂而已、、)

      十二、DMA功能(仅ADC1有)

      本博客里,因为篇幅、因此就以独立模式下的单次转换为例哈、打开参考手册能够看到这段话:

       单次转换模式下,ADC只执行一次转换。

       该模式既可经过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动也可经过外部触发启动(适用于规则通道或注入通道),这时CONT位为0

       一旦选择通道的转换完成:

       ● 若是一个规则通道被转换: ─ 转换数据被储存在16位ADC_DR寄存器中 ─ EOC(转换结束)标志被设置 ─ 若是设置了EOCIE,则产生中断。

       ● 若是一个注入通道被转换: ─ 转换数据被储存在16位的ADC_DRJ1寄存器中 ─ JEOC(注入转换结束)标志被设置 ─ 若是设置了JEOCIE位,则产生中断。

       而后ADC中止。

      此图形象的代表了其背后那鲜为人知的秘密转换关系。。虽然单凭看文字就能想象出来、可是、有图片是否是更加形象呢???

 

     对于以上的寄存器、在此我稍微提提:省得寄存器大神们产生怨气:好不容易等到你讲我老大ADC,却不把我这些背后的勤劳者给导出来

     好了,那就恕小弟容禀:

     一、ADC状态寄存器(ADC_SR) 

     

 

    二、ADC控制寄存器1(ADC_CR1)

 

    3、ADC控制寄存器2(ADC_CR2)

       EXTSEL[2:0]:选择启动规则通道组转换的外部事件 (External event select for regular group)

       ALIGN:数据对齐 (Data alignment)

       RSTCAL:复位校准 (Reset calibration)

       CAL:A/D校准 (A/D Calibration)

       CONT:连续转换 (Continuous conversion)

       ADON:开/关A/D转换器 (A/D converter ON / OFF)

    四、ADC采样时间寄存器1(ADC_SMPR1)

       SMPx[2:0]:选择通道x的采样时间 (Channel x Sample time selection)

    5、ADC规则序列寄存器1(ADC_SQR1)

       L[3:0]:规则通道序列长度 (Regular channel sequence length)

       SQ1[4:0]:规则序列中的第1个转换 (1st conversion in regular sequence)(ADC规则序列寄存器3(ADC_SQR3)

    6、ADC规则数据寄存器(ADC_DR)    

    DATA[15:0]:规则转换的数据 (Regular data) 

 (因为寄存器过于多,咱们就不在这一一列举了哈、、由于我主要是用库,因此寄存器相关的位都不具体介绍了哈、请你们参照中文手册)

   在这里,向你们介绍下:数据对齐:

                                              ALIGN位用于设置对齐方式:右或左;

                                              对于注入通道,转换结果是减去偏移量的值,能够为一个负数,在右对齐时扩展位位符号位。

 

    那咱们如今要怎么来实现呢??这个问题、相信你们在看了那么多的寄存器以后急迫想要知道的吧、、前面的只是个热身、、接下来步骤以下:

    1、开启ADC1的时钟,因为ADC1是在PA1上,因此同时也要打开PA的时钟,并进行相关的配置、对于这个配置,要把PA1设置成模拟输入,为何呢??你们打开中文参考手册能够看到

    啊哈、、这下子清楚了吧、

   2、复位ADC1,(本人以为不必、为何,待会我会跟你说,留下悬念先),设置ADC1的分频因子,(记住,这里的ADC的时钟不能超过14MHZ),并且其采样周期长点会好点,

        ADCCLK---最快可达14MHz, 时钟来自通过分频器的PCLK2(二、四、六、8分频)

        整个转换时间 = 采样时间 + 12.5个周期(固定时间)

       在14MHz和采样时间位1.5周期时  转换时间:1μs (14个周期 cycles)

       当ADCCLK=14MHz和1.5周期的采样时间:

        TCONV = 1.5 + 12.5 = 14周期 = 14×(1 / (14 × 1000000)) = 1μs

       其采样周期一览表:

 

    涉及到采样周期、这里来看看转换序列:

    最多达16个转换通道且能够采样不一样的顺序排列,不一样的采样时间和过采样的可能性。

例如:- 转换通道:一、二、八、四、七、三、11
                            - 不一样的采样时间;
                            - Oversampling of channel 7。

 

3、初始化ADC1的参数、设置ADC1的工做模式和规则序列的相关信息;

       你们经过打开"stm32f10.adc.h"能够看到:   

typedef struct
{
  uint32_t ADC_Mode;                      //设置ADC模式-->独立模式
  FunctionalState ADC_ScanConvMode;       //设置是否开启扫描模式 --->否
  FunctionalState ADC_ContinuousConvMode; //设置是否开启连续转换模式 ---->否
  uint32_t ADC_ExternalTrigConv;          //设置启动规则转换组转换模式---->软件触发              
uint32_t ADC_DataAlign; //设置数据对齐方式----->右对齐 uint8_t ADC_NbrOfChannel; //设置规则序列的长度---->顺序进行规则转换的ADC通道数目1 }ADC_InitTypeDef;

     4、使能ADC并校准

注:在设置完了以上信息后,使能AD转换器,执行复位校准和AD校准(这两步校准必定要,不然数据将不许)

还有记住,每次进行校准以后都要等待校准结束,可是经过什么方式知道校准结束呢?

这里是经过获取校准状态来判断是否校准结束,相关的库函数请看代码

      分别的库函数请看待会的代码。(请用比较老外的方式去看,也就是用英语啦,为何呢?请看下文

     5、读取AD的值

    固然,这里说读取AD值并非那么的简单,以上咱们只是准备好了AD,尚未设置相关的规则序列通道,采样顺序,以及采样周期,设置完以后启动AD转换就好了、而后才直接读取哈、、

      相关的库函数请看代码、

void Adc_Init(void)
{

    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

   /* Enable ADC1 and GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//12MHZ /* Configure PA.1 (ADC Channel) as analog input -------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); //ADC_DeInit(ADC1);//在这里复位被我注释掉了、至于为何,我待会会说 /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//这里对应上面所讲的配置,在这里就不给出注释了 ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); /* Enable ADC1 *///知道我为啥要在上面提醒你们要用老外的方式来看了吧、由于这里的注释都是用英文的
//请不要觉得我装逼,我这样作是有缘由的、、缘由我待会会说、你也会明白我最初的标题为什么那样写
ADC_Cmd(ADC1, ENABLE); /* Enable ADC1 reset calibration register */ ADC_ResetCalibration(ADC1); /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(ADC1)); /* Start ADC1 calibration */ ADC_StartCalibration(ADC1); /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1)); }
u16 Get_val(u8 ch)
{
    u16 DataValue; //又是英文注释、、啊哈 /* ADC1 regular channel14 configuration */ 
  ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5);
    
    /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    /* Test if the ADC1 EOC flag is set or not */ 

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    //FlagStatus Status;
    //Status = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
    //while(!Status);---->这样作实现不了、请注意
/*Returns the ADC1 Master data value of the last converted channel*/
DataValue = ADC_GetConversionValue(ADC1);
return DataValue;
}

u16 ADC_Get_aveg(u8 ch,u8 n)
{
u32 ad_sum
= 0;
u8 i;
for(i=0;i<n;i++)
{
ad_sum
+= Get_val(ch);
delay_ms(
5);
}
return (ad_sum / n);
}

adcx=ADC_Get_aveg(ADC_Channel_1,10);//获取AD数值(0~4095)

temp=(float)adcx*(3.3/4096);//获取相应的电压值

     到了这一步,咱们已经完成了AD采集数据的任务、接下来,有人可能有时候会以为很纳闷,为何有些人知道要完成特定的功能,它的步骤是怎么样的、为何我就不知道??这个问题嘛、、接下来我讲的但愿能稍微帮你,也但愿你能好好的借鉴、

     步骤小技巧:其实也没啥的、你们知道下载库的文件的时候,里面都有包含每一个模块的例子和一个模版、拿ADC这个模块来举例:

   

点击main.c能够看到神奇的一幕:

   你们仔细看看,能够发如今官方给的历程中的步骤里并无复位ADC的函数,我的以为因此没有必要去复位固然复位也不是什么坏事哈、看你我的、、看到这、应该明白了我前面的说法了吧、还有、你们应该也注意到了、都是英文的注释、、因此看到这你们也清楚了,前面不是我装逼、、因此呢、其实英语对于咱们来讲仍是很重要的、、那有人问,时钟的分频因子呢?怎么没有设置??不急哈、、请看:

对于分频因子的设置,也在这个函数里:而这个RCC_Configuration()在最开始已经使用 了、、

  因此你们要好好利用官方给的历程、说到这、你猜我词穷了吗?

  答案是否认的、、我还有话要说:

  作一件事要有一个目的、、才不会显得本身作的很空泛、、我写博客也同样、、我想让我本身理清思路、也但愿本身在写的过程当中能领悟到本身在学的时候没领悟到的知识点、、也但愿能帮到跟我有同样困惑的人、、我把我不懂的理解后写下来、我也知道会有人跟我同样遇到一样不懂的地方、、因此这就是个人目的哈、、但愿能帮到大家、、尽管不认识大家、、啊哈、、初学者、不免有出错、、因此、写错或理解错的请帮我指出来、臣不甚感激,今当远离,零表涕零,不知所言、、

相关文章
相关标签/搜索