搜索
查看: 4703|回复: 3

[原创] NUCLEO-STM32F767+双通道ADC+DMA

[复制链接]

该用户从未签到

19

主题

1473

帖子

27

蝴蝶豆

论坛元老

最后登录
2021-11-17
发表于 2017-7-27 21:37:14 | 显示全部楼层 |阅读模式
本帖最后由 队长shiwo 于 2017-7-27 21:39 编辑

        使用ADC1的ADC_CHANNEL_TEMPSENSOR;//ADC1 内部温度传感器通道和ADC_CHANNEL_VREFINT;//ADC1 内部参考电压通道来实现双通道ADC的转换,
内部温度传感器特性:
 支持的温度范围: -40 °C 到 125 °C
 精度: ±1.5 °C

使用以下公式计算温度:
温度(单位为 °C) = {(VSENSE – V25) / Avg_Slope} + 25
其中:
– V25 = 25 °C 时的 VSENSE 值
– Avg_Slope = 温度与 VSENSE 曲线的平均斜率(以 mV/°C 或 µV/°C 表示)
有关 V25 和 Avg_Slope 实际值的相关信息,请参见数据手册中的电气特性一节。

1、设置 ADC1, 开启内部温度传感器。
在 HAL 库中开启内部温度传感器,只需要将 ADC 通道改为 ADC_CHANNEL_TEMPSENSOR 即可,调用 HAL_ADC_ConfigChannel()函数配置通道的时候,会自动检测如果是温度传感器通道会在函数中设置 TSVREFE 位。
2、读取通道 16 AD 值,计算结果。
在设置完之后,我们就可以读取温度传感器的电压值了,得到该值就可以用上面的公式计算温度值了。

t.png tt.png
内部参考电压:
ttt.png
注意:必须将 TSVREFE 位置 1 才能同时对两个内部通道进行转换: ADC1_IN16(温度传感器)和ADC1_IN17 (VREFINT)

采用连续扫描模式,DMA循环模式,具体看代码的注释
主要代码:
  1. /**
  2.   ******************************************************************************
  3.   * File Name          : ADC.c
  4.   * Description        : This file provides code for the configuration
  5.   *                      of the ADC instances.
  6.   ******************************************************************************
  7.   内部温度值计算:
  8.   T(℃) =[(Vsense - V25)/Avg_Slope]+25
  9.   上式中:
  10.   V25=Vsense 在 25 度时的数值(典型值为: 0.76)。
  11.   Avg_Slope=温度与 Vsense 曲线的平均斜率(单位为 mv/℃或 uv/℃)(典型值为2.5mV/℃)。
  12.   */
  13. /* Includes ------------------------------------------------------------------*/
  14. #include "adc.h"
  15. #include "dma.h"

  16. /* USER CODE BEGIN 0 */
  17. #include "lcd.h"

  18. //ADC_HandleTypeDef ADC1_Handler;
  19. #define ADC1_NUMOFCHANNEL  2
  20. /* USER CODE END 0 */

  21. /* ADC1 init function */
  22. ADC_HandleTypeDef hadc1;
  23. void MX_ADC1_Init(void)
  24. {
  25.   ADC_ChannelConfTypeDef ADC1_ChanConf;

  26. /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */
  27.   hadc1.Instance = ADC1;
  28.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;//分频系数:4分频,APB2=108MHZ,  ADC时钟:108/4=27MHZ,不能高于36MHZ,精度会下降的
  29.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;          //采样分辨率
  30.   hadc1.Init.ScanConvMode = ENABLE;                    //扫描模式
  31.   hadc1.Init.ContinuousConvMode = ENABLE;              //开启连续转换模式
  32.   hadc1.Init.DiscontinuousConvMode = DISABLE;          //不连续采样模式
  33.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //外部触发边沿:无
  34.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;    //外部触发方式 :软件触发
  35.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;          //右对齐
  36.   hadc1.Init.NbrOfConversion = ADC1_NUMOFCHANNEL;      //规则序列中有多少个转换
  37.   hadc1.Init.DMAContinuousRequests = ENABLE;           //开启 DMA 请求连续模式或者单独模式
  38.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;       //EOC 标志是否设置 规则转换完成标志
  39.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  40.   {
  41.     _Error_Handler(__FILE__, __LINE__);
  42.   }

  43.   /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */
  44.   ADC1_ChanConf.Channel = ADC_CHANNEL_TEMPSENSOR;//ADC1 内部温度传感器通道
  45.   ADC1_ChanConf.Rank = 1;    //规则通道中的第1个转换
  46.   ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_144CYCLES; //采样间隔144个周期
  47.   if (HAL_ADC_ConfigChannel(&hadc1, &ADC1_ChanConf) != HAL_OK)
  48.   {
  49.     _Error_Handler(__FILE__, __LINE__);
  50.   }
  51.   
  52.   /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */
  53.   ADC1_ChanConf.Channel = ADC_CHANNEL_VREFINT;//ADC1 内部参考电压通道
  54.   ADC1_ChanConf.Rank = 2; //规则通道中的第2个转换
  55.   //ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_144CYCLES;//采样间隔144个周期
  56.   if (HAL_ADC_ConfigChannel(&hadc1, &ADC1_ChanConf) != HAL_OK)
  57.   {
  58.     _Error_Handler(__FILE__, __LINE__);
  59.   }
  60.   
  61.   //HAL_ADC_Start(&hadc1); //开启 ADC1

  62. }

  63. __IO uint16_t ADC1_DMA2_Buff[ADC1_NUMOFCHANNEL];
  64. DMA_HandleTypeDef hdma_adc1;
  65. void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
  66. {

  67.   if(adcHandle->Instance==ADC1)
  68.   {
  69.   /* USER CODE BEGIN ADC1_MspInit 0 */

  70.   /* USER CODE END ADC1_MspInit 0 */
  71.     /* ADC1 clock enable */
  72.     __HAL_RCC_ADC1_CLK_ENABLE();
  73.      /* DMA controller clock enable */
  74.     __HAL_RCC_DMA2_CLK_ENABLE();
  75.   
  76.     /* ADC1 DMA Init 看DMA2的各数据流通道映射表:ADC1-DMA2 通道0 数据流0*/
  77.     /* ADC1 Init */
  78.     hdma_adc1.Instance = DMA2_Stream0;                           // DMA2 数据流0
  79.     hdma_adc1.Init.Channel = DMA_CHANNEL_0;                      // DMA2 通道0
  80.     hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;             // 外设到内存
  81.     hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;                 // 外设地址寄存器不变
  82.     hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;                     // 内存地址寄存器递增
  83.     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;// 外设数据宽度为半字
  84.     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;   // 内存数据宽度为半字
  85.     hdma_adc1.Init.Mode = DMA_CIRCULAR;                          // 工作在循环缓存模式
  86.     hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;                 // DMA通道 x拥有高优先级
  87.     hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;              // FIFO禁止
  88.     if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
  89.     {
  90.       _Error_Handler(__FILE__, __LINE__);
  91.     }

  92.     __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);

  93.     /* ADC1 interrupt Init */
  94. //    HAL_NVIC_SetPriority(ADC_IRQn, 1, 2);
  95. //    HAL_NVIC_EnableIRQ(ADC_IRQn);
  96.    
  97.     /*DMA interrupt init DMA2_Stream0_IRQn interrupt configuration */
  98.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 1);
  99.     HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  100.   /* USER CODE BEGIN ADC1_MspInit 1 */
  101.    
  102.   /* USER CODE END ADC1_MspInit 1 */
  103.   }
  104. }

  105. void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
  106. {

  107.   if(adcHandle->Instance==ADC1)
  108.   {
  109.   /* USER CODE BEGIN ADC1_MspDeInit 0 */

  110.   /* USER CODE END ADC1_MspDeInit 0 */
  111.     /* Peripheral clock disable */
  112.     __HAL_RCC_ADC1_CLK_DISABLE();

  113.     /* ADC1 DMA DeInit */
  114.     HAL_DMA_DeInit(adcHandle->DMA_Handle);

  115.     /* ADC1 interrupt Deinit */
  116.     HAL_NVIC_DisableIRQ(ADC_IRQn);
  117.   /* USER CODE BEGIN ADC1_MspDeInit 1 */

  118.   /* USER CODE END ADC1_MspDeInit 1 */
  119.   }
  120. }

  121. /* USER CODE BEGIN 1 */
  122. uint16_t Get_Adc(uint32_t channel)
  123. {
  124. //  ADC_ChannelConfTypeDef ADC1_ChanConf;
  125. //  ADC1_ChanConf.Channel=channel; //通道
  126. //  ADC1_ChanConf.Rank=1; //第 1 个序列,序列 1
  127. //  ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
  128. //  ADC1_ChanConf.Offset=0;
  129. //  HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置
  130.   HAL_ADC_Start(&hadc1); //开启 ADC1
  131.   HAL_ADC_PollForConversion(&hadc1,10); //轮询转换
  132.   return (uint16_t)HAL_ADC_GetValue(&hadc1); //返回最近转换结果
  133. }

  134. //获取指定通道的转换值,取 count 次,然后平均
  135. //channel:获取次数
  136. //返回值:通道 ch 的 channel 次转换结果平均值
  137. uint16_t Get_Adc_Average(uint32_t channel,uint8_t count)
  138. {
  139.   uint32_t temp_val=0;
  140.   uint8_t t;
  141.   for(t=0;t<count;t++)
  142.   {
  143.     temp_val+=Get_Adc(channel);
  144.     //delay_ms(5);
  145.   }
  146.   return temp_val/count;
  147. }



  148. short Get_Temprate_Value(void)
  149. {
  150.   short result;
  151.   double temperate;
  152.   //uint32_t adcx;
  153.   
  154.   //adcx=Get_Adc_Average(ADC_CHANNEL_TEMPSENSOR,10);
  155.   //读取内部温度传感器通道,10 次取平均
  156.   temperate=(float)(ADC1_DMA2_Buff[0] *(3.3/4096)); //电压值adcx
  157.   temperate=(temperate-0.76)/0.0025 + 25; //转换为温度值
  158.   result=temperate*=100; //扩大 100 倍.
  159.   return result;
  160. }
  161. short Get_Vref_Value(void)
  162. {
  163.   uint16_t VRef;
  164.   VRef = (ADC1_DMA2_Buff[1] * VREF)/(MAX_CONVERTED_VALUE);
  165.   return VRef;
  166. }  

  167. //显示内部温度和内部参考电压值
  168. uint8_t Show_flag = 0;
  169. void Show_TempVref_Value(void)
  170. {
  171.    /*内部温度值计算:
  172.     T(℃) =[(Vsense - V25)/Avg_Slope]+25,     V25=Vsense 在 25 度时的数值(典型值为: 0.76)。   
  173.     Avg_Slope=温度与 Vsense 曲线的平均斜率(单位为 mv/℃或 uv/℃)(典型值为2.5mV/℃)。*/
  174.   
  175.    // JTemp = ((((ADC1_DMA2_Buff[0] * VREF)/MAX_CONVERTED_VALUE) - V25_TEMP) * 10 / AVG_SLOPE) + AMBIENT_TEMP;
  176.   short temp;
  177.   char Tmp_TempBuf[3]={0};
  178.   char *Tmp_TempBuff = Tmp_TempBuf;
  179.   char Tmp_VrefBuf[3]={0};
  180.   char *Tmp_VrefBuff = Tmp_VrefBuf;
  181.   if(Show_flag == 0)//只显示一次
  182.   {   
  183.     Show_flag = 1;
  184.    
  185.     LCD12896_Display_12x12str(5,12, "CPU:"); //
  186.     HAL_Delay(200);
  187.     LCD12896_Display_12x12str(5,36, "温度:"); //
  188.     HAL_Delay(200);  
  189.     LCD12896_Display_12x12str(5,92,".");    //显示小数点
  190.     HAL_Delay(200);
  191.     LCD12896_Display_12x12str(5,108, "`C"); //显示`C
  192.     HAL_Delay(200);
  193.    
  194.     LCD12896_Display_12x12str(7,12, "参考电压:"); //
  195.     HAL_Delay(200);
  196.     LCD12896_Display_12x12str(7,84,".");              //显示小数点
  197.     HAL_Delay(200);
  198.     LCD12896_Display_12x12str(7,108, "V"); //
  199.     HAL_Delay(200);
  200.    
  201.   }

  202.   temp=Get_Temprate_Value(); //得到温度值
  203.   if(temp < 0)
  204.   {
  205.     temp = -temp;
  206.     LCD12896_Display_12x12str(5,68,"-"); //显示负号
  207.   }
  208.   else
  209.     LCD12896_Display_12x12str(5,68," "); //无符号
  210.   Tmp_TempBuff[0]=temp/100/10 + 48 +'\0';
  211.   Tmp_TempBuff[1]=temp/100%10 + 48 +'\0';  
  212.   LCD12896_Display_12x12str(5,76,&Tmp_TempBuff[0]); //显示整数部分
  213.   //HAL_Delay(20);
  214.   LCD12896_Display_12x12str(5,84,&Tmp_TempBuff[1]); //显示整数部分
  215.   //HAL_Delay(20);
  216.   Tmp_TempBuff[2]=temp%100/10 + 48 +'\0';
  217.   LCD12896_Display_12x12str(5,100,&Tmp_TempBuff[2]); //显示小数部分
  218.   HAL_Delay(20);

  219.   temp = Get_Vref_Value();
  220.   Tmp_VrefBuff[0]=temp/1000 + 48 +'\0';  
  221.   LCD12896_Display_12x12str(7,76,&Tmp_VrefBuff[0]); //显示整数部分
  222.   //HAL_Delay(20);   
  223.   Tmp_VrefBuff[1]=temp/100%10 + 48 +'\0';
  224.   Tmp_VrefBuff[2]=temp%100/10 + 48 +'\0';
  225.   LCD12896_Display_12x12str(7,92,&Tmp_VrefBuff[1]); //显示小数部分
  226.   //HAL_Delay(20);
  227.   LCD12896_Display_12x12str(7,100,&Tmp_VrefBuff[2]); //显示小数部分
  228.   HAL_Delay(20);
  229.   
  230. }
  231. /* USER CODE END 1 */

  232. /**
  233.   * @}
  234.   */

  235. /**
  236.   * @}
  237.   */

  238. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码
