ADC采集
1.1 什么是ADC
ADC 全称为模拟-数字转换器,是一种用于将模拟信号转换为数字信号的模拟数字转换器。我们知道,模拟信号是连续的,其取值可以在一定范围内任意变化,如声音、光信号等。而数字信号则是离散的二进制信号,如计算机中的数据0和1,仅能取有限的值。
ADC的工作原理是将模拟信号通过采样转换为离散的数字信号,然后再通过量化、编码等处理,最终得到对应的数字表示。ADC采样的频率越高,得到的数字信号就越接近原来的模拟信号,也就是保真度越高,但是需要更多的资源和计算功耗。
ADC 通常用于从外部模拟传感器中读取模拟信号,并将其转换为数字信号供嵌入式系统或计算机进行处理,例如测量温度、湿度、压力等物理量。
1.2 MSPM0G系列的ADC介绍
MSPM0G3507采用的是逐次逼近型的12位ADC,它有 17个多路复用通道可以转换。17个外部通道,都对应单片机的某个引脚,这个引脚不是固定的,详情请参考引脚图或者数据手册。
各种通道的 A/D 转换可以配置成 单次、序列转换 模式。
单次转换模式: 每次进行一次ADC转换后,ADC会自动停止,并将结果存储在ADC数据寄存器中。
重复单次转换模式: 当ADC完成一次转换后,它会自动启动另一次转换,持续的进行转换,直到外部触发或者软件触发的方式停止连续转换。
多通道顺序单次转换模式: 用于对多个输入通道进行依次转换。在该模式下,ADC会根据配置的通道采集顺序,对多个通道进行单次采样并转换。
多通道顺序重复转换模式: 用于对多个输入通道进行依次重复转换。在该模式下,ADC会根据配置的通道采集顺序,对多个通道进行重复采样并转换。
1.3 ADC基本参数
分辨率: 表示ADC转换器的输出精度,通常以位数(bit)表示,比如8位、10位、12位等,位数越高,精度越高。MSPM0L1306支持8、10、12位的分辨率。
采样率: 表示ADC对模拟输入信号进行采样的速率,通常以每秒采样次数(samples per second,SPS)表示,也称为转换速率,表示ADC能够进行多少次模拟到数字的转换。MSPM0G3507的SPS为4Msps。
电压基准: ADC的电压基准是用于与模拟输入信号进行比较,从而实现模拟信号到数字信号的转换的一个参考电压。这个基准电压的准确性和稳定性对ADC的转换精度有着决定性的影响。而MSPM0G3507可以支持软件选择三种基准:(1)1.4V 和 2.5V 的可配置内部专用 ADC 基准电压 (VREF)(2)MCU 电源电压 (VDD) (3)通过 VREF+和 VREF- 引脚为 ADC 提供外部基准。如未配置电压基准则默认使用MCU电源电压作为ADC电压基准。
采样范围: 指ADC可以采集到的模拟输入信号的电压范围,范围见下:
其中VREF- 为设置的电压基准负,通常为0V。VREF+ 为电压基准正,根据软件的配置确定范围。
1.4 基本原理
MSPM0G3507采用的是逐次逼近型的ADC,逐次逼近型ADC是一种常见的ADC工作原理,它的思想是通过比较模拟信号与参考电压之间的大小关系来逐步逼近输入信号的数字表示。在逐次逼近型ADC中,输入信号和参考电压被加入一个差分放大器中,产生一个差分电压。然后,这个差分电压被输入到一个逐步逼近的数字量化器中,该量化器以逐步递减的方式将其与一系列参考电压进行比较。具体来说,在每个逼近阶段,量化器将输入信号与一个中间电压点进行比较,将该电压点上方或下方的参考电压作为下一个逼近阶段的参考电压。这个过程一直持续到量化器逼近到最终的数字输出值为止。
1.5 ADC优点
- 数字信号具有良好的抗干扰性。数字信号是由一系列离散的数字表示,因此可以抵抗模拟信号受到的各种干扰,如噪声、漂移等。
- 方便数字信号的存储、处理和传输。由于数字信号是离散的,因此它们可以轻松存储在计算机内存或其他数字设备中,方便进行处理和传输。
- 具有可编程性。现代的ADC出现了很多可编程的功能,例如可编程增益、采样率和滤波器等,可以根据不同的应用场景进行优化。
- 适用性广泛。ADC被广泛应用于工业、通信、医疗、电子测量、音频、视频等领域,可转换各种不同类型的模拟信号,包括电压、电流、声音、光信号等。
1.6 ADC应用
ADC的应用非常广泛。例如,我们可以用ADC将传感器的模拟信号转换为数字信号,然后通过计算机进行处理和分析;ADC在音频处理中也起着重要的作用,将模拟声音信号转换为数字信号,并接下来进行数字信号处理;无线电通信中的信号调制也需要使用ADC等。总的来说,ADC在现代电子工程中非常重要,是数字信号处理和控制技术的关键部分。
1.7 ADC的配置
本案例将以采集3.3V和GND的电压作为实验案例。通过ADC采集其电压变化,实现判断电压情况。
1.7.1 准备一个空白工程
将SDK路径下的G3507空白工程复制到SDK的根目录下:
必须复制到SDK的根目录下,不然无法找到文件
在Keil中打开我们复制的空白工程 empty。
设置图形化配置文件保存路径:
源:
cmd.exe /C "$P../../../../../../tools/keil/syscfg.bat '$P' empty.syscfg"
改:
cmd.exe /C "$P../../tools/keil/syscfg.bat '$P' empty.syscfg"
设置工程头文件路径:
改为:
设置工程链接器:
改为:
../../source/ti/driverlib/lib/keil/m0p/mspm0g1x0x_g3x0x/driverlib.a
完成之后编译,可以看到没有报错了。
1.7.2 开启SYSCONFIG配置工具
打开图形化配置界面。(需要确保keil当前界面打开了.syscfg文件)
在sysconfig中,左侧可以选择MCU的外设,我们找到并点击ADC12选项卡,在ADC12中点击ADD,就可以添加ADC外设。
1.7.3 ADC参数的配置
这里选择的配置是使用32Mhz的ADC频率,采样频率为4MHz,单次重复转换模式,通过软件触发ADC开始采样,数据格式为二进制的右对齐方式。
MSPM0G3507的ADC支持各种数据对齐方式以适应不同的应用场景。常见的数据对齐方式包括左对齐和右对齐。在右对齐模式下,ADC的数据在转换结束后被右对齐到最低位,不足的位数在高位填充0。右对齐模式允许实现在没有精度的损失下更好的动态范围。
在左对齐模式下,ADC的数据被左对齐到最高位,不足的位数在低位填充0。左对齐模式可以提高分辨率,但会导致动态范围降低。
我们配置为右对齐方式,这样我们可以直接将转换完成的数据进行运算。
1.7.3 配置ADC采集通道
配置ADC的分辨率为12位、手动控制ADC电源,设置采样时间。
开启ADC采集完成的中断。当ADC采集完成时触发中断,我们就进行数据处理。
1.7.4 其他配置
因为我们的案例需要通过串口将ADC采集到的数据发送给电脑,使用我们还需要配置串口。因为我们只需要发送不需要接收,所以串口的配置如下:
将以上配置保存,然后到Keil中编译更新。
1.8 ADC采集电压实验
在empty.c(要main函数的文件)中编写如下代码:
#include "ti_msp_dl_config.h"
#include "stdio.h"
#define delay_ms(X) delay_cycles((CPUCLK_FREQ/1000)*(X))
void uart0_send_string(char* str);//串口发送数据
volatile bool gCheckADC; //ADC采集成功标志位
unsigned int adc_getValue(void);//读取ADC的数据
int main(void)
{
char show_buff[100]={0};
unsigned int adc_value = 0;
float voltage_value = 0;
SYSCFG_DL_init();
//开启ADC中断
NVIC_EnableIRQ(ADC_VOLTAGE_INST_INT_IRQN);
uart0_send_string("adc Demo start\r\n");
while (1)
{
//获取ADC数据
adc_value = adc_getValue();
sprintf(show_buff,"adc value:%d\r\n", adc_value);
uart0_send_string(show_buff);
//将ADC采集的数据换算为电压
voltage_value = adc_value/4095.0*3.3;
sprintf(show_buff,"voltage value:%.2f\r\n",voltage_value );
uart0_send_string(show_buff);
delay_ms(1000);
}
}
//串口发送字符串
void uart0_send_string(char* str)
{
//当前字符串地址不在结尾 并且 字符串首地址不为空
while(*str!=0&&str!=0)
{
//发送字符串首地址中的字符,并且在发送完成之后首地址自增
DL_UART_transmitDataBlocking(UART_0_INST,*str++);
}
}
//读取ADC的数据
unsigned int adc_getValue(void)
{
unsigned int gAdcResult = 0;
//软件触发ADC开始转换
DL_ADC12_startConversion(ADC_VOLTAGE_INST);
//如果当前状态为正在转换中则等待转换结束
while (false == gCheckADC) {
__WFE();
}
//获取数据
gAdcResult = DL_ADC12_getMemResult(ADC_VOLTAGE_INST, ADC_VOLTAGE_ADCMEM_ADC_CH0);
//清除标志位
gCheckADC = false;
return gAdcResult;
}
//ADC中断服务函数
void ADC_VOLTAGE_INST_IRQHandler(void)
{
//查询并清除ADC中断
switch (DL_ADC12_getPendingInterrupt(ADC_VOLTAGE_INST))
{
//检查是否完成数据采集
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
gCheckADC = true;//将标志位置1
break;
default:
break;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
因为代码中使用到了一个sprintf
函数,该函数是从在stdio.h文件而来,而如果我们没有重定义sprintf,就需要开启keil端的MICROLIB
。
sprintf的说明
sprintf 是 C 语言标准库函数之一,用于格式化字符串并存储到指定的字符数组中。它的功能与 printf 类似,但是 sprintf 不是将格式化后的字符串输出到标准输出(如屏幕),而是将其存储在字符数组中。以下是 sprintf 的基本说明:
函数原型
int sprintf(char *str, const char *format, ...);
参数说明
str:指向字符数组的指针,该数组将用来存储格式化后的字符串。
format:指向格式化字符串的指针,它指定了输出格式。
...:可变参数列表,根据 format 中指定的格式占位符,可以是任意类型的数据。
实验示例
#include <stdio.h>
int main() {
char buffer[50];
int num = 123;
sprintf(buffer, "The number is: %d", num);
printf("%s\n", buffer); // 输出: The number is: 123
return 0;
}
2
3
4
5
6
7
8
9
最终结果输出:The number is: 123
虽然我们现在开启了MICROLIB,但是编译下载可能还会失败。因为MICROLIB会使用到一定的堆栈内存,所以我们还需要设置堆栈的大小。
这里我设置 Stack_Size 为 0x00001000,Heap_Size 为 0x00000100。
现在设置完成,可以编译下载了。编译通过:0报错0警告
确认编译成功后,我们将代码烧录开发板中即可。这里我使用J-LINK连接开发板。
J-LINK | 开发板 |
---|---|
5V | 5V |
CLK | CLK |
SWD | DIO |
GND | GND |
Keil中J-LINK下载的配置
配置完J-LINK后,重新编译,然后点击下载:
编译下载之后,打开串口调试助手,向PA27引脚输出3.3V的电压,ADC数据采集结果: