打印
[DemoCode下载]

nano100如何使用内部BandGap 2.5V电压来测量芯片的内部温度和供电电压

[复制链接]
131|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xinxianshi|  楼主 | 2024-2-25 20:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
EC_Nano100_Use_BandGap_Measure_VDD_And_Temperature_V1.00.zip (4.98 MB)
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
* $Revision: 6 $
* $Date: 14/05/08 4:24p $
* [url=home.php?mod=space&uid=247401]@brief[/url]    Demonstrate measure internal temperature and supply voltage of IC using internal BandGap 2.5V voltage.
*
* @note
* Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "Nano100Series.h"

volatile float fTmp = 0;
volatile float fAvdd = 0;
void ADC_IRQHandler(void);

void ADC_IRQHandler(void)
{
    uint32_t u32Flag;

    // Get ADC conversion finish interrupt flag
    u32Flag = ADC_GET_INT_FLAG(ADC, ADC_ADF_INT);

    if (u32Flag & ADC_ADF_INT)
    {
        uint32_t u32Result;
        u32Result = ADC_GET_CONVERSION_DATA(ADC, 15);
        fAvdd = 2.5 * 0xfff / u32Result;
        printf(" Channel 15 conversion result is %d, VDD is %f volt \n", u32Result, fAvdd);
        u32Result = ADC_GET_CONVERSION_DATA(ADC, 14);
        fTmp = (740 - (1000 * u32Result / 4096) * fAvdd) / 1.73 ;
        printf(" Channel 14 conversion result is %d, Temperature is %f degree \n", u32Result, fTmp);
    }

    ADC_CLR_INT_FLAG(ADC, u32Flag);
}

void SYS_EnableTempCtl()
{
    SYS->TEMPCTL  |= (SYS_TEMPCTL_VTEMP_EN_Msk);
}

void SYS_DisableTempCtl()
{
    SYS->TEMPCTL  = ((SYS->TEMPCTL & ~0x1));
}

void SYS_EnableIntVRefBGP(uint8_t iValue)
{
    if (iValue)
        SYS->Int_VREFCTL   = ((SYS->Int_VREFCTL & ~0x7) | (SYS_VREFCTL_BGP_EN_Msk | SYS_VREFCTL_REG_EN_Msk | 0x4)); // BGP 2.5V
    else
        SYS->Int_VREFCTL  = ((SYS->Int_VREFCTL & ~0x7) | (SYS_VREFCTL_BGP_EN_Msk | SYS_VREFCTL_REG_EN_Msk)); // BGP 1.8V
}

void SYS_DisableIntRefBGP()
{
    SYS->Int_VREFCTL &= ~0x7 ;
}

void ADC_SetVrefVoltage(uint8_t iValue)
{
    ADC->CR &= ~ADC_CR_REFSEL_Msk;

    if (iValue == 1) // Select Int_Vref as Voltage
    {
        ADC->CR |= (0x1 << ADC_CR_REFSEL_Pos);
    }
    else if (iValue == 2) // Select Vref as Voltage
    {
        ADC->CR |= (0x2 << ADC_CR_REFSEL_Pos);
    }
    else // default Select Power as Voltage
    {
    }
}

/*---------------------------------------------------------------------------------------------------------*/
/* Init System Clock                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
void SYS_Init(void)
{
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Set HCLK source form HXT and HCLK source divide 1  */
    CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HXT, CLK_HCLK_CLK_DIVIDER(1));

    /* Enable external 12MHz HXT, 32KHz LXT and HIRC */
    CLK_EnableXtalRC(CLK_PWRCTL_HXT_EN_Msk | CLK_PWRCTL_LXT_EN_Msk | CLK_PWRCTL_HIRC_EN_Msk);

    /* Waiting for clock ready */
    CLK_WaitClockReady(CLK_CLKSTATUS_HXT_STB_Msk | CLK_CLKSTATUS_LXT_STB_Msk | CLK_CLKSTATUS_HIRC_STB_Msk);

    /*  Set HCLK frequency 42MHz */
    CLK_SetCoreClock(32000000);

    /* Enable IP clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Enable ADC clock */
    CLK_EnableModuleClock(ADC_MODULE);

    /* Select IP clock source */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_UART_CLK_DIVIDER(1));
    CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL1_ADC_S_HXT, CLK_ADC_CLK_DIVIDER(200));

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set PB multi-function pins for UART0 RXD and TXD */
    SYS->PB_L_MFP &= ~(SYS_PB_L_MFP_PB0_MFP_Msk | SYS_PB_L_MFP_PB1_MFP_Msk);
    SYS->PB_L_MFP |= (SYS_PB_L_MFP_PB0_MFP_UART0_RX | SYS_PB_L_MFP_PB1_MFP_UART0_TX);

    /* Set PB multi-function pins for Clock Output */
    SYS->PB_H_MFP = (SYS->PB_H_MFP & ~SYS_PB_H_MFP_PB12_MFP_Msk) |  SYS_PB_H_MFP_PB12_MFP_CKO;

    /* Set PA.0 multi-function pin for ADC channel 0 */
    SYS->PA_L_MFP = (SYS->PA_L_MFP & ~SYS_PA_L_MFP_PA0_MFP_Msk) | SYS_PA_L_MFP_PA0_MFP_ADC_CH0;

    /* Disable PA.0 digital input path */
    PA->OFFD |= ((1 << 0) << GP_OFFD_OFFD_Pos);

    SYS_EnableTempCtl(); // Enable Temperature Sensor
    SYS_EnableIntVRefBGP(1); // Enable Vref is BGP

    /* Lock protected registers */
    SYS_LockReg();
}

