【前言】
准备做个可调电源,采用DCDC芯片,在原来的开发板上是用跳线来连接不同的电阻,决定电源的输出电压,因此我准备使用数字电位器来动态给出电阻,实现电压的输出。
【MCP41xxx简介】
MCP41xxx系列是由Microchip Technology(微芯科技)生产的一系列单通道数字电位器芯片。这些器件可以替代传统的机械式电位器,通过数字接口控制电阻值的变化,具有高精度、稳定性和可重复性等优点。
主要特性
基本电气特性
电阻值选择:提供10kΩ、50kΩ和100kΩ三种阻值选项
抽头数:256个等间距的抽头,提供精细的电阻调节能力
电源电压:单电源工作,电压范围2.7V - 5.5V
功耗:静态工作电流小于1μA,具有极低功耗特性
温度范围:工业级(-40°C至+85°C)和扩展级(-40°C至+125°C)
接口与控制
通信接口:标准SPI接口控制(支持模式0,0和1,1)
线性调节:电位器滑动端位置呈线性变化
精度指标:最大INL(积分非线性)和DNL(微分非线性)误差为±1LSB
功能特色
低功耗CMOS技术:采用先进的CMOS制造工艺
关断功能:软件关断功能可断开所有电阻电路,最大限度节省功耗
硬件复位:RS(复位)引脚实现硬件复位功能
非易失性存储:部分型号具有EEPROM特性,断电后保持设置值
上电复位:通电后滑动端自动重置到中间位置(第128抽头)
【工程创建】
我在zephyr的app目录下面创建app\mcp41100_ra6e2工程。
使用claude生成对应的文件目录。

【硬件连接】
由于Zephyr中FPB_RA6E2的spi0默认分配好,其连接接口如下:

由于我买到的模块只需要MOSI、SCK、CS,因此只需要连接三线即可。
【代码实现】
1、prj.conf
# MCP41100 Digital Potentiometer for FPB-RA6E2 # SPI (for MCP41100) CONFIG_SPI=y # Logging CONFIG_LOG=y CONFIG_LOG_DEFAULT_LEVEL=3
2、MCP41100.c
/*
* Copyright (c) 2025
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "mcp41100.h"
LOG_MODULE_DECLARE(mcp41100, LOG_LEVEL_INF);
#define DT_DRV_COMPAT microchip_mcp41100
static int mcp41100_spi_transfer(const struct device *dev, uint8_t cmd, uint8_t data)
{
const struct mcp41100_config *config = dev->config;
uint8_t tx_buf[2] = { cmd, data };
const struct spi_buf buf = {
.buf = tx_buf,
.len = sizeof(tx_buf)
};
const struct spi_buf_set tx = {
.buffers = &buf,
.count = 1
};
/* Assert CS */
gpio_pin_set_dt(&config->cs_gpio, 0);
int ret = spi_write(config->spi_dev, &config->spi_cfg, &tx);
/* Release CS */
gpio_pin_set_dt(&config->cs_gpio, 1);
return ret;
}
int mcp41100_init(const struct device *dev)
{
const struct mcp41100_config *config = dev->config;
struct mcp41100_data *data = dev->data;
if (!device_is_ready(config->spi_dev)) {
LOG_ERR("SPI device not ready");
return -ENODEV;
}
if (!device_is_ready(config->cs_gpio.port)) {
LOG_ERR("CS GPIO device not ready");
return -ENODEV;
}
/* Configure CS pin as output */
int ret = gpio_pin_configure_dt(&config->cs_gpio, GPIO_OUTPUT);
if (ret < 0) {
LOG_ERR("CS pin configure failed: %d", ret);
return ret;
}
/* CS inactive (high) */
gpio_pin_set_dt(&config->cs_gpio, 1);
data->wiper_pos = 0;
LOG_INF("MCP41100 initialized");
return 0;
}
int mcp41100_set_wiper(const struct device *dev, uint8_t pos)
{
struct mcp41100_data *data = dev->data;
if (pos > MCP41100_WIPER_MAX) {
pos = MCP41100_WIPER_MAX;
}
int ret = mcp41100_spi_transfer(dev, MCP41100_CMD_WRITE, pos);
if (ret < 0) {
LOG_ERR("Failed to set wiper: %d", ret);
return ret;
}
data->wiper_pos = pos;
return 0;
}
uint8_t mcp41100_get_wiper(const struct device *dev)
{
struct mcp41100_data *data = dev->data;
return data->wiper_pos;
}
int mcp41100_set_resistance(const struct device *dev, uint32_t total_ohm, uint32_t target_ohm)
{
uint8_t pos = mcp41100_calc_position(total_ohm, target_ohm);
return mcp41100_set_wiper(dev, pos);
}
int mcp41100_sleep(const struct device *dev)
{
return mcp41100_spi_transfer(dev, MCP41100_CMD_SLEEP, 0);
}
int mcp41100_wake(const struct device *dev)
{
return mcp41100_spi_transfer(dev, MCP41100_CMD_WAKE, 0);
}3、MCP4110.h
/*
* Copyright (c) 2025
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief MCP41100 Digital Potentiometer Driver
*
* MCP41100 is a 100K ohm digital potentiometer with 256 wiper positions.
* Communicates via SPI (3-wire).
*/
#ifndef MCP41100_H__
#define MCP41100_H__
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
/** MCP41100 SPI commands */
#define MCP41100_CMD_WRITE 0x11 /* Write to wiper (potentiometer mode) */
#define MCP41100_CMD_SLEEP 0x21 /* Shutdown pot */
#define MCP41100_CMD_WAKE 0x20 /* Wake from shutdown */
/** MCP41100 wiper positions */
#define MCP41100_WIPER_MIN 0
#define MCP41100_WIPER_MAX 255
/**
* @brief MCP41100 device configuration
*/
struct mcp41100_config {
/** SPI device */
const struct device *spi_dev;
/** SPI bus configuration */
struct spi_config spi_cfg;
/** CS GPIO specification */
struct gpio_dt_spec cs_gpio;
};
/**
* @brief MCP41100 device data
*/
struct mcp41100_data {
/** Current wiper position */
uint8_t wiper_pos;
};
/**
* @brief Initialize MCP41100 device
*
* @param dev MCP41100 device pointer
* @return 0 on success, negative errno on failure
*/
int mcp41100_init(const struct device *dev);
/**
* @brief Set wiper position
*
* @param dev MCP41100 device pointer
* @param pos Wiper position (0-255)
* @return 0 on success, negative errno on failure
*/
int mcp41100_set_wiper(const struct device *dev, uint8_t pos);
/**
* @brief Get current wiper position
*
* @param dev MCP41100 device pointer
* @return Current wiper position (0-255)
*/
uint8_t mcp41100_get_wiper(const struct device *dev);
/**
* @brief Calculate wiper position for target resistance
*
* @param total_ohm Total potentiometer resistance in ohms
* @param target_ohm Target resistance in ohms
* @return Wiper position (0-255)
*/
static inline uint8_t mcp41100_calc_position(uint32_t total_ohm, uint32_t target_ohm)
{
if (target_ohm >= total_ohm) {
return MCP41100_WIPER_MAX;
}
return (uint8_t)((target_ohm * MCP41100_WIPER_MAX) / total_ohm);
}
/**
* @brief Set resistance (convenience function)
*
* @param dev MCP41100 device pointer
* @param total_ohm Total potentiometer resistance in ohms
* @param target_ohm Target resistance in ohms
* @return 0 on success, negative errno on failure
*/
int mcp41100_set_resistance(const struct device *dev, uint32_t total_ohm, uint32_t target_ohm);
/**
* @brief Put MCP41100 to sleep (shutdown mode)
*
* @param dev MCP41100 device pointer
* @return 0 on success, negative errno on failure
*/
int mcp41100_sleep(const struct device *dev);
/**
* @brief Wake MCP41100 from sleep
*
* @param dev MCP41100 device pointer
* @return 0 on success, negative errno on failure
*/
int mcp41100_wake(const struct device *dev);
#endif /* MCP41100_H__ */3、\boards\fpb_ra6e2.overlay
&spi0 {
status = "okay";
};
/* SPI0 CS controlled via GPIO (P3_01) - software control only, don't use hw cs */
&spi0 {
cs-gpios = <&ioport3 1 GPIO_ACTIVE_HIGH>; /* 1=high=inactive, 0=low=active */
};在这里使能spi0, 以及定义0为使能CS,即低电平选中。
4、main.c
/*
* MCP41100 Digital Potentiometer Control
* FPB-RA6E2 + SPI0 -> MCP41100 (100K ohm, 实测89K)
*
* Output: 50K resistance (校准后)
* - 校准: 89K实测 → 50K目标 → 位置=143 (0x8F)
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "mcp41100.h"
LOG_MODULE_REGISTER(mcp41100, LOG_LEVEL_INF);
/* SPI device */
#define SPI_DEV DEVICE_DT_GET(DT_NODELABEL(spi0))
/* MCP41100 配置 - 使用设备树中的 cs-gpios */
static const struct gpio_dt_spec cs_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(spi0), cs_gpios);
/* SPI config - Mode 0 (CPOL=0, CPHA=0), 1MHz */
static struct spi_config spi_cfg = {
.frequency = 1000000,
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
.slave = 0,
};
/* MCP41100 设备配置 */
static const struct mcp41100_config mcp41100_config = {
.spi_dev = SPI_DEV,
.spi_cfg = {
.frequency = 1000000,
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
.slave = 0,
},
.cs_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(spi0), cs_gpios),
};
/* MCP41100 设备数据 */
static struct mcp41100_data mcp41100_data;
/* MCP41100 设备定义 */
DEVICE_DEFINE(mcp41100, "MCP41100", mcp41100_init, NULL,
&mcp41100_data, &mcp41100_config, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
int main(void)
{
const struct device *dev;
LOG_INF("MCP41100 Digital Pot Control Demo");
dev = device_get_binding("MCP41100");
if (dev == NULL) {
LOG_ERR("Failed to get MCP41100 device");
return -ENODEV;
}
/* 校准参数: 实测90.5K → 目标50K */
uint32_t total_ohm = 90500;
uint32_t target_ohm = 50000;
uint8_t pos = mcp41100_calc_position(total_ohm, target_ohm);
LOG_INF("Target: %d ohm, Wiper pos: %d (0x%02x)", target_ohm, pos, pos);
int ret = mcp41100_set_resistance(dev, total_ohm, target_ohm);
if (ret < 0) {
LOG_ERR("Failed to set resistance: %d", ret);
return ret;
}
LOG_INF("Resistance set to ~%d ohm", target_ohm);
while (1) {
k_sleep(K_SECONDS(10));
}
return 0;
}【编译与下载】
执行west build -b fpb_ra6e2即可以编译生成工程。
由于开发板板载了jlink-ob因此可以直接使用west下载,执行:west flash --runner jlink即可以实现工程下载到开发板。
【验证】
下载好工程后,连接好开发板,可以测到正确的电阻值为50K
我要赚赏金
