一、单通道

》单通道很简单

1.配置ADC的初始化

(1)初始化通道引脚的时钟和ADC的时钟,并且注意ADC是特殊的最大14Hz所以需要分频

(2)GPIO配置

(3)配置ADC

注意开关什么的都是最后配置

首先对ADC的常规规则通道进行配置,

之后初始化ADC,

之后可以配置ADC相关的中断或者模拟看门狗,

最后开启ADC的总开关,触发输入的开关(硬件开关/软件开关),

(4)开启校准

2.封装取DR下的值函数

3.main函数不断调用这个函数


mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
 
uint16_t AD_Value;
float Voltage;
 
int main()
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "AD_Value:");
	OLED_ShowString(2, 1, "Voltage:0.00V");
	
	while(1)
	{
		AD_Value = AD_GetValue();
		Voltage = (float)AD_Value / 4095 * 3.3;			// 整数除以小数会舍弃小数部分
		
		OLED_ShowNum(1, 10, AD_Value, 4);
		OLED_ShowNum(2, 9, Voltage, 1);								// 显示整数部分
		OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);	// 显示小数部分
		
		Delay_ms(100);
	}
}
 

adc.c

#include "stm32f10x.h"                  // Device header
 
/**
  * @brief  ADC初始化函数(软件触发,且这里不使用模拟看门狗和中断)
  * @param  无
  * @retval 无
  */
void AD_Init(void)
{
	// 1. RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);	// ADCCLK = 72MHz / 6 = 12MHz
	
	// 2. 配置GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 3. 将指定的GPIO端口接入规则组列表中
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	// 把通道0填入序列1中,通道的采样周期是55.5个ADCCLK的周期
	
	// 4. 配置ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;						// ADC模式(独立模式或双ADC模式):独立模式						
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;					// ADC数据对齐:右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	// ADC外部触发源选择:不使用外部源触发(这里使用软件触发)
	ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;					// ADC连续转换模式:单次转换
	ADC_InitStruct.ADC_ScanConvMode = DISABLE;							// ADC扫描模式:非扫描
	ADC_InitStruct.ADC_NbrOfChannel = 1;								// 扫描模式下通道的数量
	ADC_Init(ADC1, &ADC_InitStruct);
	
	/*	中断和模拟看门狗在此配置	*/
	
	// 5. 开关控制
	ADC_Cmd(ADC1, ENABLE);
	
	// 6. 对ADC进行校准
	ADC_ResetCalibration(ADC1);								// 复位校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);		// 等待复位校准完成
	ADC_StartCalibration(ADC1);								// 开始校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);			// 等待校准完成
}
 
/**
  * @brief  ADC结果读取函数(软件触发)
  * @param  无
  * @retval 转换之后的结果
  */
uint16_t AD_GetValue(void)
{
	// 1. 软件触发开启转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	
	// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);		// 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
	
	// 3. 读取ADC数据寄存器并返回
	return ADC_GetConversionValue(ADC1);	// 读取之后会自动清除EOC标志位
}
 
 

二、多通道

因为多通道单次常规转换会导致值的覆盖,所以后续使用DMA

这里未使用DMA,所以只读取就行,不管覆盖

所以这里,多初始化了几个引脚,然后主函数轮流实现getValue()

这里的getValue()做了特殊处理,即在每次转换前,根据函数形参灵活更改规则组的通道1

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
 
uint16_t AD0, AD1, AD2, AD3;
 
int main()
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
 
	
	while(1)
	{
		AD0 = AD_GetValue(ADC_Channel_0);
		AD1 = AD_GetValue(ADC_Channel_1);
		AD2 = AD_GetValue(ADC_Channel_2);
		AD3 = AD_GetValue(ADC_Channel_3);
		
		OLED_ShowNum(1, 5, AD0, 4);
		OLED_ShowNum(2, 5, AD1, 4);
		OLED_ShowNum(3, 5, AD2, 4);
		OLED_ShowNum(4, 5, AD3, 4);
 
		Delay_ms(100);
	}
}
 

adc.c

#include "stm32f10x.h"                  // Device header
 
/**
  * @brief  ADC初始化函数(单次转换非扫描实现多通道转换,软件触发,且这里不使用模拟看门狗和中断)
  * @param  无
  * @retval 无
  */
void AD_Init(void)
{
	// 1. RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);	// ADCCLK = 72MHz / 6 = 12MHz
	
	// 2. 配置GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 3. 将指定的GPIO端口接入规则组列表中
	/*	这里要在每一次转换前都更改转换列表中要转换的GPIO端口	*/
	
	// 4. 配置ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;						// ADC模式(独立模式或双ADC模式):独立模式						
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;					// ADC数据对齐:右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	// ADC外部触发源选择:不使用外部源触发(这里使用软件触发)
	ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;					// ADC连续转换模式:单次转换
	ADC_InitStruct.ADC_ScanConvMode = DISABLE;							// ADC扫描模式:非扫描
	ADC_InitStruct.ADC_NbrOfChannel = 1;								// 扫描模式下通道的数量
	ADC_Init(ADC1, &ADC_InitStruct);
	
	/*	中断和模拟看门狗在此配置	*/
	
	// 5. 开关控制
	ADC_Cmd(ADC1, ENABLE);
	
	// 6. 对ADC进行校准
	ADC_ResetCalibration(ADC1);								// 复位校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);		// 等待复位校准完成
	ADC_StartCalibration(ADC1);								// 开始校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);			// 等待校准完成
}
 
/**
  * @brief  ADC结果读取函数(单次转换非扫描实现多通道转换,软件触发)
  * @param  无
  * @retval 转换之后的结果
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	// 把通道作为参数填入序列1中,通道的采样周期是55.5个ADCCLK的周期
	
	// 1. 软件触发开启转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	
	// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);		// 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
	
	// 3. 读取ADC数据寄存器并返回
	return ADC_GetConversionValue(ADC1);	// 读取之后会自动清除EOC标志位
}
 
 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