【RTT-Studio】详细使用教程十六:DAC7311外部DAC使用

一、简介

  8 位 DAC5311、10 位 DAC6311 和 12 位 DAC7311 (DACx311) 是低功耗、单通道、电压输出数模转换器 (DAC)。DACx311 在正常工作状态下具有低功耗(5V 时为 0.55mW,断电模式下可降至 2.5μW),使其成为便携式电池供电应用的理想选择。

器件信息:DAC7311系列芯片手册

器件型号分辨率
DAC731112位
DAC631110位
DAC53118位

驱动电路:
在这里插入图片描述


二、驱动程序

  本文主要使用模拟IIC来进行通信,所以其他的驱动程序可以不用打开,只需要GPIO引脚的驱动程序,软件生成的工程是默认打开引脚驱动,只需要编写模拟IIC的时序即可。

1.DAC7311选择
  DAC的输出结果根据以下公式进行计算,其中参数含义如下:

  • n:每位的分辨率:8(DAC5311)、10(DAC6311)或12(DAC7311)
  • D:加载到DAC寄存器的二进制代码的十进制等值值。D的范围为8位DAC5311为0到255,10位DAC6311为0到1023,12位DAC7311为0到4095。
  • AVdd:是带边芯片的供电电压。

在这里插入图片描述

2.DAC7311时序图
  通过时钟、SYN和DIN的时序来编写发送数据的函数即可。
在这里插入图片描述
3.模式选择
  DACx311包含四种独立的操作模式。这些模式可以通过在控制寄存器中设置两个位(PD1和PD0)来进行编程。表8-1显示了位的状态如何对应于设备的操作模式,通常我们设置为空模式
在这里插入图片描述
4.数据寄存器
  DB15和DB14两位代表模式设置,为00;DB0-DB11代表发送的数据;DB0和DB1则不使用,设置为00。
在这里插入图片描述


三、DAC设置注册

  将DAC芯片注册为一个DAC设备,注册设备的函数如下,并且在函数中需要编写对应的功能,在调用的使用进行设备的初始化,然后调用写函数来发送数据,进行DAC输出电压设置。

/*=====================================================##### 设备注册 #####==================================================*/
/**
 * @brief DAC设备初始化
 * @param dev:设备
 */
static rt_err_t DAC7311_Init(rt_device_t dev)
{
    dac_device_t *user = (dac_device_t *)dev->user_data;

    user->dev_name = DAC7311_DEV_NAME;
    user->scl      = DAC7311_SCL_PIN;
    user->syn      = DAC7311_SYN_PIN;
    user->sda      = DAC7311_SDA_PIN;
    user->delay_us = 10;

    rt_pin_mode(user->scl, PIN_MODE_OUTPUT);
    rt_pin_mode(user->syn, PIN_MODE_OUTPUT);
    rt_pin_mode(user->sda, PIN_MODE_OUTPUT);

    rt_pin_write(user->syn, PIN_HIGH);
    rt_pin_write(user->scl, PIN_HIGH);
    rt_pin_write(user->sda, PIN_LOW);

    return RT_EOK;
}

/**
 * @brief 设备关闭
 * @param dev:设备
 * @param oflag:打开方式
 */
static rt_err_t DAC7311_Open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

/**
 * @brief 设备关闭
 * @param dev:设备
 */
static rt_err_t DAC7311_Close(rt_device_t dev)
{
    return RT_EOK;
}

/**
 * @brief 设备读取
 * @param dev:设备
 * @param pos:读取的位置
 * @param buffer:数据缓冲区
 * @param size:缓冲区的大小
 */
static rt_size_t DAC7311_Read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    return RT_EOK;
}

/**
 * @brief 设备写入
 * @param dev:设备
 * @param pos:写入的位置
 * @param buffer:写入的数据缓冲区
 * @param size:缓冲区大小
 */
static rt_size_t DAC7311_Write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    uint16_t *data = (uint16_t *)buffer;
    rt_size_t ret = DAC7311_Write_Data((dac_device_t *)dev->user_data, *data);
    return ret;
}

/**
 * @brief 设备控制
 * @param dev:设备
 * @param cmd:指令
 * @param args:命令参数
 */
static rt_err_t DAC7311_Control(rt_device_t dev, int cmd, void *args)
{
    dac_device_t *cfg = (dac_device_t *)dev->user_data;
    int ret = -RT_ERROR;

    switch(cmd)
    {
        case RT_DEVICE_CTRL_LOCK:
        {
            lock(cfg);
            ret = RT_EOK;
            break;
        }

        case RT_DEVICE_CTRL_UNLOCK:
        {
            unlock(cfg);
            ret = RT_EOK;
            break;
        }

        default:
        {
            ret = -RT_ERROR;
            break;
        }
    }

    return ret;
}

