stm32学习-AD单通道

配置流程

初始化 

1.开启RCC时钟(ADC、GPIO和ADCCLK的预分频器的时钟)

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
作用:配置预分频器系数。(可以对APB2的72MHz时钟选择2/4/6/8分频,输入到ADCCLK中)

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
作用:外设时钟控制(根据外设连接的总线选择要开启的时钟)

RCC_AHBPeriph/RCC_APB2Periph/RCC_APB1Periph:选择外设

NewState:使能/使能

2.配置GPIO(把需要的GPIO配置为模拟输入的模式)

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:用结构体的参数初始化GPIO。

用法:先定义一个结构体变量,再给变量赋值,最后调用这个函数即可(这个函数就会自动读取结构体的值,然后自动把外设的各个参数配置好)。      

3.配置多路开关(把左边通道接到后边的规则组列表里)

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
作用:ADC规则组通道配置

ADCx:选择的ADC外设

ADC_Channel:指定ADC通道

Rank:序列几的位置

ADC_SampleTime:指定通道的采样时间

4.配置ADC转换器和AD数据寄存器

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
作用:用结构体的参数初始化ADC。

(如果需要模拟看门狗的话,可以通过库函数配置阈值和监测通道;如果想开启中断,就在中断输出控制里用ITConfig函数开启对应的中断输出,然后在NVIC里配置优先级,就可以触发中断了)

我们本篇先不需要配置看门狗和中断

5.开启ADC

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
作用:开启ADC

6.校准

(根据手册要求,在配置完后我们需要对其进行校准)

void ADC_ResetCalibration(ADC_TypeDef* ADCx);

作用:复位校准

FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);

作用:获取复位校准状态

void ADC_StartCalibration(ADC_TypeDef* ADCx);

作用:开始校准

FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

作用:获取开始校准状态

获取AD值

流程:

1.软件触发转换

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
作用:ADC软件开始转换状态(用于软件触发)

2.等待转换完成(EOC标志位置1)

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

作用:获取标志位状态

void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

作用:清除标志位状态

获取EOC的标志位,判断是否置1 

3.读取ADC数据寄存器

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
作用:ADC获取转换值(获取AD转换的数据寄存器,读取转换结果就需要使用这个库函数)

代码

AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	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);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

AD.h

#ifndef __AD_H
#define __AD_H

void AD_Init(void);
uint16_t AD_GetValue(void);

#endif

例题

通过电位器调节电压,调节后的AD值和电压值显示在OLED上。

接线

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t ADValue;
float Voltage;

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "Volatge:0.00V");
	
	while (1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue / 4095 * 3.3;
		
		OLED_ShowNum(1, 9, ADValue, 4);
		OLED_ShowNum(2, 9, Voltage, 1);
		OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);
		
		Delay_ms(100);
	}
}

其他重要库函数

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
作用:开启DMA输出信号(如果使用DMA转运数据,就得调用这个函数)

void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
作用:中断输出控制(用于控制某个中断能不能通往NVIC)

FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
作用:获取软件开始转换状态(一般不用)

void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
作用:配置间断模式(ADC_DiscModeChannelCountConfig是每隔几个通道间断一次;ADC_DiscModeCmd函数是确定要不要启用间断模式)

void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
作用:ADC外部触发转换控制(是否允许外部触发转换)

uint32_t ADC_GetDualModeConversionValue(void);

作用:ADC获取双模式转换值(双ADC模式读取转换结果的函数)(暂时不用)

void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);

作用:是否启用看门狗

void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold,                                                                                                                 uint16_t LowThreshold);

作用:配置高低阈值

void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);

作用:配置看门的通道

void ADC_TempSensorVrefintCmd(FunctionalState NewState);
作用:ADC温度传感器内部电压控制(用于开启内部的两个通道)

ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);

作用:获取中断状态

void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);

作用:清除中断挂起位

有什么问题欢迎在评论区里提出来




 

  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是STM32F103AD通道扫描连续转换程序的示例代码: ```c #include "stm32f10x.h" #define ADC1_DR_Address ((uint32_t)0x4001244C) uint16_t ADCConvertedValue[4]; void ADC1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); } void ADC1_Mode_Config(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 4; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } void DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 4; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); } int main(void) { ADC1_GPIO_Config(); ADC1_Mode_Config(); DMA_Config(); while(1); } ``` 在此示例中,我们使用了ADC1和DMA1的通道扫描连续转换模式。我们将4个通道(PA0,PA1,PA2,PA3)配置为模拟输入,并使用DMA传输转换数据。 在程序中,我们使用了以下函数: - `ADC1_GPIO_Config()` - 配置ADC的GPIO引脚 - `ADC1_Mode_Config()` - 配置ADC的工作模式 - `DMA_Config()` - 配置DMA通道 - `main()` - 主函数,其中我们将配置函数调用并启用DMA传输 程序的核心是在`ADC1_Mode_Config()`函数中,其中我们配置了ADC的工作模式,包括通道扫描模式和连续转换模式。在这里,我们将ADC的4个通道配置为模拟输入,并将DMA传输启用以传输转换数据。 请注意,此示例中的ADC采样时间为55.5个时钟周期。您可以根据您的具体应用程序要求进行调整。 此外,请确保您已正确地配置ADC和DMA的中断和错误处理程序,以便在发生错误时进行适当的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值