草帽王子 发表于 2021-4-23 10:43:09

第十一章:CH32V103应用教程——内置温度传感器

本帖最后由 草帽王子 于 2021-9-10 16:30 编辑

本章教程使用CH32V103的内部温度传感器检测器件周围温度,并通过串口调试助手打印显示。


1、温度传感器简介及相关函数介绍

CH32V103内置温度传感器,连接ADC_INT16通道,通过 ADC 将传感器输出的电压转换成数字值来反馈器件周围温度,推荐设置采样时间是 17.1us。温度传感器输出的电压随温度线性变化,由于生产差异,其线性变化的曲线斜率和偏移有所不同,所以内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温度,应该使用一个外置的温度传感器。

通过设置ADC_CTLR2寄存器的TSVREFE位置1,唤醒ADC内部采样通道,软件启动或者外部触发启动ADC的温度传感器通道转换,读取数据结果(mV)。其中,数字值和温度(℃)换算公式如下:


[*]    温度(℃) = ((VSENSE-V25)/Avg_Slope)+25
[*]    VSENSE:温度传感器的当前输出电压;
[*]    V25:温度传感器在 25℃下的电压值;
[*]    Avg_Slope:温度与 VSENSE曲线的平均斜率(mV/℃)
[*]    参考数据手册电气特性章节中 V25和 Avg_Slope 的实际值。

    注:内部温度传感器上电(TSVREFE 位从 0 改为 1)需要一个建立时间,而 ADC 模块上电也需要一个建立时间(ADON 位从 0 改为 1),所以为了缩短等待时间,可以同时设置 ADON 和 TSVREFE 位。

关于CH32V103内置温度传感器具体信息,可参考CH32V103应用手册。温度检测程序所用库函数在ADC教程中已介绍,在此不再赘述。


2、硬件设计

内置温度传感器属于其内部资源,无需进行硬件连接,只需进行软件设计即可。



3、软件设计

本章教程通过ADC_INT16通道读取内置温度传感器值,其程序相较于ADC,变化不大,增加了使能内部温度传感器和温度值计算,主要程序如下:

temdet.h文件
#ifndef __TEMDET_H
#define __TEMDET_H

#include "ch32v10x_conf.h"

void adc_Init(void);
u16get_adc(u8 ch);
u16get_adc_average(u8 ch,u8 times);
float get_temperature(void);

#endiftemdet.h文件主要是相关函数的声明。

temdet.c文件
#include "temdet.h"

void adc_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_TempSensorVrefintCmd(ENABLE);

    ADC_Cmd(ADC1, ENABLE);

    ADC_ResetCalibration(ADC1);

    while(ADC_GetResetCalibrationStatus(ADC1));

    ADC_StartCalibration(ADC1);

    while(ADC_GetCalibrationStatus(ADC1));
}

u16 get_adc(u8 ch)
{
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
    return ADC_GetConversionValue(ADC1);
}

u16 get_adc_average(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t<times;t++)
    {
      temp_val+=get_adc(ch);
      Delay_Ms(5);
    }
    return temp_val/times;
}

float get_temperature(void)
{
    u32 adcx;
    float temperate;
    adcx=get_adc_average(ADC_Channel_16,20);
    temperate=(float)adcx*(3.3/4096);
    temperate=(1.43-temperate)/0.0043+25;
    return temperate;
}

temdet.c文件主要是内置温度传感器进行温度检测的相关配置,其配置流程和ADC差不多,主要增加了使能内部温度传感器和温度值计算,在此不再对流程进行介绍。

main.c文件
int main(void)
{
    float tem;
    Delay_Init();
      USART_Printf_Init(115200);
      adc_Init();
      while(1)
    {
            Delay_Ms(500);
            tem=get_temperature();
      printf("temp=%.2f\n",tem);
      }
}main.c文件主要进行相关函数初始化以及打印输出温度值。



4、下载验证

将编译好的程序下载到开发板并复位,串口打印情况具体如下:

温度检测.rar附件下载

链接:https://pan.baidu.com/s/1MaHijvVBpQxuQvXYvJGgIA
提取码:kuk7
复制这段内容后打开百度网盘手机App,操作更方便哦



ziakalis 发表于 2023-7-9 16:11:31

我发现,printf这个函数不支持“%f”输出浮点数,但是“%d”是可以的,不知道为啥。

51MCU 发表于 2023-7-10 16:16:19

ziakalis 发表于 2023-7-9 16:11
我发现,printf这个函数不支持“%f”输出浮点数,但是“%d”是可以的,不知道为啥。 ...

编译器问题:在某些编译器中,printf 函数的实现可能与标准 C 语言规范不符。在这种情况下,%f格式控制符可能无法输出正确的结果。

解决方法是使用其他编译器或者尝试使用其他 printf 函数实现。

如果遇到了%f格式控制符不能输出的问题,可以尝试检查变量类型是否正确,是否需要强制转换为浮点数类型,以及浮点数精度是否满足要求。另外,可以尝试使用其他 printf 函数实现,例如%e、%g等格式控制符。

51MCU 发表于 2023-7-10 16:18:04

ziakalis 发表于 2023-7-9 16:11
我发现,printf这个函数不支持“%f”输出浮点数,但是“%d”是可以的,不知道为啥。 ...

因printf()之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,以下是解决方法:
方法1.使用微库,因为使用微库的话,不会使用半主机模式.
方法2.仍然使用标准库,在主程序添加下面代码:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;

51MCU 发表于 2023-7-10 16:21:24

ziakalis 发表于 2023-7-9 16:11
我发现,printf这个函数不支持“%f”输出浮点数,但是“%d”是可以的,不知道为啥。 ...

仔细参考下 C 库函数 - printf()
C 标准库 - <stdio.h>   
https://www.runoob.com/cprogramming/c-function-printf.html

32位单片机上的编译和X86有区别

#include <stdio.h>
int main()
{
   char ch = 'A';
   char str = "www.runoob.com";
   float flt = 10.234;
   int no = 150;
   double dbl = 20.123456;
   printf("字符为 %c \n", ch);
   printf("字符串为 %s \n" , str);
   printf("浮点数为 %f \n", flt);
   printf("整数为 %d\n" , no);
   printf("双精度值为 %lf \n", dbl);
   printf("八进制值为 %o \n", no);
   printf("十六进制值为 %x \n", no);
   return 0;
}
执行输出结果为:

字符为 A
字符串为 www.runoob.com
浮点数为 10.234000
整数为 150
双精度值为 20.123456
八进制值为 226
十六进制值为 96
页: [1]
查看完整版本: 第十一章:CH32V103应用教程——内置温度传感器