首页 > 其他分享 >STM32学习记录(七):ADC

STM32学习记录(七):ADC

时间:2024-07-31 16:06:27浏览次数:12  
标签:DMA ENABLE 记录 STM32 InitStructure ADC ADC1 GPIO

STM32学习记录(七):ADC

模拟/数字转换器(Analog-to-digital converter:ADC)将模拟量转为数字量。STM32F103C8T6中的有2个12bit转换时间为1us的A/D转换器,内置了一个温度传感器,可以通过ADC读取。

ADC的系统框图

image

image

ADC读取温度传感器

STM32内部有一个温度传感器,只有使用ADC1时,内部温度传感器才是可用的。

使用单片机STM32F103C8T6的ADC1读取内部温度传感器的步骤:

  1. 配置ADC1的时钟、初始化结构体等
  2. 配置规则组或注入组的采样通道和采样时间,采样时间应在17.1us
  3. 使能温度传感器和内部参考电压通道
  4. 开启ADC1、重置ADC校准器、开始转换
  5. 读取数据寄存器的16位或者32位(仅在ADC1的双倍模式下)的值
  6. 将读取的值使用公式转换为温度:\((V_{25}-V_{SENCE})/AVG\_Slope+25\),其中\(V_{25}\)是25摄氏度时的\(V_{SENCE}\)值,查阅数据手册第5章《Electrical characteristics》,可得典型值\(V_{25}\) =1.43V、\(AVG\_Slope\) = 4.3mv/℃

STM32F103C8T6 ADC的模拟输入通道与GPIO的对应关系如下,共有10个可用的模拟输入通道。ADC1和ADC2的模拟输入通道是共用的。

ADC1/ADC2 GPIO
ADC12_IN0 PA0
ADC12_IN1 PA1
ADC12_IN2 PA2
ADC12_IN3 PA3
ADC12_IN4 PA4
ADC12_IN5 PA5
ADC12_IN6 PA6
ADC12_IN7 PA7
ADC12_IN8 PB0
ADC12_IN9 PB1

ADC1的通道16与内部温度传感器相连,ADC1的通道17与内部参考电压\(V_{REFER}\)相连。

ADC的时钟设置

PCLK2默认等于SYSCLK,也就是72MHz,而ADC最大频率为14MHz。查阅数据手册中的表格 "Table 47. RAIN max for fADC = 14 MHz"可知,在ADC时钟为14MHz、采样时间17.1us对应的采样时间(时钟周期为单位)为239.5个时钟周期。ADC要得到14MHz的时钟,HCLK的时钟应设置为56MHz,APB2预分频器再进行二分频可得14MHz的ADC时钟频率。HAL库编程时,使用STM32CubeMX很容易配置时钟。在STM32CubeMX的时钟配置中更加直观。

image

那么使用标准库时如何将系统时钟SYSCLK修改为56MHz?参照另一篇博客:STM32修改系统时钟频率

主要程序

ADC_InitTypeDef结构体的配置需查阅固件库函数手册和参考手册。

初始化ADC

因为温度传感器是芯片内部的传感器,温度传感器已经与ADC的通道16连接,内部参考电压\(V_{REFINT}\)已经与ADC的通道17连接。注意ADC必须要开启校准,否则得到的结果是不正确的。

ADC工作模式:ADC工作模式分独立模式(independent mode)和双ADC模式(dual mode)。 见参考手册11.9 Dual ADC mode

  • 独立模式:每个ADC单独工作
  • 双ADC模式:设备有2个或更多ADC的时候才能使用。双ADC模式包括以下模式,以下模式还可以进行组合
    • 同步注入模式
    • 同步规则模式
    • 快速交错模式
    • Slow interleaved mode
    • 交替触发模式

持续转换模式:开启后,持续进行数据转换

扫描模式:此模式用于扫描一组模拟通道。对于多通道,需要开启扫描模式;单通道无需开启。

数据右对齐:转换之后数据的右对齐。对于规则组而言,数据右对齐就是12bit数据从低位到高位的顺序存放在16位的内存或者寄存器中,前高4位补0。见参考手册Figure 27. Right alignment of data。其余各个取值参照参考手册。

外部触发:转换可以由外部事件触发(例如定时器捕获、EXTI线)。事件(event)和中断(interrupt)是不同的,外部中断线配置为事件模式时,中断请求寄存器是不会被置位的,仅仅是通过脉冲发生器产生一个脉冲。

