以下是一份基于STM32F103标准库的MCP41010驱动代码。

MCP41010是一款通过SPI接口控制的8位(256级)数字电位器,它接收16位(两个字节)数据:第一个字节是命令,第二个字节是数据。

硬件连接部分:

MCP41010 引脚连接至 STM32F103ZET6说明
CS (Pin 1)PA15片选引脚,低电平有效
SCK (Pin 2)PB3SPI 时钟线
SI (Pin 3)PB5SPI 数据输入线
VDD (Pin 8)3.3V电源正极
VSS (Pin 4)GND电源地

驱动代码部分(封装了MCP41010的初始化与电阻值设置功能):

1.头文件mcp41010.h

#ifndef __MCP41010_H
#define __MCP41010_H

#include "stm32f10x.h"

// 根据您的接线定义引脚
#define MCP41010_CS_PORT      GPIOA
#define MCP41010_CS_PIN       GPIO_Pin_15
#define MCP41010_SCK_PORT     GPIOB
#define MCP41010_SCK_PIN      GPIO_Pin_3
#define MCP41010_MOSI_PORT    GPIOB
#define MCP41010_MOSI_PIN     GPIO_Pin_5

// 操作宏定义
#define MCP41010_CS_LOW()     GPIO_ResetBits(MCP41010_CS_PORT, MCP41010_CS_PIN)
#define MCP41010_CS_HIGH()    GPIO_SetBits(MCP41010_CS_PORT, MCP41010_CS_PIN)

// 函数声明
void MCP41010_Init(void);
void MCP41010_SetResistance(uint8_t value);

#endif

2.源文件mcp41010.c

#include "mcp41010.h"

// SPI1 初始化配置
static void SPI1_Init(void) {
    SPI_InitTypeDef SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    // 1. 使能相关时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_SPI1, ENABLE);

    // 2. 配置 CS 引脚 (PA15) 为推挽输出
    GPIO_InitStructure.GPIO_Pin = MCP41010_CS_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MCP41010_CS_PORT, &GPIO_InitStructure);
    MCP41010_CS_HIGH(); // 默认不选中

    // 3. 配置 SCK (PB3) 和 MOSI (PB5) 为复用推挽输出
    GPIO_InitStructure.GPIO_Pin = MCP41010_SCK_PIN | MCP41010_MOSI_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(MCP41010_SCK_PORT, &GPIO_InitStructure);

    // 4. SPI1 模式配置: 模式0, 主机模式, 8位数据, 高位先行
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; // 仅发送模式 (MCP41010只需接收)
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;   // 时钟空闲时为低电平 (CPOL=0)
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 第一个时钟沿采样数据 (CPHA=0)
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;    // 软件管理片选信号
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // 分频后约1.125MHz
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 高位先行
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    
    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_Cmd(SPI1, ENABLE);
}

// 发送一个字节数据
static void SPI1_SendByte(uint8_t byte) {
    // 等待发送缓冲区为空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, byte);
    // 等待发送完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    SPI_I2S_ReceiveData(SPI1);
}

// MCP41010 初始化
void MCP41010_Init(void) {
    SPI1_Init();
}

// 设置电位器阻值
// value: 0 ~ 255, 对应电阻值从最低(约100Ω)到最高(10kΩ)
void MCP41010_SetResistance(uint8_t value) {
    // 1. 选中设备
    MCP41010_CS_LOW();
    
    // 2. 发送命令字节:写数据指令
    //    命令字节 = (C1, C0 = 0,1) | (P1, P0 = X,1) | 其他位为 0
    //    = (0x01) << 4 | (0x01) = 0x10 + 0x01? 等等。
    //    根据数据手册, 命令字节格式: [X, X, C1, C0, X, X, P1, P0]
    //    C1=0, C0=1 (写命令) -> 0b0001xxxx = 0x10
    //    P1=0(无关), P0=1(选择电位器0) -> 最后两位为 0b01
    //    所以命令字节 = 0b00010001 = 0x11
    uint8_t cmd_byte = 0x11;
    SPI1_SendByte(cmd_byte);
    
    // 3. 发送数据字节
    SPI1_SendByte(value);
    
    // 4. 取消选中
    MCP41010_CS_HIGH();
}

3.main.c文件中调用方式

#include "mcp41010.h"

int main(void) {
    // 初始化系统时钟等...
    MCP41010_Init();        // 初始化MCP41010
    MCP41010_SetResistance(128);  // 设置到中点阻值
    // MCP41010_SetResistance(255);  // 最大阻值
    // MCP41010_SetResistance(0);    // 最小阻值
    
    while(1) {
        // 您的其他程序代码...
    }
}

4.代码要点解析

SPI模式配置:MCP41010支持SPI模式0(空闲时时钟为低,第一个跳变沿采样),在SPI1_Init()完成了相应配置。

数据格式:通信时高位(MSB)先发送,代码中配置SPI_FirstBit_MSB与之匹配。

发送流程:片选拉低后,连续发送命令字节和数据字节,注意两者必须在16个连续时钟周期内完成。发送完两个字节后将CS拉高以执行命令。

命令字节构造:如注释所示,代码发送写数据指令0x11,其中:

                        高4位中的0x1代表C1=0、C0=1,即“写数据”命令。

                        低4位中的0x1代表P1=0、P0=1,选择控制唯一的电位器通道0。

软件NSS:选用软件模式SPI_NSS_Soft,让您自由控制PA15作为片选引脚。

关于PA15和PB3引脚的特别提醒:

PA15(JTDI)和PB3(JTDO)在STM32F103中默认是调试端口,直接用作普通GPIO时需要先禁用JTAG功能。建议在系统时钟初始化代码后,调用 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 来禁用JTAG,使能SWD。请根据调试需求,在“”时参考以下代码:

// 禁用 JTAG 功能,仅保留 SWD (需 SWDIO (PA13) 和 SWCLK (PA14) 接调试器)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

以上代码可以直接集成到程序项目中测试使用。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