一、MCP41010 数字电位器简介

MCP41010 是一款单通道、256 抽头的数字电位器,通过 SPI 接口进行通信。它可以在许多应用中用于调节电压、电流或作为可编程电阻,具有低功耗、非易失性存储等优点。该器件可以通过 SPI 命令来改变其内部电阻值,实现对电路的动态调整。

二、SPI 接口简介

SPI(Serial Peripheral Interface)是一种同步串行通信协议,通常由主设备(如 STM32)发起通信,通过四条线与从设备(如 MCP41010)连接:

  • SCK(Serial Clock):时钟信号,由主设备产生,用于同步数据传输。
  • MOSI(Master Out Slave In):主设备发送数据到从设备的数据线。
  • MISO(Master In Slave Out):从设备发送数据到主设备的数据线(MCP41010 不使用此线)。
  • CS(Chip Select):片选信号,用于选择特定的从设备。

三、STM32 与 MCP41010 的硬件连接

假设以下连接方式:

  • STM32 的 SPI 引脚连接:
    • SCK:PA5
    • MOSI:PA7
    • CS:PA4

四、STM32 配置步骤

  1. 使能 SPI 时钟和 GPIO 时钟

    • 使用 RCC_APB2PeriphClockCmd 函数使能 SPI 时钟和相应的 GPIO 时钟。
  2. 配置 GPIO 引脚

    • 配置 SCK、MOSI 和 CS 引脚为复用推挽输出模式,使用 GPIO_Init 函数。
  3. 配置 SPI 模块

    • 设置 SPI 的工作模式(如主模式、时钟极性、时钟相位等),使用 SPI_Init 函数。
  4. 使能 SPI 模块

    • 使用 SPI_Cmd 函数使能 SPI 模块。

五、代码示例(使用 STM32 Standard Peripheral Library)

#include "stm32f10x.h"


// 函数声明
void SPI_Configuration(void);
void GPIO_Configuration(void);
void MCP41010_SetWiperValue(uint8_t value);


// 主函数
int main(void)
{
    // 配置 GPIO 和 SPI
    GPIO_Configuration();
    SPI_Configuration();

    // 设置数字电位器的抽头位置
    MCP41010_SetWiperValue(128); // 设置到中间位置

    while (1)
    {
        // 可以添加其他代码,如动态调整抽头位置等
    }
}


// GPIO 配置函数
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能 SPI 和 GPIO 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 SCK 和 MOSI 引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置 CS 引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 初始时使 CS 为高电平
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}


// SPI 配置函数
void SPI_Configuration(void)
{
    SPI_InitTypeDef SPI_InitStructure;

    // 配置 SPI 基本参数
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; // 仅发送
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主模式
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位数据
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 时钟极性低
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 第一时钟沿采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 软件片选
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // 时钟分频
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 高位先发送
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    // 使能 SPI
    SPI_Cmd(SPI1, ENABLE);
}


// 设置 MCP41010 抽头值函数
void MCP41010_SetWiperValue(uint8_t value)
{
    // 使 CS 为低电平,选中芯片
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送命令字节,假设使用非易失性写命令
    SPI_I2S_SendData(SPI1, 0x11); // 0x11 是写命令,包含写使能和非易失性存储操作
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成

    // 发送抽头值
    SPI_I2S_SendData(SPI1, value);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成

    // 使 CS 为高电平,释放芯片
    GPIO_SetBits(GPIOA, GPIO_Pin_4);
}

代码解释

  • main 函数中,首先调用 GPIO_ConfigurationSPI_Configuration 函数进行硬件和 SPI 的初始化。
  • GPIO_Configuration 函数:
    • 使能 SPI1 和 GPIOA 的时钟。
    • 配置 PA5(SCK)和 PA7(MOSI)为复用推挽输出,因为它们用于 SPI 功能。
    • 配置 PA4(CS)为推挽输出,并初始化为高电平,表示未选中 MCP41010。
  • SPI_Configuration 函数:
    • 配置 SPI1 的各项参数,包括方向(仅发送)、模式(主模式)、数据大小(8 位)、时钟极性、时钟相位、软件片选等。
    • 使能 SPI1 模块。
  • MCP41010_SetWiperValue 函数:
    • 拉低 CS 引脚,选中 MCP41010。
    • 发送命令字节,这里使用 0x11 作为非易失性写命令,包含写使能和存储操作。
    • 等待发送完成标志,确保命令发送成功。
    • 发送抽头值(0 到 255),表示要设置的电位器抽头位置。
    • 拉高 CS 引脚,完成一次操作。

六、高级功能和扩展

  1. 读取当前抽头值
    • MCP41010 也支持读取当前抽头值,需要发送相应的读命令,并接收返回的数据。
    • 可以修改 MCP41010_SetWiperValue 函数,添加读取功能。

七、代码示例(添加读取功能)

// 修改 MCP41010_SetWiperValue 函数,添加读取功能
uint8_t MCP41010_SetWiperValue(uint8_t value)
{
    uint8_t readValue = 0;

    // 使 CS 为低电平,选中芯片
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送写命令
    SPI_I2S_SendData(SPI1, 0x11); // 0x11 是写命令,包含写使能和非易失性存储操作
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成

    // 发送抽头值
    SPI_I2S_SendData(SPI1, value);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成

    // 使 CS 为高电平,释放芯片
    GPIO_SetBits(GPIOA, GPIO_Pin_4);


    // 使 CS 为低电平,选中芯片
    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    // 发送读命令
    SPI_I2S_SendData(SPI1, 0x0C); // 0x0C 是读命令
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送完成

    // 读取抽头值
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); // 等待接收数据
    readValue = SPI_I2S_ReceiveData(SPI1);

    // 使 CS 为高电平,释放芯片
    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    return readValue;
}

代码解释

  • 在修改后的 MCP41010_SetWiperValue 函数中,添加了读取功能:
    • 发送读命令(0x0C)。
    • 等待接收标志,使用 SPI_I2S_ReceiveData 函数接收返回的数据。

八、总结

通过上述 STM32 与 MCP41010 的 SPI 接口例程,可以实现对数字电位器的基本控制。该例程涵盖了 GPIO 和 SPI 的配置,以及 MCP41010 的抽头值设置和读取功能。在实际应用中,可以根据具体需求对代码进行优化和扩展,例如添加错误处理、动态调整抽头值的算法等。同时,如果使用不同的 STM32 系列或不同的开发环境(如使用 HAL 库或 LL 库),部分函数的调用和参数设置会有所不同,但基本原理相同。

✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