0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32片内信号的ADC应用演示案例

茶话MCU 来源:茶话MCU 2024-01-13 13:42 次阅读

很多STM32芯片里往往内置了专用的ADC通道,比方用来测量Vrefint,VBAT的分压或温度传感器的输出电压信号。不同系列所内置的模拟信号通道可能有差异。这里以STM32G4系列为例,它内置了对应于Vrefint,VBAT的三分之一分压和温度传感器的输出电压的专用模拟通道。

55e3b76c-b1ce-11ee-8b88-92fbcf53809c.png

55eed25a-b1ce-11ee-8b88-92fbcf53809c.png

下面的示例就是针对上述3个通道进行AD,并测量相关电压和片内温度,最终得到3个结果,分别是VRefint电压,VBAT的电压,片内温度。

5601ae20-b1ce-11ee-8b88-92fbcf53809c.png

实现过程是这样的,大体分四步:【有点点麻雀虽小五脏俱全的味道】

1、TIMER1 更新事件触发ADC的转换;

2、CPU基于EOC中断获取ADC结果;

3、对ADC结果进行换算,得到电压值和温度值存放在特定内存位置;

4、基于DMA传输通过UART将最终结果在串口终端显示;

其中,TIMER1的CH1输出PWM波形,其更新事件做ADC的转换启动信号。每次的TIMER更新事件触发ADC,3个通道扫描方式转换。这里的UART使用片内LPUART,使用它主要是考虑它跟板载虚拟串口直接相连,没有其它特别用意。

56178920-b1ce-11ee-8b88-92fbcf53809c.png

我使用STM32G474Nucleo板来进行下面实验。其中VDD=3.3v,VBAT与VDD相连。另外,ADC模块的参考电压也是3.3v.

使用CubeMx图形化工具进行配置,先看TIMER配置:

56327942-b1ce-11ee-8b88-92fbcf53809c.png

再看看ADC的基本配置:

564d2ba2-b1ce-11ee-8b88-92fbcf53809c.png

LPUART的基本配置:

567b7d90-b1ce-11ee-8b88-92fbcf53809c.png

因为要使用ADC中断和UART的DMA传输,记得做ADC的中断响应使能配置和LPUART的DMA配置,这里只使用UART的TX DMA功能。

568bdb0e-b1ce-11ee-8b88-92fbcf53809c.png

使用CubeMx主要配置主要是上面这些。

在组织用户代码前,先简单介绍下片内温度传感器的内容。该温度传感器针对不同温度有不同电压输出,其输出电压跟温度呈线性关系。ST公司针对片内温度传感器在两个特定温度【30℃和110℃或30℃和130℃】、基于特定参考电压【3v或3.3v,不同系列以数据手册为准】生成了1组校准值并存放于片内特定FLASH位置。

STM32G4系列的校准值是在参考电压为3v,30℃和110℃条件下的两个值,在数据手册里还给出了校准值的片内存放地址。

569b3356-b1ce-11ee-8b88-92fbcf53809c.png

针对这个温度传感器的使用,ST公司在参考手册里还给出了计算公式。其实,有无这个公式无所谓,我们不难自行推理出来。【TS_DATA代表某时刻测得的传感器输出电压对应的转换值,TS_CAL1/TS_CAL2分别表示在30℃和110℃条件下基于传感器输出电压的转换值。】

56b32d8a-b1ce-11ee-8b88-92fbcf53809c.png

另外,前面提过,ST公司在手册里给出了温度传感器的两个温度下的校准值,但要注意生成校准值的ADC模块所用参考电压跟我们实际应用时AD模块所用的参考基准电压可能不一致。如果不一致,就必须将ADC值换算成同一基准参考电压条件下的数据。目前在ST手册里也特别强调这点了。我把上面一副图再贴一遍于此【见黄色语句提醒】。

55eed25a-b1ce-11ee-8b88-92fbcf53809c.png

关于这点,我们也不难理解。同一待测信号、同一ADC模块在不同基准参考电压下转换值往往是不一样的。见下面示意图加以理解。

56d1ca4c-b1ce-11ee-8b88-92fbcf53809c.png

完成各项配置后,创建软件工程。添加必需的用户代码:

#define TX_Timeout (9999)


#define TS_CAL1_ADDR  (0x1FFF75A8)  //用于计算温度传感器数据
#define TS_CAL2_ADDR  (0x1FFF75CA) //用于计算温度传感器数据


#define size1 (40)


char WDVol[size1],BatVol[size1],InVol[size1];


uint16_t ts_c30,ts_c110;


uint16_t ADCResult[3],convCNT;


volatile  uint32_t Completed,EndofCon_Flag;


floatVBATVolt;//存放BBAT电压最终结果
floatVRefint;//存放Vrefint电压最终结果
floatTemperature;//存放片外温度℃最终结果


