打印
[MM32软件]

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

[复制链接]
4369|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2021-2-3 17:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
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
测试结果

使用特权

评论回复
沙发
51xlf| | 2021-2-17 21:18 | 只看该作者
AMetal?         

使用特权

评论回复
板凳
i1mcu| | 2021-2-17 21:18 | 只看该作者
AMetal没有直接的引用官方的库  

使用特权

评论回复
地板
pmp| | 2021-2-17 21:19 | 只看该作者
深入了解AMetal框架         

使用特权

评论回复
5
mmbs| | 2021-2-17 21:19 | 只看该作者
AMetal 提供了操作GPIO 的标准接口函数  

使用特权

评论回复
6
1988020566| | 2021-2-17 21:19 | 只看该作者
ametal的技术应用   

使用特权

评论回复
7
lzbf| | 2021-2-17 21:20 | 只看该作者
AMetal助你三步搞定传感器   

使用特权

评论回复
8
youtome| | 2021-2-17 21:20 | 只看该作者
           

使用特权

评论回复
9
cemaj| | 2021-2-17 21:20 | 只看该作者
AMetal是广州周立功科技股份有限公司开发的一套轻量级嵌入式开发平台

使用特权

评论回复
10
jimmhu| | 2021-2-17 21:20 | 只看该作者
面向AMetal框架和接口的C编程  

使用特权

评论回复
11
lihuami| | 2021-2-17 21:21 | 只看该作者
基于抢占式的实时多任务内核?  

使用特权

评论回复
12
pmp| | 2021-2-17 21:21 | 只看该作者
理论上,Ametal支持所有的MCU  

使用特权

评论回复
13
i1mcu| | 2021-2-17 21:21 | 只看该作者
官方库架构有吗 ?      

使用特权

评论回复
14
mmbs| | 2021-2-17 21:21 | 只看该作者
AMetal是芯片级的裸机软件包  

使用特权

评论回复
15
51xlf| | 2021-2-17 21:21 | 只看该作者
AMetal是什么系统呢?   

使用特权

评论回复
16
1988020566| | 2021-2-17 21:21 | 只看该作者
metal的设计资料   

使用特权

评论回复
17
cemaj| | 2021-2-17 21:21 | 只看该作者
为各种外设定义了统一的抽象接口   

使用特权

评论回复
18
youtome| | 2021-2-17 21:22 | 只看该作者
谢谢楼主分享的资料了。   

使用特权

评论回复
19
lihuami| | 2021-2-17 21:22 | 只看该作者
有完整的移植过程吗   

使用特权

评论回复
20
jimmhu| | 2021-2-17 21:22 | 只看该作者
灵动微电子MM32系列MCU将陆续入驻AMetal平台

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1332

主题

3883

帖子

0

粉丝