STM32之ADC通道采集片内温度并通过串口传输

STM32之ADC通道采集片内温度并通过串口传输

软件实验要求

系统主频 16 MHZ,采用内部晶振,通过 DMA 采样三个数,一个是 PA4 引脚上的电压电平,一个是内部温度传感器数值,还有个是 VREF 电压。然后通过芯片 PB6,PB7 的 USART1 口,实现串口通信传输数据。

使用STM32CubeMX创建项目

使用STM32CubeMX新建并配置好 PA4 为 ADC 口,内部温度采集,以及内部参考电压采集,再配置 DMA 以及中断。

  1. 新建好 STM32G030C8T6 的 STM32CubeMX 工程之后,在如图 2.1 在Pinout&Configuration 栏目的 System Core 下,先点击 SYS,再勾选 Serial Wire 框,配置好 SWD 下载引脚设置,系统默认采用内部 16MHZ 晶振,默认系统主频是 16MHZ,所以不需要配晶振与 PLL。

图2.1

  1. 如图 2.2 的 1,2,3 步骤完成 PA4 引脚作为 ADC 通道 4 引脚,内部参考电压采集以及温度采集。

图2.2

  1. 如图 2.4,如图 2.5 完成 DMA 配置。

图2.4

图2.5

  1. 如图 2.3 的 1,2,3,4,5 步骤完成 ADC 采集参数配置。

图2.3

  1. 如图2.6,图2.7配置 PB6,PB7 为 USART1 收发引脚以及相应的中断使能。

图2.6

图2.7

  1. 如图2.8,图2.9 配置项目

图2.8

图2.9

完成配置之后,生成工程代码。

使用 Keil uVision 5编辑

main.h中添加

//...
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

#define DIGITAL_SCALE_12BITS ((uint32_t) 0xFFF)

/* Init variable out of ADC expected conversion data range */
#define VAR_CONVERTED_DATA_INIT_VALUE (DIGITAL_SCALE_12BITS + 1)

/* Definition of ADCx conversions data table size */
#define ADC_CONVERTED_DATA_BUFFER_SIZE ((uint32_t)  3)

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */
//...

usart.h中添加

//...
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

void UART_Print(char *msg);

/* USER CODE END Includes */

extern UART_HandleTypeDef huart1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */
// ...

usart.c中定义

//...

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
#include "string.h"

/* USER CODE BEGIN 0 */

void UART_Print(char *msg) {
    HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
}

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

//...

main.c中修改,首先添加头文件#include "stdio.h",然后

//...
//存放3组数据,分别是ADC1_Ch4,温度,参考电压
__IO   uint16_t   aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE];

//定义变量,在ADC采样结束,DMA传送完成置位,方便主程序取数据
__IO   uint8_t ubDmaTransferStatus = 2;

//温度值,单位度
uint32_t Tempruate;

//参考电压值,ADC1_Ch4采样电压值,单位V
uint16_t VrefData, VolDta;

//ADC数据采样结束回调函数,用于置位采样结束标志位
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  /* Prevent unused argument(s) compilation warning */
     UNUSED(hadc);

    //置1
   ubDmaTransferStatus=1;
}
//...
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

    uint32_t tmp_index_adc_converted_data = 0;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

    for (tmp_index_adc_converted_data = 0; tmp_index_adc_converted_data < ADC_CONVERTED_DATA_BUFFER_SIZE; tmp_index_adc_converted_data++)
  {
        //采样数组清零
    aADCxConvertedData[tmp_index_adc_converted_data] = VAR_CONVERTED_DATA_INIT_VALUE;  
  }

    //ADC自校准
    if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
  {
    /* Calibration Error */
    while(1);
  }

    //启动ADC DMA传输
    if (HAL_ADC_Start_DMA(&hadc1,
                        (uint32_t *)aADCxConvertedData,
                        ADC_CONVERTED_DATA_BUFFER_SIZE
                       ) != HAL_OK)
  {
    /* ADC conversion start error */
    while(1);
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

        /* Clear DMA buffer when filled before refilling it */
    if (ubDmaTransferStatus == 1)//判断数据是否已经转换完成
    {
            VolDta=aADCxConvertedData[0]*3300/4096;//计算通道ADC1_Ch4采样到的电压值
            VrefData=__LL_ADC_CALC_VREFANALOG_VOLTAGE(aADCxConvertedData[2],ADC_RESOLUTION_12B);//计算参考电压
          Tempruate=__HAL_ADC_CALC_TEMPERATURE(VrefData,aADCxConvertedData[1],ADC_RESOLUTION_12B);//计算温度值

            char message[100];
            sprintf(message, "Voltage: %d mV, Temp: %lu C, Vref: %d mV\n", VolDta, Tempruate, VrefData);
            UART_Print(message);

            HAL_Delay(5000);

      for (tmp_index_adc_converted_data = 0; tmp_index_adc_converted_data < ADC_CONVERTED_DATA_BUFFER_SIZE; tmp_index_adc_converted_data++)
      {
        aADCxConvertedData[tmp_index_adc_converted_data] = VAR_CONVERTED_DATA_INIT_VALUE;//采样数组清0
      }
      /* Update status variable of DMA transfer */
      ubDmaTransferStatus = 0;//完成标志清0
    }

  }
  /* USER CODE END 3 */
}

点击编译,导入程序

使用TTL转USB接上开发板,打开串口程序

为什么会出现923,922等数据,我暂时还没搞懂,之后再更新。

2025年3月28日更新:

之前有遇到会出现923,922这样的数据,大概是因为

char message[100];
sprintf(message, "Voltage: %d mV, Temp: %lu C, Vref: %d mV\n", VolDta, Tempruate, VrefData);
UART_Print(message);

这样的方法,造成了溢出,可以根据 https://www.syuez.com/blog/STM32%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1%E5%AE%9E%E9%AA%8C.html 文章中的printf()重定向来解决。

将发送方法改成

printf("Voltage: %d mV, Temp: %d C, Vref: %d mV\n", VolDta, Tempruate, VrefData);

文字部分代码由GPT-4o生成