int main(void)
{
/* USER CODE BEGIN 1 */


/* 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_LPUART1_UART_Init();
  MX_TIM1_Init();
/* USER CODE BEGIN 2 */


ts_c30=*(uint16_t*)(TS_CAL1_ADDR);//读取30℃时的ADC校准值


   ts_c110 =  *(uint16_t *)(TS_CAL2_ADDR);//读取110℃时的ADC校准值


  HAL_ADCEx_Calibration_Start(&hadc1 , ADC_SINGLE_ENDED);//ADC校准


  HAL_ADC_Start_IT(&hadc1);//启动ADC并开启转换中断


  HAL_TIM_PWM_Start(&htim1,  TIM_CHANNEL_1);




/* USER CODE END 2 */


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


/* USER CODE BEGIN 3 */


if (EndofCon_Flag!=0)
  {
    VBATVolt=(ADCResult[0]/4095.)* 3.3 * 3.;  


    VRefint=(ADCResult[1]/4095.) * 3.3;  


    Temperature = 30.+ (88.*(ADCResult[2]-((ts_c30/1.1))))/(ts_c110 - ts_c30);


      EndofCon_Flag=0;


//HAL_UART_Transmit(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol), TX_Timeout);


HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_RESET);//forauxiliarytest


      HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol));


while(Completed==0){}
      Completed =0;



//HAL_UART_Transmit(&hlpuart1, (uint8_t *)InVol ,sizeof(InVol), TX_Timeout);
HAL_UART_Transmit_DMA(&hlpuart1,(uint8_t*)InVol,sizeof(InVol));


while(Completed==0)  {}
      Completed =0;




//HAL_UART_Transmit(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol), TX_Timeout);
      HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol));

while(Completed==0){}
      Completed =0;


      HAL_GPIO_WritePin( GPIOC,GPIO_PIN_3,GPIO_PIN_SET);  //for auxiliary test


   }    


  }
/* USER CODE END 3 */
}


//ADCEOC 中断处理函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{


  ADCResult[convCNT]=HAL_ADC_GetValue(&hadc1); //获取转换结果并存入数组


  convCNT++;


if(convCNT==3)  


{
    convCNT=0;


    EndofCon_Flag=0xff;


sprintf(WDVol,"Internal PN Temperature: %5.3f  
",Temperature);  


sprintf(InVol,"Internal Reference Volt: %5.3f  
",VRefint);  


sprintf(BatVol,"Current Battery Volt:   %5.3f  

",VBATVolt);


}


}


//UART DMA传输完成处理函数


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{


  Completed=0xff;
}

基于上面的配置和测试代码,我们就可以看到最终的结果了。定时器周期性地触发ADC,每得到3个ADC结果就进行数据处理,然后通过UART以DMA方式传输到串口终端。注意VBat电压是测量结果再乘以3得到的。

56e29926-b1ce-11ee-8b88-92fbcf53809c.png

56ef71be-b1ce-11ee-8b88-92fbcf53809c.png

针对上面的应用演示,最后给几点相关应用提醒:

1、针对温度传感器做测量时,校准时使用的参考电压与实际应用不一致时要做换算,换算成相同参考电压的数据后再做计算。这点前面也提过了。

2、使用TIMER的TRGO触发ADC,如果选择类似比较事件、更新事件来触发ADC时,此时ADC对触发极性的选择是无效的,或者说ADC的转换仅依赖于触发事件时间点。如果是选择TIMER的Ocref信号作为触发源,此时ADC的硬件触发的极性选择是有效的,可以是上沿或下沿触发,甚至是双沿触发。这时就得根据需要选择合适的触发沿。【可以进一步阅读本公众号文章《STM32定时器触发ADC的时序话题》】

3、这里使用UART的DMA传输依次显示三个结果于串口终端,三个启动UART DMA传输的函数须保留适当时间间隔,即等上次传输完成后再启动下一次传输,因为这里每次传输使用的是同一DMA通道。否则没法全部正常输出。比如上面3次UART DMA传输的代码改成下面这样子:

 HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol));

 HAL_UART_Transmit_DMA(&hlpuart1,(uint8_t*)InVol,sizeof(InVol));


  HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol))

这时输出结果会变成下面的情形,总是只能看到一个结果的输出,即第一次启动的DMA传输结果。

5704c6c2-b1ce-11ee-8b88-92fbcf53809c.png

如果想省事点,直接在相邻2次DMA传输间加上合适延时也行。我这里根据DMA传输完成事件来决定执行下一次发送。在DMA传输完成中断里设置Completed变量为非0值表示当前一轮DMA传输完成。

4、对于那些在中断和主程序里都会被访问的变量,记得将它们冠以volatile。

下图的三路波形是我调试时辅助使用的。

第一路表示计数器的计数变化,显然是单向向上计数模式。

第二路是TIMER1通道1的PWM输出波形。

第三路是我每次基于DMA实现UART发送时拉高拉低的波形。平常管脚电平为高,在实现DMA传输过程中拉低。

57198de6-b1ce-11ee-8b88-92fbcf53809c.png

