环境:STM32F103RC,主频 72MHz(外部晶振)或64MHz(HSI)

两块DAC8760菊花链链接,采用SPI1驱动

note:发生电流回路开路等时,ALARM脚持续低,当电流回路等正常,DAC芯片能自动恢复正常,故程序无需特殊处理。

代码实现:

//DAC8760.c#define DAC8760_GLOBALS
#include "DAC8760.h"static const uint8_t ORange[6] =
{0, // 0~5V(OFF)0, // 1~5V1, // 0~10V3, // -10~10V6, // 0~20mA5, // 4~20mA
}/******************************************************
函数名称:WriteSingle_DAC8760
函数描述:单块DAC的写函数
Calls:HAL_SPI_TransmitReceive
Called by: Init_DAC8760
输入参数:    ch_Addr:写操作地址ch_Data:数据
返回值:HAL status
******************************************************/
static HAL_StatusTypeDef WriteSingle_DAC8760(uint8_t ch_Addr, uint16_t ch_Data)
{HAL_StatusTypeDef status;uint8_t liv_Data[3]; // 0: ch_Addr  1:ch_Datadata高8位 2:ch_Datadata低8位uint8_t liv_RXData[3] = {0};liv_Data[0] = ch_Addr;liv_Data[1] = (ch_Data & 0xff00) >> 8;liv_Data[2] = ch_Data & 0x00ff;DAC8760_LATCH_0;status = HAL_SPI_TransmitReceive(&hSPI1, liv_Data, liv_RXData, 3, TIMEOUT); DAC8760_LATCH_1;   delay_us(1);return status;
}/******************************************************
函数名称:Write_DAC8760
函数描述:2块DAC菊花链的写函数
Calls:HAL_SPI_TransmitReceive
Called by: EnableOutputControl、ChangeOutputRange等
输入参数:    ch1_Addr:通道1写操作地址ch1_Data:通道1的数据ch2_Addr:通道2写操作地址ch2_Data:通道2的数据
返回值:HAL status
******************************************************/
static HAL_StatusTypeDef Write_DAC8760(uint8_t ch1_Addr, uint16_t ch1_Data, uint8_t ch2_Addr, uint16_t ch2_Data)
{HAL_StatusTypeDef status;uint8_t liv_Data[6]; // 0: ch2_Addr  1:ch2_Datadata高8位 2:ch2_Datadata低8位// 0: ch1_Addr  1:ch1_Datadata高8位 2:ch1_Datadata低8位   uint8_t liv_RXData[6] = {0};liv_Data[0] = ch2_Addr;liv_Data[1] = (ch2_Data & 0xff00) >> 8;liv_Data[2] = ch2_Data & 0x00ff;liv_Data[3] = ch1_Addr;liv_Data[4] = (ch1_Data & 0xff00) >> 8;liv_Data[5] = ch1_Data & 0x00ff;DAC8760_LATCH_0;status = HAL_SPI_TransmitReceive(&hSPI1, liv_Data, liv_RXData, 6, TIMEOUT); DAC8760_LATCH_1;    delay_us(1);return status;
}/******************************************************
函数名称:Read_DAC8760
函数描述:2块DAC菊花链的读函数
Calls:HAL_SPI_TransmitReceive
Called by: EnableOutputControl、ChangeOutputRange等
输入参数:    ch1_Addr:通道1读的寄存器地址ch2_Addr:通道2读的寄存器地址data: data[0]--Ch1 data;data[1]--Ch2 data
返回值:HAL status
******************************************************/
static HAL_StatusTypeDef Read_DAC8760(uint8_t ch1_Addr, uint8_t ch2_Addr, uint16_t *data)
{HAL_StatusTypeDef status;uint8_t liv_TXData[6]; // 0: ch2_Addr  1:ch2_Datadata高8位 2:ch2_Datadata低8位// 0: ch1_Addr  1:ch1_Datadata高8位 2:ch1_Datadata低8位 uint8_t liv_RXData[6];liv_TXData[0] = W_ADDR_READ;liv_TXData[1] = (ch2_Addr & 0xff00) >> 8;liv_TXData[2] = ch2_Addr & 0x00ff;liv_TXData[3] = W_ADDR_READ;liv_TXData[4] = (ch1_Addr & 0xff00) >> 8;liv_TXData[5] = ch1_Addr & 0x00ff;DAC8760_LATCH_0;status = HAL_SPI_TransmitReceive(&hSPI1, liv_TXData, liv_RXData, 6, TIMEOUT); DAC8760_LATCH_1;delay_us(1);
//  if (status == HAL_OK)
//  {
//      *(data + 1) = (liv_RXData[4] << 8) | liv_RXData[5];
//  }liv_TXData[0] = W_ADDR_NOP;liv_TXData[1] = 0;liv_TXData[2] = 0;liv_TXData[3] = W_ADDR_NOP;liv_TXData[4] = 0;liv_TXData[5] = 0;DAC8760_LATCH_0;status = HAL_SPI_TransmitReceive(&hSPI1, liv_TXData, liv_RXData, 6, TIMEOUT); DAC8760_LATCH_1;delay_us(1);    if (status == HAL_OK){*data = (liv_RXData[1] << 8) | liv_RXData[2];*(data + 1) = (liv_RXData[4] << 8) | liv_RXData[5];  // 2018.9.18修改}return status;
}/******************************************************
函数名称:EnableOutputControl
函数描述:输出使能控制
Calls:Read_DAC8760、Write_DAC8760
Called by: Clear2RoadsOutput、Init_DAC8760
输入参数:ch1Enable:1--使能输出;0--禁能ch2Enable:1--使能输出;0--禁能
返回值:无
******************************************************/
static void EnableOutputControl(uint8_t ch1Enable, uint8_t ch2Enable)
{#ifdef READ_CTRLuint16_t oldStatus[2], newStatus[2];#endifassert_param((ch1Enable <= 1) && (ch2Enable <= 1));#ifdef READ_CTRLif (Read_DAC8760(R_ADDR_CTRL, R_ADDR_CTRL, oldStatus) == HAL_OK){oldStatus[0] &= ~(CTRL_OUTEN);oldStatus[1] &= ~(CTRL_OUTEN);newStatus[0] = oldStatus[0] | SET_OUTEN(ch1Enable);newStatus[1] = oldStatus[1] | SET_OUTEN(ch2Enable);Write_DAC8760(W_ADDR_CTRL, newStatus[0], W_ADDR_CTRL, newStatus[1]);}#elseif (ch1Enable == 1){gUCTRL_Value.usCTRL1Value |= SET_OUTEN;}else{gUCTRL_Value.usCTRL1Value &= ~SET_OUTEN;}if (ch2Enable == 1){gUCTRL_Value.usCTRL2Value |= SET_OUTEN;}else{gUCTRL_Value.usCTRL2Value &= ~SET_OUTEN;}Write_DAC8760(W_ADDR_CTRL, gUCTRL_Value.usCTRL1Value, W_ADDR_CTRL, gUCTRL_Value.usCTRL2Value);#endif   }   /******************************************************
函数名称:Clear2RoadsOutput
函数描述:使两通道的输出为0
Calls:EnableOutputControl
Called by: Init_DAC8760
输入参数:无
返回值:无
******************************************************/
static void Clear2RoadsOutput(void)
{EnableOutputControl(OUTPUT_DISENABLE, OUTPUT_DISENABLE);DAC8760_CLR_1;delay_us(6);DAC8760_CLR_0;
}/******************************************************
函数名称:ChangeOutputRange
函数描述:改变输出范围,并且当需要将量程改成(1~5V)或(0~5V)时进行一些处理
Calls:Read_DAC8760、Write_DAC8760、SetCh1DACData、SetCh2DACData
Called by: sDoIntSomething
输入参数:pUHoldingReg: 传入gUHoldingReg共用体指针         roadFlag:需要修改量程的通道bkpFlag:BKP备份标志
返回值:无
******************************************************/
void ChangeOutputRange(UHoldingReg *pUHoldingReg, uint32_t roadFlag, SFlag *pSFlag, uint32_t bkpFlag)
{if (bkpFlag == TRUE){// 备份gUBKPData.CH1_AOUT_Range = pUHoldingReg->CH1_AOUT_Range;gUBKPData.CH2_AOUT_Range = pUHoldingReg->CH2_AOUT_Range;gSFlag.Write_BKP_Flag = TRUE;}#ifdef READ_CTRLuint8_t ch1Range = ORange[pUHoldingReg->CH1_AOUT_Range];uint8_t ch2Range = ORange[pUHoldingReg->CH2_AOUT_Range];    uint16_t oldRange[2], newRange[2];Read_DAC8760(R_ADDR_CTRL, R_ADDR_CTRL, oldRange);oldRange[0] &= ~(CTRL_RANGE);oldRange[1] &= ~(CTRL_RANGE);newRange[0] = oldRange[0] | SET_RANGE(ch1Range);newRange[1] = oldRange[1] | SET_RANGE(ch2Range);Write_DAC8760(W_ADDR_CTRL, newRange[0], W_ADDR_CTRL, newRange[1]);#elsegUCTRL_Value.usCTRL1Value &= (ORange[pUHoldingReg->CH1_AOUT_Range] | 0xFFF8);gUCTRL_Value.usCTRL1Value |= ORange[pUHoldingReg->CH1_AOUT_Range];gUCTRL_Value.usCTRL2Value &= (ORange[pUHoldingReg->CH2_AOUT_Range] | 0xFFF8);gUCTRL_Value.usCTRL2Value |= ORange[pUHoldingReg->CH2_AOUT_Range];  Write_DAC8760(W_ADDR_CTRL, gUCTRL_Value.usCTRL1Value, W_ADDR_CTRL, gUCTRL_Value.usCTRL2Value);#endif// 当用户选择量程为1~5V,需要软件将输出设为1Vswitch (roadFlag){case CH1AOUT_RANGE_ADD:{pUHoldingReg->Ch1_AOUT_Value = 0;if (pUHoldingReg->CH1_AOUT_Range == VORANGE_1_5){SetCh1DACData(0x3333);pUHoldingReg->Ch1_AOUT_Value = 1;}else if(pUHoldingReg->CH1_AOUT_Range == VORANGE_0_5){SetCh1DACData(0);}else if (pUHoldingReg->CH1_AOUT_Range ==IORANGE_4_20){pUHoldingReg->Ch1_AOUT_Value = 4;}pSFlag->Aout1Rang_ChangeFlag = TRUE;break;}case CH2AOUT_RANGE_ADD:{pUHoldingReg->Ch2_AOUT_Value = 0;if (pUHoldingReg->CH2_AOUT_Range == VORANGE_1_5){SetCh2DACData(0x3333);pUHoldingReg->Ch2_AOUT_Value = 1;}else if(pUHoldingReg->CH2_AOUT_Range == VORANGE_0_5){SetCh2DACData(0);}else if (pUHoldingReg->CH2_AOUT_Range ==IORANGE_4_20){pUHoldingReg->Ch2_AOUT_Value = 4;}pSFlag->Aout2Rang_ChangeFlag = TRUE;         break;}default:break;}}/******************************************************
函数名称:SetCh1DACData
函数描述:设置通道1DAC输出,并立即更新。
Calls:Write_DAC8760
Called by: ChangeOutputRange、sDoFloatSomething
输入参数:dacValue: 0~65535
返回值:无
******************************************************/
void SetCh1DACData(uint16_t dacValue)
{Write_DAC8760(W_ADDR_DATA, dacValue, W_ADDR_NOP, 0);
}/******************************************************
函数名称:SetCh2DACData
函数描述:设置通道2DAC输出,并立即更新。
Calls:Write_DAC8760
Called by: ChangeOutputRange、sDoFloatSomething
输入参数:dacValue: 0~65535
返回值:无
******************************************************/
void SetCh2DACData(uint16_t dacValue)
{Write_DAC8760(W_ADDR_NOP, 0, W_ADDR_DATA, dacValue);
}/******************************************************
函数名称:Init_DAC8760
函数描述:SPI1和DAC8760的初始化代码
Calls:WriteSingle_DAC8760、Write_DAC8760、Clear2RoadsOutput等
Called by: main
输入参数:hspi:传入SPI_HandleTypeDef结构体指针pUHoldingReg:传入gUHoldingReg共用体指针 pUCTRL_Value:用来存放2块DAC芯片的控制寄存器值
返回值:无
******************************************************/
void Init_DAC8760(SPI_HandleTypeDef *hspi, UHoldingReg *pUHoldingReg, UCTRL_Value *pUCTRL_Value)
{/**********************SPI1模块的初始化代码,配置成主机模式******************/__HAL_RCC_SPI1_CLK_ENABLE();hspi->Instance = SPI1;hspi->Init.Mode = SPI_MODE_MASTER; // 主模式hspi->Init.Direction = SPI_DIRECTION_2LINES; // 双线模式hspi->Init.DataSize = SPI_DATASIZE_8BIT; // 发送接收8位帧结构hspi->Init.CLKPolarity = SPI_POLARITY_LOW; // 串行同步时钟空闲状态为低电平hspi->Init.CLKPhase = SPI_PHASE_1EDGE; // 串行同步时钟的第1个跳变沿(上升沿)数据被采样hspi->Init.NSS =  SPI_NSS_SOFT; // SS信号由硬件(NSS管脚)还是软件控制hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // SPI波特率预分频值 18M/8hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;hspi->Init.TIMode = SPI_TIMODE_DISABLE;hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 关闭硬件CRChspi->Init.CRCPolynomial = 7; // CRC值计算的多项式HAL_SPI_Init(hspi);__HAL_SPI_ENABLE(hspi);/****************************************************************************/    /**********************DAC8760初始化部分*************************************/WriteSingle_DAC8760(W_ADDR_RESET, SOFTWARE_RESET); pUCTRL_Value->usCTRL1Value |= CTRL_DCEN;WriteSingle_DAC8760(W_ADDR_CTRL, CTRL_DCEN);    Write_DAC8760(W_ADDR_NOP, 0, W_ADDR_RESET, SOFTWARE_RESET);pUCTRL_Value->usCTRL2Value |= CTRL_DCEN;     Write_DAC8760(W_ADDR_NOP, 0, W_ADDR_CTRL, CTRL_DCEN ); // 菊花链使能         pUCTRL_Value->usCTRL1Value &= (ORange[pUHoldingReg->CH1_AOUT_Range] | 0xFFF8);pUCTRL_Value->usCTRL1Value |= ORange[pUHoldingReg->CH1_AOUT_Range];pUCTRL_Value->usCTRL2Value &= (ORange[pUHoldingReg->CH2_AOUT_Range] | 0xFFF8);pUCTRL_Value->usCTRL2Value |= ORange[pUHoldingReg->CH2_AOUT_Range];Write_DAC8760(W_ADDR_CTRL, pUCTRL_Value->usCTRL1Value, W_ADDR_CTRL, pUCTRL_Value->usCTRL2Value); // 菊花链使能和输出范围设置                Clear2RoadsOutput();    EnableOutputControl(TRUE, TRUE);    /****************************************************************************/
}
// DAC8760.h
ifndef _DAC8760_H
#define _DAC8760_H#ifdef DAC8760_GLOBALS
#define DAC8760_EXT
#else
#define DAC8760_EXT extern
#endif#include "global.h"#define DAC8760_CLR_0            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET)
#define DAC8760_CLR_1           HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET)
#define DAC8760_LATCH_0         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET)
#define DAC8760_LATCH_1         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)
#define ALARM_PORT_STATUS()     HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)/* 通道定义 */
#define AOUT_CH1    1
#define AOUT_CH2    2/* DAC8760 8位地址 */
#define W_ADDR_NOP           0x00
#define W_ADDR_DATA          0x01 // 写数据寄存器
#define W_ADDR_READ          0x02 // 读
#define W_ADDR_CTRL          0x55 // 写控制寄存器
#define W_ADDR_RESET         0x56 // 写复位寄存器
#define W_ADDR_CONFIG        0x57 // 写配置寄存器
#define W_ADDR_GAIN          0x58 // 写增益校准寄存器
#define W_ADDR_ZERO          0x59 // 写零校准寄存器
#define W_ADDR_WDT           0x95 // 写看门狗寄存器/* 读操作命令寻址的寄存器地址 */
#define R_ADDR_SATUS       0x00
#define R_ADDR_DATA        0x01
#define R_ADDR_CTRL        0x02
#define R_ADDR_CONFIG      0x0B
#define R_ADDR_GAIN        0x13
#define R_ADDR_ZERO        0x17/* 寄存器值宏定义 */
#define SOFTWARE_RESET      1
#define CTRL_DCEN           (1 << 3) // 菊花链使能
#define CTRL_OUTEN          (1 << 12)
#define CTRL_RANGE          (7 << 0)
#define TIMEOUT             500#define OUTPUT_ENABLE       1
#define OUTPUT_DISENABLE    0//#define READ_CTRL
#ifdef READ_CTRL
#define SET_OUTEN(x)        (x << 12)
#else
#define SET_OUTEN           (1 << 12)
#endif
#define SET_RANGE(x)        (x & 0x07)#pragma anon_unions
typedef union
{uint16_t usCTRLValue[2];struct{uint16_t usCTRL1Value;uint16_t usCTRL2Value;};
}UCTRL_Value;#pragma no_anon_unionsDAC8760_EXT SPI_HandleTypeDef hSPI1;
DAC8760_EXT UCTRL_Value gUCTRL_Value;void ChangeOutputRange(UHoldingReg *pUHoldingReg, uint32_t roadFlag, SFlag *pSFlag, uint32_t bkpFlag);
void SetDACData(uint16_t dac1Value, uint16_t dac2Value);
void SetCh1DACData(uint16_t dacValue);
void SetCh2DACData(uint16_t dacValue);
void Init_DAC8760(SPI_HandleTypeDef *hspi, UHoldingReg *pUHoldingReg, UCTRL_Value *pUCTRL_Value);
#endif

DAC8760 菊花链驱动相关推荐

  1. 外设驱动库开发笔记2:AD8400系列数字电位器驱动

    一些时候我们需要在系统使用过程中改变某些电路电阻值以达到改变设定的目的,这时候我们就会使用电位器.在我们使用数字控制电路时多选择数字电位器.在这一篇我们就来设计AD8400系列数字电位器的驱动. 1. ...

  2. 【ADS867x】14 位 500kSPS 4/8 通道 ADC 简介及驱动应用示例

    器件特性 具有集成模拟前端的 14 位模数转换器 (ADC) 具有自动和手动扫描功能的 4 通道.8 通道多路复用器 通道独立可编程输入: ±10.24V.±5.12V.±2.56V.±1.28V.± ...

  3. 基于STM32的ADS8688驱动

    ADS8688模块介绍: 概述: ▶ 完整的 ADS8688 应用电路模块. ▶ 外部单电源供电,电源范围 2.7-5.5Vdc : 3.3V 供电时, 典型工作电流为 33mA : 5.0V 供电时 ...

  4. 基于Windows8与Visual Studio11开发第一个USB驱动应用程序

    USB ,是英文Universal Serial BUS(通用串行总线)的缩写,而其中文简称为"通串线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在PC领域的接口技术.U ...

  5. DAC8760+STM32F407单电源电路硬件测试

    DAC8760+STM32F407单电源电路硬件测试 特性 16位DAC +10V至+36V单电源,或者18V的双电源供电 输出电流:4-20mA或0-20mA或0-24mA 输出电压:0-5V或0- ...

  6. ADBMS1818菊花链通信

    ADBMS1818是一款多通道电池堆监控器,可测量多 达18串电池电压,总测量误差(TME)小于3.0 mV.ADBMS1818具有0V至5V的电池测量范围,适合大多数电池应用.可在290 μs内完成 ...

  7. 集成式单片机外部模块驱动编写详解——AD5689为例

    集成式单片机外部模块驱动编写详解--AD5689为例 集成式驱动原理 AD5689基本介绍 AD5689驱动抽象及源码解释 源码 参考资料 具体的代码和例程请参照以下GitHub仓库,记得给我star ...

  8. 内存走线 菊花链_菊花链拓扑结构布线注意事项和端接方法

    作者:王萍   一博科技高速先生团队队员    拓扑和端接序列文章 上一篇我们讨论了星形拓扑结构,这篇接着讨论菊花链.这两种都是多负载情况下常用的拓扑结构,星形拓扑要求每个分支尽量等长,而菊花链是把所 ...

  9. 联想服务器和显示屏怎么连接,显示器的菊花链(串联)的连接方法以及要求

    操作步骤: 原理:配备有DisplayPort接口,那你就可以利用到一种名叫菊花链的功能,可让你将多台显示器彼此串联并连接到单独一个接口.一个DisplayPort接口可驱动最多4台1080p显示器( ...

最新文章

  1. [转载]如何用关键字优化网站?
  2. 陌生人社会_陌生人之旅
  3. insert ... on duplicate key update产生death lock死锁原理
  4. 运行SQL文件时报Lost connection to MySQL server during query
  5. 程序猿,这里有你想学的10门机器学习课程 | 资源
  6. 【重点!记忆化递归+DP】LeetCode 72. Edit Distance
  7. [体验编译原理]编写简易计算器
  8. ue4缓存位置怎么改_[UE4]动态液体材质浅谈
  9. si4438 的初始化
  10. 如何注册知乎小号,利用知乎一天引流超高转化精准粉
  11. 网易支付分布式事务实战-java课堂笔记
  12. 基于算力驱动、数据与功能协同的分布式动态(协同)渲染/功能运行时
  13. 跨越适配性能那道坎,企鹅电竞Android weex优化
  14. CPU内部原理,一文解析
  15. 公司 邮件 翻译 培训 长难句 13
  16. String Similarity
  17. 应用软件之xx文库破解器
  18. xss漏洞学习心得(泪目)
  19. 取消SVN感叹号即去除版本库
  20. 计算机专业用移动硬盘,评测 篇四十三:国产之光,看这款可做移动硬盘又可系统盘的Orico SSD...

热门文章

  1. spyder(python3.7)使用教程_使用spyder3调试python程序的简明教程
  2. Cinemachine(二)制作不会穿墙(会避开障碍物)的摄像头(Cinemachine Collider)
  3. python pandas 教程_python pandas教程入门与实战练习
  4. ICCV 2023 | 腾讯优图实验室16篇论文入选,含掌纹生成,人脸隐私保护,图像和谐化等研究方向...
  5. nRF 广播 扫描 long range 相关
  6. Git - push 提交失败变成:(master|MERGING)
  7. Hbase原理与实践-1
  8. 通过微信无法下载APP的最佳解决方案
  9. .zip 文件和 .tar.gz文件 的区别
  10. 几种常见的版本控制工具