1s读取一次DMA BUFF的值来转换:
  1. while (1)
  2.   {
  3.   /* USER CODE END WHILE */

  4.   /* USER CODE BEGIN 3 */
  5.    
  6.    
  7.    
  8.    
  9.     if(TempVref_count >= TEMP_REFRESH_PERIOD)//1s
  10.     {
  11.       Show_TempVref_Value();
  12.       TempVref_count = 0;
  13.       
  14.     }
  15.    
  16.    
  17.   }
复制代码
CPU周围的温度在36度到40度左右,具体看CPU执行的任务程度吧,
内部参考电压维持在1.20V--1.21V
IMG_20170727_210423_BURST002.jpg IMG_20170727_210626.jpg IMG_20170727_210640.jpg





评分

参与人数 1ST金币 +10 收起 理由
zero99 + 10

查看全部评分

回复

使用道具 举报

该用户从未签到

22

主题

1027

帖子

12

蝴蝶豆

金牌会员

最后登录
2021-7-23
发表于 2017-7-28 08:44:23 | 显示全部楼层
多谢队长分享
回复 支持 反对

使用道具 举报

该用户从未签到

3

主题

1002

帖子

363

蝴蝶豆

版主

最后登录
2021-4-15
发表于 2017-7-28 09:47:06 | 显示全部楼层
貌似不错!!!
回复

使用道具 举报

该用户从未签到

8

主题

734

帖子

3

蝴蝶豆

金牌会员

最后登录
2023-5-15
发表于 2019-3-8 08:48:38 | 显示全部楼层
谢谢楼主的无私分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-4-26 17:19 , Processed in 0.183604 second(s), 41 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表