/**
 * @brief DAC设备注册
 * @return 返回注册结果
 */
static int DAC7311_Device_Register(void)
{
    rt_device_t dac_dev = &(dac_device_config.base_device);

    // 初始化互斥量
    rt_err_t ret = rt_mutex_init(&dac_device_config.dac_lock, DAC7311_DEV_NAME, RT_IPC_FLAG_PRIO);
    RT_ASSERT(ret == RT_EOK);

    // 设置设备类型和设备标志
    dac_dev->type        = RT_Device_Class_SPIDevice; // 设备类型--SPI设备
    dac_dev->rx_indicate = RT_NULL;
    dac_dev->tx_complete = RT_NULL;

    // 设置设备操作接口
    dac_dev->init        = DAC7311_Init;              // 设备初始化
    dac_dev->open        = DAC7311_Open;              // 设备打开
    dac_dev->close       = DAC7311_Close;             // 设备关闭
    dac_dev->read        = DAC7311_Read;              // 设备读取
    dac_dev->write       = DAC7311_Write;             // 设备写入
    dac_dev->control     = DAC7311_Control;           // 设备控制
    dac_dev->user_data   = &dac_device_config;        // 用户数据

    // 注册设备
    ret = rt_device_register(dac_dev, DAC7311_DEV_NAME, RT_DEVICE_FLAG_RDWR);
    if (ret != RT_EOK)
    {
        LOG_E("Failed to register DAC7311 device");
        return -RT_ERROR;
    }

    return RT_EOK;
}
INIT_DEVICE_EXPORT(DAC7311_Device_Register);
/*=====================================================#######  END  #######=================================================*/

四、完整代码

1.dac7311.h

#ifndef APPLICATIONS_DAC7311_H_
#define APPLICATIONS_DAC7311_H_

#include <drv_common.h>
#include <stdlib.h>
#include <rtdef.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/**====================================================###### 宏定义 ######==================================================*/
#define DAC7311_DEV_NAME        "dac7311"

#define DAC7311_MODE            0x3FFF                  // 选择模式为Normal

#define DAC7311_SCL_PIN         GET_PIN(F, 14)          // SCL引脚
#define DAC7311_SYN_PIN         GET_PIN(F, 2)           // SYN引脚
#define DAC7311_SDA_PIN         GET_PIN(F, 15)          // SDA引脚

#define RT_DEVICE_CTRL_LOCK     0x13                    // 上锁
#define RT_DEVICE_CTRL_UNLOCK   0x14                    // 解锁

//#define lock(x)         rt_mutex_take(x, RT_WAITING_FOREVER)    // 上锁
//#define unlock(x)       rt_mutex_release(x)                     // 销毁
#define lock(x)         rt_mutex_take(&x->dac_lock, RT_WAITING_FOREVER)
#define unlock(x)       rt_mutex_release(&x->dac_lock)

typedef struct
{
    struct rt_device base_device;   // 继承 rt_device 结构体
    struct rt_mutex  dac_lock;      // 设备互斥量

    rt_uint8_t scl;                 // 时钟线
    rt_uint8_t sda;                 // 数据线
    rt_uint8_t syn;                 // 片选
    rt_uint32_t delay_us;           // 延时
    const char *dev_name;           // 设备名称

} dac_device_t;

dac_device_t dac_device_config;     // 设备信息
rt_device_t  dac_device;            // DAC设备

extern void DAC_Device_Init(void);
extern void write_dac_data(uint16_t data);

/**====================================================#######  END  #######=================================================*/

#endif /* APPLICATIONS_DAC7311_H_ */

2.dac7311.c

#include "dac7311.h"

/*=====================================================### 静态函数调用 ###==================================================*/
/**
 * @brief DAC延时
 * @param us:延时时间
 */
static void DAC7311_Delay(uint8_t us)
{
    for (; us != 0; us--);
}

/**
 * @brief 设置SYN状态
 * @param data:用户数据
 * @param state:状态
 */
static void set_syn(void *data, rt_int32_t state)
{
    dac_device_t *cfg = (dac_device_t *)data;
    if (state)
    {
        rt_pin_write(cfg->syn, PIN_HIGH);
    }
    else
    {
        rt_pin_write(cfg->syn, PIN_LOW);
    }
}

