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

news/2024/9/23 22:15:29/

文章目录

    • 一、简介
    • 二、驱动程序
    • 三、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设备编程可以参考本次例程。



http://www.ppmy.cn/news/1529514.html

相关文章

哪个快?用300万个图斑测试ArcGIS Pro的成对叠加与经典叠加

​​​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 在使用ArcGIS Pro的过程中&#xff0c;很多朋友发现&#xff0c;Pro有个成对叠加工具集。很多…

是德科技Keysight N4433D ECal模块 26.5GHz 4端口3.5毫米

是德科技Keysight N4433D ECal模块 26.5GHz 4端口3.5毫米 Keysight N4433D 射频电子校准 (ECal) 模块使是德科技矢量网络分析仪的校准变得快速、简单和准确。N4433D 是一款精密 4 端口电子校准件模块&#xff0c;支持选择 3.5 毫米连接器&#xff0c;最高可混频至 26.5 GHz。选…

数据结构:时间复杂度与空间复杂度

目录 算法效率时间复杂度大O渐进表示法时间复杂度计算案例 空间复杂度空间复杂度案例 复杂度算法题 算法效率 算法在编写成可执行程序后&#xff0c;运⾏时需要耗费时间资源和空间(内存)资源 。因此衡量⼀个算法的好坏&#xff0c;⼀般是从时间和空间两个维度来衡量的&#xf…

Spring 全局与局部异常处理解析 + 实战案例

Spring 全局与局部异常处理解析 实战案例 在 Java 开发中&#xff0c;异常处理是非常重要的一环。它不仅能够提升代码的健壮性&#xff0c;还能为用户提供有意义的错误提示。在 Spring Framework 中&#xff0c;我们可以通过全局和局部异常处理来优雅地管理异常。本文将结合 …

大数据毕业设计选题推荐-高校考试分析系统-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

【计算机网络】传输层协议TCP

目录 一、重新理解封装和解包二、TCP协议段格式三、确认应答(ACK)机制四、超时重传机制五、连接管理机制六、理解TIME_WAIT状态和CLOSE_WAIT状态七、流量控制八、滑动窗口九、拥塞控制十、延迟应答十一、面向字节流十二、粘包问题 一、重新理解封装和解包 在网络协议栈中&…

【手写数据库内核组件】1001词法分析器,语言被程序识别的第一步,将语句分解为最小词根token

1001 词法分析器 ​专栏内容: postgresql使用入门基础手写数据库toadb并发编程个人主页:我的主页 管理社区:开源数据库 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 文章目录 1001 词法分析器一、概述 二、词法分析机制原理 2.1 分析流程 2.2 预定义规则 2.3 …

9月23日

思维导图 作业 统计家目录下.c文件的个数 #!/bin/bashnum0for file in ~/*.c; doif [ -f "$file" ]; then((num))fi doneecho "家目录下.c文件的个数: $num"