目录
是不是现在每个人都会表演点小魔术?
不会吧?
不会还有人不会吧?
STM32开发板都有模数(转换)表演了!!!!!
下面小蛋糕带大家看一看来自STM32开发板的模数表演!!!🌹🌹🌹🌹🌹
ADC简介
ADC即Analog-to-Digital Converter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。
典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
模数转换原理
STM32的ADC是12位逐次逼近型的模拟数字转换器。它有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或者右对齐方式存储在16位数据寄存器中。
其转换过程可以分成四个基本部分:
1.采样:定时对连续变化的模拟信号进行检测得到瞬间值。
2.保持:采样结束后将得到的信号保持一段时间,使ADC有充分的时间进行ADC转换。一般采样脉冲频率越高、采样越密、采样值就越多,采样保持电路输出信号就越接近输入信号的波形。
3.量化:将采样电压转化为某个最小单位电压的整数倍。
4.编码:用二进制代码表示量化后的量化电平,量化级越细,量化误差就越小。
模数转换实验内容
模数转换的实验内容可以分为以下四部分:
1. ADC初始化函数编写
1.1使能ADC时钟,使能使用的IO口时钟;
编写代码的老规矩了,用到什么了,使能使能什么的时钟。
1.2初始化GPIO;
由于我们使用PA1作为输入引脚,所以我们要去初始化IO口。
1.3复位ADC;
将外设ADC1的全部寄存器重设设为缺省值。
1.4 初始化ADC;
根据我们的需要,为相关的参数赋值,进行ADC的初始化。
1.5 使能ADC,并进行ADC的校准
使用外设之前要进行使能的操作。
2.获得输入值函数编写;
在获得转化值函数中,我们使用软件转换功能。
3.求平均值函数编写;
和C语言的求平均值函数相同,利用for循环求出数值之和,再去求平均值。
4.主函数编写;
除了调用之前编写好的函数之外,我们需要将我们需要输出的数字显示到LCD屏幕上。
模数转换实验代码
话不多说,上代码!
1.1首先我们开启ADC1和PA1的时钟,由于它们都在一个时钟源上,所以我们可以用一个或语句开启两个时钟。
//使能两个时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );
1.2然后,我们开始吧初始化GPIOA,由于之前已经进行了多次讲解,这里,我们不再作说明。
//定义初始化函数参数结构体
GPIO_InitTypeDef GPIO_InitStructure;
//为结构体的变量赋值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//设置为模拟输入模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//调用初始化函数
GPIO_Init(GPIOA, &GPIO_InitStructure);
1.3 复位ADC,设置ADC的分频因子。
//根据ADC的最大时间,设置ADC的分频因子
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//复位ADC1
ADC_DeInit(ADC1);
1.4根据相关需要对ADC进行初始化,由于我们使用ADC1进行独立的工作,所以我们将ADC_InitStructure.ADC_Mode赋值为ADC_Mode_Independent;我们的模数转换是在单通道的模式下进行,不需要开启扫描模式,不需要进行连续扫描,所以将ADC_InitStructure.ADC_ScanConvMode赋值为DISABLE,并且将ADC_InitStructure.ADC_ContinuousConvMode赋值为DISABLE;我们使用软件进行模数转换,所以ADC_InitStructure.ADC_ExternalTrigConv 赋值为 ADC_ExternalTrigConv_None;我们使用通道1,所以将ADC_InitStructure.ADC_NbrOfChannel 赋值为 1;并且我们根据通常习惯,将数据设置为右对齐,所以将ADC_InitStructure.ADC_DataAlign 赋值为 ADC_DataAlign_Right。
//定义初始化函数参数结构体
ADC_InitTypeDef ADC_InitStructure;
//为初始化函数参数赋值
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);
1.5最后我们使能指定的ADC,并且进行复位校准。
//使能指定的ADC
ADC_Cmd(ADC1, ENABLE);
//使ADC1进行复位校准
ADC_ResetCalibration(ADC1);
//等待复位结束
while(ADC_GetResetCalibrationStatus(ADC1));
//开启ADC校准
ADC_StartCalibration(ADC1);
//等待ADC校准结束
while(ADC_GetCalibrationStatus(ADC1));
2.然后我们获得ADC值,这一步主要是通过返回值来传递转换后的数据。
u16 Get_Adc(u8 ch)
{
//设置指定的ADC通道,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
//使能指定的ADC的润建转换启动功能
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
//返回转换后的数据
return ADC_GetConversionValue(ADC1);
}
3.然后我们按照常规的方式求出转换后的平均值。
//同C语言中的求平均值方法一致
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
4.最后,我们根据需求编写主函数即可。(代码见附录)
附录
adc.c中的完整代码
#include "adc.h"
#include "delay.h"
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE );
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1);
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);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
// ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
u16 Get_Adc(u8 ch)
{
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
return ADC_GetConversionValue(ADC1);
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
主函数的完整代码
int main(void)
{
u16 adcx;
float temp;
delay_init();
uart_init(9600);
LED_Init(); /
LCD_Init();
Adc1_Init();
POINT_COLOR=RED;
LCD_ShowString(60,50,200,16,16,"Mini STM32");
LCD_ShowString(60,70,200,16,16,"ADC TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2014/3/9");
POINT_COLOR=BLUE;
LCD_ShowString(60,130,200,16,16,"ADC_CH1_VAL:");
LCD_ShowString(60,150,200,16,16,"ADC_CH1_VOL:0.000V");
while(1)
{
adcx=Get_Adc_Average(ADC_Channel_1,10);
LCD_ShowxNum(156,130,adcx,4,16,0);
temp=(float)adcx*(3.3/4096);
adcx=temp;
LCD_ShowxNum(156,150,adcx,1,16,0);
temp-=adcx;
temp*=1000;
LCD_ShowxNum(172,150,temp,3,16,0X80);
LED0=!LED0;
delay_ms(250);
}
}
关于ADC我们就讲到这里,今天你学废了吗?下篇文章见!!