好,今天的分享就到这里,供君参考。下次再聊。







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 温度传感器
    +关注

    关注

    48

    文章

    2912

    浏览量

    155878
  • 输出电压
    +关注

    关注

    2

    文章

    1092

    浏览量

    38013
  • PWM波
    +关注

    关注

    0

    文章

    99

    浏览量

    16838
  • VDD
    VDD
    +关注

    关注

    1

    文章

    311

    浏览量

    33101
  • STM32芯片
    +关注

    关注

    0

    文章

    38

    浏览量

    4365

原文标题:基于STM32片内信号的ADC应用演示

文章出处:【微信号:stmcu832,微信公众号:茶话MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32FLASH操作说明

    STM32FLASH操作说明
    发表于 07-08 09:51

    STM32FLASH操作步骤

    STM32FLASH可分为哪几类?如何去使用STM32FLASH呢?
    发表于 11-01 06:36

    STM32FLASH有何功能

    怎么去操作STM32的FLSAH呢?STM32FLASH有何功能?
    发表于 11-01 06:35

    STM32FLASH该如何去使用呢

    STM32FLASH可分成哪几部分?STM32的FLASH共有几个键值呢?
    发表于 11-02 07:08

    2812ADC采样时间计算

    本内容提供了2812ADC采样时间计算。1)序列采样模式(SMODE = 0)[attach]12497[/attach]
    发表于 09-05 11:39 3376次阅读

    STM32F0xx_FLASH编程() 配置详细过程

    STM32F0xx_FLASH编程()配置详细过程
    的头像 发表于 04-07 14:21 3154次阅读
    <b class='flag-5'>STM32</b>F0xx_FLASH编程(<b class='flag-5'>片</b><b class='flag-5'>内</b>) 配置详细过程

    STM32F1_ FLASH编程

    STM32F1_FLASH编程
    的头像 发表于 04-08 10:28 3831次阅读
    <b class='flag-5'>STM32</b>F1_ <b class='flag-5'>片</b><b class='flag-5'>内</b>FLASH编程

    STM32 ADC基础内容

    STM32的每个ADC有数条复用模拟输入通道,具体通道数因不同系列及型号而异。温度传感器、内部参考电压、VBAT还可以与内部模拟通道相连,便于测量和使用。
    的头像 发表于 03-12 13:51 5873次阅读
    <b class='flag-5'>STM32</b> <b class='flag-5'>ADC</b>基础内容

    AD7760:24位、2.5 MSPS、100 dB,Σ-Δ ADC,内置缓冲 数据手册

    AD7760:24位、2.5 MSPS、100 dB,Σ-Δ ADC,内置缓冲 数据手册
    发表于 03-20 17:19 11次下载
    AD7760:24位、2.5 MSPS、100 dB,Σ-Δ <b class='flag-5'>ADC</b>,内置<b class='flag-5'>片</b><b class='flag-5'>内</b>缓冲 数据手册

    STM32CubeMX | 28 - STM32Flash的使用

    本系列文章汇总:STM32CubeMX系列教程本篇文章主要介绍如何使用STM32中的FLash。1. 准备工作硬件准备开发板首先需要准备一个开发板,这里我准备的是
    发表于 12-01 20:36 6次下载
    <b class='flag-5'>STM32</b>CubeMX | 28 - <b class='flag-5'>STM32</b><b class='flag-5'>片</b><b class='flag-5'>内</b>Flash的使用

    STM32FLASH烧写错误导致ST-li

    STM32FLASH烧写错误导致ST-li
    发表于 12-02 18:06 7次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>片</b><b class='flag-5'>内</b>FLASH烧写错误导致ST-li

    STM32F1 使用easyflash操作flash

    STM32F1 使用easyflash操作flash
    发表于 12-09 10:06 15次下载
    <b class='flag-5'>STM32</b>F1 使用easyflash操作<b class='flag-5'>片</b><b class='flag-5'>内</b>flash

    STM32U5系列ADC1和ADC4实现过程(上)

    有人使用STM32U5系列MCU开发产品,在用到ADC结合DMA传输时遇到点障碍,这里针对ADC1和
    的头像 发表于 07-30 09:27 1167次阅读
    <b class='flag-5'>STM32</b>U5系列<b class='flag-5'>片</b><b class='flag-5'>内</b><b class='flag-5'>ADC</b>1和<b class='flag-5'>ADC</b>4实现过程(上)

    STM32U5系列ADC1和ADC4实现过程(下)

    现在对ADC4基于DMA链表模式做演示,其实就一个节点。 选择ADC4的4个内部信号通道,扫描模式,连续转换,DMA传输转换结果,并令DMA工作在外设字到内存字的循环模式。使用Cube
    的头像 发表于 07-30 09:30 1293次阅读
    <b class='flag-5'>STM32</b>U5系列<b class='flag-5'>片</b><b class='flag-5'>内</b><b class='flag-5'>ADC</b>1和<b class='flag-5'>ADC</b>4实现过程(下)

    【深度测评】HPM6750 MCU16位ADC精度测试

    【深度测评】HPM6750 MCU16位ADC精度测试
    的头像 发表于 10-30 17:43 2686次阅读
    【深度测评】HPM6750 MCU<b class='flag-5'>片</b><b class='flag-5'>内</b>16位<b class='flag-5'>ADC</b>精度测试