07:STM32----ADC 아날로그-디지털 변환기

목차

1: 이력서

2: 연속 근사 ADC

3:ADC 기본 구조

 4:입력 채널

5: 규칙 그룹의 4가지 변환 모드 

1: 단일 변환, 비스캔 모드

2: 연속 변환, 비스캔 모드

3: 단일 변환, 스캐닝 모드

4: 단일 변환, 스캐닝 모드

6: 트리거 제어

7: 데이터 정렬

 8:변환 시간

9: 교정

10:ADC 하드웨어 회로

A: AD 단일 채널

1: 연결 다이어그램 

2: 기능 소개

3: 단계

4: 코드

 B:AD 다중 채널

 1: 연결 다이어그램  

2: 코드


1: 이력서

        ADC(아날로그-디지털 변환기) 아날로그-디지털 변환기

        ADC는 핀의 지속적으로 변화하는 아날로그 전압을 메모리에 저장된 디지털 변수로 변환하여 아날로그 회로에서 디지털 회로로의 브리지를 설정할 수 있습니다.

        12비트 연속 근사 ADC, 1us 변환 시간

        입력 전압 범위: 0~3.3V, 변환 결과 범위: 0~4095

        16개의 외부(GPIO) 및 2개의 내부 신호 소스(내부 온도 센서 및 내부 기준 전압)를 측정하기 위한 18개의 입력 채널

        두 가지 변환 단위: 규칙 그룹과 주입 그룹

        아날로그 감시 자동 모니터링

        입력 전압 범위 STM32F103C8T6 ADC 리소스: ADC1, ADC2, 외부 입력 채널 10개

        12비트 연속 근사 ADC, 1us 변환 시간: 

        분해능: 12비트 AD 값을 표현하기 위해 일반적으로 사용되는 자릿수, 표현 범위는 0~2^12-1, 양자화 결과의 범위는 0~4095. 자릿수가 높을수록 미세함 해상도에 해당하는 양자화 결과, 속도가 높을수록

        Conversion time: 변환 빈도로, AD 변환은 짧은 시간이 소요되며 여기서 1us는 AD 변환 시작부터 결과 생성까지 1us가 소요된다는 의미입니다. AD 변환에 해당하는 주파수는 1MHZ이며 이는 STM32 ADC의 가장 빠른 변환 주파수입니다.

 두 가지 변환 단위: 규칙 그룹 및 주입 그룹:

        일반적인 AD 변환 프로세스는 변환을 한 번 시작하고 값을 한 번 읽은 다음 다시 시작하고 값을 다시 읽는 것입니다. 

STM32의 ADC는 상대적으로 고급입니다: 그룹을 나열하고, 그룹을 한 번에 시작하고, 여러 값을 지속적으로 변환할 수 있습니다. 두 그룹이 있는데, 하나는 일반 사용을 위한 규칙 그룹이고 다른 하나는 비상용 주입 그룹입니다.

2: 연속 근사 ADC

         ADC0809: 독립적인 8비트 연속 근사 ADC 칩
        EOC는 변환 종료: 변환 종료 신호

        START: 변환 시작, 입력 펄스 제공, 변환 시작

        CLOCK: ADC 클록입니다. ADC는 REF+ 내부에서 단계적으로 판단되고
        VREF-: DAC의 기준 전압으로 판단되기 때문입니다.

3:ADC 기본 구조

 4:입력 채널

5: 규칙 그룹의 4가지 변환 모드 

ADC 초기화 시 구성되는 매개변수

단일 변환:  ADC가 한 번의 변환을 수행한 후 ADC가 중지됩니다.

지속적인 변환:  단일 변환과 달리 하나의 변환이 완료된 후에 멈추지 않고 즉시 다음 변환 라운드를 시작하고 계속합니다. 이런 식으로 처음에 한 번만 트리거하면 계속할 수 있습니다. 그 후에 변환하세요. 알겠습니다

스캔 모드 : 그룹 내 몇 개의 채널을 채워 넣으면 효과적입니다. 하나 이상의 채널을 채울 때 덮어쓰기 문제를 피해야 합니다. DMA를 사용하십시오.

Non-scanning mode : 이 그룹에서는 첫 번째 시퀀스 1의 위치만 유효하며, 이때 그룹 선택 방법은 간단히 하나를 선택하는 방식으로 축소됩니다.

 X.ADC_ContinuousConvMode=DISABLE;//연속 변환 또는 단일 변환 선택---단일 X.ADC_ScanConvMode=DISABLE;//스캔 모드 또는 비스캔 모드를 선택할 수 있습니다---비스캔 모드

1: 단일 변환, 비스캔 모드

 

        비스캐닝 모드에서는 이 그룹의 첫 번째 시퀀스 1의 위치만 유효하며, 이때 그룹을 선택하는 방법은 단순히 하나를 선택하는 방식으로 전락한다.

        채널 2와 같이 시퀀스 1의 위치에서 변환하려는 채널을 지정할 수 있습니다. 그런 다음 변환을 트리거할 수 있으며 ADC는 채널 2에서 아날로그-디지털 변환을 수행합니다. 잠시 후 변환이 수행됩니다. 변환이 완료되면 변환 결과가 데이터 레지스터에 저장되고 EOC 플래그 비트를 1로 설정 ---- 변환 프로세스가 종료됩니다. 이 EOC 플래그 비트를 판단하여 변환이 완료되면 결과를 얻을 수 있습니다. 데이터 레지스터를 읽습니다. 다른 변환을 시작하려면 다시 트리거가 필요하며 변환이 완료되고 EOC 플래그가 설정되고 결과가 읽혀집니다.

2: 연속 변환, 비스캔 모드

 

        우선 아직은 비스캔 모드이기 때문에 그룹 목록에서는 첫 번째만 사용되는데, 단일 변환과 달리 한 번의 변환이 완료된 후에 멈추지 않고 바로 다음 변환을 시작하여 바로 다음 변환을 시작하게 됩니다. 계속해서 영원히. , 처음에 한 번만 실행하면 계속해서 변환할 수 있습니다.

        장점: 변환을 시작한 후 일정 시간을 기다릴 필요가 없습니다. 항상 변환 중이므로 수동으로 변환을 시작할 필요도 없고 완료 여부를 판단할 필요도 없습니다. AD 값을 읽으려면 데이터 레지스터에서 직접 가져오면 됩니다.

3: 단일 변환, 스캐닝 모드

 

        이 모드도 단일 변환이므로 트리거될 때마다 변환이 완료된 후 중지되며 시작하려면 다음 변환을 다시 트리거해야 합니다.

        스캔 모드: 이 그룹이 사용됩니다. 순서대로 채널을 채우십시오. 여기에서 각 위치의 채널 수는 임의로 지정하고 반복할 수 있습니다. 또한 초기화 구조에 매개변수가 있습니다. ofchannels (x.ADC_NbrOfChannel=) 예를 들어 여기에 지정된 채널 수가 7이면 처음 7개 위치만 보고 x.ADC_NbrOfChannel=7이면 처음 7개 AD 채널만 변환하고, 변환 결과는 데이터 레지스터에 저장됩니다. 데이터가 덮어쓰이는 것을 방지하려면 DMA를 사용하여 적시에 데이터를 제거해야 합니다. 7개 채널의 변환이 완료된 후 EOC 신호가 생성됩니다( EOC가 1)로 설정되고 변환이 완료된 후 다음 트리거가 트리거되고 새로운 변환 라운드가 수행됩니다.

DMA 사용---채널 데이터 덮어쓰기 방지

        일반 그룹의 데이터 레지스터는 하나뿐이므로 스캔 모드를 사용하여 그룹의 7개 채널을 열면 마지막 채널만 유지되고 처음 6개 채널은 덮어쓰게 됩니다. 통로 하나.

        채널 적용 범위 문제를 피하기 위해 다음 채널이 오기 전에 현재 데이터를 MDA에 넣으려면 여기에서 MDA를 사용하십시오.

4: 단일 변환, 스캐닝 모드

         첫 번째 변환이 완료되면 다음 변환이 즉시 시작되며 그룹도 열립니다.

6: 트리거 제어

ADC 구성 시 사용되는 매개변수 -----X.ADC_ExternalTrigConv

7: 데이터 정렬

