第二十七天-ADC模数转换实验
一、实验要求
使用ADC模块来测量3.3v电压。
使用ADC1的通道0(PA0)。
二、硬件连接
PA1连接3.3v引脚。
GPIO设置模拟输入。
三、实验流程
为什么要校准?
即便是在同一片晶圆上生产出来的微控制器,其内部的ADC模块在性能上也会有微小的差异,这些差异主要来源于:
- 零点误差(Offset Error):当输入电压为0时,转换结果可能不是0。
- 增益误差(Gain Error):在满量程时,转换结果与理想值之间存在偏差。
- 工艺偏差:半导体制造过程中的微小差异会导致每个芯片的模拟特性不完全一致。
如果不进行校准,直接使用ADC读取的值可能会存在一个固定的、可预测的偏差,导致测量到的电压、温度等物理量不准确。
四、实验代码
1、adc.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"void Adc_Init(void);
u16 Get_Adc(u8 ch);
float Get_Adc_Average(u8 ch,u8 times); u8 Dis_Vol(u8 ch,u8 times);#endif
2、adc.c
#include "adc.h"
#include "delay.h"
#include "lcd.h"void Adc_Init(void)
{//时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE);//GPIOA1 初始化GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);//ADC时钟设置RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC初始化ADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_NbrOfChannel = 0x1;ADC_InitStruct.ADC_ScanConvMode = DISABLE;ADC_DeInit(ADC1);ADC_Init(ADC1,&ADC_InitStruct);ADC_Cmd(ADC1,ENABLE);//校准ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));
}//输入 ch:通道序号
//输出 单次采样转化值
u16 Get_Adc(u8 ch)
{//设置 通道组成员ADC_RegularChannelConfig(ADC1,ADC_Channel_1,ch, ADC_SampleTime_7Cycles5);//软件触发ADC_SoftwareStartConvCmd(ADC1,ENABLE);//获取转化值return ADC_GetConversionValue(ADC1);}
//输入 ch:通道序号 times:采样次数
//输出 转化值平均值
float Get_Adc_Average(u8 ch,u8 times)
{u16 sum = 0;for(u8 i = times; i > 0;i--){sum += Get_Adc(ch);delay_ms(10);}float temp = (float)sum / times;//转化电压值float result = temp / 4096 * 3.3;return result;
} u8 Dis_Vol(u8 ch,u8 times)
{float vol = Get_Adc_Average(ch,times);//取首位u16 value1 = vol;//取小数位 只保留三位小数float temp = vol - value1;u16 value2 = temp * 1000;if(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) != RESET){//lcd显示LCD_ShowNum(144,50,value1,1,24);LCD_ShowChar(156,50,'.',24,0);LCD_ShowNum(168,50,value2,3,24);}}
3、main.c
#include "stm32f10x.h"
#include "rtc.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "wkup.h"
#include "adc.h"int main(void){ u16 t = 0;delay_init();uart_init(115200);LED_Init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);RTC_Init();LCD_Init(); Adc_Init();LCD_ShowString(60,50,200,24,24,"VOLUME: v");LCD_ShowString(60,120,200,24,24," - - ");LCD_ShowString(60,174,200,24,24," : : ");while(1){++t;if(t % 100 == 0){LED0 =! LED0;}//采集电压 显示Dis_Vol(1,4);delay_ms(10);}}