void ADC_Configuration(void)
{
	/* 开启GPIO、ADC1时钟 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	/* 配置ADC */
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//独立工作模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//关闭多通道扫描模式,只有1个通道
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发,由软件触发
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//1个ADC通道
	ADC_Init(ADC1, &ADC_InitStructure);

	/* Configures ADC1 Channel16 as: first converted channel with an 239 cycles sample time */ 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); //采样时间239.5/14MHz = 17.1us

	/* 使能温度传感器和内部参考电压通道 */ 
	ADC_TempSensorVrefintCmd(ENABLE); 

	/* 开启ADC */
	ADC_Cmd(ADC1, ENABLE);

	/* 重置ADC校准寄存器 */
	ADC_ResetCalibration(ADC1);

	/* 检查复位ADC校准是否结束 */
	while(ADC_GetResetCalibrationStatus(ADC1));

	/* 开启ADC校准 */
	ADC_StartCalibration(ADC1);

	/* 检查校准是否结束 */
	while(ADC_GetCalibrationStatus(ADC1));
    
    /* 开始ADC软件转换 */
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

读取数据

可以选择读取多次的数据,然后求平均值,这里演示没有多次读取并求平均值。

int main()
{
    COM_Init();
    ADC_Configuration();
    while(1)
    {
        showTemperature();
        delay_ms(1000);
    }
}

void showTemperature(void)
{
	/*Returns the ADC1 Master data value of the last converted channel*/ 
	uint16_t DataValue = 0; 
	DataValue = ADC_GetConversionValue(ADC1);
	
    // ADC精度:(VDDA/4096),VDDA是ADC供电电压,使用的是3.3v
    // VSENSE = DataValue*(3.3/4096);
	// Temperature (in °C) = {(V25 - VSENSE ) / Avg_Slope} + 25.
	// v25典型值1.43V  Avg_Slope 4.3mv/°c VSENSE=DataValue
	//精度Vdda/4096
	double temperature;
	double VSENSE = DataValue*(3.3/4096);
	temperature = (1.43 - VSENSE) / (0.0043) + 25;
	printf("VSENSE: %.2f, temperature: %.2f",VSENSE, temperature);	//向串口发送消息
}

演示结果

以下是没有加ADC校准得到的错误结果。正确的演示结果参照后面的演示结果。

image

ADC使用DMA多通道读取

什么是DMA?引用参考手册第13章:

Direct memory access (DMA) is used in order to provide high-speed data transfer between peripherals and memory as well as memory to memory. Data can be quickly moved by DMA without any CPU actions. This keeps CPU resources free for other operations.

DMA用于外设和内存之间的高速数据传输,数据通过DMA能够没有在CPU的参与下进行快速传输,DMA减轻了CPU的压力。STM32F103C8T6有一个7通道的DMA控制器,支持的外设包括ADC、SPI、I2C、USART。

ADC1在独立工作模式下的数据寄存器只有16位,对于ADC的多通道采样有两种方式:

  1. 不使用DMA。ADC应当被配置为:单次转换、关闭扫描模式、采样通道为1。通过软件设置采样通道来读取不同通道的数据
  2. 使用DMA。ADC将多个通道按照设置的采样顺序,将数据经过DMA的传输,传输到一个用户设置的缓冲区,只需读取这个缓冲区的值就可以获得每个通道的采样数据

这里介绍使用DMA的方式,ADC1的通道0、通道7、通道16这3个通道完成,连线:

  • 寻迹传感器(反射式光电传感器)AO引脚接PA0
  • 光敏电阻传感器接AO口接PA7
  • STM32内部温度传感器与通道16已经相连无需连接GPIO。

在这里传感器不做介绍。

主要程序

初始化以及配置DMA1

__IO uint16_t ADCConvertedValue[3]; //缓冲区,存放DMA将读取到的数据

void DMA_Configuration(void)
{
	/* 开启DMA时钟 */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	/* 反初始化DMA1通道1 */
	DMA_DeInit(DMA1_Channel1);

	/* 配置DMA初始化结构体 */
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);		//配置外设基地址,这里是ADC1数据寄存器的地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//外设数据大小,16位
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;	//配置内存基地址,这里是存数据的内存地址
	DMA_InitStructure.DMA_BufferSize = 3;		//缓存区中数据的个数
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	//外设作为数据传输的来源 
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	//关闭DMA的内存到内存模式
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	//内存数据大小,16位
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;	//内存地址递增,缓冲区要存放3个数据
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;		//循环缓存模式,即多次读取数据到缓冲区
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;		//优先级高
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//外设地址不递增
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);	//初始化DMA
	DMA_Cmd(DMA1_Channel1, ENABLE);	//使能DMA
}

配置ADC

void ADC_Configuration(void)
{
	/* 开启GPIO、ADC1时钟 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	/* 配置ADC */
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//独立工作模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//关闭多通道扫描模式,只有1个通道
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发,由软件触发
	ADC_InitStructure.ADC_NbrOfChannel = 3;	//1个ADC通道
	ADC_Init(ADC1, &ADC_InitStructure);

	/* ADC通道按照0、7、16的顺序进行采样,采样时间为239.5个时钟周期 */ 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us
	ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us
	ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us

	/* 打开ADC内部温度传感器通道、参考电压通道 */ 
	ADC_TempSensorVrefintCmd(ENABLE); 

	/* 开始ADC1的DMA模式 */
	ADC_DMACmd(ADC1, ENABLE);

    /* ADC校准是固定流程,且是必须要的 */
	/* 开启ADC1 */
	ADC_Cmd(ADC1, ENABLE);

	/* 重置ADC校准寄存器 */
	ADC_ResetCalibration(ADC1);

	/* 检查复位ADC校准是否结束 */
	while(ADC_GetResetCalibrationStatus(ADC1));

	/* 开启ADC校准 */
	ADC_StartCalibration(ADC1);

	/* 检查校准是否结束 */
	while(ADC_GetCalibrationStatus(ADC1));

	/* ADC1开始转换 */
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

读取数据

将ADC1采样的数据读取到自行设置的缓冲区中,DMA会直接将ADC1的数据读取到地址为ADCConvertedValue的内存单元,不再使用ADC_GetConversionValue(ADC1)读取ADC1的数据,DMA的存在减少了CPU的负担,CPU不再处理ADC1的读取操作,而是直接读从DMA读取出来的数据

int main(void)
{
	COM_Init();		//串口初始化
	GPIO_Configuration()
	DMA_Configuration();	
	ADC_Configuration();

	while (1)
	{
		showData();
		delay_ms(3000);	//每3s读取一次采样数据
	}
}

void showData(void)
{
	double temperature;
	double VSENSE = (double)ADCConvertedValue[2]*(3.3/4096);
	temperature = (1.43 - VSENSE) / (0.0043) + 25;
    /* 分别打印出3个采样到的数据,下标为0:寻迹传感器的数据,1:光敏电阻传感器的数据 */
	printf("ch1: %d, ch2: %d, ch3: %.2f", ADCConvertedValue[0], ADCConvertedValue[1], temperature);
}

void GPIO_Configuration()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	 /* 配置GPIO */
    GPIO_InitTypeDef GPIO_InitStructure;

	/*	配置通道7、通道0对应的GPIO口 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7  | GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

演示结果

手指按住STM32芯片,温度会明显上升。ch1是通道0采样的数据,ch2是通道7采样的数据,ch3是通道16采样的数据

image

双ADC模式:规则同步模式

举个例子说明双ADC模式下的规则同步模式(Regular simultaneous mode)。双ADC模式下每次转换的通道不能相同,比如ADC1使用通道1时,ADC2不要同时使用通道1进行转换。

参考手册11.9.2 Regular simultaneous mode写道:

At the end of conversion event on ADC1 or ADC2:

  • A 32-bit DMA transfer request is generated (if DMA bit is set) which transfers to SRAM the ADC1_DR 32-bit register containing the ADC2 converted data in the upper halfword and the ADC1 converted data in the lower halfword.
  • An EOC interrupt is generated (if enabled on one of the two ADC interfaces) when ADC1/ADC2 regular channels are all converted.

大致意思是说,当ADC转换完成时,一个32位的DMA传输请求就会生成,DMA将32位的数据传输值SRAM中。双ADC模式下,32位的数据寄存器ADC1_DR高16位存放的是ADC2转换后的数据,低16位存放的是ADC1转换后的数据

主要程序

大致流程图如下:

flowchart TB id["开启GPIO、ADC1、ADC2、DMA1时钟"] --> id6["配置GPIO为模拟输入模式"] --> id1["配置DMA1初始化结构体,开启DMA1"] --> id2["配置ADC1、ADC2初始化结构体"] --> id3["配置ADC1、ADC2的模拟输入通道"] --> id4["打开ADC1的DMA请求"] --> id5["校准ADC1、ADC2,并开启ADC1、ADC2的转换"]

开启时钟、配置GPIO

void RCC_Configuration(void)
{
    /* 对PCLK2进行二分频 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us 

	/* 开启GPIOB、ADC1时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC2, ENABLE);

	/* 开启DMA时钟 */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}

