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

文章目录

    • 一、简介
    • 二、驱动程序
    • 三、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.xdnf.cn/news/148111.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Qt笔记】QStackedWidget控件详解

目录 引言 一、基础功能 二、属性设置 2.1 属性介绍 2.2 代码示例 2.3 代码解析 三、常用API 3.1 添加子部件 3.2 插入子部件 3.3 移除子部件 3.4 设置当前页面索引值 3.5 设置当前显示子部件 3.6 返回索引处子部件指针 3.7 返回子部件索引值 四、信号与槽 4.…

蓝牙AOA基站助力打造智慧医院管理系统

随着科技的飞速发展&#xff0c;智慧医院的概念逐渐深入人心。其中&#xff0c;蓝牙AOA&#xff08;到达角&#xff09;定位技术以其高精度、低功耗、低成本等优势&#xff0c;在智慧医院建设中扮演着重要角色。本文将深入探讨蓝牙AOA基站如何助力智慧医院的建设与发展。 一、蓝…

Linux C高级 day4

一、思维导图 二、练习 1、统计家目录下.c文件的个数 #!/bin/bashcount0 for file in ~/*.cdo((count)) done echo $count 2、定义一个稀疏数组(下标不连续)&#xff0c;写一个函数&#xff0c;求该稀疏数组的和&#xff0c;要求稀疏数组中的数值通过参数传递到函数中。arr(…

【例题】证明极限

已知&#xff1a; ∀ ε > 0 , ∃ n > N , ∣ a n − A ∣ < ε \forall \varepsilon >0, \exist n>N,|a_n-A|<\varepsilon ∀ε>0,∃n>N,∣an​−A∣<ε 目标&#xff1a; ∀ ε > 0 , ∃ n > N 1 , ∣ a 1 . . . a n n − A ∣ < ε \…

codeforces round974 div3 分层图 树形dp

A Robin Helps 问题&#xff1a; 思路&#xff1a;模拟 代码&#xff1a; #include <bits/stdc.h> using namespace std;const int N 2e5 10;void solve() {int n, k;cin >> n >> k;vector<int> a(n 1);for(int i 1; i < n; i ) cin >&…

9.23 My_string.cpp

my_string.h #ifndef MY_STRING_H #define MY_STRING_H#include <iostream> #include <cstring>using namespace std;class My_string { private:char *ptr; //指向字符数组的指针int size; //字符串的最大容量int len; //字符串当前…

车载视频监控:安全生产与管理的新趋势

随着社会的快速发展&#xff0c;车载视频监控技术已成为现代安防领域不可或缺的一部分。车载视频监控设备是专为车载安防设计的新型视频监控设备&#xff0c;其安装已经成为社会发展的必然趋势。对于企业的安全生产和管理来说&#xff0c;车载视频监控设备起着至关重要的作用。…

wpf,工具栏上,最小化按钮的实现

工具栏上&#xff0c;最小化按钮的实现。工具栏做成的是用户控件。 用户控件的xaml <Button HorizontalAlignment"Right" Height"32" Click"MinimizeClick" /> 用户控件的cs代码 private void MinimizeClick(object sender, RoutedEven…

2024年408真题计算机网络篇

1 https://zhuanlan.zhihu.com/p/721169467。最小割可以看作是切断水流的最薄弱环节——通过切断这些关键的“水管”&#xff0c;就可以完全阻止水从源点流到汇点。 在下列二进制数字调制方法中&#xff0c;需要2个不同频率载波 的是 A. ASK B. PSK C. FSK D. DPSK 解答…

【行为树】02-基础的端口

Input and Output Ports 输入和输出端口 正如我们之前解释的那样,自定义的TreeNodes可以用于执行任意简单或复杂的软件。它们的目标是提供一个具有更高抽象层级的接口。 因此,它们在概念上与函数没有不同。 类似于函数,我们经常想要: 将参数传递给一个节点(inputs)从一…

论文Query2Label: A Simple Transformer Way to Multi-Label Classification

本文将Transformer解码器用于多标签分类&#xff0c;将label embedding作为query&#xff0c;计算与feature map的cross-attention&#xff0c;取得了SOTA结果。 论文&#xff1a;https://arxiv.org/pdf/2107.10834.pdf 代码&#xff1a;https://github.com/SlongLiu/query2lab…

洛谷-P3916 图的遍历

题目描述 给出 N 个点&#xff0c;M 条边的有向图&#xff0c;对于每个点 v&#xff0c;求A(v) 表示从点 v 出发&#xff0c;能到达编号最大的点。 思路 既然是要找到最大的点&#xff0c;那么我从最大的点开始DFS是否可以&#xff1f; 于是可以反向建图&#xff0c;然后从最…

Excel的基本应用 ___2

快速插入函数 方法一&#xff1a; 方法二&#xff1a;快捷键 Alt&#xff1a;求和 动态查看 利用函数清单选择函数 相对地址和绝对地址的转换 FnF4

寻觅义乌自闭症学校:了解寄宿制教育的选择

在义乌乃至全国范围内&#xff0c;为自闭症儿童寻找一所合适的学校&#xff0c;是许多家庭面临的重大挑战。随着特殊教育的发展&#xff0c;越来越多的寄宿制学校以其独特的优势和全面的教育体系&#xff0c;为这些特殊的孩子提供了更加专业和细致的关怀。今天&#xff0c;我们…

MySQL实战面试题(附案例答案+建表语句+模拟数据+案例深度解析),练完直接碾压面试官

知识点思维导图 案例1 建表语句与模拟数据 用户表 users CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL UNIQUE, signup_date DATE NOT NULL ); INSERT INTO users (username, email, signu…

9月23日

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

多个异构系统用户权限如何统一管理?

企业内部往往部署了多个业务系统来支撑不同的业务流程&#xff0c;然而&#xff0c;这些系统之间的标准不一&#xff0c;导致跨系统操作时权限不透明&#xff0c;难以确保数据安全与合规操作。同时&#xff0c;频繁的权限变更与维护工作量大且效率低&#xff0c;给企业带来了诸…

基于单片机的智能窗帘控制系统-设计说明书

设计摘要&#xff1a; 智能窗帘控制系统是一种利用单片机技术实现的智能化控制系统&#xff0c;可以实现窗帘的自动开合和定时控制功能。本系统的设计基于单片机技术&#xff0c;结合传感器、电机和执行器等硬件设备&#xff0c;实现对窗帘的智能化控制。通过传感器采集环境信…

电动车车牌识别系统源码分享

电动车车牌识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

微服务架构的挑战与解决方案 —— Spring Cloud

文章目录 微服务架构的挑战与解决方案 —— Spring Cloud挑战微服务挑战解决方案 - Spring Cloud什么是Spring CloudSpring Cloud 版本Spring Cloud实现方案Spring Cloud NetflixSpring Cloud Alibaba 微服务架构的挑战与解决方案 —— Spring Cloud 挑战 服务依赖复杂性 随着…