ADC,analog-to-Digital Converter的缩写,是指将连续变量的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字信号,ADC能够将模拟信号转换成数字信号。MM32L073有一个ADC,具有以下特征:
- 最高12位可编程分辨率的 SAR ADC,多达10路外部输入通道和2路内部信号源
- 高达1Msps转换速率
- 支持多种工作模式:
▷ 单次转换模式:A/D 转换在指定通道完成一次转换
▷ 单周期扫描模式:A/D 转换在所有指定通道完成一个周期 (从低序号通道到高序号通道) 转换
▷ 连续扫描模式:A/D 转换连续执行单周期扫描模式直到软件停止A/D转换
- 通道采样时间,分辨率可软件配置
- 支持 DMA 传输
- A/D 转换开始条件:
▷ 软件启动
▷ 外部触发启动
▷ timer 匹配
- 转换结果支持左对齐或右对齐方式存储在16位数据寄存器
- 模拟看门狗,转换结果可和指定的值相比较,当转换值和设定值相匹配时,用户可设定是否产生中断请求
- ADC供电要求:2.5V-5.5V
AMetal平台已经为客户封装好了相关的函数,用户根据实际项目需求直接用相关函数即可。要读取电压值,需要经过这几个步骤:读取指定通道的 ADC 转换值、对转换值做均值处理、获取转换精度、获取 ADC 参考电压、计算出转换值对应的电压值。
01
初始化
AMetal平台提供了ADC初始化函数,可以直接调用初始化函数。函数原型为:
am_adc_handle_t am_mm32l073_adc_inst_init(void);
该函数在user_config目录下的am_hwconf_mm32l073_adc.c文件中定义,在am_mm32l073_inst_init.h中声明。因此使用ADC初始化函数时,需要包含头文件am_mm32l073_inst_init.h。
调用该函数初始化ADC时,需要定义一个am_adc_handle_t类型的变量,用于保存获取的ADC服务句柄,ADC初始化程序为:
am_adc_handle_t adc_handle;
adc_handle = am_mm32l073_adc_inst_init();
使用前,一般需要修改引脚初始化函数;以ADC通道0为例,ADC_IN0为PIOA_0的复用功能,需把ADC平台初始化函数的更改为:
static void __zlg_plfm_adc_init (void)
{
am_gpio_pin_cfg(PIOA_0, PIOA_0_ADC_IN0 | PIOA_0_AIN);
am_clk_enable(CLK_ADC1);
}
把解除ADC平台初始化函数的更改为:
static void __zlg_plfm_adc_deinit (void)
{
am_gpio_pin_cfg(PIOA_0, PIOA_0_INPUT_FLOAT);
am_clk_disable (CLK_ADC1);
}
如需修改ADC的参考电压和转换精度等信息,可以直接调用宏。
宏名
| 转换精度
| AMHW_ZLG_ADC_DATA_VALID_8Bit
| 8位
| AMHW_ZLG_ADC_DATA_VALID_9BIT
| 9位
| AMHW_ZLG_ADC_DATA_VALID_10BIT
| 10位
| AMHW_ZLG_ADC_DATA_VALID_11BIT
| 11位
| AMHW_ZLG_ADC_DATA_VALID_12BIT
| 12位
|
表1 转换精度宏定义
AMetal提供了5个ADC相关的接口函数。
函数原型
| 功能简介
| int am_adc_rate_get(am_adc_handle_t handle, int chan, uint32_t *p_rate);
| 获取ADC通道的采样率
| int am_adc_rate_set(am_adc_handle_t handle, int chan, uint32_t rate);
| 设置ADC通道的采样率
| int am_adc_vref_get(am_adc_handle_t handle, int chan);
| 获取参考电压
| int am_adc_bits_get(am_adc_handle_t handle, int chan);
| 获取ADC通道的转换位数
| int am_adc_read_mv(am_adc_handle_t handle,int chan,am_adc_val_t *p_mv,uint32_t count);
| 读取指定通道的电压值
|
表2 ADC 通用接口函数
02
获取ADC通道的采样率
获取当前ADC通道的采样率。其函数原型为:
int am_adc_rate_get(
am_adc_handle_t handle, // ADC 实例句柄
int chan, // ADC 通道
uint32_t *p_rate); // 用于获取采样率的指针
获取到的采样率的单位为Samples/s。如果返回AM_OK,说明获取成功;如果返回-AM_EINVAL,说明因参数无效导致获取失败。
uint32_t rate; // 定义用于保存获取的采样率值的变量
am_adc_rate_get(adc0_handle, 7, &rate); // 获取 ADC0通道7的采样率
参数无效是由于handle不是标准的ADChandle或者通道号不支持造成的。
03
设置ADC通道的采样率
设置ADC通道的采样率。实际采样率可能与设置的采样率存在差异,实际采样率可由am_adc_rate_get()函数获取。注意,在一个ADC中,所有通道的采样率往往是一样的,因此设置其中一个通道的采样率时,可能会影响其它通道的采样率。其函数原型为:
int am_adc_rate_set (
am_adc_handle_t handle, // ADC 实例句柄
int chan, // ADC 通道
uint32_t rate); // 设置的采样率,单位 Samples/s
如果返回 AM_OK,说明设置成功;如果返回-AM_EINVAL,说明因参数无效导致设置失败,其相应的代码如下:
am_adc_rate_set(adc0_handle,7,1000000);//设置ADC0通道7的采样率为1Msamples/s
04
获取ADC通道的参考电压
获取ADC通道的参考电压,其函数原型为:
int am_adc_vref_get(
am_adc_handle_t handle, // ADC 实例句柄
int chan); // ADC 通道
如果返回值大于0,表示获取成功,其值即为参考电压(单位:mV);如果返回-AM_EINVAL,说明因参数无效导致获取失败,其相应的代码如下:
int vref = am_adc_vref_get(adc0_handle, 7); // 获取通道 7 的参考电压
IF (vref < 0 )
{
// 获取失败
}
05
获取ADC通道的转换位数
获取ADC通道的转换位数,其函数原型为:
int am_adc_bits_get(
am_adc_handle_t handle, // ADC 实例句柄
int chan); // ADC 通道
如果返回值大于0,表示获取成功,其值即为转换位数;如果返回-AM_EINVAL,说明因参数无效导致获取失败,其相应的代码如下:
int bits =am_adc_bits_get(adc0_handle, 7); // 获取通道7的转换位数
if (bits < 0 )
{
// 获取失败
}
06
读取指定通道的电压值
直接读取ADC通道的电压值(单位:mV),该函数会等到电压值读取完毕后返回。其函数原型为:
int am_adc_read_mv(
am_adc_handle_t handle, // ADC实例句柄
int chan, // ADC 通道
am_adc_val_t *p_mv, // 存放电压值的缓冲区
uint32_t length); // 缓冲区的长度
其中 p_mv 是指向存放电压值的缓冲区,类型am_adc_val_t在am_adc.h中定义,即:typedef uint32_t am_adc_val_t;length 表示缓冲区的长度,决定了实际获取电压值的个数。如果返回AM_OK,表示读取通道电压值成功,相应缓冲区中已经填充好了读取到的电压值;如果返回-AM_EINVAL,说明因参数无效导致获取失败。其相应的代码如下:
am_adc_val_t vol_buf[10]; // 存放电压值的缓冲区
am_adc_read_mv(adc0_handle, 7, vol_buf,10); // 读取ADC0通道7对应引脚的10次电压值
07
应用实例
在使用过程中,我们需要通过多次采样然后取平均值来减小误差,读取ADC采样值的函数原型为:
int am_adc_read (am_adc_handle_t handle,
int chan,
void *p_val,
uint32_t length);
- handle 为ADC的服务句柄
- chan 为ADC的通道编号
- p_val 指向保存采样值的数组
- length 代表着采样的次数
采样完成后,我们需把p_val指向的数组里的值加起来,除以length,来得到多次采样的平均值:
for (sum = 0, i = 0; i < length; i++)
{
sum += p_val ;
}
sum /= length;
得到平均值后,可用 AM_ADC_VAL_TO_MV()将它装换为电压值:
adc_mv = AM_ADC_VAL_TO_MV(handle, chan,adc_code);
其中adc_mv为保存电压值的变量;handle为ADC的服务句柄;chan为ADC的通道编号;adc_code为多次采样额平均值。
每隔500ms读取ADC通道0的电压值并通过串口打印的应用范例如下:
#include "ametal.h"
#include "am_vdebug.h"
#include "am_delay.h"
#include "am_adc.h"
#include "am_mm32l073_inst_init.h"
static uint32_t __adc_code_get (am_adc_handle_t handle, int chan) //获取ADC转换值
{
int i;
uint32_t sum;
uint16_t val_buf[12];
am_adc_read(handle, chan, val_buf,12);
for (sum = 0, i = 0; i <12; i++) // 均值处理
{
sum += val_buf;
}
return (sum /12);
}
void am_main ()
{
am_adc_handle_t handle=am_mm32l073_adc_inst_init();
int adc_bits = am_adc_bits_get(handle , 1); // 获取ADC转换精度
int adc_vref = am_adc_vref_get(handle , 1);
uint32_t adc_code; // 采样 Code 值
uint32_t adc_mv; // 采样电压
am_kprintf("The ADC value channel is %d: \r\n",1);
if (adc_bits < 0 || adc_bits >= 32)
{
am_kprintf("The ADC channel is error, Please check! \r\n");
return;
}
AM_DBG_INFO("demo mm32l073_core std adc int!\r\n");
while (1)
{
adc_code = __adc_code_get(handle, 1);
adc_mv = AM_ADC_VAL_TO_MV(handle, 1,adc_code); //转换为 mv
/* 串口输出采样电压值 */
am_kprintf("Sample : %d, Vol: %d mv\r\n",adc_code,adc_mv);
am_mdelay(500);
}
}
08
测试结果
|
|