cr315 发表于 2021-2-3 17:10

基于MM32 MCU的OS移植与应用——AMetal ADC采样配置

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);
读取指定通道的电压值

表2ADC 通用接口函数





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;                   // 存放电压值的缓冲区
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;
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
测试结果

51xlf 发表于 2021-2-17 21:18

AMetal?         

i1mcu 发表于 2021-2-17 21:18

AMetal没有直接的引用官方的库

pmp 发表于 2021-2-17 21:19

深入了解AMetal框架         

mmbs 发表于 2021-2-17 21:19

AMetal 提供了操作GPIO 的标准接口函数

1988020566 发表于 2021-2-17 21:19

ametal的技术应用   

lzbf 发表于 2021-2-17 21:20

AMetal助你三步搞定传感器   

youtome 发表于 2021-2-17 21:20

         

cemaj 发表于 2021-2-17 21:20

AMetal是广州周立功科技股份有限公司开发的一套轻量级嵌入式开发平台

jimmhu 发表于 2021-2-17 21:20

面向AMetal框架和接口的C编程

lihuami 发表于 2021-2-17 21:21

基于抢占式的实时多任务内核?

pmp 发表于 2021-2-17 21:21

理论上,Ametal支持所有的MCU

i1mcu 发表于 2021-2-17 21:21

官方库架构有吗 ?      

mmbs 发表于 2021-2-17 21:21

AMetal是芯片级的裸机软件包

51xlf 发表于 2021-2-17 21:21

AMetal是什么系统呢?   

1988020566 发表于 2021-2-17 21:21

metal的设计资料   

cemaj 发表于 2021-2-17 21:21

为各种外设定义了统一的抽象接口   

youtome 发表于 2021-2-17 21:22

谢谢楼主分享的资料了。   

lihuami 发表于 2021-2-17 21:22

有完整的移植过程吗   

jimmhu 发表于 2021-2-17 21:22

灵动微电子MM32系列MCU将陆续入驻AMetal平台
页: [1] 2
查看完整版本: 基于MM32 MCU的OS移植与应用——AMetal ADC采样配置