单片机之STM32入门——(5)ADC调试
1.ADC函数
1.1 初始化函数
1.1.1GPIO初始化函数
因为我们这里读取模拟量输出需要用到GPIO接口,所以也需要GPIO初始化函数。
GPIO的初始化函数我们现在已经非常熟悉了,只是这里有一点不同的是模式需要定义为模拟量输入。
GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//打开GPIOC时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//定义模式为模拟量输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//定义端口0
GPIO_Init(GPIOC, &GPIO_InitStructure);
1.1.2ADC初始化函数
ADC初始化函数与GPIO初始化函数有着一定的相似之处。
- 定义结构体
- 使能端口时钟
- 定义模式、变量、端口等
不同的是,ADC初始化还需要有对模拟量进行处理的函数模块。
void ADC_init(){
ADC_InitTypeDef ADC_InitStructure;//ADC结构体
GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1, ENABLE);//打开GPIOC、ADC1时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADC设置分频 72M/6 = 12 ,因为ADC最大时间不超过14M
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//定义模式为模拟量输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//定义端口0
GPIO_Init(GPIOC,&GPIO_InitStructure);
ADC_DeInit(ADC1);//复位ADC1
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次转换模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//关闭扫描
ADC_Init(ADC1,&ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);//使能ADC1
ADC_ResetCalibration(ADC1);//复位校准ADC1
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_GetCalibrationStatus(ADC1);//开启ADC1校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准结束
}
1.2 模拟量读取与求平均值函数
模拟量读取
u16 Get_ADC(u8 ch){
ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5);//设置ADC1通道规则组,采样时间为239.5个周期
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//开启转换使能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待转换结束
return ADC_GetConversionValue(ADC1); //返回转换值
}
求平均值
u16 Get_ADC_Ave(u8 ch, u8 times){
u32 temp = 0;
u8 t;
for(t=0;t<times;t++){
temp += Get_ADC(ch);
delay_ms(5);
}
return temp/times;//返回平均值
}
1.3头文件
头文件主要是对函数进行声明。
#ifndef _ADC_H
#define _ADC_H
#include "sys.h"
#include "delay.h"
void ADC_init();//ADC初始化
void ADC_Get(u8 ch);//获取ADC函数值
void ADC_Get_ave(u8 ch,u8 times);//获取ADC的值,并多次采样,取平均值
#endif
2.主函数
主程序中我们首先定义两个无符号的int类型变量用于在OLED上显示电压值,再定义两个无符号的short类型变量用于存放u16 Get_ADC_Ave(u8 ch, u8 times)
函数得到的ADC平均值。然后我们在OLED上分别显示出读取电压值和转换后的电压值并延时1s。
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "usart.h"
#include "oled.h"
#include "adc.h"
int main(void)
{
u32 num, end_num;
u16 adcvalue;
u16 temp;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
delay_init();
ADC_init();
OLED_Init();
OLED_ColorTurn(0); //0 正常显示 ;1 反色显示
OLED_DisplayTurn(0);//0 正常显示 1 屏幕反转显示
OLED_Clear();//清屏
while(1)
{
adcvalue = Get_ADC_Ave(ADC_Channel_10, 10);
temp = adcvalue*3280/4096;
num = adcvalue;
end_num = temp;
//void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode);
//void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode)
OLED_ShowString(0,0,"ADC Value:",16,1);
OLED_ShowNum(0,16,num,4,16,1);
OLED_ShowString(0,32,"convert Value:",16,1);
OLED_ShowNum(0,48,end_num,4,16,1);
OLED_Refresh();
delay_ms(1000);
}
}
3.使用及效果展示
3.1接3.3.V
因为我们定义的模拟量输入端的GPIO接口为PC0,所以我们可以将3.3V接值PC0端口,观察OLED上显示的电压值约为3.24V
用万用表测得约为3.28V,可以看到两者非常接近,但是仍然存在一定的误差。
3.2接7号干电池
当我们接入7号干电池后,发现测得的电压约为1.66V
用万用表测得约为1.68V。
通过该函数,我们发现可以测量电压值,通过改动,便可以制作成为电压表。
同时我们还能够将其与温度传感器,红外线传感器,超声波传感器等制作成测温,测距仪。