NXP JN5169 使用 ADC 模数转换器
一、模拟外设
JN5169 包含许多模拟外设,可直接连接各种外部传感器和开关。
为了提供与数字噪声的良好隔离,模拟外设和无线电由无线电调节器供电,该无线电调节器由模拟电源 VDDA 供电,并以模拟接地 VSSA 为参考。
可以选择 ADC 的参考信号 Vref 为提供给 VREF 引脚的内部带隙参考或外部参考电压。 如果需要外部基准电压源,则不能使用 ADC 输入 2,因为它使用与 VREF 相同的引脚。 还要注意,ADC3,ADC4,ADC5 和 ADC6 分别使用与 DIO0,DIO1,DIO2 和 DIO3 相同的引脚。 如果这些引脚的任何其他功能均不需要,则这些引脚只能用于 ADC。 同样,比较器输入与 DIO16 和 DIO17 共享。 如果将这些 DIO 用于其模拟功能,则必须通过将其配置为禁止上拉的输入来使其处于被动状态。
ADC 由源自 16 MHz 时钟的通用时钟源提供时钟。
1、模数转换器(ADC)
10 位 ADC 使用逐次逼近设计来执行高精度转换,这是无线传感器网络应用中通常需要的。 它具有 8 个多路复用单端输入通道:6 个在外部可用,1 个连接到内部温度传感器,1 个连接到内部电源监控电路。
①、运作方式
ADC 的输入范围可以设置为 0 V 至基准电压或两倍于基准电压。 可以从内部参考电压或从施加到 VREF 引脚的外部电压获取参考电压。 例如,提供给 VREF 的 1.2 V 外部基准电压可用于将 ADC 范围设置为 0 V 至 2.4V。
ADC最大输入范围:
VREF | 增益设定 | 最大输入范围 | 电源电压范围(VDDD) |
---|---|---|---|
1.2 V | 0 | 1.2 V | 2.2 V to 3.6 V |
1.6 V | 0 | 1.6 V | 2.2 V to 3.6 V |
1.2 V | 1 | 2.4 V | 2.6 V to 3.6 V |
1.6 V | 1 | 3.2 V | 3.4 V to 3.6 V |
ADC 的输入时钟为 16 MHz,可以分为 2 MHz,1 MHz,500 kHz 或 250 kHz。在 ADC 转换期间,将对选定的输入通道进行固定采样,然后保持不变。该采样周期定义为 ADC 时钟周期的数量,可以设置为 2、4、6 或 8。转换周期为((3 x 采样周期)+ 13)个时钟周期。例如,对于采样周期为 2 的 500 kHz 转换,转换周期为((3 x 2)+ 13)= 19个时钟周期,等于 38μs,等于 26.32 kHz 的转换速率。 ADC 可以单转换模式运行,也可以在前一个转换完成后立即开始新的转换,以进行连续转换。
关于内部参考电压,见 JN5169 datasheet.pdf 附录表 24 带隙参考
当 VDD = 2 V ~ 3.6 V 时,内部参考电压典型值 1.235 V,最小值 1.198 V,最大值 1.260 V
ADC 采样示例图:
如果输入电压的源电阻为 1 kW 或更小,则应使用 2 个时钟的默认采样时间。 ADC 的输入可建模为 5kΩ(典型值)和 10kΩ(最大)的电阻,以表示开关和采样电容器 8 pF 的导通电阻。然后,可以通过将传感器源电阻与开关电阻相加,再乘以电容来得出时间常数,从而计算出所需的采样时间。假设正常的指数 RC 充电,可以计算出可以接受的误差所需的时间常数。 7 次时间常数的误差为 0.091%,因此对于 10 位精度,应将 7 次时间常数作为目标。对于零电阻源,其 7 倍常数为 640 ns,因此可以使用 2 个时钟周期的最小采样窗口。
ADC 输入等效电路如下图:
ADC 采样周期,输入范围和模式(单次或连续)通过软件控制。
ADC 转换完成后,将产生一个中断。 或者,可以查询转换状态。 当以连续模式运行时,建议使用中断来表示转换结束,因为转换时间可能在 9.5μs 至 148μs 的范围内。 在此期间进行轮询将浪费处理器带宽。
为了促进 ADC 值的平均,这是微控制器的常见做法,已添加了专用累加器。 用户可以将累积配置为发生在 2、4、8 或 16 个样本上。 可以将转换中断的结束时间修改为发生在所选累加周期的末尾。 或者,仍然可以使用轮询。 然后可以使用软件来应用适当的舍入和移位以生成平均值,以及设置累加功能。
③、内部电源监控器
内部电源监控器允许测量模拟电源引脚 VDDA 上的电压。 这是通过一个分压器实现的,该分压器将电压缩放为 0.666 倍,当输入范围设置为内部基准电压的两倍时,它可以落入 ADC 的输入范围内。 执行电压降低的电阻器链被禁用,直到进行测量以避免电源上的连续消耗为止。
④、温度传感器
片上温度传感器可用于提供器件温度的绝对测量值或检测环境温度的变化。 与大多数片上温度传感器一样,它不会被修整,因此绝对精度变化很大。 用户可能希望在使用前校准传感器。 传感器迫使恒定电流流过正向偏置二极管,以提供与芯片裸片温度成比例的电压输出,然后可以使用 ADC 对其进行测量。
因为该传感器是片上传感器,所以进行的任何测量都必须考虑热时间常数。 例如,如果设备刚刚退出睡眠模式,则用户应用程序应等待温度稳定后再进行测量。
⑤、ADC 采样缓冲模式(DMA)
在这种模式下,ADC 与直接内存访问(DMA)引擎一起运行,如下所示:
- 使用一个片上定时器(TimerX,其中 X = 1、2、3 或 4)以可配置的速率触发 ADC 采样。
- ADC 样本使用 DMA 机制自动存储在 RAM 中的缓冲区中。
- ADC 输入可以在不同的模拟源之间复用。
10 位 ADC 数据样本以 16 位字的形式传输到 RAM 的缓冲区中。 RAM 中可为 ADC 样本存储分配的最大 16 位字数为 2047。
缓冲区可以配置为满时自动回绕到起点。 可以将中断配置为指示缓冲区何时为半满,满或溢出。
当数据传输和存储由 DMA 引擎独立管理时,CPU 可能执行其他任务-发生中断时,CPU 仅需要配置 ADC 采样缓冲区模式并处理缓冲区中存储的采样。
ADC 采样缓冲模式允许组合多达 8 个模拟输入。 这些输入包括六个外部输入(ADC1 至 6,对应于 IO 引脚),一个片上温度传感器和一个内部电压监控器。 来自所有选定输入的样本将在每个定时器触发器上产生,并存储在连续的 RAM 单元中。
2、比较器
JN5169 包含一个模拟比较器 COMP1,该模拟比较器设计为具有真正的轨到轨输入,并在模拟电源 VDDA 的整个电压范围内工作。迟滞电平可以设置为 0 mV,10 mV,20 mV 或 40 mV 的标称值。可以将用于比较器的负输入信号的源设置为内部参考电压,负外部引脚(COMP1M,使用与 DIO17 相同的引脚)或正外部引脚(COMP1P,与 DIO16 相同的引脚)。正输入信号的源可以是 COMP1P 或 COMP1M。如果需要外部比较器输入,则不能使用 DIO16 和 DIO17。比较器输出被路由到内部寄存器,可以被查询,或者可以用来产生中断。可以禁用比较器以降低功耗。使用比较器时,应将 DIO16 和 DIO17 配置为禁止上拉的输入。
比较器还具有低功耗模式,在正常模式下比较器的响应时间较慢,但所需电流大大降低。这是睡眠期间可能使用的唯一模式,比较器输出的转换将唤醒器件。唤醒动作和比较器输出边沿有效的配置通过软件控制。在休眠模式下,负输入信号源必须配置为由外部引脚驱动。
二、代码实现
1、ADC 单发模式
#define REFERENCE_VOLTAGE 1.235 //内部参考电压典型值
#define RANGE_VOLTAGE (2 * REFERENCE_VOLTAGE) //参考电压为内部参考电压,增益设定,输入电压范围 0 to 2Vref
#define ADC_VALUE_TO_VOLTAGE_PARAMETER (0x3FF / RANGE_VOLTAGE) //ADC值转换为电压值参数
#define ADC3 1 << 0
#define ADC4 1 << 1
#define ADC5 1 << 2
#define ADC6 1 << 3
//初始化ADC引脚
//ADC3,ADC4,ADC5 和 ADC6 分别使用与 DIO0,DIO1,DIO2 和 DIO3 相同的引脚
//如果将这些 DIO 用于其模拟功能,则必须通过将其配置为禁止上拉的输入来使其处于被动状态。
PUBLIC void vAdcDioInit(void)
{
//IO配置为输入
vAHI_DioSetDirection(ADC3 | ADC4 | ADC5 | ADC6, 0);
//关闭上拉
vAHI_DioSetPullup(0, ADC3 | ADC4 | ADC5 | ADC6);
}
//初始化ADC
PUBLIC void vAdcInit(void)
{
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //禁用ADC转换完成中断
E_AHI_AP_SAMPLE_8, //采样间隔
E_AHI_AP_CLOCKDIV_500KHZ, //ADC时钟
E_AHI_AP_INTREF); //使用内部参考电压
while (!bAHI_APRegulatorEnabled()) ; //等待用于为模拟外围设备供电的调节器启动
vAHI_AdcEnable(E_AHI_ADC_SINGLE_SHOT, //单发模式
E_AHI_AP_INPUT_RANGE_2, //增益设定,输入电压范围 0 to 2Vref
E_AHI_ADC_SRC_ADC_1); //使用 ADC1
}
//读 ADC 转换值
PUBLIC uint16 u16AdcRead(void)
{
uint16 val;
vAHI_AdcStartSample(); //开启采样
//例如,对于采样周期为 2 的 500 kHz 转换,转换周期为((3 x 2)+ 13)= 19个时钟周期,等于 38μs
while (bAHI_AdcPoll()); //等待转换完成
val = u16AHI_AdcRead(); //读取转换值
return (val);
}
PUBLIC void AppColdStart (void)
{
uint16 adc, val;
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vAdcInit();
while (1) {
adc = u16AdcRead();
vPrintf("ADC1 Value: %x \n", adc);
val = adc / ADC_VALUE_TO_VOLTAGE_PARAMETER * 100; //保留两位小数
vPrintf("ADC1 Voltage: %d.%d V\n", val / 100, val % 100);
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果图:
2、ADC 累加模式
#define REFERENCE_VOLTAGE 1.235 //内部参考电压典型值
#define RANGE_VOLTAGE (2 * REFERENCE_VOLTAGE) //参考电压为内部参考电压,增益设定,输入电压范围 0 to 2Vref
#define ADC_VALUE_TO_VOLTAGE_PARAMETER (0x3FF / RANGE_VOLTAGE) //ADC值转换为电压值参数
#define ADC3 1 << 0
#define ADC4 1 << 1
#define ADC5 1 << 2
#define ADC6 1 << 3
//初始化ADC引脚
//ADC3,ADC4,ADC5 和 ADC6 分别使用与 DIO0,DIO1,DIO2 和 DIO3 相同的引脚
//如果将这些 DIO 用于其模拟功能,则必须通过将其配置为禁止上拉的输入来使其处于被动状态。
PUBLIC void vAdcDioInitAS(void)
{
//IO配置为输入
vAHI_DioSetDirection(ADC3 | ADC4 | ADC5 | ADC6, 0);
//关闭上拉
vAHI_DioSetPullup(0, ADC3 | ADC4 | ADC5 | ADC6);
}
//初始化ADC
PUBLIC void vAdcInitAS(void)
{
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //禁用ADC转换完成中断
E_AHI_AP_SAMPLE_8, //采样间隔
E_AHI_AP_CLOCKDIV_500KHZ, //ADC时钟
E_AHI_AP_INTREF); //使用内部参考电压
while (!bAHI_APRegulatorEnabled()) ; //等待用于为模拟外围设备供电的调节器启动
vAHI_AdcEnable(E_AHI_ADC_SINGLE_SHOT, // ADC 在累加模式中启动时,vAHI_AdcEnable()中选择的转换模式被忽略。
E_AHI_AP_INPUT_RANGE_2, //增益设定,输入电压范围 0 to 2Vref
E_AHI_ADC_SRC_ADC_1); //使用 ADC1
}
//读 ADC 转换值
PUBLIC uint16 u16AdcReadAS(void)
{
uint16 val;
vAHI_AdcStartAccumulateSamples(E_AHI_ADC_ACC_SAMPLE_16);//开启累加模式采样,16个样本
//例如,对于采样周期为 2 的 500 kHz 转换,转换周期为((3 x 2)+ 13)= 19个时钟周期,等于 38μs
//16次采样 = 38 * 16 = 608μs
while (bAHI_AdcPoll()); //等待转换完成
val = u16AHI_AdcRead(); //读取转换值,输出的是16次采样的总和
return (val);
}
PUBLIC void AppColdStart (void)
{
uint16 adc, val;
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vAdcInitAS();
while (1) {
adc = u16AdcReadAS();
adc = adc / 16; //求16次采样的平均值
vPrintf("ADC1 Value: %x \n", adc);
val = adc / ADC_VALUE_TO_VOLTAGE_PARAMETER * 100; //保留两位小数
vPrintf("ADC1 Voltage: %d.%d V\n", val / 100, val % 100);
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果图:
3、ADC DMA 模式
#define REFERENCE_VOLTAGE 1.235 //内部参考电压典型值
#define RANGE_VOLTAGE (2 * REFERENCE_VOLTAGE) //参考电压为内部参考电压,增益设定,输入电压范围 0 to 2Vref
#define ADC_VALUE_TO_VOLTAGE_PARAMETER (0x3FF / RANGE_VOLTAGE) //ADC值转换为电压值参数
#define TIMER3 E_AHI_TIMER_3
#define TIMER_PRESCALE 3 //定时器预分值,TIMER_FREQUENCY = 16 / (2 ^ TIMER_PRESCALE)
#define TIMER_FREQUENCY 16.0 / (pow(2, TIMER_PRESCALE)) //定时器时钟 2MHz
#define TIMER_TIMING 100 //定时器定时时间 time = 100us ,时间单位us
#define TIMER_COUNT TIMER_FREQUENCY * TIMER_TIMING //定时器一个有效的脉冲周期的时钟周期数, 即定时器初值
#define LOW_PULSE 50 //低电平占比(0 - 100),为一个有效的脉冲周期内低电平所占的时钟周期数
#define LOW_PULSE_VALUE TIMER_COUNT * (LOW_PULSE / 100.0)//低电平时钟数值
#define BUFF_LENGTH 16 //缓冲区长度
#define ADC3 1 << 0
#define ADC4 1 << 1
#define ADC5 1 << 2
#define ADC6 1 << 3
uint16 AdcValueBuff[BUFF_LENGTH]; //ADC转换值缓冲区,这里设置16个采样长度
//初始化ADC引脚
//ADC3,ADC4,ADC5 和 ADC6 分别使用与 DIO0,DIO1,DIO2 和 DIO3 相同的引脚
//如果将这些 DIO 用于其模拟功能,则必须通过将其配置为禁止上拉的输入来使其处于被动状态。
PUBLIC void vAdcDioInitDMA(void)
{
//IO配置为输入
vAHI_DioSetDirection(ADC3 | ADC4 | ADC5 | ADC6, 0);
//关闭上拉
vAHI_DioSetPullup(0, ADC3 | ADC4 | ADC5 | ADC6);
}
//DMA中断回调函数
void vDmaIntCallback(uint32 u32DeviceId,uint32 u32ItemBitmap)
{
uint8 i;
uint16 adc = 0, val;
if(E_AHI_DEVICE_ANALOGUE == u32DeviceId){ //模拟外设中断
if((u32ItemBitmap & (1 << 2)) == E_AHI_AP_INT_DMA_MID_MASK){ //DMA半满中断
}
if((u32ItemBitmap & (1 << 3)) == E_AHI_AP_INT_DMA_END_MASK){ //DMA全满中断
for(i = 0; i < BUFF_LENGTH; i++){
adc = adc + AdcValueBuff[i];
}
adc = adc / BUFF_LENGTH; //求16个采样的平均值
vPrintf("ADC1 Value: %x \n", adc);
val = adc / ADC_VALUE_TO_VOLTAGE_PARAMETER * 100; //保留两位小数
vPrintf("ADC1 Voltage: %d.%d V\n", val / 100, val % 100);
vAdcStopDMA();//停止ADC转换
}
if((u32ItemBitmap & (1 << 4)) == E_AHI_AP_INT_DMA_OVER_MASK){ //DMA满出中断
}
}
}
//初始化ADC DMA和定时器
PUBLIC void vAdcInitDMA(void)
{
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //禁用ADC转换完成中断
E_AHI_AP_SAMPLE_2, //采样间隔
E_AHI_AP_CLOCKDIV_500KHZ, //ADC时钟
E_AHI_AP_INTREF); //使用内部参考电压
while (!bAHI_APRegulatorEnabled()) ; //等待用于为模拟外围设备供电的调节器启动
vAHI_TimerEnable(TIMER3, //定时器3
TIMER_PRESCALE, //8分频,定时器时钟为2MHz
FALSE, //上升输出(从低到高)中断,必须关闭
FALSE, //定时器周期结束时(从高到低)中断,必须关闭
FALSE); //关闭DIO上定时器信号的输出
//100us采样一次,采样16次即1600μs(不算采样周期)
vAHI_TimerStartRepeat(TIMER3, //定时器3
LOW_PULSE_VALUE, //一个有效的脉冲周期的低电平时钟周期数。中断可以在这个跳变时产生;
TIMER_COUNT); //一个有效的脉冲周期的时钟周期总数。中断可以在这个跳变时产生。
vAHI_APRegisterCallback(vDmaIntCallback); //注册DMA中断回调函数
}
//开启ADC转换
PUBLIC void vAdcStartDMA(void)
{
bAHI_AdcEnableSampleBuffer(E_AHI_AP_INPUT_RANGE_2 , //0 to 2Vref
TIMER3, //和启动的定时器一致
E_AHI_ADC_DMA_SRC_ADC_1_MASK, //使用ADC1
AdcValueBuff, //ADC转换值缓冲区
BUFF_LENGTH, //缓冲区大小
TRUE, //缓冲区回环,只要缓冲区已满转换就自动停止(如果配置了就会产生中断)。TRUE:缓冲区已满时回到起始处。
E_AHI_AP_INT_DMA_END_MASK); //缓冲区全满中断
}
//停止ADC转换
PUBLIC void vAdcStopDMA(void)
{
vAHI_AdcDisableSampleBuffer(); //停止ADC转换
}
PUBLIC void AppColdStart (void)
{
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vAdcInitDMA();
while (1) {
vAdcStartDMA();//2秒输出一次16次采样的结果
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果图:
4、比较器
对于 API 函数 vAHI_ComparatorEnable() 的 u8SignalSelect 参数有如下选择,用于选择输入信号和参考信号
输入信号 | 参考信号 | 枚举值(u8SignalSelect) |
---|---|---|
COMP1P(DIO16) | COMP1M(DIO17) | E_AHI_COMP_SEL_EXT |
COMP1P(DIO16) | Vref(内部参考电压) | E_AHI_COMP_SEL_BANDGAP |
COMP1M(DIO17) | COMP1P(DIO16) | E_AHI_COMP_SEL_EXT_INVERSE |
COMP1M(DIO17) | Vref(内部参考电压) | E_AHI_COMP_SEL_BANDGAP_INVERSE |
#define COMP 1 << 16 | 1 << 17
#define LED 1 << 0
bool flag = TRUE; //灯开关
//初始化比较器引脚
//如果将这些 DIO 用于其模拟功能,则必须通过将其配置为禁止上拉的输入来使其处于被动状态。
PUBLIC void vCmpDioInit(void)
{
//COMP IO配置为输入,LED输出
vAHI_DioSetDirection(COMP, LED);
//COMP关闭上拉,LED开启上拉
vAHI_DioSetPullup(LED, COMP);
}
//比较器中断回调函数
void vComparatorIntCallback(uint32 u32DeviceId,uint32 u32ItemBitmap)
{
if(E_AHI_DEVICE_SYSCTRL == u32DeviceId){
//比较器1中断,由于AppHardwareApi_JN516x.h中没有E_AHI_SYSCTRL_COMP1_MASK,JN5169只有比较器1
//所以手动添加中断位u32ItemBitmap的第29位为比较器1中断
if(0x10000000 == u32ItemBitmap){
vPrintf("Comparator Interrupt! \n");
flag = !flag;
if(flag){
vAHI_DioSetOutput(0, LED);
}
else{
vAHI_DioSetOutput(LED, 0);
}
}
}
}
//初始化比较器
PUBLIC void vCmpInit(void)
{
//因为使用内部参考电压与COM1M(-)DIO17输入电压比较,所以需要调用vAHI_ApConfigure()开启片上模拟外设电源
//如果不使用内部参考电压,则可注释vAHI_ApConfigure和bAHI_APRegulatorEnabled这两行,在vAHI_ComparatorEnable设置输入信号和参考信号
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //关闭ADC中断
E_AHI_AP_SAMPLE_2,
E_AHI_AP_CLOCKDIV_500KHZ,
E_AHI_AP_INTREF); //内部参考电源
while (!bAHI_APRegulatorEnabled()) ; //等待用于为模拟外围设备供电的调节器启动
vAHI_ComparatorEnable(E_AHI_AP_COMPARATOR_1, //比较器标识,必须是这个参数,JN5169只有比较器1
E_AHI_COMP_HYSTERESIS_40MV, //迟滞电压
E_AHI_COMP_SEL_BANDGAP_INVERSE); //COM1M(-)DIO17 输入,内部参考基准信号
vAHI_ComparatorLowPowerMode(TRUE); //低功耗模式
vAHI_ComparatorIntEnable(E_AHI_AP_COMPARATOR_1,
TRUE, //使用比较器中断
FALSE); //如果开启中断,TRUE:输入信号高于参考值时产生中断,FALSE:输入信号低于参考值产生中断
vAHI_SysCtrlRegisterCallback(vComparatorIntCallback); //比较器产生的中断为系统中断
flag = TRUE; //初始化灯开关
}
PUBLIC void AppColdStart (void)
{
uint16 adc, val;
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vCmpDioInit();
vCmpInit();
while (1) {
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
串口输出:
(当 DIO17 接 GND 时,比内部参考电压低,产生比较器中断,串口输出,LED(DIO0)反转 IO 状态)
5、片上温度传感器
片上温度传感器参数
传感器迫使恒定电流流过正向偏置二极管,以提供与芯片裸片温度成比例的电压输出,然后可以使用 ADC 对其进行测量。测量的是片上温度,不是环境温度。
当 VDD 为 3.0 V 且温度等于 25 °C,温度传感器电压典型值为 720 mV,温度精度为 ±7℃。输出电压范围为 540 mV ~ 840 mV
#define REFERENCE_VOLTAGE 1.235 //内部参考电压典型值
#define RANGE_VOLTAGE (2 * REFERENCE_VOLTAGE) //参考电压为内部参考电压,增益设定,输入电压范围 0 to 2Vref
#define ADC_VALUE_TO_VOLTAGE_PARAMETER (0x3FF / RANGE_VOLTAGE) //ADC值转换为电压值参数
#define REFERENCE_TEMPERATURE 25 //当 VDD 为 3.0 V 且温度等于 25 °C,温度传感器电压典型值为 720 mV
#define TEMPERATURE_REFERENCE_VOLTAGE 0.720
#define VOLTAGE_TO_TEMPERATURE_PARAMETER (REFERENCE_TEMPERATURE / TEMPERATURE_REFERENCE_VOLTAGE) //电压值转换为温度值参数
//初始化ADC Temp
PUBLIC void vAdcInitTemp(void)
{
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //禁用ADC转换完成中断
E_AHI_AP_SAMPLE_8, //采样间隔
E_AHI_AP_CLOCKDIV_500KHZ, //ADC时钟
E_AHI_AP_INTREF); //使用内部参考电压
while (!bAHI_APRegulatorEnabled()); //等待用于为模拟外围设备供电的调节器启动
vAHI_AdcEnable(E_AHI_ADC_SINGLE_SHOT, // ADC 在累加模式中启动时,vAHI_AdcEnable()中选择的转换模式被忽略。
E_AHI_AP_INPUT_RANGE_2, //增益设定,输入电压范围 0 to 2Vref
E_AHI_ADC_SRC_TEMP); //使用 Temp
}
//读 ADC Temp转换值
PUBLIC uint16 u16AdcReadTemp(void)
{
uint16 val;
vAHI_AdcStartAccumulateSamples(E_AHI_ADC_ACC_SAMPLE_16);//开启累加模式采样,16个样本
while (bAHI_AdcPoll()); //等待转换完成
val = u16AHI_AdcRead(); //读取转换值,输出的是16次采样的总和
return (val);
}
PUBLIC void AppColdStart (void)
{
uint16 adc, val;
float temp;
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vAdcInitTemp();
vPrintf("System init...\n");
while (1) {
adc = u16AdcReadTemp();
adc = adc / 16; //求16次采样的平均值
vPrintf("Temp Value: %x \n", adc);
val = (adc / ADC_VALUE_TO_VOLTAGE_PARAMETER) * 1000; //保留3位小数
vPrintf("Temp Voltage: %d.%d%d%d V\n", val / 1000, val / 100 % 10, val / 10 % 10, val % 10);
temp = (float)val / 1000;
//测量的是片上温度,不是环境温度
vPrintf("Temperature: %d ℃\n", (uint16)(temp * VOLTAGE_TO_TEMPERATURE_PARAMETER));
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果图:
6、内部电源监控器
ADC 测量的内部电源为 VDDA 的电压
#define REFERENCE_VOLTAGE 1.235 //内部参考电压典型值
#define RANGE_VOLTAGE (2 * REFERENCE_VOLTAGE) //参考电压为内部参考电压,增益设定,输入电压范围 0 to 2Vref
#define ADC_VALUE_TO_VOLTAGE_PARAMETER (0x3FF / RANGE_VOLTAGE) //ADC值转换为电压值参数
//初始化ADC Volt
PUBLIC void vAdcInitVolt(void)
{
vAHI_ApConfigure(E_AHI_AP_REGULATOR_ENABLE, //开片上模拟外设电源
E_AHI_AP_INT_DISABLE, //禁用ADC转换完成中断
E_AHI_AP_SAMPLE_8, //采样间隔
E_AHI_AP_CLOCKDIV_500KHZ, //ADC时钟
E_AHI_AP_INTREF); //使用内部参考电压
while (!bAHI_APRegulatorEnabled()); //等待用于为模拟外围设备供电的调节器启动
vAHI_AdcEnable(E_AHI_ADC_SINGLE_SHOT, // ADC 在累加模式中启动时,vAHI_AdcEnable()中选择的转换模式被忽略。
E_AHI_AP_INPUT_RANGE_2, //增益设定,输入电压范围 0 to 2Vref
E_AHI_ADC_SRC_VOLT); //使用 Temp
}
//读 ADC Volt转换值
PUBLIC uint16 u16AdcReadVolt(void)
{
uint16 val;
vAHI_AdcStartAccumulateSamples(E_AHI_ADC_ACC_SAMPLE_16);//开启累加模式采样,16个样本
while (bAHI_AdcPoll()); //等待转换完成
val = u16AHI_AdcRead(); //读取转换值,输出的是16次采样的总和
return (val);
}
PUBLIC void AppColdStart (void)
{
uint16 adc, val;
float temp;
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
vAdcInitVolt();
vPrintf("System init...\n");
while (1) {
adc = u16AdcReadVolt();
adc = adc / 16; //求16次采样的平均值
vPrintf("Volt Value: %x \n", adc);
val = (adc / ADC_VALUE_TO_VOLTAGE_PARAMETER) * 1000; //保留3位小数
vPrintf("Volt Voltage: %d.%d%d%d V\n", val / 1000, val / 100 % 10, val / 10 % 10, val % 10);
temp = (float)val / 0.666;
vPrintf("VDDA Volt: %d.%d%d V\n", (uint16)temp / 1000, (uint16)temp / 100 % 10, (uint16)temp / 10 % 10);
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果图: