Peixu 发表于 2024-10-25 17:23

基于APM32F003的TPL0102驱动程序

本帖最后由 Peixu 于 2024-10-25 17:26 编辑

TPL0102 是一种双通道数字电位器,常用于各种电子设备的音量控制、亮度调节等应用。它通过 I2C 总线与主控进行通信,能够实现精确的电位调节。本文将详细介绍如何使用 APM32F003 微控制器驱动 TPL0102。
TPL0102内部简化原理图如下所示:
TPL0102内有A、B两个电位器,通过IIC协议可以分别控制A、B两个电位器输出0-100K的电阻值,当然也可以将A、B两个电位器串联起来实现0-200K的电阻值输出。

下来就是驱动代码实现:
1、首先是I2C 初始化这里使用的是模拟IIC 如下所示

#include "i2c1.h"

// 初始化I2C的GPIO引脚
void I2C_Init(void) {
       
    GPIO_Config_T gpioConfig;

    gpioConfig.mode = GPIO_MODE_OUT_OD;
    gpioConfig.speed = GPIO_SPEED_10MHz;
    gpioConfig.intEn = GPIO_EINT_DISABLE;
    gpioConfig.pin = I2C_SCL_PIN | I2C_SDA_PIN;
    GPIO_Config(I2C_GPIO_PORT, &gpioConfig);
                I2C_Stop();
}

/**
* @brief I2C 开始,SCL为高电平的时候SDA产生一个下降沿信号
*/
void I2C_Start(void) {
       
        /*    _____
       *SDA      \_____________
       *    __________
       *SCL         \________
       */
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    timer_delay_ms(1);
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);       
}

// 生成I2C停止条件
void I2C_Stop(void) {
    /*               _______
   *SDA __________/
   *          ____________
   *SCL _____/
   */       
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    timer_delay_ms(1);
}

// 发送I2C应答信号
void I2C_Ack(void) {
    /*         ____
   *SCL ______/    \______
   *    ____         _____
   *SDA   \_______/
   */       
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    timer_delay_ms(1);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
}

// 发送I2C非应答信号
void I2C_NAck(void) {
    /*         ____
   *SCL ______/    \______
   *    __________________
   *SDA
   */       
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    timer_delay_ms(1);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
}

// 发送一个字节
void I2C_SendByte(uint8_t byte) {
    for (uint8_t i = 0; i < 8; i++) {
      if (byte & 0x80) {
            GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
      } else {
            GPIO_ClearBit(I2C_GPIO_PORT, I2C_SDA_PIN);
      }
      byte <<= 1;
      timer_delay_ms(1);
      GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
      timer_delay_ms(1);
      GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    }
    // 读取应答信号
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    timer_delay_ms(1);
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
    timer_delay_ms(1);
    GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
}

// 读取一个字节
uint8_t I2C_ReadByte(uint8_t ack) {
    uint8_t byte = 0;
    GPIO_SetBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    for (uint8_t i = 0; i < 8; i++) {
      byte <<= 1;
      GPIO_SetBit(I2C_GPIO_PORT, I2C_SCL_PIN);
      timer_delay_ms(1);
      if (GPIO_ReadInputBit(I2C_GPIO_PORT, I2C_SDA_PIN)) {
            byte |= 0x01;
      }
      GPIO_ClearBit(I2C_GPIO_PORT, I2C_SCL_PIN);
      timer_delay_ms(1);
    }
    if (ack) {
      I2C_Ack();
    } else {
      I2C_NAck();
    }
    return byte;
}
2、TPL0102的代码读写:
#include "tpl0102.h"

#define TPL0102_ADDR 0x50// TPL0102 I2C地址

//TPL0102 Register Addresses
#define TPL0102_REG_RA    0x00
#define TPL0102_REG_RB    0x01

void Test(void)
{       
        I2C_Init();
       
        // 设置电位器值
        TPL0102_SetWiper(TPL0102_REG_RA, 0X66);
        TPL0102_SetWiper(TPL0102_REG_RB, 0X66);

}


// 写入TPL0102寄存器
void TPL0102_WriteReg(uint8_t reg, uint8_t value) {
    I2C_Start();
    I2C_SendByte(TPL0102_ADDR << 1);// 发送设备地址和写命令
    I2C_SendByte(reg);                // 发送寄存器地址
    I2C_SendByte(value);            // 发送数据
    I2C_Stop();
}


// 读取TPL0102寄存器
uint8_t TPL0102_ReadReg(uint8_t reg) {
    uint8_t value;
    I2C_Start();
    I2C_SendByte(TPL0102_ADDR << 1);// 发送设备地址和写命令
    I2C_SendByte(reg);                // 发送寄存器地址
    I2C_Start();
    I2C_SendByte((TPL0102_ADDR << 1) | 1);// 发送设备地址和读命令
    value = I2C_ReadByte(0);         // 读取数据
    I2C_Stop();
    return value;
}

// 设置TPL0102的电位器值
void TPL0102_SetWiper(uint8_t wiper, uint8_t value) {
    if (wiper == 0) {
      TPL0102_WriteReg(TPL0102_REG_RA, value);// 设置电位器0
    } else if (wiper == 1) {
      TPL0102_WriteReg(TPL0102_REG_RB, value);// 设置电位器1
    }
}

// 读取TPL0102的电位器值
uint8_t TPL0102_GetWiper(uint8_t wiper) {
    if (wiper == 0) {
      return TPL0102_ReadReg(TPL0102_REG_RA);// 读取电位器0
    } else if (wiper == 1) {
      return TPL0102_ReadReg(TPL0102_REG_RB);// 读取电位器1
    }
    return 0;
}接下来按照TPL0102的手册就可以在main函数中进行测试了
int main(void)
{
                TMR4_Init();       
                I2C_Init();                       
    while(1)
    {                                               
                        // 将目标电阻值映射到TPL0102的步进值                       
                        TPL0102_SetWiper(TPL0102_REG_RA, 0Xff);
                        TPL0102_SetWiper(TPL0102_REG_RB, 0X00);
                }
}


······
······
······

我想看大海 发表于 2024-11-20 20:41

有没有用硬件IIC的案例
页: [1]
查看完整版本: 基于APM32F003的TPL0102驱动程序