void GPIO_Configuration(void)
{
	/* 配置GPIO */    
    GPIO_InitTypeDef GPIOInitStructure;
    GPIOInitStructure.GPIO_Mode = GPIO_Mode_AIN;	//模拟输入
    GPIOInitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7;	//PA0:通道0,PA7:通道7
    GPIOInitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_Init(GPIOA, &GPIOInitStructure);
}

初始化以及配置DMA1

__IO uint32_t ADCConvertedValue[2]; //缓存区,DMA将读取到的数据存放到其中

void DMA_Configuration(void)
{
	/* 反初始化DMA1通道1 */
	DMA_DeInit(DMA1_Channel1);

	/* 配置DMA初始化结构体 */
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);		//配置外设基地址,这里是ADC1数据寄存器的地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	//外设数据大小,32位, 双ADC模式
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;		//配置内存基地址,这里是数据存放的内存地址
	DMA_InitStructure.DMA_BufferSize = 2;		//缓存区中数据的个数
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	//外设作为数据传输的来源 
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	//关闭DMA的内存到内存模式
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;	//内存数据大小,32位
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	//内存地址需要递增,缓存区中数据个数>1
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;		//循环缓存模式,即多次读取数据到缓冲区
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;		//优先级高
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//外设地址不递增
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);	//初始化DMA

	DMA_Cmd(DMA1_Channel1, ENABLE);	//使能DMA
}

配置ADC

void ADC_Configuration(void)
{
	/* 开启GPIO、ADC1时钟 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
    
	/* 配置ADC1 */
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	//常规同步模式Regular simultaneous mode
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//开启扫描转换模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发
	ADC_InitStructure.ADC_NbrOfChannel = 2;	//2个ADC通道
	ADC_Init(ADC1, &ADC_InitStructure);

	/* 配置ADC1规则组通道 */ 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us

	/* 打开温度传感器通道和内部参考电压通道 */ 
	ADC_TempSensorVrefintCmd(ENABLE); 
	
	/* 开始ADC1的DMA模式 */
	ADC_DMACmd(ADC1, ENABLE);

	/* 配置ADC2 */
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	//常规同步模式Regular simultaneous mode
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//开启扫描转换模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//1个ADC通道
	ADC_Init(ADC2, &ADC_InitStructure);

	ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us

	/* 开启ADC1 */
	ADC_Cmd(ADC1, ENABLE);

	/* 重置ADC校准寄存器 */
	ADC_ResetCalibration(ADC1);

	/* 检查复位ADC校准是否结束 */
	while(ADC_GetResetCalibrationStatus(ADC1));

	/* 开启ADC校准 */
	ADC_StartCalibration(ADC1);

	/* 检查校准是否结束 */
	while(ADC_GetCalibrationStatus(ADC1));

	/* 开启ADC2 */
	ADC_Cmd(ADC2, ENABLE);

	/* 重置ADC校准寄存器 */
	ADC_ResetCalibration(ADC2);

	/* 检查复位ADC校准是否结束 */
	while(ADC_GetResetCalibrationStatus(ADC2));

	/* 开启ADC校准 */
	ADC_StartCalibration(ADC2);

	/* 检查校准是否结束 */
	while(ADC_GetCalibrationStatus(ADC2));

	/* ADC1、ADC2开始转换 */
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	ADC_SoftwareStartConvCmd(ADC2, ENABLE);

	/* 测试DMA1是否传输完成 */
	while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));

	/* 清除DMA1传输完成标志位 */
	DMA_ClearFlag(DMA1_FLAG_TC1);	
}

读取数据

在\(f_{ADC}=14MHz\)下,ADC的转换时间为1us,见参考手册中11章的内容:11.6 Channel-by-channel programmable sample time。因此无需判断标志位,直接读取结果即可。

__IO uint32_t ADCConvertedValue[2]; //缓存区,DMA将读取到的数据存放到其中

int main()
{
    COM_Init();				//串口初始化,用于输出采样结果
	RCC_Configuration();	//时钟配置
	GPIO_Configuration();	//GPIO配置
	DMA_Configuration();	//DMA配置	
	ADC_Configuration();	//ADC配置
	while (1)
	{
		parseData();
		delay_ms(1000);	//delay 1s
	}
}

void parseData(void)
{
	double temperature;
	uint16_t adc1_data, adc2_data, adc1_data2;
	/* 低16位是ADC1的数据,高16位是ADC2的数据 */
	adc1_data = ADCConvertedValue[0] & 0xffff;
	adc2_data = (ADCConvertedValue[0] >> 16) ;
	adc1_data2 = ADCConvertedValue[1] & 0xffff;
	double VSENSE = (double)adc1_data*(3.3/4096);
	temperature = (1.43 - VSENSE) / (0.0043) + 25;
	printf("t: %.2f, d1: %d, d2: %d", temperature, adc2_data, adc1_data2);
}