void UART0_Init()
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    UART_Open(UART0, 115200);
}

int32_t main(void)
{
    //uint32_t u32Result;

    /* Init System, IP clock and multi-function I/O
       In the end of SYS_Init() will issue SYS_LockReg()
       to lock protected register. If user want to write
       protected register, please issue SYS_UnlockReg()
       to unlock protected register if necessary */
    SYS_Init();

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %dHz\n", SystemCoreClock);

    printf("\n This sample code demonstrate measure VDD and Temperature.\n");
    printf(" It convert ADC channel 14, 15 and print conversion result \n");
    printf(" ADC channel 15 is VDD \n");
    printf(" ADC channel 14 is Temperature \n\n");

    // Set ADC
    ADC_Open(ADC, ADC_INPUT_MODE_SINGLE_END, ADC_OPERATION_MODE_SINGLE_CYCLE, ADC_CH_14_MASK | ADC_CH_15_MASK);
    ADC_SetExtraSampleTime(ADC, ADC_CH_14_MASK, 1024);

    ADC_SetVrefVoltage(0); // Set Vref voltage

    // Power on ADC
    ADC_POWER_ON(ADC);

    // Enable ADC ADC_IF interrupt
    ADC_EnableInt(ADC, ADC_ADF_INT);
    NVIC_EnableIRQ(ADC_IRQn);

    ADC_START_CONV(ADC);

    while (1);
}

/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/




使用特权

评论回复
沙发
xinxianshi|  楼主 | 2024-2-25 20:21 | 只看该作者
这段代码是一个示例程序,用于演示如何使用内部BandGap 2.5V电压来测量芯片的内部温度和供电电压。下面是对代码的分析总结:

在代码开头的注释中,提供了文件名、版本信息、修订版本和日期等基本信息,以及简要的代码功能说明。

程序中使用了Nuvoton Nano100系列的头文件和相关函数。

定义了两个全局的浮点型变量 fTmp 和 fAvdd,用于存储温度和供电电压的测量结果。

实现了 ADC_IRQHandler 函数,用于处理 ADC 的中断事件。当 ADC 转换完成时,该函数会获取转换结果,并通过printf函数输出温度和供电电压的值。

定义了一些系统初始化函数,包括使能温度传感器、使能内部参考电压 BGP、设置 ADC 参考电压等。

实现了 SYS_Init 函数,用于初始化系统时钟、外设时钟和多功能IO。

实现了 UART0_Init 函数,用于初始化 UART0 模块,以便通过串口打印信息。

在主函数 main 中,首先调用 SYS_Init 进行系统初始化,然后调用 UART0_Init 初始化 UART0,接着通过printf函数打印CPU时钟频率信息和示例代码说明,然后配置 ADC,并使能 ADC 中断,并启动 ADC 转换。

最后是一个空的死循环,程序将在此处无限循环执行。

总的来说,这段代码通过内部ADC模块实现了对芯片内部温度和供电电压的测量,并通过串口输出结果。

使用特权

评论回复
板凳
xinxianshi|  楼主 | 2024-2-25 20:21 | 只看该作者
使用内部2.5V BandGap电压作为IC的内部参考电压。
启用内部ADC通道14,并启用温度检测寄存器来测量IC的内部温度。
计算函数如下所示:
Vtemp(mV) = 2.51000 (ADC_14/4096)
Vtemp (mV) = -1.73 (mV/℃) x Temperature (℃) + 740 (mV)。
使用ADC通道15测量供电电压。
计算函数如下所示:
VDD = (4096/ADC_15)*2.5V

使用特权

评论回复
地板
jiekou001| | 2024-2-26 17:12 | 只看该作者
新唐的很多单片机系列貌似都提供了这个功能,可以省略一个外部的参靠电压源。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

820

帖子

1

粉丝