功能描述:使用STM32F405RGT6的ADC1的通道4对输入到PA4上的模拟电压进行模数转换,并在OLED上显示ADC的原始采样值和实际电压值。ADC配置为独立模式、单通道、单次转换、硬件触发、非扫描模式,硬件触发源为TIM2的TRGO输出,每一秒触发一次即ADC1每一秒对PA4上的电压采样转换一次。
- main.c文件内容如下
#include "stm32f4xx.h" // Device header
#include "OLED.h"
#include "MyADC.h"
#include "Timer.h"
uint16_t ADC_Value;
double Voltage;
int main(void)
{
Timer_Init();
MyADC_Init();
OLED_Init();
OLED_Clear(); //清屏OLED
OLED_Refresh(); //刷新OLED
while(1)
{
if(MyADC_GetFlag() == 1)
{
ADC_Value = MyADC_GetValue(); //获取ADC采样值
Voltage = ((double)ADC_Value/4096)*3.3; //计算对应的电压
OLED_Printf(0,0,8,"ADC_Value = %d",ADC_Value); //显示ADC采样值
OLED_Printf(0,16,8,"Voltage = %.2lfV",Voltage); //显示电压值
OLED_Refresh(); //刷新OLED
}
}
}
- MyADC.c文件内容如下
#include "MyADC.h"
uint16_t MyADC_Value;
uint8_t MyADC_GetValueFlag = 0;
/**
* @摘要 初始化ADC和相应的GPIO
* @参数 无
* @返回值 无
* @说明 无
*/
void MyADC_Init(void)
{
//开启GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStructure;
//初始化上述结构体
GPIO_StructInit(&GPIO_InitStructure);
//配置GPIO模式为模拟输入模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
//配置GPIO输出类型为推挽输出(此处无用)
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//指定GPIO引脚为Pin4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
//配置GPIO输入类型为浮空输入(此处无用)
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//配置GPIO的速度为快速50MHZ
GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
//初始化对应的GPIO
GPIO_Init(GPIOA, &GPIO_InitStructure);
//开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//定义所有ADC共用配置的初始化结构体
ADC_CommonInitTypeDef ADC_CommonInitStructure;
//初始化上述结构体
ADC_CommonStructInit(&ADC_CommonInitStructure);
//配置为独立模式
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
//配置ADC时钟的预分频器的值为4,即21MHZ(<30MHZ)
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
//失能DMA
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
//配置多ADC模式下的两个ADC采样间隔(此处无用)
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_8Cycles;
//初始化所有ADC共用配置
ADC_CommonInit(&ADC_CommonInitStructure);
//定义ADC初始化结构体
ADC_InitTypeDef ADC_InitStructure;
//初始化上述结构体
ADC_StructInit(&ADC_InitStructure);
//配置ADC分辨率为12位
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
//配置ADC为单次转换模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
//配置ADC为非扫描模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
//配置ADC数据对齐方式为右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//配置ADC外部触发为下降沿触发
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling;
//配置ADC外部触发源为TIM2的TRGO输出
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
//配置ADC转换通道数为1(此处无用)
ADC_InitStructure.ADC_NbrOfConversion = 1;
//初始化对应的ADC
ADC_Init(ADC1, &ADC_InitStructure);
//配置每一个规则通道的排序和采样周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_56Cycles);
//开启ADC1的更新中断到NVIC的通道
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
//NVIC优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//定义NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStructure;
//选择NVIC通道为ADC_IRQn
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
//使能该通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//配置抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//配置响应优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
//初始化NVIC
NVIC_Init(&NVIC_InitStructure);
//开启ADC1,此时ADC1进入等待触发的状态
ADC_Cmd(ADC1, ENABLE);
}
/**
* @摘要 获取ADC采样的状态
* @参数 无
* @返回值 表明ADC是否已经完成采样转换,1(完成)、0(未完成)
* @说明 无
*/
uint8_t MyADC_GetFlag(void)
{
if(MyADC_GetValueFlag == 1)
{
MyADC_GetValueFlag = 0;
return 1;
}
return 0;
}
/**
* @摘要 获取ADC的采样值
* @参数 无
* @返回值 ADC的采样值
* @说明 无
*/
uint16_t MyADC_GetValue(void)
{
return MyADC_Value;
}
/**
* @摘要 ADC中断服务函数
* @参数 无
* @返回值 无
* @说明 无
*/
void ADC_IRQHandler(void)
{
if(ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET)
{
//获取ADC采样值,此时硬件会自动清除EOC标志位
MyADC_Value = ADC_GetConversionValue(ADC1);
//置采样完成标志位为1
MyADC_GetValueFlag = 1;
//清除中断挂起标志位,可以省略,原因如上所诉
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
}
- MyADC.h文件内容如下
#ifndef __MYADC_H
#define __MYADC_H
#include "stm32f4xx.h" // Device header
void MyADC_Init(void);
uint8_t MyADC_GetFlag(void);
uint16_t MyADC_GetValue(void);
#endif
- Timer.c文件内容如下
#include "Timer.h"
/**
* @摘要 初始化TIM
* @参数 无
* @返回值 无
* @说明 无
*/
void Timer_Init(void)
{
//开启TIM2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//选择TIM2的时钟模式为内部模式,时钟源为内部时钟(42*2=84MHZ)
TIM_InternalClockConfig(TIM2);
//定义时基单元初始化结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//初始化上述结构体
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
//配置预分频系数为8400
TIM_TimeBaseInitStructure.TIM_Prescaler = 8400-1;
//配置自动重装值为10000
TIM_TimeBaseInitStructure.TIM_Period = 10000-1;
//配置计数模式为向上计数
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
//配置定时器时钟频率与数字滤波器所使用的采样时钟之间的分频比
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//配置重复计数器的值为0
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
//初始化时基单元
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//选择更新事件作为触发输出
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
//开启TIM2,此时计数器开始工作
TIM_Cmd(TIM2, ENABLE);
}
- Timer.h文件内容如下
#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f4xx.h" // Device header
void Timer_Init(void);
#endif