ADC 초기화 구성---X.ADC_DataAlign

 

        우리의 ADC는 12비트이고 변환 결과는 12비트 데이터인데, 데이터 레지스터가 16비트이므로 데이터 정렬 문제가 있습니다.

오른쪽 정렬 : 12비트 데이터를 오른쪽으로 정렬하고 상위 비트의 나머지 비트를 0으로 채웁니다. 일반적으로 12비트 데이터를 오른쪽으로 정렬합니다.

이 16비트 레지스터를 읽을 때 변환 결과가 직접적으로 나오도록 오른쪽 정렬을 사용하십시오.

왼쪽 정렬 : 12비트 데이터를 왼쪽으로 이동시키고, 하위 비트를 0으로 채워 결과 데이터가 실제 크기보다 커지게 됩니다. 왼쪽 정렬은 실제로 데이터를 왼쪽으로 이동시키는 것을 의미합니다. 4번, 데이터를 왼쪽으로 한 번 이동하면 이 데이터에 2를 곱한 것과 같고, 직접 읽으면 데이터를 16번 확장한 것과 같습니다. 

 8:변환 시간

 

 

9: 교정

        ADC에는 자체 교정 모드가 내장되어 있습니다. 교정은 내부 커패시터 뱅크의 변화로 인해 발생하는 정확도 오류를 크게 줄입니다. 교정하는 동안 각 커패시터에서 오류 수정 코드(디지털 값)가 계산되며, 이 코드는 후속 변환에서 각 커패시터에서 발생하는 오류를 제거하는 데 사용됩니다.

        전원을 켤 때마다 교정을 수행하는 것이 좋습니다.

        교정을 시작하기 전에 최소 2개의 ADC 클록 사이클 동안 ADC의 전원을 꺼야 합니다.

10:ADC 하드웨어 회로

 

A: AD 단일 채널

1: 연결 다이어그램

 

2: 기능 소개

stm32f10x rcc.h 파일에서 ----- ADCCLK 구성

무효 RCC_ADCCLKConfig(uint32_t RCC_PCLK2)

RCC_ADCCLKConfig : APB2 클록 72MHz 클록 신호는 ADC 프리스케일러로 나누어 ADCCLK 클록 신호를 얻습니다. 최대 ADCCLK는 14MHz이므로 6 또는 8로만 나눌 수 있습니다.

        6방향 주파수: 72Mhz/6=12Mhz, 8방향 주파수: 72Mhz/8=9Mhz

stm32f10x adc.h 파일에서----그룹 선택----규칙 그룹의 입력 채널을 선택합니다.

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);

 ADC_RegularChannelConfig : 매개변수 2-채널 선택, 매개변수 3-시퀀스 범위 1~16 선택 매개변수 3: 채널의 샘플링 시간 지정

stm32f10x adc.h 파일에서 ----ADC 초기화

무효 ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

ADC_InitTypeDef ADC_initstruct;


    ADC_initstruct.ADC_ContinuousConvMode=DISABLE;//연속 변환 또는 단일 변환 선택---단일
    ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //데이터 정렬---오른쪽 정렬
    ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//트리거 제어의 트리거 소스- --Do 외부 트리거를 사용하지 않고 내부 소프트웨어 트리거를 사용합니다.
    ADC_initstruct.ADC_Mode=ADC_Mode_Independent; //ADC 작업 모드 ---독립 모드
    ADC_initstruct.ADC_NbrOfChannel=1; //채널 수--스캔 모드에서 지정됨, 총 여러 채널
    ADC_initstruct. ADC_ScanConvMode=DISABLE;//스캔 모드 또는 비스캔 모드를 선택할 수 있습니다---비스캔 모드
    ADC_Init(ADC1,&ADC_initstruct);

stm32f10x adc.h 파일에서 ---- ADC 활성화

무효 ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)

stm32f10x adc.h 파일에서 ----ADC 교정

첫 번째 단계는 첫 번째 함수를 호출하고 교정을 재설정하는 것입니다.

두 번째 단계는 두 번째 함수를 호출하고 재설정 교정이 완료될 때까지 기다리는 것입니다.

세 번째 단계는 세 번째 함수를 호출하여 교정을 시작하는 것입니다.

네 번째 단계는 네 번째 함수를 호출하고 교정이 완료될 때까지 기다리는 것입니다.

