当前位置: 首页 > news >正文

模数转换【1】AD7699

1.开发背景

       一款可以模数转换芯片,兼容通用 SPI 接口,支持最多支持 8 个通道和 500KSPS 的采样率。支持单个通道采集和扫描采集模式。

        同系列的芯片还有 AD7682 和 AD7689 等。

2.开发需求

        配置内部参考电压4.096V,实现单个通道采集和扫描采集模式。

3.开发环境

        Window10 + MDK + STM32F407VET6

4.详细设计

4.1 关键寄存器

        配置信息可以随时更改,每次 SPI 传输 2 个字节,需要注意的是:配置寄存器需要左移2位, SPI 模式 CPHA = CPOL = 0。

4.2 控制流程

4.2.1 单个读取

        例如读取通道 0 = 单极性 + IN0 + 全带宽 + 内部基准电压源 + 禁用序列器

4.2.2 扫描读取

        扫描读取0-3 = 单极性 + IN3 + 全带宽 + 内部基准电压源 + 扫描IN0至IN[7:0]

4.3 软件实现

4.3.1 AD7699 头文件
#ifndef BSP_AD7699_H
#define BSP_AD7699_H#include <stdio.h>#define AD7699_LOG  printf/* 采集极性选择 Default eAd7699_Incc_Single */
typedef enum
{eAd7699_Incc_DoubleDiff = 0,     // 0 0 xeAd7699_Incc_Double = 0x02,      // 0 1 0eAd7699_Incc_Temperaure = 0x03,  // 0 1 1eAd7699_Incc_SingleDiff = 0x04,  // 1 0 xeAd7699_Incc_SingleCom = 0x06,   // 1 1 0eAd7699_Incc_Single = 0x07,      // 1 1 1   }EnumAd7699_Incc_t;/* 通道选择 选择从 Ch0 扫描到 CHx */
typedef enum
{eAd7699_Channnel_0 = 0,         // 通道eAd7699_Channnel_1,eAd7699_Channnel_2,eAd7699_Channnel_3,eAd7699_Channnel_4,eAd7699_Channnel_5,eAd7699_Channnel_6,eAd7699_Channnel_7,}EnumAd7699_Channel_t;/* 带宽选择 Default eAd7699_BandWidth_All */
typedef enum
{eAd7699_BandWidth_Quarter = 0,  // 1/4 带宽eAd7699_BandWidth_All,          // 全带宽      }EnumAd7699_BandWidth_t;/* 参考电压 Default eAd7699_Ref_Internal */
typedef enum
{eAd7699_Ref_Disable = 0x0,eAd7699_Ref_Internal = 0x01,            // 内部参考电压 4.096V + 温度传感器eAd7699_Ref_ExterAndTemp = 0x02,        // 外部电压 + 温度传感器eAd7699_Ref_ExterAndTempAndBuf = 0x03,  // 外部电压 + 温度传感器 + 缓存eAd7699_Ref_Exter = 0x06,               // 外部电压eAd7699_Ref_ExterAndBuf = 0x07,         // 外部电压 + 缓存}EnumAd7699_Ref_t;/* 通道序列器 */
typedef enum
{eAd7699_Seq_Disable = 0,                // 禁用   DefaulteAd7699_Seq_Update,                     // 序列扫描期间更新序列eAd7699_Seq_ChannelAndTemp,             // 扫描通道和温度eAd7699_Seq_Channel,                    // 扫描通道}EnumAd7699_Seq_t;/* __weak 弱定义 必须先配置好 否者无效!!!  */
void Ad7699_FuncDelayUs(int us);
void Ad7699_FuncChipSelect(void);
void Ad7699_FuncChipUnselect(void);
int  Ad7699_FuncSpiTxRx(char *pTxData, char *pRxData, int size);/* 可调用接口 温度传感器读取的不准 */
int bAd7699_Init(void);
int bAd7699_SingleSample(EnumAd7699_Channel_t eChannel, unsigned short *pData, int num);
int bAd7699_ScanSample(EnumAd7699_Channel_t eLastCh, unsigned short *pData, int num);
int bAd7699_ScanSampleWithTemp(EnumAd7699_Channel_t eLastCh, unsigned short *pData, int num);
unsigned short bAd7699_GetChannelValue(EnumAd7699_Channel_t eChannel);/* 扩展接口 */
void bAd7699_SetIncc(EnumAd7699_Incc_t eIncc);
void bAd7699_SetBaudWidth(EnumAd7699_BandWidth_t eBaudWidth);
void bAd7699_SetRefVoltage(EnumAd7699_Ref_t eRef);
float bAd7699_GetTempFromValue(unsigned short data);    // 温度测量不是很准 不建议使用/* 测试接口 */
int bAd7699_Test(void);#endif

        需要注意的是  需要给定 __weak 的接口,否者读不到数据。 

4.3.2 AD7699 源文件
#include "bspAd7699.h"#include <stdio.h>#define AD7699_FULL_VALUE       (65536)
#define AD7699_INTERNAL_REF_V   (4.096f)
#define AD7699_TEMP_25_MAP_MV   (283.0f)/* 控制结构体 */
typedef struct
{/* 关键配置 */EnumAd7699_Incc_t eIncc;EnumAd7699_BandWidth_t eBandWidth;EnumAd7699_Ref_t eRef;}Ctrl_t;/* 初始化 */
static Ctrl_t s_ctrl = {.eIncc = eAd7699_Incc_Single,.eBandWidth = eAd7699_BandWidth_All,.eRef = eAd7699_Ref_Internal,
};
static Ctrl_t *p = &s_ctrl;__weak void Ad7699_FuncDelayUs(int us)  {}
__weak void Ad7699_FuncChipSelect(void) {}
__weak void Ad7699_FuncChipUnselect(void) {}
__weak int  Ad7699_FuncSpiTxRx(char *pTxData, char *pRxData, int size)  {   return 0;  }/* 开始转换 */
static int Ad7699_StartConversion(void)
{Ad7699_FuncChipSelect();Ad7699_FuncDelayUs(120);Ad7699_FuncChipUnselect();Ad7699_FuncDelayUs(1);return 0;
}/* 读写数据 */
static unsigned short Ad7699_ReadWriteData(unsigned short data)
{char txData[2] = {0};char rxData[2] = {0};/* 填充数据 */txData[0] = (data >> 8) & 0xFF;txData[1] = (data >> 0) & 0xFF;/* 片选 读写数据 */Ad7699_FuncChipSelect();Ad7699_FuncSpiTxRx(txData, rxData, 2);Ad7699_FuncChipUnselect();/* 返回读写值 */return ((rxData[0] << 8) | rxData[1]);
}/* 写配置寄存器 返回回读数据 */
static unsigned short Ad7699_WriteConfig(unsigned short config)
{/* 地址左移 2 位 */config = config << 2;return Ad7699_ReadWriteData(config);
}/* 初始化 */
int bAd7699_Init(void)
{for (int i = 0; i < 1; i++){Ad7699_StartConversion();
//        bAd7699_GetChannelValue(eAd7699_Channnel_0);}return 0;
}/* 采集通道数据 */
int bAd7699_SingleSample(EnumAd7699_Channel_t eChannel, unsigned short *pData, int num)
{if (pData == NULL){return -1;}/* 因为获取的数据延迟 2 个节奏,第三次才是有效值, 前两次无效 */for (int i = 0; i < num + 2; i++){unsigned short config = 0x3001;config |= (p->eIncc << 10);config |= (eChannel << 7);config |= (p->eBandWidth << 6);config |= (p->eRef << 3);config |= (eAd7699_Seq_Disable << 1);/* 前 2 次数据丢弃 */if (i < 2){Ad7699_WriteConfig(config);}else{pData[i - 2] = Ad7699_WriteConfig(config);}}return  0;
}/* 扫描采样 采集的顺序 从 CH0 到 eLastCh 顺序排列 num 是采集的数据个数 */
int bAd7699_ScanSample(EnumAd7699_Channel_t eLastCh, unsigned short *pData, int num)
{if (pData == NULL){return -1;}unsigned short config = 0x3001;config |= (p->eIncc << 10);config |= (eLastCh << 7);config |= (p->eBandWidth << 6);config |= (p->eRef << 3);config |= (eAd7699_Seq_Channel << 1);Ad7699_WriteConfig(config);/* 数据交互 */unsigned short txData = 0;for (int i = 0; i < num; i++){pData[i] = Ad7699_ReadWriteData(txData);}return 0;
}/* 扫描采样 + 温度 */
int bAd7699_ScanSampleWithTemp(EnumAd7699_Channel_t eLastCh, unsigned short *pData, int num)
{if (pData == NULL){return -1;}unsigned short config = 0x3001;config |= (p->eIncc << 10);config |= (eLastCh << 7);config |= (p->eBandWidth << 6);config |= (p->eRef << 3);config |= (eAd7699_Seq_ChannelAndTemp << 1);Ad7699_WriteConfig(config);/* 数据交互 */unsigned short txData = 0;for (int i = 0; i < num; i++){pData[i] = Ad7699_ReadWriteData(txData);}return 0;
}/* 获取通道数据 */
unsigned short bAd7699_GetChannelValue(EnumAd7699_Channel_t eChannel)
{unsigned short readData;bAd7699_SingleSample(eChannel, &readData, 1);return readData;
}/* 设置采集极性 */
void bAd7699_SetIncc(EnumAd7699_Incc_t eIncc)
{p->eIncc = eIncc;
}/* 设置带宽 */
void bAd7699_SetBaudWidth(EnumAd7699_BandWidth_t eBaudWidth)
{p->eBandWidth = eBaudWidth;
}/* 设置参考电压 */
void bAd7699_SetRefVoltage(EnumAd7699_Ref_t eRef)
{p->eRef = eRef;
}/* 数值转换温度接口 */
float bAd7699_GetTempFromValue(unsigned short data)
{/* 内部参考电压 */if (p->eRef == eAd7699_Ref_Internal){float voltage = (float)data / AD7699_FULL_VALUE * AD7699_INTERNAL_REF_V;float temp = (voltage * 1000 - AD7699_TEMP_25_MAP_MV) / 1.0f + 25.0f;
//        AD7699_LOG("data = %d, voltage = %f, temp = %f\r\n", data, voltage, temp);return temp;}else{}return 0;
}/* 测试 */
int bAd7699_Test(void)
{AD7699_LOG("%s\r\n", __func__);/* 循环遍历 */for (int i = 0; i < 8; i++){unsigned short data = bAd7699_GetChannelValue((EnumAd7699_Channel_t)i);AD7699_LOG("%s [%d] data = %d\r\n", __func__, i, data);if (p->eRef == eAd7699_Ref_Internal){float voltage = (float)data / AD7699_FULL_VALUE * AD7699_INTERNAL_REF_V;AD7699_LOG("%s [%d] voltage = %.3f\r\n", __func__, i, voltage);}#define SAMPLE_DATA_NUM (100)unsigned short dataList[SAMPLE_DATA_NUM] = {0};bAd7699_SingleSample((EnumAd7699_Channel_t)i, dataList, SAMPLE_DATA_NUM);AD7699_LOG("%s DataList[%d] = ", __func__, i);for (int j = 0; j < SAMPLE_DATA_NUM; j++){AD7699_LOG("%d ", dataList[j]);}AD7699_LOG("\r\n");}/* 扫描采集 */#define SCAN_SAMPLE_DATA_NUM (100)unsigned short sampleDataList[SCAN_SAMPLE_DATA_NUM] = {0};bAd7699_ScanSample(eAd7699_Channnel_3, sampleDataList, SCAN_SAMPLE_DATA_NUM);AD7699_LOG("%s bAd7699_ScanSample = ", __func__);for (int j = 0; j < SCAN_SAMPLE_DATA_NUM; j++){AD7699_LOG("%d ", sampleDataList[j]);if ((j % 8) == 0){AD7699_LOG("\r\n");}}AD7699_LOG("\r\n");    bAd7699_ScanSampleWithTemp(eAd7699_Channnel_7, sampleDataList, SCAN_SAMPLE_DATA_NUM);AD7699_LOG("%s bAd7699_ScanSampleWithTemp = ", __func__);for (int j = 0; j < SCAN_SAMPLE_DATA_NUM; j++){AD7699_LOG("%d ", sampleDataList[j]);if ((j % 9) == 0){float temp = bAd7699_GetTempFromValue(sampleDataList[j]);AD7699_LOG("%.2f ", temp);AD7699_LOG("\r\n");}}AD7699_LOG("\r\n");    return 0;
}

4.4 测试结果

        调用 bAd7699_Test 验证各个接口功能。除了内部温度传感器不准,其他的还符合预期

相关文章:

  • MySQL知识点讲解
  • 【软件工程】软件测试基础知识
  • MYDB仿MySQL手写数据库项目总结
  • 【Maven】项目管理工具
  • 深度学习-全连接神经网络-2
  • Rust: 从内存地址信息看内存布局
  • 问题 | RAIM + LSTM 你怎么看???
  • Day5-UFS总结
  • WPS科大讯飞定制版 11.4.1.5| 无广告,省电和降低占用,可与普通版本共存
  • stm32week12
  • 如何在量子计算时代保障 Sui 的安全性
  • (14)VTK C++开发示例 --- 将点投影到平面上
  • 中通 Redis 集群从 VM 迁移至 PVE:技术差异、PVE 优劣势及应用场景深度解析
  • 【GIT】为什么要变基下拉,变基下拉失败,提示没有暂存如何解决?
  • 使用QEMU(8.2.10)调试ARM64 Linux内核6.6.30
  • 【STM32单片机】#10.5 串口数据包
  • 50道SQL经典练习题
  • 如何通过API获取淘宝评论?实战讲解
  • JVM面试题学习
  • JumpServer多用户VNC桌面配置指南:实现多端口远程访问
  • 宇树的任务已经完成?王兴兴也在等待行业拐点
  • 普京签署有关批准俄罗斯与伊朗全面战略伙伴关系条约的联邦法令
  • 广东省东莞市委原书记、市人大常委会原主任徐建华被开除党籍
  • 著名政治学学者、中国人民大学教授仝志敏逝世
  • 人民日报:当阅读成为“刚需”
  • 建投读书会·东西汇流|西风东渐中的上海营造