如何使用 MCP4452 的命令和数据位将一行写入 I2C 设备

如何解决如何使用 MCP4452 的命令和数据位将一行写入 I2C 设备

我正在尝试修改最初为 AD5245 设计的一段代码,以便将其用于 MCP4452。两者都是 Raspberry PI 上的 I2C 设备。我正在尝试根据图像/

enter image description here

中的文档找出如何为设备制定写入代码

enter image description here

如何将所有这些合并到 AD5245 的示例代码中?

static void writeAD5245(uint8_t i2cMCPAddress,uint8_t mcpdevice,uint8_t value) {
  beginMCP(i2cMCPAddress);
  uint8_t lsb = (uint8_t)(value >> 8);
  uint8_t msb = (uint8_t)value;
  uint16_t payload = (msb << 8) | lsb;
  i2c_smbus_write_word_data(i2cMCPHandle,MCP_WRITE,payload);
  endMCP();
}

完整的数据表:MCP4452 Datasheet

编辑以包含完整的 .h 和 .cpp 文件。

mcp4452.h

#include <sys/ioctl.h>
#include <unistd.h>
extern "C" {
    #include <linux/i2c.h>
   #include <linux/i2c-dev.h>
   #include <i2c/smbus.h>
}

#define MCP_ADDRESS     (0x2C)

#define MCP_READ            (0x01)
#define MCP_WRITE           (0x00)

#define NV_WIPER_0      (0x02)//10
#define NV_WIPER_1      (0x03)//11
#define NV_WIPER_2      (0x08)//1000
#define NV_WIPER_3      (0x09)//1001

#define MCP_CHANNEL_0   (0x00)//0
#define MCP_CHANNEL_1   (0x01)//1
#define MCP_CHANNEL_2   (0x06)//6
#define MCP_CHANNEL_3   (0x07)//7

#define MCP_CMD_WRITE   (0x00)//WRITE NEXT BYTE (SET VALUE)
#define MCP_CMD_INC     (0x01)//INCREMENT BY 1
#define MCP_CMD_DEC     (0x02)//DECREMENT BY 1
#define MCP_CMD_READ        (0x03)//READ DATA

#define MCP_RESET           (0xFF)//RESET DEVICE

class MCP4452
{
    protected:
        uint8_t   m_i2cMCPAddress;
        uint8_t   m_MCPbitShift;
        uint8_t  m_MCPChannel;
        uint8_t  m_MCPCommand;
    public:
        MCP4452(uint8_t i2cMCPAddress = MCP_ADDRESS);
        uint8_t setWPOS(uint8_t channel,uint8_t wiper_position,int command,int delay);
    private:
};

mcp4452.cpp:

#include "mcp4452.h"
#include <iostream>
#include <bitset> //CAN BE REMOVED AFTER FUNCTIONING

int i2cMCPHandle;

static void beginMCP(uint8_t i2cMCPAddress) {
  i2cMCPHandle = open("/dev/i2c-1",O_RDWR);
  if(i2cMCPHandle < 0)
  {
    fprintf(stderr,"Error while opening the i2c-2 device! Error: %s\n",strerror(errno));
    exit(1);
  }
  if(ioctl(i2cMCPHandle,I2C_SLAVE,i2cMCPAddress) < 0)
  {
    fprintf(stderr,"Error while configuring the slave address %d. Error: %s\n",i2cMCPAddress,strerror(errno));
    exit(1);
  }
}
static void endMCP(void) {
    close(i2cMCPHandle);
}
static void resetMCP(uint8_t i2cMCPAddress,int delay) {
    beginMCP(i2cMCPAddress);
   i2c_smbus_write_word_data(i2cMCPHandle,MCP_RESET);
   endMCP();
}
static void setPOS(uint8_t i2cMCPAddress,uint8_t mcpchannel,uint8_t position) {
    beginMCP(i2cMCPAddress);
    uint16_t payload = (mcpchannel << 12) | (MCP_CMD_WRITE << 10) | (position);
    std::cout << "WRITE PAYLOAD: " << std::bitset<16>(payload) <<std::endl;
    i2c_smbus_write_word_data(i2cMCPHandle,payload);
    endMCP();
}
static void incPOS(uint8_t i2cMCPAddress,uint8_t mcpchannel) {
    beginMCP(i2cMCPAddress);
    uint16_t payload = (mcpchannel << 12) | (MCP_CMD_INC << 10);
    std::cout << "INC PAYLOAD: " << std::bitset<16>(payload) <<std::endl;
    i2c_smbus_write_word_data(i2cMCPHandle,payload);
    endMCP();
}
static void decPOS(uint8_t i2cMCPAddress,uint8_t mcpchannel) {
    beginMCP(i2cMCPAddress);
    uint16_t payload = (mcpchannel << 12) | (MCP_CMD_DEC << 10);
    std::cout << "DEC PAYLOAD: " << std::bitset<16>(payload) <<std::endl;
    i2c_smbus_write_word_data(i2cMCPHandle,payload);
    endMCP();
}
static uint16_t readMCP(uint8_t i2cMCPAddress) {
    beginMCP(i2cMCPAddress);
    uint16_t res = i2c_smbus_read_word_data(i2cMCPHandle,MCP_READ);
    std::cout << "BYTES READ: " << std::bitset<8>(res >> 8) << std::endl;
    endMCP();
    return res;
}
MCP4452::MCP4452(uint8_t i2cMCPAddress) 
{
    m_i2cMCPAddress = i2cMCPAddress;
    m_MCPChannel = MCP_CHANNEL_0;
    m_MCPbitShift = 8;
    m_MCPCommand = MCP_CMD_WRITE;
}
uint8_t MCP4452::setWPOS(uint8_t channel,int delay) {
  if (wiper_position > 255 || wiper_position < 0)
  {
    std::cout << "Wiper Pos Error" <<std::endl;
    return -2;
  }
  if (channel!=0 && channel!=1 && channel!=2 && channel!=3) {
    std::cout << "Channel Error" <<std::endl;
    return -2;
  }
  switch (channel) {
    case 0:
        m_MCPChannel=MCP_CHANNEL_0;
        //m_MCPChannel= NV_WIPER_0;
        break;
    case 1:
        m_MCPChannel=MCP_CHANNEL_1;
        //m_MCPChannel= NV_WIPER_1;
        break;
    case 2:
        m_MCPChannel=MCP_CHANNEL_2;
        //m_MCPChannel= NV_WIPER_2;
        break;
    case 3:
        m_MCPChannel=MCP_CHANNEL_3;
        //m_MCPChannel= NV_WIPER_3;
        break;
  }
  std::cout << "m_i2cMCPAddress: " << std::bitset<8>(m_i2cMCPAddress) << "  ON CHANNEL: " << std::bitset<4>(m_MCPChannel) << " USING m_MCPCommand: " << std::bitset<8>(m_MCPCommand) << std::endl;
  int w = -1;
  if (command==0) {//WRITE WIPER POSITION
      setPOS(m_i2cMCPAddress,m_MCPChannel,wiper_position);
      usleep(delay);
      // Read the conversion results
      w = readMCP(m_i2cMCPAddress) >> m_MCPbitShift;
      std::cout << "FIRST READ VALUE: " << w << std::endl;
      usleep(delay);
      if (int(w)!=int(wiper_position)) {
            w = -1;
            int counter=0;
            while (int(w) != int(wiper_position) && counter<10) {
                counter++;
                w = -1;
                setPOS(m_i2cMCPAddress,wiper_position);
                usleep(delay);
                w = readMCP(m_i2cMCPAddress) >> m_MCPbitShift;
                std::cout << "SECOND READ VALUE: " << w << std::endl;
            }
        }
    } else if (command==1) {//INCREMENT WIPER BY 1
        incPOS(m_i2cMCPAddress,m_MCPChannel);
        usleep(delay);
        w = readMCP(m_i2cMCPAddress) >> m_MCPbitShift;
       std::cout << "INC READ VALUE: " << w << std::endl;
    } else if (command==2) {//DECREMENT WIPER BY 1
        decPOS(m_i2cMCPAddress,m_MCPChannel);
        usleep(delay);
        w = readMCP(m_i2cMCPAddress) >> m_MCPbitShift;
       std::cout << "DEC READ VALUE: " << w << std::endl;
     } else if (command==3) {//RESET DEVICE
        resetMCP(m_i2cMCPAddress,delay);
        usleep(delay);
        w = readMCP(m_i2cMCPAddress) >> m_MCPbitShift;
        std::cout << "WIPER RESET " << w << std::endl;
    } else {
        std::cout << "INVALID COMMAND RECEIVED" << std::endl;
    }
  return w;
}

EDIT2:测试有效载荷数据和结果

0000 0000 0000 0000<<CHANNEL 1 SET TO 0--WORKS
0000 0000 1111 1111<<CHANNEL 1 SET TO 255--WORKS
0000 0100 0000 0000<<CHANNEL 1 INCREMENT--DOES NOT WORK
0000 1000 0000 0000<<CHANNEL 1 DECREMENT--DOES NOT WORK

0111 0000 0000 0000<<CHANNEL 4 SET TO 0--DOES NOT WORK
0111 0000 1111 1111<<CHANNEL 4 SET TO 255--DOES NOT WORK
0111 0100 0000 0000<<CHANNEL 4 INCREMENT--WORKS
0111 1000 0000 0000<<CHANNEL 4 DECREMENT--WORKS

解决方法

您的代码未正确实现 I²C 写入。

正如在 datasheet 和其他用于处理 I²C 总线的 tutorials 中所见,重要的是对于写入,您发送包含数据的第三字节(适用写入命令期间的单个字节写入)。

因此,

  • 字节 1 - 控制字节包括设备地址R/W位
  • 字节 2 - 命令字节包括数据地址命令
  • 字节 3 - 写入命令期间预期的数据字节

据我所知,<i2c/smbus.h> 驱动程序会为您整理格式,您只需要提供命令字节数据字节写作时。

因此,您的方法 setPOS 变为:

static void setPOS(uint8_t i2cMCPAddress,uint8_t mcpchannel,uint8_t position) {
    beginMCP(i2cMCPAddress);
    uint8_t command = mcpchannel << 4;          // Set the data address
    command = command | (MCP_CMD_WRITE) << 2;   // Set the command type
    
    std::cout << "WRITE COMMAND: " << std::bitset<8>(command) <<std::endl;
    std::cout << "WRITE DATA: " << std::bitset<8>(position) <<std::endl;

    // Changed from write *word* to write *byte* data
    i2c_smbus_write_byte_data(i2cMCPHandle,command,position);
    endMCP();
}

来自以下测试调用:

setPOS(MCP_ADDRESS,MCP_CHANNEL_0,0xFF);
setPOS(MCP_ADDRESS,MCP_CHANNEL_1,0xFF);

给出以下输出:

WRITE COMMAND: 00000000
WRITE DATA: 11111111
WRITE COMMAND: 00010000
WRITE DATA: 11111111

参见上面的示例 here

我很清楚这就是导致您问题的原因

奇怪的是,现在我可以将值 (0-255) 写入设备第一个雨刷器,并且我可以增加/减少 (+1/-1) 雨刷器 2-4,但我无法向其写入值雨刷器 2-4,我不能增加/减少雨刷器 1。

请注意,从数据表中我确实看到在 p53 上设置了 MSB:

‘1000 00d’b - 将下一个字节(第三个字节)写入易失性抽头 0 寄存器。

在上面的例子中我没有设置它。您应该验证是否应该设置/不设置。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-