ADC(Analog to Digital) 模拟转数字是经常使用的外设,本示例将演示如何调用adc接口来实现扩展MCU的ADC功能。运行该应用后,会间隔采集EXT_PA2引脚上的电压,并通过日志输出。
CSK6 ADC驱动具有如下特性:
int adc_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg);
采样通道配置,成功返回0,失败返回非0。
参数说明
字段 | 说明 |
---|---|
dev | 指向ADC Device的指针 |
channel_cfg | 采样通道配置 |
uint16_t adc_ref_internal(const struct device *dev);
获取内部参考电压,返回与ADC_REF_INTERNAL相对应的电压,以毫伏(mV)为单位。
返回大于0的正值则是参考电压值,返回0表示参考电压信息不可用。
参数说明
字段 | 说明 |
---|---|
dev | 指向ADC Device的指针 |
int adc_read(const struct device *dev, const struct adc_sequence *sequence);
获取采样值,如果从用户模式调用,回调的sequence.options都必须是NULL。
adc_read的函数返回值见下述说明。
参数说明
字段 | 说明 |
---|---|
dev | 指向ADC Device的指针 |
sequence | 指定请求的采样序列的结构 |
返回值说明
返回值 | 说明 |
---|---|
0 | 成功 |
-EINVAL | 传入的参数有误 |
-ENOMEM | 用于采样的buf定义太小,无法保存所有请求的采样结果 |
-ENOTSUP | 请求的操作模式不支持 |
-EBUSY | 在前一个采样仍在进行时触发了另一个采样,则返回-EBUSY |
int adc_raw_to_millivolts(int32_t ref_mv, enum adc_gain gain, uint8_t resolution, int32_t *valp);
将原始ADC采样值转换为以毫伏(mV)为单位的电压,返回0表示成功,非0表示失败。
参数说明
字段 | 说明 |
---|---|
ref_mv | 测量的参考电压,单位为毫伏,该值可能是从adc_ref_internal()函数调用获取,或者从外部获取的参考电压值。 |
gain | 用于采样输入的ADC增益配置 |
resolution | 样本绝对值中的位数,对于差分采样,该值必须小于adc_sequence结构体里面的resolution值 |
valp | 输入时指向原始采样值的指针,成功转换后指向相应的毫伏值。如果转换失败,则存储值保持不变。 |
更多ADC driver API接口可查看Zephyr官网ADC driver API。
SDK 中提供了 exmcu_ADC 的示例。
{SDK}\.sdk\csk\samples\driver\exmcu_adc
演示如何调用adc接口来实现扩展MCU的ADC功能。运行该应用后,会间隔采集EXT_PA2引脚上的电压,并通过日志输出。
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
使用引脚:
在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk/csk/samples/driver/exmcu_adc/ -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
烧录完成后,连接串口终端,按下开发板复位按钮,可看到串口有对应的信息输出。
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
CONFIG_ADC=y
CONFIG_ADC_CSK6_CH32V003=y
CONFIG_I2C_CSK6=y
CONFIG_I2C=y
设备树文件csk6_duomotai_devkit.overlay
配置如下:
/*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
/**
*
* external adc channel map
*
* CH0 --> PA2
* CH1 --> PA1
* CH2 --> PC4
* CH3 --> PD2
* CH4 --> PD3
* CH5 --> PD5
* CH6 --> PD6
* CH7 --> PD4
*
*/
zephyr,user {
/* this sample use ch0*/
io-channels = <&exadc 0>;
};
};
NOTE
如果您想了解更多关于设备树的信息,请学习设备树章节。
1.获取ADC设备的句柄
const struct device *dev_adc = DEVICE_DT_GET(ADC_NODE);
2.遍历配置每个ADC通道
3.设置每个ADC通道的配置信息
adc_channel_setup(dev_adc, &channel_cfg);
4.读取每个ADC通道的模拟信号
err = adc_read(dev_adc, &sequence);
5.将读取的模拟电压信号转换为毫伏值
adc_raw_to_millivolts(adc_vref, ADC_GAIN_1, ADC_RESOLUTION,&mv_value);
6.通过串口打印每个ADC通道的模拟信号
按下开发板复位按钮,运行程序,观察串口打印信息。
int main(void)
{
int err;
const struct device *dev_adc = DEVICE_DT_GET(ADC_NODE);
printk("ADC Sample start, ch:%d\n", ADC_NUM_CHANNELS);
if (!device_is_ready(dev_adc)) {
printk("ADC device not found\n");
return 0;
}
/*
* Configure channels individually prior to sampling
*/
for (uint8_t i = 0; i < ADC_NUM_CHANNELS; i++) {
channel_cfg.channel_id = channel_ids[i];
adc_channel_setup(dev_adc, &channel_cfg);
sequence.channels |= BIT(channel_ids[i]);
}
int32_t adc_vref = adc_ref_internal(dev_adc);
printk("adc_vref %d.\n", adc_vref);
while (1) {
/*
* Read sequence of channels (fails if not supported by MCU)
*/
err = adc_read(dev_adc, &sequence);
if (err != 0) {
printk("ADC reading failed with error %d.\n", err);
return 0;
}
for (uint8_t i = 0; i < ADC_NUM_CHANNELS; i++) {
int32_t raw_value = sample_buffer[i];
if (adc_vref > 0) {
/*
* Convert raw reading to millivolts if driver
* supports reading of ADC reference voltage
*/
int32_t mv_value = raw_value;
adc_raw_to_millivolts(adc_vref, ADC_GAIN_1, ADC_RESOLUTION,
&mv_value);
printk(" adc(%d)= %d mV ", raw_value, mv_value);
}
}
printk("\n");
k_sleep(K_MSEC(1000));
}
}