当前位置:首页 > Software > C > 正文内容

使用FT232H实现MCP4725 DAC的I2C输出电压控制

chanra1n17小时前C18

1、下载库libMPSSE.zip

2、安装VS,安装C++编译库

3、修改

image.png

为:

/*!
 * \file sample-dynamic.c
 *
 * \author FTDI
 * \date 20110512
 *
 * Copyright © 2000-2014 Future Technology Devices International Limited
 *
 * THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Project: libMPSSE
 * Module: I2C Sample Application - Interfacing MCP4725 DAC
 */

/******************************************************************************/
/*                           Include files                                         */
/******************************************************************************/
/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#else // _WIN32
#include<dlfcn.h>
#include <unistd.h> // For Sleep() on Linux/macOS
#define Sleep(ms) usleep(ms * 1000)
#endif // _WIN32

/* Include D2XX header*/
#include "ftd2xx.h"

/* Include libMPSSE header */
#include "libMPSSE_i2c.h"


/******************************************************************************/
/*                              Macro and type defines                             */
/******************************************************************************/
/* Helper macros */
#ifdef _WIN32
    #define GET_FUN_POINTER GetProcAddress
    #define CHECK_ERROR(exp) {if(exp==NULL){printf("%s:%d:%s(): NULL expression\
        encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};
#else // _WIN32
    #define GET_FUN_POINTER dlsym
    #define CHECK_ERROR(exp) {if(dlerror() != NULL){printf("line %d: ERROR \
        dlsym\n",__LINE__);}}
#endif // _WIN32

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
    != FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define APP_CHECK_STATUS_NOEXIT(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
    != FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
    encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Application specific macro definations */
#define I2C_DEVICE_BUFFER_SIZE          256
#define CHANNEL_TO_OPEN                 0
#define I2C_DEVICE_ADDRESS_MCP4725      0x60
#define VDD_VOLTAGE                     3.3f // !!重要!! 请根据您的实际电路修改此值

/* Application configuration/debugging */
#define TEST_EEPROM                     0 // 禁用原始的EEPROM测试
#define FAST_TRANSFER                   0

/* Declaration of function pointers */
typedef FT_STATUS(*pfunc_I2C_GetNumChannels)(uint32 *numChannels);
typedef FT_STATUS(*pfunc_I2C_GetChannelInfo)(uint32 index, FT_DEVICE_LIST_INFO_NODE *chanInfo);
typedef FT_STATUS(*pfunc_I2C_OpenChannel)(uint32 index, FT_HANDLE *handle);
typedef FT_STATUS(*pfunc_I2C_CloseChannel)(FT_HANDLE handle);
typedef FT_STATUS(*pfunc_I2C_InitChannel)(FT_HANDLE handle, ChannelConfig *config);
typedef FT_STATUS(*pfunc_I2C_DeviceRead)(FT_HANDLE handle, uint32 deviceAddress, uint32 sizeToTransfer, uint8 *buffer, uint32 *sizeTransfered, uint32 options);
typedef FT_STATUS(*pfunc_I2C_DeviceWrite)(FT_HANDLE handle, uint32 deviceAddress, uint32 sizeToTransfer, uint8 *buffer, uint32 *sizeTransfered, uint32 options);

static pfunc_I2C_GetNumChannels p_I2C_GetNumChannels = NULL;
static pfunc_I2C_GetChannelInfo p_I2C_GetChannelInfo = NULL;
static pfunc_I2C_OpenChannel p_I2C_OpenChannel = NULL;
static pfunc_I2C_CloseChannel p_I2C_CloseChannel = NULL;
static pfunc_I2C_InitChannel p_I2C_InitChannel = NULL;
static pfunc_I2C_DeviceRead p_I2C_DeviceRead = NULL;
static pfunc_I2C_DeviceWrite p_I2C_DeviceWrite = NULL;

/* 新增函数原型声明 */
void TestDeviceMCP4725();
static FT_STATUS read_mcp4725_status();


/******************************************************************************/
/*                              Global variables                                    */
/******************************************************************************/
static FT_HANDLE ftHandle;
static uint8 buffer[I2C_DEVICE_BUFFER_SIZE] = {0};


/******************************************************************************/
/*                      Public function definitions                                */
/******************************************************************************/
static uint8 initialize_library()
{
#ifdef _WIN32
    HMODULE h_libMPSSE = LoadLibraryA("libMPSSE.dll");
    if (!h_libMPSSE)
    {
        printf("Failed loading libMPSSE.dll. Please check if the file exists in the working directory\n");
        return 0;
    }
#else 
    void *h_libMPSSE = dlopen("libMPSSE.so", RTLD_LAZY);
    if(!h_libMPSSE)
    {
        printf("Failed loading libMPSSE.so. Please check if the file exists in the shared library folder(/usr/lib or /usr/lib64)\n");
        exit(1);
    }
#endif

    p_I2C_GetNumChannels = (pfunc_I2C_GetNumChannels)GET_FUN_POINTER(h_libMPSSE, "I2C_GetNumChannels");
    p_I2C_GetChannelInfo = (pfunc_I2C_GetChannelInfo)GET_FUN_POINTER(h_libMPSSE, "I2C_GetChannelInfo");
    p_I2C_OpenChannel = (pfunc_I2C_OpenChannel)GET_FUN_POINTER(h_libMPSSE, "I2C_OpenChannel");
    p_I2C_CloseChannel = (pfunc_I2C_CloseChannel)GET_FUN_POINTER(h_libMPSSE, "I2C_CloseChannel");
    p_I2C_InitChannel = (pfunc_I2C_InitChannel)GET_FUN_POINTER(h_libMPSSE, "I2C_InitChannel");
    p_I2C_DeviceRead = (pfunc_I2C_DeviceRead)GET_FUN_POINTER(h_libMPSSE, "I2C_DeviceRead");
    p_I2C_DeviceWrite = (pfunc_I2C_DeviceWrite)GET_FUN_POINTER(h_libMPSSE, "I2C_DeviceWrite");

    CHECK_ERROR(p_I2C_GetNumChannels);
    CHECK_ERROR(p_I2C_GetChannelInfo);
    CHECK_ERROR(p_I2C_OpenChannel);
    CHECK_ERROR(p_I2C_CloseChannel);
    CHECK_ERROR(p_I2C_InitChannel);
    CHECK_ERROR(p_I2C_DeviceRead);
    CHECK_ERROR(p_I2C_DeviceWrite);

    return 1;
}

static void cleanup_library() { }


/******************************************************************************/
/*                      新增的MCP4725相关函数                                 */
/******************************************************************************/

/*!
 * \brief 从MCP4725读取当前状态和数据
 * \return 返回 FT_STATUS 状态码
 */
static FT_STATUS read_mcp4725_status()
{
    FT_STATUS status;
    uint8 readBuffer[5]; // MCP4725读取操作返回5个字节
    uint32 bytesRead = 0;
   
    printf("\n--- Reading MCP4725 Status ---\n");
   
    // 执行I2C读操作。对于MCP4725,读取时不需要先写入寄存器地址。
    // Master必须在读取最后一个字节后发送NACK信号。
    status = p_I2C_DeviceRead(ftHandle, I2C_DEVICE_ADDRESS_MCP4725, 5, readBuffer, &bytesRead,
        I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT | I2C_TRANSFER_OPTIONS_NACK_LAST_BYTE);
   
    if (status != FT_OK) {
        printf("!! I2C read failed with status: %d\n", status);
        return status;
    }
   
    if (bytesRead != 5) {
        printf("!! I2C read failed: expected 5 bytes but received %d\n", bytesRead);
        return FT_IO_ERROR;
    }

    // 解析并打印读取到的数据
    // 字节 1: 状态字节
    uint8 isReady = (readBuffer[0] & 0x80) >> 7;
    uint8 powerDownMode = (readBuffer[0] & 0x06) >> 1;
   
    // 字节 2 & 3: 当前DAC寄存器值
    uint16 dacValue = ((readBuffer[1] & 0x0F) << 8) | readBuffer[2];
    float currentVoltage = (float)dacValue / 4095.0 * VDD_VOLTAGE;

    // 字节 4 & 5: EEPROM中存储的值
    uint8 eepromPowerDown = (readBuffer[3] & 0x60) >> 5;
    uint16 eepromValue = ((readBuffer[3] & 0x0F) << 8) | readBuffer[4];
    float eepromVoltage = (float)eepromValue / 4095.0 * VDD_VOLTAGE;

    printf("  EEPROM Write Status : %s\n", isReady ? "Ready (Completed)" : "Busy");
   
    printf("  Current DAC Settings:\n");
    printf("    - Power Mode        : ");
    switch(powerDownMode) {
        case 0: printf("Normal\n"); break;
        case 1: printf("Power-Down (1kOhm to GND)\n"); break;
        case 2: printf("Power-Down (100kOhm to GND)\n"); break;
        case 3: printf("Power-Down (500kOhm to GND)\n"); break;
    }
    printf("    - Register Value    : %u (0x%03X)\n", dacValue, dacValue);
    printf("    - Output Voltage    : %.3f V\n", currentVoltage);
   
    printf("  Stored EEPROM Settings:\n");
    printf("    - Power Mode        : ");
    switch(eepromPowerDown) {
        case 0: printf("Normal\n"); break;
        case 1: printf("Power-Down (1kOhm to GND)\n"); break;
        case 2: printf("Power-Down (100kOhm to GND)\n"); break;
        case 3: printf("Power-Down (500kOhm to GND)\n"); break;
    }
    printf("    - Stored Value      : %u (0x%03X)\n", eepromValue, eepromValue);
    printf("    - Power-up Voltage  : %.3f V\n", eepromVoltage);
    printf("--------------------------------\n");

    return FT_OK;
}

/*!
 * \brief 设置MCP4725的输出电压
 * \param[in] voltage 想要设置的目标电压值 (浮点数)
 * \return 返回 FT_STATUS 状态码
 */
static FT_STATUS set_mcp4725_voltage(float voltage)
{
    FT_STATUS status;
    uint32 bytesTransfered = 0;
    uint16 digitalValue;
    uint8 dataBuffer[2];

    if (voltage < 0.0) voltage = 0.0;
    if (voltage > VDD_VOLTAGE) voltage = VDD_VOLTAGE;
    digitalValue = (uint16)((voltage / VDD_VOLTAGE) * 4095.0);

    // 准备I2C快速写入模式的数据包 (2字节)
    dataBuffer[0] = (digitalValue >> 8) & 0x0F;
    dataBuffer[1] = digitalValue & 0xFF;

    printf("-> Setting voltage to %.3fV (Digital: %u). Sending bytes [0x%02X, 0x%02X]...\n",
           voltage, digitalValue, dataBuffer[0], dataBuffer[1]);

    status = p_I2C_DeviceWrite(ftHandle, I2C_DEVICE_ADDRESS_MCP4725, 2, dataBuffer, &bytesTransfered,
        I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT);
   
    if (status != FT_OK) {
        printf("!! I2C write failed with status: %d\n", status);
    } else if (bytesTransfered != 2) {
        printf("!! I2C write failed: incorrect number of bytes transferred (%d)\n", bytesTransfered);
        status = FT_IO_ERROR;
    } else {
        printf("   OK\n");
    }
   
    return status;
}

/*!
 * \brief MCP4725 DAC 交互式测试函数
 */
void TestDeviceMCP4725()
{
    char inputBuffer[32];
    float targetVoltage;

    while(1)
    {
        printf("\nEnter a voltage (0.0 to %.1f) or 'q' to quit: ", VDD_VOLTAGE);
       
        // 使用fgets安全地读取用户输入
        if (fgets(inputBuffer, sizeof(inputBuffer), stdin) == NULL) {
            break; // 遇到文件结尾或错误
        }
       
        // 检查退出条件
        if (inputBuffer[0] == 'q' || inputBuffer[0] == 'Q') {
            printf("Exiting...\n");
            break;
        }
       
        // 尝试将输入字符串转换为浮点数
        if (sscanf(inputBuffer, "%f", &targetVoltage) != 1) {
            printf("Invalid input. Please enter a number or 'q'.\n");
            continue;
        }
       
        // 检查电压范围
        if (targetVoltage < 0.0 || targetVoltage > VDD_VOLTAGE) {
            printf("Voltage out of range. Please enter a value between 0.0 and %.1f.\n", VDD_VOLTAGE);
            continue;
        }
       
        // 设置电压
        set_mcp4725_voltage(targetVoltage);
    }
}

/*!
 * \brief Main function / Entry point of the sample application
 */
int main()
{
    FT_STATUS status = FT_OK;
    FT_DEVICE_LIST_INFO_NODE devList = {0};
    ChannelConfig channelConf;
    uint32 channels = 0;
    uint32 i = 0;

    if (!initialize_library())
    {
        printf("initialize_library failed!\n");
        return 0;
    }

    memset(&channelConf, 0, sizeof(channelConf));
    channelConf.ClockRate = I2C_CLOCK_FAST_MODE; // 400 kbps
    channelConf.LatencyTimer = 255;

    status = p_I2C_GetNumChannels(&channels);
    APP_CHECK_STATUS(status);
    printf("Number of available I2C channels = %d\n",(int)channels);
    if(channels>0)
    {
        for(i=0;i<channels;i++)
        {
            status = p_I2C_GetChannelInfo(i,&devList);
            APP_CHECK_STATUS(status);
            printf("Information on channel number %u:\n",(unsigned int)i);
            printf("        Flags=0x%x\n",devList.Flags);
            printf("        Type=0x%x\n",devList.Type);
            printf("        ID=0x%x\n",devList.ID);
            printf("        LocId=0x%x\n",devList.LocId);
            printf("        SerialNumber=%s\n",devList.SerialNumber);
            printf("        Description=%s\n",devList.Description);
            printf("        ftHandle=0x%p\n",devList.ftHandle);
        }

        status = p_I2C_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
        APP_CHECK_STATUS(status);
        printf("\nhandle=0x%p status=%d\n",ftHandle,(unsigned int)status);
       
        status = p_I2C_InitChannel(ftHandle,&channelConf);
        APP_CHECK_STATUS(status);
       
        // **新增功能**: 在开始交互前,先读取并显示芯片当前状态
        status = read_mcp4725_status();
        if (status != FT_OK) {
            printf("Could not communicate with MCP4725. Please check wiring and address.\n");
            p_I2C_CloseChannel(ftHandle);
            cleanup_library();
            #ifdef _WIN32
                system("pause");
            #endif
            return 1;
        }

        // 调用交互式测试函数
        TestDeviceMCP4725();

        status = p_I2C_CloseChannel(ftHandle);
    }

    cleanup_library();

#ifdef _WIN32
    system("pause");
#endif
    return 0;
}

4、打开工程

image.png

5、编译运行

image.png

运行截图:

image.png

拔掉I2C设备:

image.png

测试通过。

附上可直接运行的成品:Debug.zip


扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:https://world.myfpga.cn/index.php/post/465.html

分享给朋友:
返回列表

上一篇:C中的结构体

没有最新的文章了...

“使用FT232H实现MCP4725 DAC的I2C输出电压控制” 的相关文章