简介
本文介绍如何在nrf52840上使用adc。
环境
1、zephyr v3.5.99
2、nrf connect sdk v2.6.1
具体操作
编写设备树
/ {
zephyr,user {
io-channels = <&adc 2>;
};
};
&adc {
#address-cells = <1>;
#size-cells = <0>;
channel@2 {
reg = <2>;
zephyr,gain = "ADC_GAIN_1_6";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,vref-mv = <600>;
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_AIN2>;
zephyr,resolution = <12>;
zephyr,oversampling = <4>;
};
};
编写驱动代码
#include "adc.h" // 包含 ADC 相关头文件
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#if !DT_NODE_EXISTS(DT_NODELABEL(adc))
#error "No suitable ADC devicetree node found"
#endif
// ADC 原始值缓冲区
static uint16_t raw_val_buf;
// ADC 信息结构体
adc_info_t adc_info = {
.adc_channel = ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0),
.sequence = {
.buffer = &raw_val_buf,
.buffer_size = sizeof(raw_val_buf),
}
};
/**
* @description: 初始化自定义 ADC
* @param: info 指向 adc_info_t 结构体的指针
* @return: 0 表示成功,-1 表示失败
*/
int custom_adc_init(adc_info_t* info)
{
int err;
/* 在采样之前单独配置通道 */
if (!adc_is_ready_dt(&info->adc_channel)) {
printk("ADC controller device %s not ready\n", info->adc_channel.dev->name);
return -1;
}
err = adc_channel_setup_dt(&info->adc_channel);
if (err < 0) {
printk("Could not setup channel (%d)\n", err);
return -1;
}
err = adc_sequence_init_dt(&info->adc_channel, &info->sequence);
if (err < 0) {
printk("Could not init sequence (%d)\n", err);
return -1;
}
return 0;
}
/**
* @description: 读取自定义 ADC 值
* @param: info 指向 adc_info_t 结构体的指针
* @return: 0 表示成功,-1 表示失败
*/
int custom_adc_read(adc_info_t* info)
{
int err = 0;
int32_t val_mv;
printk("- %s, channel %d: ",
info->adc_channel.dev->name,
info->adc_channel.channel_id);
err = adc_read_dt(&info->adc_channel, &info->sequence);
if (err < 0) {
// 返回 -22 表示提供的参数值无效
printk("Could not read (%d)\n", err);
return -1;
}
/*
* 如果使用差分模式,ADC 采样缓冲区中的 16 位值
* 应该是一个有符号的 2's 补码值。
*/
if (info->adc_channel.channel_cfg.differential) {
val_mv = (int32_t)((int16_t)raw_val_buf);
} else {
val_mv = (int32_t)raw_val_buf;
}
//printk("%"PRId32, val_mv);
err = adc_raw_to_millivolts_dt(&info->adc_channel, &val_mv);
/* 如果不支持转换到 mV, 则跳过 */
if (err < 0) {
printk(" (value in mV not available)\n");
} else {
printk(" = %"PRId32" mV\n", val_mv);
info->val_mv = val_mv;
}
return 0;
}
编写应用代码
int main(void)
{
int err = 0;
int rc = 0;
char temp[50];
err = custom_ble_init();
if (err) {
LOG_ERR("Failed to initialize BLE (err: %d)", err);
}
else k_sem_give(&ble_init_ok);
custom_adc_init(&adc_info);
for (;;) {
k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
custom_adc_read(&adc_info);
temp[0] = adc_info.val_mv/1000;
temp[0] <<= 4;
temp[0] |= adc_info.val_mv%1000/100;
temp[1] = adc_info.val_mv%100/10;
temp[1] <<= 4;
temp[1] |= adc_info.val_mv%10;
if (bt_custom_send(NULL, temp, 2)) {
LOG_WRN("Failed to send adc data over BLE connection");
}
}
}