6.ADC模数转换(内容详细,有几点明白20171113)

来源:互联网 发布:js验证用户名重复 编辑:程序博客网 时间:2024/06/05 14:16

6.ADC模数转换

回顾了一下学习嵌入式软件的整个过程,我发现缺少了一种探索的精神?这些设计都有实例,我也是按照实例先理解后然后在利用自己的想法实现。看到实验题目,我首先会看例程代码,看看用到了哪些库中外设器件的知识,然后学习相关库,最后根据了解到的流程和学习到的相关函数库方面的知识自己在重新写一遍程序,最后在仿真,然后下载到板子中测试,成功后写总结,这从学习角度来说似乎已经足够了,但是其中少了最重要的一步,思考?这个实验的目的是什么?为了实现这个目的我需要知道什么,需要怎么做?知道结果再重新处理直接处理省下了这一步,是简单,但效果却并不好,特别是想脱离底层代码作整体架构的设计,学会选择和思考这一步才是最重要的,也是关键的。因此我决定转换思路,从现在开始改变实验的方法。

1.要求

    本次ADC模数转换实验要求并不复杂,接收板上电位器的输入电压,经过A/D转换后通过串口在PC机上输出。

2.问题解析

分析要求,就会发现ADC、GPIO、USART以及RCC模块就是本次实验所需要的用到的外设,因为其它模块通过前面的学习和实践都有了一定的基础,那么学习ADC模块,掌握寄存器以及相关库函数就是本程序设计的第一个关键。首先根据开发板手册,了解STM32处理器所带的ADC是12位的模拟数字转换器,它有18个通道,其中16个外部通道和2个内部信号源,而本次电位器对应通道10,且GPIO口对应为PC0,电位器最高3.3V,这是硬件相关的资料(来自原理图/开发板手册,学会查资料也是软件编写的基础)。

 3.总结

  以上我们可以得出输入电压的范围为0~3.3V,输出的数字量为0~0xFFF,这样我们将得到的数字量即可通过公式digital = (analog/0x1000)*3.3转换成模拟量,通过串口输出,我们初始化需要配置的就有AD1的10号外部通道(单通道模式)以及GPIOC的端口0,配置为模拟输入(具体参考STM32中文参考手册8.1.11),同时选择串口1输出到PC端,配置同上一章节。

 

 

<库函数学习即使用>

因为ADC1对应的GPIO口为PC0,所以要进行PC0端口的初始化,并不难,这里不再赘述。

typedefstruct

{

u32 ADC_Mode;                          //明确ADC1和ADC2的工作方式,独立或其它组合

FunctionalState  ADC_ScanConvMode; //通道工作方式,单通道还是多通道(扫描)

FunctionalState  ADC_ContinuousConvMode;//工作在连续还是单次模式

u32 ADC_ExternalTrigConv;         //A/D转换启动规则

u32 ADC_DataAlign;                    //判断转换数据的对齐方式

u8 ADC_NbrOfChannel;                  //明确规则转换通道的具体数目 1~16

}ADC_InitTypeDef

了解上述结构体代表含义,下面就可以初始化相关寄存器实现ADC外设的配置:

ADC_InitTypeDef ADC_InitStructure;

ADC_InitStructure.ADC_Mode =ADC_Mode_Independent;    //ADC1和ADC2工作在独立模式

ADC_InitStructure.ADC_ScanConvMode =ENABLE;           //工作在多通道(扫描)模式  

ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;    //工作在连续模式  

 ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None;//软件触发启动

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐

ADC_InitStructure.ADC_NbrOfChannel =1;                 //ADC通道数目为1

ADC_Init(ADC1, &ADC_InitStructure);

 

上面的其它都好理解,但是最后一个ADC_NbrOfChannel有内容需要了解,

ADC通道的规则组和注入组:规则组可配置1~16个,注入组最多配置4个

在AD转换中,规则组定义的是ADC扫描通道的顺序,按照规则组配置时的采样顺序从小到大依次扫描ADC通道,而注入组的优先级高于规则组,当注入组转换触发时就打断规则组的扫描而执行注入组的通道扫描,具体流程类似于中断中的抢占。本次ADC的转换仅仅使用到一个端口,这些不用考虑,但是在多通道AD/DA采集时,规则组和注入组要根据实际情况进行配置。

注意:配置通道的规则组和注入组是一定要在使能ADC转换之前的。

配置规则组/注入组的函数如下:

ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1, ADC_SampleTime_55Cycles5 );

上面函数共有四个变量,分别对应着选择的AD口,AD转换通道(具体值可通过查看原理图确定),采样顺序(本例子表示采样顺序1,不同端口不可重复),采样周期(55.5个ADC时钟周期,具体时间可根据设定的时钟频率计算).

ADC_Cmd(ADC1, ENABLE);     //使能ADC转换

下面这一段就是ADC的校准,可以减小因电容器组变化而照成的准精度误差。这个校准具体的实现我也不清楚,就按照下面的库函数调用吗,但是一定不能忘了它,千里之堤,溃于蚁穴;细节真的很重要,特别是在大型软件中。 

ADC_ResetCalibration(ADC1);                   //重置ADC校准寄存器

while(ADC_GetCalibrationStatus(ADC1))       //等待ADC校准寄存器重置完成

{

}

ADC_StartCalibration(ADC1);                   //ADC进入校准状态

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

{

}

ADC_SoftwareStartConvCmd(ADC1,ENABLE);    //软件方式启动ADC1转换

那么直接定义

u16  ADValue;

ADValue =ADC_GetConversionValue(ADC1);    //返回最近一次规则组的转换结果

Precent = (ADValue*100/0x1000);

Voltage = Precent*33;

printf("\r\n\n ADCConvertedValue is0x%x, Percent is %d%%, voltage is %d.%d%dV",

    ADValue,Precent,Voltage/1000,(Voltage%1000)/100,(Voltage%100)/10);

printf("\n ADC output output");

注意:使用了printf函数作为输入输出时,包含头文件#include”stdio.h” ;

Target下要选择useMicroLib,否则是不会有输出的(串口章节已经说明,重要)。

即可以实现模数的转换。看到这你是不是觉得实验已经结束了,毕竟我们已经实现要求了吗。从功能上,本实验已经够了。

但是ADValue =ADC_GetConversionValue(ADC1);  /*返回最近一次规则组的转换结果*/,

    通过该函数,就可以实现ADC转换后每一次数据的读取,在通过串口输出到PC端显示,这当然没有问题,

但是ADC转换是很快的,通过上述函数获得ADC转换后的信息的话CPU资源占用率会很高,那么有没有什么简单的方法呢?这里就涉及到DMA模块,具体参见下章。 
原创粉丝点击