演示结果

image

参考资料

《STM32F103xx固件函数库用户手册》

《STM32F10xxx Reference manual》

https://doc.embedfire.com/mcu/stm32/f103zhinanzhe/std/zh/latest/book/ADC.html

标签:DMA,ENABLE,记录,STM32,InitStructure,ADC,ADC1,GPIO
From: https://www.cnblogs.com/qianxiaohan/p/18334868

相关文章

  • 【STM32 HAL库】HC-05 蓝牙通信
    【STM32HAL库】蓝牙通信理论模块功能接线应用CubeMX配置轮询模式发送DMA模式发送Keil5代码理论模块功能将复杂的蓝牙协议简化为串口透传即以HC-05作为串口与主机之间通信的桥梁,实现串口与主机的通信本质上就是无线的串口通信接线HC-05STM32TXRXRXTXGNDGNDV......
  • 【STM32 HAL库】TIM定时器与CubeMX配置
    【STM32HAL库】TIM定时器与CubeMX配置前言TIM定时器基本理论定时器的本质就是计数器!定时器的基本作用定时器分类定时器的外部时钟与从模式TIM基本定时器理论应用CubeMX配置Keil5代码输入捕获理论应用CubeMX配置Keil5代码PWM理论应用CubeMX配置Keil5代码前言......
  • 记录--别想调试我的前端页面代码
    ......
  • 探索Amazon S3:存储解决方案的基石(Amazon S3使用记录)
    探索AmazonS3:存储解决方案的基石本文为上一篇minio使用的衍生版相关链接:1.https://www.cnblogs.com/ComfortableM/p/18286363​ 2.https://blog.csdn.net/zizai_a/article/details/140796186?spm=1001.2014.3001.5501目录探索AmazonS3:存储解决方案的基石引言AmazonS3......
  • 搭建 STM32 网关服务器的全流程:集成嵌入式 C++、TCP/IP 通信、Flash 存储及 JWT 认证(
    引言随着物联网(IoT)技术的快速发展,基于STM32的服务器(类似网关)在数据采集、设备控制等方面的应用越来越广泛。本文将介绍搭建一个基于STM32的服务器所需的技术栈,以及详细的搭建步骤和代码示例。技术栈介绍在搭建基于STM32的服务器时,我们需要用到以下技术栈和组件:1.硬......
  • STM32F103+FreeRTOS的使用ESP8266与手机APP实现TCP连接通信控制
    前言本人初学FreeRTOS,来自不知名普通院校,大二物联网专业,简单看完百问网韦东山老师FreeRTOS就想随便找个小项目试试看,手头里没什么元器件,只有一块ESP8266wifi模块以及温湿度模块显示屏模块,所以用到的模块不多,这俩个模块可能不太适用于FreeRTOS,但主要目的想着以最少的资源练练......
  • VS2017 最近的项目记录清理 项目历史记录清理
    1、桌面右键—>新建—>快捷方式,输入路径:%USERPROFILE%\AppData\Local\Microsoft\VisualStudio\2、打开第1步创建好的快捷方式VisualStudio,找到15.0_开头的文件夹,我的系统上是15.0_33d5230f,进入该文件夹。3、找到“ApplicationPrivateSettings.xml”文件,用记事本打开,找到CodeContai......
  • HarmonyOS 集成 Flutter 问题记录
    1、DevEco-Studio升级到DevEco-StudioNEXTDeveloperBeta25.0.3版本之后报错:>hvigorERROR:Schemavalidatefailed.Detail:Pleasecheckthefollowingfields.{instancePath:'modules[2].srcPath',keyword:'pattern',params:{pa......
  • 暑假解题记录-part-1
    [LitCTF2023]easy_shark首先有一个伪加密环节的解除将6下的09改为00最下面的09也要改为00找到第一个post的http流可以发现连接的密钥为a然后找黑客进行攻击的返回包进行查看找到如下返回包,下面的flag以提示的形式为该方程解出来后的仿射密码,解得a=17,b=77解出根据题目题干,得到fl......
  • Educational Codeforces Round 168 (Rated for Div. 2) 补题记录(A~E)
    A直接暴力枚举字符添加在哪里,以及添加的字符是什么即可。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=500100;signedmain(){intT;cin>>T;while(T--){strings;cin>>s;stringans;i......