/**
 * @brief 设置SDA状态
 * @param data:用户数据
 * @param state:状态
 */
static void set_sda(void *data, rt_int32_t state)
{
    dac_device_t *cfg = (dac_device_t *)data;
    if (state)
    {
        rt_pin_write(cfg->sda, PIN_HIGH);
    }
    else
    {
        rt_pin_write(cfg->sda, PIN_LOW);
    }
}

/**
 * @brief 设置SCL状态
 * @param data:用户数据
 * @param state:状态
 */
static void set_scl(void *data, rt_int32_t state)
{
    dac_device_t *cfg = (dac_device_t *)data;
    if (state)
    {
        rt_pin_write(cfg->scl, PIN_HIGH);
    }
    else
    {
        rt_pin_write(cfg->scl, PIN_LOW);
    }
}

/**
 * @brief DAC写数据
 * @param data:需要写入的数据
 */
static rt_size_t DAC7311_Write_Data(void *conf, uint16_t data)
{
    dac_device_t *cfg = (dac_device_t *)conf;

    uint16_t temp = data << 2;  // 7311需要移动两位
    temp &= DAC7311_MODE;

    set_syn(conf, 1);
    set_scl(conf, 1);
    DAC7311_Delay(cfg->delay_us);
    set_syn(conf, 0);
    DAC7311_Delay(cfg->delay_us);

    for (int i = 0; i < 16; ++i)
    {
        set_scl(conf, 1);

        if (0x8000 == (temp & 0x8000))
        {
            set_sda(conf, 1);
        }
        else
        {
            set_sda(conf, 0);
        }

        DAC7311_Delay(cfg->delay_us);
        set_scl(conf, 0);
        DAC7311_Delay(cfg->delay_us);
        temp <<= 1;
    }

    set_syn(conf, 1);

    rt_size_t ret = sizeof(uint16_t);
    return ret;
}
/*=====================================================#######  END  #######=================================================*/

/*=====================================================##### 设备注册 #####==================================================*/
/**
 * @brief DAC设备初始化
 * @param dev:设备
 */
static rt_err_t DAC7311_Init(rt_device_t dev)
{
    dac_device_t *user = (dac_device_t *)dev->user_data;

    user->dev_name = DAC7311_DEV_NAME;
    user->scl      = DAC7311_SCL_PIN;
    user->syn      = DAC7311_SYN_PIN;
    user->sda      = DAC7311_SDA_PIN;
    user->delay_us = 10;

    rt_pin_mode(user->scl, PIN_MODE_OUTPUT);
    rt_pin_mode(user->syn, PIN_MODE_OUTPUT);
    rt_pin_mode(user->sda, PIN_MODE_OUTPUT);

    rt_pin_write(user->syn, PIN_HIGH);
    rt_pin_write(user->scl, PIN_HIGH);
    rt_pin_write(user->sda, PIN_LOW);

    return RT_EOK;
}

/**
 * @brief 设备关闭
 * @param dev:设备
 * @param oflag:打开方式
 */
static rt_err_t DAC7311_Open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

/**
 * @brief 设备关闭
 * @param dev:设备
 */
static rt_err_t DAC7311_Close(rt_device_t dev)
{
    return RT_EOK;
}

/**
 * @brief 设备读取
 * @param dev:设备
 * @param pos:读取的位置
 * @param buffer:数据缓冲区
 * @param size:缓冲区的大小
 */
static rt_size_t DAC7311_Read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    return RT_EOK;
}

/**
 * @brief 设备写入
 * @param dev:设备
 * @param pos:写入的位置
 * @param buffer:写入的数据缓冲区
 * @param size:缓冲区大小
 */
static rt_size_t DAC7311_Write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    uint16_t *data = (uint16_t *)buffer;
    rt_size_t ret = DAC7311_Write_Data((dac_device_t *)dev->user_data, *data);
    return ret;
}

/**
 * @brief 设备控制
 * @param dev:设备
 * @param cmd:指令
 * @param args:命令参数
 */
static rt_err_t DAC7311_Control(rt_device_t dev, int cmd, void *args)
{
    dac_device_t *cfg = (dac_device_t *)dev->user_data;
    int ret = -RT_ERROR;

    switch(cmd)
    {
        case RT_DEVICE_CTRL_LOCK:
        {
            lock(cfg);
            ret = RT_EOK;
            break;
        }

        case RT_DEVICE_CTRL_UNLOCK:
        {
            unlock(cfg);
            ret = RT_EOK;
            break;
        }

        default:
        {
            ret = -RT_ERROR;
            break;
        }
    }

    return ret;
}

/**
 * @brief DAC设备注册
 * @return 返回注册结果
 */
static int DAC7311_Device_Register(void)
{
    rt_device_t dac_dev = &(dac_device_config.base_device);

    // 初始化互斥量
    rt_err_t ret = rt_mutex_init(&dac_device_config.dac_lock, DAC7311_DEV_NAME, RT_IPC_FLAG_PRIO);
    RT_ASSERT(ret == RT_EOK);

    // 设置设备类型和设备标志
    dac_dev->type        = RT_Device_Class_SPIDevice; // 设备类型--SPI设备
    dac_dev->rx_indicate = RT_NULL;
    dac_dev->tx_complete = RT_NULL;

    // 设置设备操作接口
    dac_dev->init        = DAC7311_Init;              // 设备初始化
    dac_dev->open        = DAC7311_Open;              // 设备打开
    dac_dev->close       = DAC7311_Close;             // 设备关闭
    dac_dev->read        = DAC7311_Read;              // 设备读取
    dac_dev->write       = DAC7311_Write;             // 设备写入
    dac_dev->control     = DAC7311_Control;           // 设备控制
    dac_dev->user_data   = &dac_device_config;        // 用户数据

    // 注册设备
    ret = rt_device_register(dac_dev, DAC7311_DEV_NAME, RT_DEVICE_FLAG_RDWR);
    if (ret != RT_EOK)
    {
        LOG_E("Failed to register DAC7311 device");
        return -RT_ERROR;
    }

    return RT_EOK;
}
INIT_DEVICE_EXPORT(DAC7311_Device_Register);
/*=====================================================#######  END  #######=================================================*/

/*=====================================================##### 外部调用 #####==================================================*/
/**
 * @brief 设备初始化
 */
void DAC_Device_Init(void)
{
    dac_device = rt_device_find(DAC7311_DEV_NAME);
    RT_ASSERT(dac_device != RT_NULL);

    rt_err_t ret = rt_device_open(dac_device, RT_DEVICE_FLAG_RDWR);
    RT_ASSERT(ret == RT_EOK);

    ret = rt_device_init(dac_device);
    RT_ASSERT(ret == RT_EOK);
}

/**
 * @brief 写DAC值
 * @param data:写入的数据
 */
void write_dac_data(uint16_t data)
{
    rt_device_control(dac_device, RT_DEVICE_CTRL_LOCK, RT_NULL);
    rt_device_write(dac_device, 0, &data, sizeof(uint16_t));
    rt_device_control(dac_device, RT_DEVICE_CTRL_UNLOCK, RT_NULL);
}

/**
 * @brief 指令设置DAC的值
 * @param argc
 * @param argv
 * @return
 */
static int DAC_Param_Set(int argc, char **argv)
{
    RT_ASSERT(argc == 2);

    write_dac_data(atoi(argv[1]));

    return RT_EOK;
}
MSH_CMD_EXPORT_ALIAS(DAC_Param_Set, dac, DAC Param Set);
/*=====================================================#######  END  #######=================================================*/

3.main.c

#include <rtthread.h>
#include <drv_common.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "dac7311.h"

/* 心跳灯线程的入口函数 */
static void thread_heartbeat_entry(void *parameter)
{
    int count = 1;

    while (1)
    {
        count++;
        rt_pin_write(GET_PIN(E, 12), count % 2);
        rt_thread_mdelay(1000);
    }
}

/* 创建心跳灯线程 */
static int thread_heartbeat(void)
{
    rt_pin_mode(GET_PIN(E, 12), PIN_MODE_OUTPUT);

    /* 创建线程 1,名称是 thread1,入口是 thread1_entry,动态创建*/
    rt_thread_t tid1 = rt_thread_create("heartbeat", thread_heartbeat_entry, RT_NULL, 256, 25, 5);

    /* 如果获得线程控制块,启动这个线程 */
    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);

    return 0;
}

int main(void)
{
    int count = 1;

    thread_heartbeat();

    DAC_Device_Init();
    write_dac_data(2048);

    while (count)
    {
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

五、测试验证

  通过在main函数中调用写DAC函数,就可以实现对DAC数据的发送,并且通过测试设置的电压和实际的电压是相吻合的,所以该芯片的驱动程序可用,并且该程序还是使用设备的方式来实现的,后面的RTT设备编程可以参考本次例程。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值