文章目录
- 一、简介
- 二、驱动程序
- 三、DAC设置注册
- 四、完整代码
- 五、测试验证
一、简介
8 位 DAC5311、10 位 DAC6311 和 12 位 DAC7311 (DACx311) 是低功耗、单通道、电压输出数模转换器 (DAC)。DACx311 在正常工作状态下具有低功耗(5V 时为 0.55mW,断电模式下可降至 2.5μW),使其成为便携式电池供电应用的理想选择。
器件信息:DAC7311系列芯片手册
器件型号 | 分辨率 |
---|---|
DAC7311 | 12位 |
DAC6311 | 10位 |
DAC5311 | 8位 |
驱动电路:
二、驱动程序
本文主要使用模拟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设备编程可以参考本次例程。