00. 目录
文章目录
01. ADC简介
ADC(Analog-to-Digital Converter) 指模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。模数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。与之相对应的 DAC(Digital-to-Analog Converter),它是 ADC 模数转换的逆向过程。ADC 最早用于对无线信号向数字信号转换。如电视信号,长短播电台发射接收等。
ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接,其物理连线如图1所示:
转换过程
如下图所示模数转换一般要经过采样、保持和量化、编码这几个步骤。在实际电路中,有些过程是合并进行的,如采样和保持,量化和编码在转换过程中是同时实现的。
采样是将时间上连续变化的模拟信号转换为时间上离散的模拟信号。采样取得的模拟信号转换为数字信号都需要一定时间,为了给后续的量化编码过程提供一个稳定的值,在采样电路后要求将所采样的模拟信号保持一段时间。
将数值连续的模拟量转换为数字量的过程称为量化。数字信号在数值上是离散的。采样保持电路的输出电压还需要按照某种近似方式归化到与之相应的离散电平上,任何数字量只能是某个最小数量单位的整数倍。量化后的数值最后还需要编码过程,也就是 A/D 转换器输出的数字量。
分辨率
分辨率以二进制(或十进制)数的位数来表示,一般有8位、10位、12位、16位等,它说明模数转换器对输入信号的分辨能力,位数越多,表示分辨率越高,恢复模拟信号时会更精确。
精度
精度表示 ADC 器件在所有的数值点上对应的模拟值和真实值之间的最大误差值,也就是输出数值偏离线性最大的距离。
转换速率
转换速率是指 A/D 转换器完成一次从模拟到数字的 AD 转换所需时间的倒数。例如,某 A/D 转换器的转换速率为 1MHz,则表示完成一次 AD 转换时间为 1 微秒。
02. Hi3861板载ADC通道
开发板上搭载的 Hi3861 芯片有8个 ADC 通道(ADC0-ADC7),其中通道 ADC7 为内部 VBAT 电压检测通道,不能进行 AD 转换,通道 ADC0-ADC6 是12位逐次逼近型的模拟数字转换器(Analog to Digital Converter),实现将模拟信号转换为数字信号的功能。
Hi3861 芯片的 ADC 功能没有独立的引脚, ADC 功能与 GPIO 功能之间存在引脚复用。对于同时具备这两种或以上功能的引脚,同一时刻只能使用其中的一种功能。 Hi3861 芯片的 ADC 通道与 GPIO 引脚对应关系见下表所示 。
ADC 通道与 GPIO 引脚对应关系
GPIO 引脚 | ADC 通道 |
---|---|
GPIO04 | ADC1 |
GPIO05 | ADC2 |
GPIO07 | ADC3 |
GPIO09 | ADC4 |
GPIO11 | ADC5 |
GPIO12 | ADC0 |
GPIO13 | ADC6 |
03. 相关头文件关系
04. ADC相关类型
4.1 hi_adc_channel_index
/**
* @ingroup iot_ls_adc
*
* channel ID。CNcomment:通道编号.CNend
*/
typedef enum {
HI_ADC_CHANNEL_0,
HI_ADC_CHANNEL_1,
HI_ADC_CHANNEL_2,
HI_ADC_CHANNEL_3,
HI_ADC_CHANNEL_4,
HI_ADC_CHANNEL_5,
HI_ADC_CHANNEL_6,
HI_ADC_CHANNEL_7,
HI_ADC_CHANNEL_BUTT,
} hi_adc_channel_index;
4.2 hi_adc_cur_bais
/**
* @ingroup iot_ls_adc
*
* Analog power control. CNcomment:模拟电源控制。CNend
*/
typedef enum {
HI_ADC_CUR_BAIS_DEFAULT, /**< 0:Auto control.
CNcomment:自动识别模式 */
HI_ADC_CUR_BAIS_AUTO, /**< 1:Auto control.
CNcomment:自动识别模式 */
HI_ADC_CUR_BAIS_1P8V, /**< 2:Manual control, AVDD=1.8V.
CNcomment:手动控制,AVDD=1.8V */
HI_ADC_CUR_BAIS_3P3V, /**< 3:Manual control, AVDD=3.3V.
CNcomment:手动控制,AVDD=3.3V */
HI_ADC_CUR_BAIS_BUTT,
} hi_adc_cur_bais;
4.3 hi_adc_equ_model_sel
/**
* @ingroup iot_ls_adc
*
* Average algorithm mode CNcoment:平均算法模式。CNend
*/
typedef enum {
HI_ADC_EQU_MODEL_1, /**< 0:The average value is not used.
CNcomment:1次平均,即不进行
平均 CNend */
HI_ADC_EQU_MODEL_2, /**< 1:2-time average algorithm mode.
CNcomment:2次平均算法模式 CNend */
HI_ADC_EQU_MODEL_4, /**< 2:4-time average algorithm mode.
CNcomment:4次平均算法模式 CNend */
HI_ADC_EQU_MODEL_8, /**< 3:8-time average algorithm mode.
CNcomment:8次平均算法模式 CNend */
HI_ADC_EQU_MODEL_BUTT,
} hi_adc_equ_model_sel;
05. ADC相关API
5.1 hi_adc_read
/**
* @ingroup iot_ls_adc
* @brief Read one data in single ADC channel. CNcomment:从一个ADC通道读一个数据。CNend
*
* @par 描述:
* Read one data in single ADC channel.
CNcomment:从一个ADC通道读一个数据。CNend
*
* @attention None
* @param channel [IN] type #hi_adc_channel_index,channel to be read. CNcomment:要读的channel。CNend
* @param data [OUT] type #hi_u16 * ,data point to store the data.
CNcomment:读取的ADC数据保存地址。CNend
* @param equ_model [IN] type #hi_adc_equ_model_sel ,Average algorithm mode.
CNcomment:平均算法模式。CNend
* @param cur_bais [IN] type #hi_adc_cur_bais ,Analog power control.
CNcomment:模拟电源控制。CNend
* @param delay_cnt [IN] type #hi_u16 ,Countings from config to start collect,One count is 334ns,[0, 0xFF0].
CNcomment:从配置采样到启动采样的延时时间计数,一次计数是334ns,其值需在0~0xFF0之间。CNend
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. See hi_errno.h for details.
* @par 依赖:
* @li hi_adc.h:Describes ADC APIs.
CNcomment:文件用于描述ADC相关接口。CNend
* @see hi_adc_read。
*/
hi_u32 hi_adc_read(hi_adc_channel_index channel, hi_u16 *data, hi_adc_equ_model_sel equ_model,
hi_adc_cur_bais cur_bais, hi_u16 delay_cnt);
功能:
从一个ADC通道读一个数据
参数:
channel:表示指定的 ADC 通道,根据使用引脚对应的通道选择
data:表示指向存储读取数据的地址的指针
equ_model:表示平均算法模式
cur_bais:表示模拟电源控制模式,通常使用的是 3V3
delay_cnt:从配置采样到启动采样的延时时间计数,一次计数是 334ns,其值需在 0~0xFF0 之间
返回值:
0 成功,1 失败
5.2 hi_adc_convert_to_voltage
/**
* @ingroup iot_ls_adc
* @brief Convert adc read data to voltage. CNcomment:将ADC读取到的码字转换为电压。CNend
*
* @par 描述:
* Convert adc read data to voltage.
CNcomment:将ADC读取到的码字转换为电压。CNend
*
* @attention None
* @param data [IN] type #hi_u16,data read by adc. CNcomment:ADC读取到的码字。CNend
* @retval votalge converted by data. CNcomment: 码字转换得到的电压。CNend
* @par 依赖:
* @li hi_adc.h:Describes ADC APIs.
CNcomment:文件用于描述ADC相关接口。CNend
* @see hi_adc_read。
*/
hi_float hi_adc_convert_to_voltage(hi_u16 data)
功能:
将读取 ADC 值转换为电压
参数:
data:ADC 读取数据
返回值:
ADC 读取电压
06. 硬件设计
由图可知,P1 端子的 R_ADC 脚为电位器电压输出端,可将该引脚与 Hi3861的 ADC 脚连接即可采集。
07. 软件设计
bsp_adc.h
#ifndef __BSP_ADC_H__
#define __BSP_ADC_H__
#include <unistd.h>
#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
//ADC5 --> IO11
#define ADC5_PIN HI_IO_NAME_GPIO_11
#define ADC5_GPIO_FUN HI_IO_FUNC_GPIO_11_GPIO
//函数声明
void adc5_init(void);
uint16_t adc5_get_value(void);
float adc5_get_voltage(void);
#endif /*__BSP_ADC_H__*/
bsp_adc.c
#include <unistd.h>
#include "bsp_adc.h"
#include "hi_adc.h"
//函数声明
void adc5_init(void)
{
hi_gpio_init();
hi_io_set_pull(ADC5_PIN, HI_IO_PULL_UP);
hi_io_set_func(ADC5_PIN, ADC5_GPIO_FUN);
hi_gpio_set_dir(ADC5_PIN, HI_GPIO_DIR_IN);
}
uint16_t adc5_get_value(void)
{
uint16_t value = 0;
hi_adc_read(HI_ADC_CHANNEL_5, &value, HI_ADC_EQU_MODEL_8, HI_ADC_CUR_BAIS_3P3V, 0xFF);
return value;
}
float adc5_get_voltage(void)
{
return hi_adc_convert_to_voltage(adc5_get_value());
}
template.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
#include "bsp_led.h"
#include "bsp_adc.h"
#define TASK_STACK_SIZE 1024
//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;
//线程回调入口函数
void task1 (void *arg)
{
//LED初始化
led_init();
while(1)
{
//LED 高电平
//hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_2, HI_GPIO_VALUE1);
LED(HI_GPIO_VALUE1);
sleep(1);
//LED 低电平
//hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_2, HI_GPIO_VALUE0);
LED(HI_GPIO_VALUE0);
sleep(1);
}
}
void task2(void *arg)
{
adc5_init();
while(1)
{
printf("adc value: %d\n", adc5_get_value());;
printf("adc voltate: %f\n", adc5_get_voltage());
sleep(1);
}
}
/**
* @description: 初始化并创建任务
* @param {*}
* @return {*}
*/
static void template_demo(void)
{
osThreadAttr_t attr;
attr.name = "task1"; //任务名称
attr.attr_bits = osThreadDetached; //分离状态
attr.cb_mem = NULL;
attr.cb_size = 0;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = osPriorityNormal;
//创建任务1
task1_id = osThreadNew(task1, NULL, &attr);
if (NULL != task1_id)
{
printf("任务1创建OK task1_id = %d\n", task1_id);
}
attr.name = "task2"; //任务名称
//创建任务2
task2_id = osThreadNew(task2, NULL, &attr);
if (NULL != task2_id)
{
printf("任务2创建OK task2_id = %d\n", task2_id);
}
}
SYS_RUN(template_demo);
08. 实验现象
下载程序前,按照如下接线
实验现象:ADC 采集电位器 0-3.3V 电压,并输出在串口监视器显示。