1 : 무효 ADC_ResetCalibration(ADC_TypeDef* ADCx);
2 : FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
3 : 무효 ADC_StartCalibration(ADC_TypeDef* ADCx);
4 : FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

ADC_ResetCalibration : 교정 재설정

ADC_GetResetCalibrationStatus : 재설정 교정이 완료될 때까지 기다립니다.

ADC_StartCalibration : 교정 시작

ADC_GetCalibrationStatus : 교정 상태 가져오기

stm32f10x adc.h 파일에서 ----변환을 시작하고 결과를 얻습니다.

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)

ADC_SoftwareStartConvCmd : 소프트웨어 트리거 변환

ADC_GetFlagStatus : 플래그 상태를 가져오는 함수

ADC_GetConversionValue : ADC가 변환 값을 가져옵니다.

3: 단계

1:RCC가 시계를 켭니다------ADC 및 GPIO 시계

2: ADCCLK 구성----RCC_ADCCLKConfig

3: 배치 GPIO--------GPIO_Init

4: 그룹 선택----규칙 그룹의 입력 채널을 선택합니다------ADC_RegularChannelConfig

5: ADC 초기화-----ADC_Init

6: ADC 켜기---ADC_Cmd

7:ADC 교정:

A: 교정 재설정------ADC_ResetCalibration

B: 재설정 교정이 완료되기를 기다리는 중----ADC_GetResetCalibrationStatus

C: 교정 시작------ADC_StartCalibration

D: 교정 상태 가져오기----ADC_GetCalibrationStatus 

4: 코드

        단일 변환, 비스캔 모드 사용

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

#include "AD.h"
void AD_init(void){
	//RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//配置ADCCLK
	//APB2时钟72MHz时钟信号然后通过ADC预分频器进行分频,得到ADCCLK钟信号
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_initstruct;
	GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN;  //模拟输入,可以理解为ADC的专属模式
	GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_initstruct);
	
	//选择AD转化器----我们选择规则组的输入通道
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);  
	/*ADC_Channel_0--通道o
	1----1~16的范围规则组第几个序列
	ADC_SampleTime_55Cycles5-----指定通道的采样时间
	*/
	
	//初始化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的工作模式---独立模式
	ADC_initstruct.ADC_NbrOfChannel=1;  //通道数目--指定在扫描模式下,总共会用到几个通道
	ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以选择是扫描模式还是非扫描模式---非扫描模式
	ADC_Init(ADC1,&ADC_initstruct);

	//开启ADC
	ADC_Cmd(ADC1,ENABLE);
	
	//校准ADC
	
	//复位校准
	ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set这一位置一
	//等待复位校准完成--ADC_GetResetCalibrationStatus作用:返回复位校准的状态
	while (ADC_GetResetCalibrationStatus(ADC1)==SET);   //SET=1
	/*获取的是这个CR2_RSTCAL_Set的标志位 ,该位由软件设置并由硬件清除
	在校准寄存器被初始化后该位将被清除,所以该位的用法就是:
	你软件置该位为1,那硬件就会开始复位校准 , 当复位校准完成后,该位就会由硬件自动清0
	*/
	//开始校准
	ADC_StartCalibration(ADC1);
	//获取校准状态
	while(ADC_GetCalibrationStatus(ADC1)==SET);

}

uint16_t ad_getvalue(){
	//启动转换,获取结果
	
	//软件触发转换
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	//获取标志位状态的函数
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	/*
	EOC是规则组或注入组完成时都会置1 , 0(RESET):转换未完成:
	1(SET):转换完成
	*/
	//ADC 获取转换值
	return ADC_GetConversionValue(ADC1);
	/*ADC_GetConversionValue---那这里,因为读取DR寄存器会自动清除EOC标志位
	所以这之后我们就不需要再手动清除标志位了
	
	*/
	

}



uint16_t advalue;
float volatge;
int main(void)
{
	OLED_Init();
	AD_init();
	
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "volatge:0.00V");
	
	
	while (1)
	{
		advalue=ad_getvalue();
		volatge=(float)advalue /4095 *3.3;
		OLED_ShowNum(1, 9, advalue, 4);
		OLED_ShowNum(2, 9, volatge, 1);
//浮点数不能取余
		OLED_ShowNum(2, 11, (uint16_t)(volatge * 100) % 100, 2);
		Delay_ms(100);
//OLED_ShowNum函数是写整数的,所以使用这中方法表示小数

	}
}

