MSPM0L1306例程学习系列
使用的TI的官方例程,即SDK里边包含的例程代码。
可以到TI官网下载并且安装SDK: https://www.ti.com.cn/tool/cn/download/MSPM0-SDK/
MCU使用的是MSPM0L1306, 对于ADC部分,有10个例程:
前边讲了3个例程,今天讲第4个例程,使用ADC的内部通道,对系统的电源电压进行测量。 ADC模块硬件上预留有多个内部通道,可以用于系统的内部测量。如下图所示,A0-A9是连接到外部IO引脚的,其它通道是连接到内部模块的。
电源监测使用A15,系统内部将电源电压进行1/3分压之后,送到ADC模块。
官方的这个例程设计得一般,比大小没有太大意义,不如直接设断点看计算出的电源电压;更多可以查看下边的代码注释。
同样的,因为用了sysconfig图形配置工具,系统的初始化配置如下:
与前边的代码例程相比,不需要每次转换完以后都调用DL_ADC12_enableConversions(ADC12_0_INST)来使能ADC转换,即ENC=1。 因为这个例程ADC的工作模式变了,配置成单通道、多次转换模式。
实验步骤:
- 下载程序;
- 添加查看的变量gAdcResultVolts;
- 设置断点,查看ADC的采样结果值(有可能被优化了),查看计算出来的电压值gAdcResultVolts;
- 万用表测量电源电压,对比计算出来的电压值;
添加注释后的详细代码参考如下:
/*
* ADC转换的SDK例程
* 文件名:adc12_monitor_supply.c
* 描述:
* 使用ADC内部通道(有专门的一路用于监测电源电压),测量系统的电源电压。
* 1、单通道、多次转换、自动采样模式、软件触发;
* 2、使用MEM0,选择ADC通道15(内部电源监控通道,取电源电压的1/3送到ADC模块)
* 3、使用内部参考电压,2.5V
* 4、PA0引脚连接有LED灯;
* 5、对通道15进行AD采样和转换,根据转换结果进行LED的指示操作:
* a.当转换结果小于ADC12_SUPPLY_MONITOR_VALUE时,LED灭; 否则,点亮LED
* b.例程这个灯亮和灯灭设计的没啥意义,建议通过断点直接查看电源电压;
*
* 操作描述:
* 1、下载程序;
* 2、添加查看的变量gAdcResultVolts;
* 3、设置断点,查看ADC的采样结果值(有可能被优化了),查看计算出来的电压值gAdcResultVolts;
* 4、万用表测量电源电压,对比计算出来的电压值;
*
* 注意事项:
* 1、从数据手册里可以查看到,电源电压监测通道为A15(内部通道);将电源电压分压后使用,1/3*VDD
* 2、查看ADC的采样结果值,这个变量有可能被优化了,但不影响计算的电压值;思考下,怎么才能不优化?
*
* 思考:
* 万用表测量电源电压,看测量值是否符合预取结果。
*
* 修改:
* 基于官方的sdk例程增加注释,xie_sx@126.com
*/
#include "ti_msp_dl_config.h"
/*
* 作为入门例程,这个宏定义把系统整复杂了;
* 定义了这么多,最终就是想等到一个变量: ADC12_SUPPLY_MONITOR_VALUE
* 用于将ADC的转换结果跟它进行比较;
* 这个例程,比大小没有太大意义,不如直接设断点看计算出的电源电压;
*
* 能理解这个公式就行,根据AD的转换结果反算出电压;
* gAdcResultVolts = (adcResult * ADC12_REF_VOLTAGE) / (1 << ADC12_BIT_RESOLUTION) * 3;
*
* (1 << ADC12_BIT_RESOLUTION) --》12位的AD,2的12次方;
* AD的转换结果adcResult / 2的12次方, 再✖参考电压ADC12_REF_VOLTAGE, 计算出当前AD的采样对应的电压;
* 电源电压还要再✖3
*/
/* clang-format off */
#define ADC12_BIT_RESOLUTION (12)
#define ADC12_REF_VOLTAGE (2.5)
#define ADC12_SUPPLY_MONITOR_VOLTAGE (2.5)
#define ADC12_SUPPLY_MONITOR_VALUE ( (1 << ADC12_BIT_RESOLUTION) * \
(ADC12_SUPPLY_MONITOR_VOLTAGE / \
(3 * ADC12_REF_VOLTAGE)))
/* clang-format on */
volatile bool gCheckADC;
volatile float gAdcResultVolts;
int main(void)
{
uint16_t adcResult;
//器件初始化
SYSCFG_DL_init();
//配置器件的中断
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);
//ADC12的结果更新标志位清零
gCheckADC = false;
//软件启动ADC12转换
DL_ADC12_startConversion(ADC12_0_INST);
while (1)
{
//等待转换完成
//如果标志位gCheckADC不是true,程序在while循环等待
//gCheckADC=true后,程序继续往下执行
while (false == gCheckADC)
{
__WFE();
}
//ADC12的结果更新标志位清零
gCheckADC = false;
//从结果寄存器读取本次的转换结果
adcResult = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0);
//将ADC的转换结果换算成电压值?
gAdcResultVolts = (adcResult * ADC12_REF_VOLTAGE) / (1 << ADC12_BIT_RESOLUTION) * 3;
//比较的话,还是直接用ADC的采样的结果进行比较,整型数.结果为整数以进行高效处理
if (adcResult > ADC12_SUPPLY_MONITOR_VALUE)
{
DL_GPIO_clearPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
}
else
{
DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
}
}
}
/*
* ADC12中断处理函数
*
* 中断里只设置结果更新标志位gCheckADC
*
*/
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST))
{
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
gCheckADC = true;
break;
default:
break;
}
}