ADC SET=1 RESET=0 교정

       //교정 재설정
    ADC_ResetCalibration(ADC1);
   //교정 재설정이 완료될 때까지 기다립니다.
    while (ADC_GetResetCalibrationStatus(ADC1)==SET);   
    //교정 시작
    ADC_StartCalibration(ADC1);
    //교정 상태 가져오기
    while(ADC_GetCalibrationStatus(ADC1)== 설정) ;

        교정 재설정(ADC_ResetCalibration) 기능은 CR2_RSTCAL_Set 비트를 1로 설정하는 것입니다. 

         재설정 교정이 완료되기를 기다리는 중(while (ADC_GetResetCalibrationStatus(ADC1)==SET): 얻은 것은 이 CR2_RSTCAL_Set의 플래그 비트이며, 이는 소프트웨어에 의해 설정되고 하드웨어에 의해 지워집니다. 이 비트는 교정 레지스터 후에 지워집니다. 초기화되므로 비트 사용법은 다음과 같습니다: 소프트웨어가 이 비트를 1로 설정하면 하드웨어는 재설정 교정을 시작합니다. 재설정 교정이 완료되면 비트는 하드웨어에 의해 자동으로 0으로 지워집니다.

        교정 시작(ADC_StartCalibration): 이 방법으로 교정을 시작할 수 있습니다.

        캘리브레이션 상태 가져오기(while(ADC_GetCalibrationStatus(ADC1)==SET);): 캘리브레이션이 완료되었는지 확인

변환을 시작하고 결과를 얻습니다.    SET=1 RESET=0

        ​​​​​//소프트웨어 트리거 변환
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);
    //플래그 상태를 가져오는 함수
    while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
     //ADC는 변환 값을 가져옵니다.
    return ADC_GetConversionValue(ADC1) ;
          소프트웨어 트리거 변환(ADC_SoftwareStartConvCmd): ADC가 변환을 시작합니다.

        플래그 상태를 가져오는 함수(while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);)

:  EOC는 룰 그룹이나 주입 그룹이 완료되면 1로 설정되고, 0(RESET): 변환이 완료되지 않음: 1(SET): 변환이 완료됨

        ADC는 변환 값(ADC_GetConversionValue(ADC1);)을 가져옵니다. ADC_GetConversionValue---여기서 DR 레지스터를 읽으면 EOC 플래그가 자동으로 지워지기 때문에 이후에는 플래그를 수동으로 지울 필요가 없습니다.
    

위 프로세스를 따르면 괜찮습니다. 먼저 소프트웨어가 변환을 트리거한 다음 변환이 완료될 때까지 기다립니다. 즉, EOC 플래그 위치가 1이 될 때까지 기다린 다음 마지막으로 ADC 데이터 레지스터를 읽습니다.

GPIO 구성---모드 선택 아날로그 입력 

GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN;

        AIN 모드에서는 GPIO 포트가 유효하지 않으므로 GPIO 포트의 입출력이 아날로그 전압에 간섭을 일으키지 않도록 GPIO를 분리하십시오.따라서 AIN 모드는 ADC의 전용 모드입니다.

핀아웃

       

연속 변환, 비스캔 모드 사용

        장점: 변환이 완료될 때까지 지속적으로 트리거하거나 기다릴 필요가 없습니다.

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

#include "AD.h"
void AD_init(void){
	//RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//配置ADCCLK
	//APB2时钟72MHz时钟信号然后通过ADC预分频器进行分频,得到ADCCLK钟信号
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_initstruct;
	GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN;  //模拟输入,可以理解为ADC的专属模式
	GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_initstruct);
	
	//选择AD转化器----我们选择规则组的输入通道
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);  
	/*ADC_Channel_0  --通道o
	1----1~16的范围规则组第几个序列
	ADC_SampleTime_55Cycles5-----指定通道的采样时间
	*/
	
	//初始化ADC
	ADC_InitTypeDef ADC_initstruct;
	ADC_initstruct.ADC_ContinuousConvMode=ENABLE;//选择是连续转换还是单次转换---单次
	ADC_initstruct.ADC_DataAlign=ADC_DataAlign_Right; //数据对齐---右对齐
	ADC_initstruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//触发控制的触发源---不使用外部触发,使用内部软件触发
	ADC_initstruct.ADC_Mode=ADC_Mode_Independent;//ADC的工作模式---独立模式
	ADC_initstruct.ADC_NbrOfChannel=1;  //通道数目--指定在扫描模式下,总共会用到几个通道
	ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以选择是扫描模式还是非扫描模式---非扫描模式
	ADC_Init(ADC1,&ADC_initstruct);

	//开启ADC
	ADC_Cmd(ADC1,ENABLE);
	
	//校准ADC
	
	//复位校准
	ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set这一位置一
	//等待复位校准完成--ADC_GetResetCalibrationStatus作用:返回复位校准的状态
	while (ADC_GetResetCalibrationStatus(ADC1)==SET);   //SET=1
	/*获取的是这个CR2_RSTCAL_Set的标志位 ,该位由软件设置并由硬件清除
	在校准寄存器被初始化后该位将被清除,所以该位的用法就是:
	你软件置该位为1,那硬件就会开始复位校准 , 当复位校准完成后,该位就会由硬件自动清0
	*/
	//开始校准
	ADC_StartCalibration(ADC1);
	//获取校准状态
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	
	//软件触发转换
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//连续模式下只需要触发一次

}

uint16_t ad_getvalue(){
	//启动转换,获取结果

	return ADC_GetConversionValue(ADC1);
	/*ADC_GetConversionValue---那这里,因为读取DR寄存器会自动清除EOC标志位
	所以这之后我们就不需要再手动清除标志位了
	*/	

}


uint16_t advalue;
float volatge;
int main(void)
{
	OLED_Init();
	AD_init();
	
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "volatge:0.00V");
	
	
	while (1)
	{
		advalue=ad_getvalue();
		volatge=(float)advalue /4095 *3.3;
		OLED_ShowNum(1, 9, advalue, 4);
		OLED_ShowNum(2, 9, volatge, 1);
		OLED_ShowNum(2, 11, (uint16_t)(volatge * 100) % 100, 2);
		Delay_ms(100);

	}
}

        연속 모드를 사용하기 때문에 한 번만 실행하면 되며 //소프트웨어 트리거 변환 ADC_SoftwareStartConvCmd(ADC1,ENABLE);을 void AD_init 함수로 이동합니다.

        //플래그 상태를 가져옵니다. while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);

초기화가 완료된 후 한 번만 트리거하면 내부 ADC는 우리가 지정한 채널 0을 지속적으로 변환하고 변환 결과는 데이터 레지스터에 저장됩니다. 이때 데이터 레지스터는 최신 변환 결과를 지속적으로 새로 고칩니다. uint16_t ad_getvalue()에서 사용됩니다. 여기서는 플래그 상태 기능을 가져올 필요가 없습니다.

 B:AD 다중 채널

 1: 연결 다이어그램  

 AO----아날로그 출력 핀

세 모듈의 AO는 각각 PA1, PA2 및 PA3 포트에 연결됩니다.

DO----디지털 출력

        AO는 센서가 출력하는 아날로그 전기 신호를 의미합니다. 이는 전압이나 전류와 같이 지속적으로 변화하는 신호일 수 있으며 그 값은 광도(또는 기타 측정된 매개변수)와 관련됩니다. AO 신호는 후속 처리 또는 제어를 위해 ADC(아날로그-디지털 변환기)를 통해 디지털 신호로 변환될 수 있습니다.

        DO는 센서에 의해 출력되는 디지털 신호를 의미합니다. 일반적으로 논리 레벨(예: 하이 레벨 또는 로우 레벨)로 표현되며 광도(또는 기타 측정된 매개변수)가 설정된 임계값에 도달하거나 초과하는지 여부를 나타냅니다. DO 신호는 스위치, 알람 또는 기타 디지털 제어 애플리케이션을 트리거하는 데 직접 사용할 수 있습니다.

AO와 DO를 동시에 사용함으로써 감광성 센서는 더 풍부한 정보 출력을 제공하고 다양한 응용 시나리오의 요구 사항을 충족할 수 있습니다.

이전에는 DO를 사용했지만 여기서는 A0을 사용합니다.

2: 코드

사용법: 단일 비스캔 모드

        다중 채널: 먼저 스캐닝 모드를 생각하고 그룹을 시작하고 그룹에서 사용하려는 채널을 채워야 하지만 적용 범위 문제로 인해 DMA(다음 섹션 참조)를 사용해야 하므로 스캐닝이 모드는 사용되지 않습니다

        //AD 변환기 선택----규칙 그룹
    ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5)의 입력 채널을 선택합니다. 두 번째 매개변수는 채널이며, 채널을 매개변수로 사용하고 이를 첫 번째 항목에 넣습니다. 그룹 순서대로 메인 함수에서 ad_getvalue 함수를 계속해서 호출하면 됩니다.

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

#include "AD.h"
void AD_init(void){
	//RCC开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//配置ADCCLK
	//APB2时钟72MHz时钟信号然后通过ADC预分频器进行分频,得到ADCCLK钟信号
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72Mhz/6=12Mhz
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_initstruct;
	GPIO_initstruct.GPIO_Mode=GPIO_Mode_AIN;  //模拟输入,可以理解为ADC的专属模式
	GPIO_initstruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_initstruct);
	
	 
	/*ADC_Channel_0  --通道o
	1----1~16的范围规则组第几个序列
	ADC_SampleTime_55Cycles5-----指定通道的采样时间
	*/
	
	//初始化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的工作模式---独立模式
	ADC_initstruct.ADC_NbrOfChannel=1;  //通道数目--指定在扫描模式下,总共会用到几个通道
	ADC_initstruct.ADC_ScanConvMode=DISABLE;//可以选择是扫描模式还是非扫描模式---非扫描模式
	ADC_Init(ADC1,&ADC_initstruct);

	//开启ADC
	ADC_Cmd(ADC1,ENABLE);
	
	//校准ADC
	
	//复位校准
	ADC_ResetCalibration(ADC1);//---把CR2_RSTCAL_Set这一位置一
	//等待复位校准完成--ADC_GetResetCalibrationStatus作用:返回复位校准的状态
	while (ADC_GetResetCalibrationStatus(ADC1)==SET);   //SET=1
	/*获取的是这个CR2_RSTCAL_Set的标志位 ,该位由软件设置并由硬件清除
	在校准寄存器被初始化后该位将被清除,所以该位的用法就是:
	你软件置该位为1,那硬件就会开始复位校准 , 当复位校准完成后,该位就会由硬件自动清0
	*/
	//开始校准
	ADC_StartCalibration(ADC1);
	//获取校准状态
	while(ADC_GetCalibrationStatus(ADC1)==SET);

}

uint16_t ad_getvalue(uint8_t ADC_Channel){
	//启动转换,获取结果
	
	//选择AD转化器----我们选择规则组的输入通道
	ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5); 
	
	//软件触发转换
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	//获取标志位状态的函数
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	/*
	EOC是规则组或注入组完成时都会置1 , 0(RESET):转换未完成:
	1(SET):转换完成
	*/
	//ADC 获取转换值
	return ADC_GetConversionValue(ADC1);
	/*ADC_GetConversionValue---那这里,因为读取DR寄存器会自动清除EOC标志位
	所以这之后我们就不需要再手动清除标志位了
	
	*/
	


}



uint16_t AD1,AD2,AD3,AD4;
float volatge;
int main(void)
{
	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)
	{
		
		AD1=ad_getvalue(ADC_Channel_0);
		AD2=ad_getvalue(ADC_Channel_1);
		AD3=ad_getvalue(ADC_Channel_2);
		AD4=ad_getvalue(ADC_Channel_3);

		OLED_ShowNum(1, 5, AD1, 4);
		OLED_ShowNum(2, 5, AD2, 4);
		OLED_ShowNum(3, 5, AD3, 4);
		OLED_ShowNum(4, 5, AD4, 4);
		Delay_ms(100);

	}
}

 

Supongo que te gusta

Origin blog.csdn.net/m0_74739916/article/details/132523089
Recomendado
Clasificación