【学习笔记】AD7708/18(1)-理解官网的参考代码
文章目录
- 参考教程
- AD7708 概述
- AD7708 特性
- 引脚布局
- 参考教程1
- 代码
- SPI通信函数详解:
- 关键设计思想:
背景:需要用到AD芯片,为了学习使用它,从官网找到了通过8051单片机控制它的参考代码。本篇主要是尝试理解参考教程1中的文件。
参考教程
教程1:
analog-ad7718中的AD7718参考代码
教程2:
MSP430程序库<六>通过SPI操作AD7708
教程3:
AD7708-7718寄存器(中文)
AD7708 概述
AD7708、AD7718是适合低频测量应用的完整模拟前端。AD7718内置一个含PGA的24位Σ-Δ ADC,可配置为4/5个全差分输入通道或8/10个伪差分输入通道。该器件上的两个引脚可配置为模拟输入或基准电压输入。AD7708是AD7718的16位版本。利用这些ADC,可以直接转换20mV至2.56V范围的输入信号,支持传感器信号直接输入,无需进行信号调理。
AD7708 特性
8/10通道、高分辨率Σ-Δ ADC
16位分辨率
出厂校准
单转换周期设置
可编程增益前端
50 Hz、60 Hz同时抑制
VREF Select ™ 提供绝对测量和比率测量能力
可针对模拟性能(CHOP‾=0\overline{CHOP} = 0CHOP=0)
或通道吞吐量(CHOP‾=1\overline{CHOP} = 1CHOP=1)优化操作
引脚布局
模拟输入通道1.可编程增益模拟输入,与AINCOM配合使用时可用作伪差分输入,与AIN2配合使用时可用作全差分输入对的正输入。(参见ADC控制寄存器部分。)
模拟输入通道3。可编程增益模拟输入,与AINCOM配合使用时可用作伪差分输入,与AIN4配合使用时可用作全差分输入对的正输入。(参见ADC控制寄存器部分。)
参考教程1
代码
/*********************************************************************Author : ADI - CAST Date : September 2003File : AD7718.cHardware : ADuC832Description :*********************************************************************/
/******************************************************************
DEFINE CONTROL PINS OF ADUC832 FOR THE PURPOSE OF AD7718 CONTROL.
Customers should define the pins according to their design.
If P0 is used as the control port, pull-up resistors should be added to each pin of P0.
******************************************************************/
#include<stdio.h>
#include<aduc832.h>sbit CS=0x085;
sbit DIN=0x0B4;
sbit DOUT=0x0B5;
sbit DRDY=0x0B3;
sbit RESET=0x084;
sbit SCLOCK=0x0A7;
int sig;
void int0_int() interrupt 0{sig=0;return; }
void writetoreg(unsigned char);
void readfromreg(int);
void read(int);
void main()
{int tim;/* Set up UART */
T3CON = 0x082;
T3FD = 0x02D;
SCON = 0x052;tim=1000;
/* PRECONFIGURE...*/
RESET=0;
while(tim--);
RESET=1;
SCLOCK=1;
DIN=1;
DOUT=1;
CS=1;
DRDY=1;
printf("\n");
writetoreg(0x03); //write to communication register. The next step is writing to FILTER REGISTER
writetoreg(0x45); //set the FILTER register
writetoreg(0x02); //write to communication register. The next step is writing to ADC CONTROLO register
writetoreg(0x0F); //unipolar,2.56V input channel AIN1-AINCOM
IT0=1;EA=1;EX0=1;
sig=1;
while(sig);
writetoreg(0x01);//write to communication register. The next step is writing to MODE register
writetoreg(0x06);//system zero-scale calibration
while(DRDY);
printf("system zero-scale calibration finished.\n");
sig=1;
while(sig);writetoreg(0x01);//write to communication register. The next step is writing to MODE register
writetoreg(0x07);//system full-scale calibrationwhile(DRDY);
printf("system full-scale calibration finished.\n");sig=1;
while(sig);writetoreg(0x01);//writing to communication register, the next step is write to MODE register
writetoreg(0x03);//continuous conversion mode
writetoreg(0x40); //read from status
readfromreg(8);
printf("\n");
writetoreg(0x41); //read from mode
readfromreg(8);
printf("\n");
writetoreg(0x42); //read from adc control
readfromreg(8);
printf("\n");
writetoreg(0x43); //read from filter
readfromreg(8);
printf("\n");
writetoreg(0x45);//read from offset register
readfromreg(24);
printf("\n");
writetoreg(0x46);//read from gain register
readfromreg(24);
printf("\n");read(200);
}void writetoreg(byteword) //The subroutine write byteword to the corresponding registers of AD7709
unsigned char byteword;{
unsigned char temp;
int i;
CS=0;
temp=0x80;
for(i=0;i<8;i++){if((temp&byteword)==0)DIN=0;else DIN=1;SCLOCK=0;SCLOCK=1;temp=temp>>1;}
CS=1;
}void readfromreg(bytenumber) //The subroutine read from the corresponding register
int bytenumber;
{int j;unsigned char temp1;CS=0;temp1=0x00;for(j=0;j<bytenumber;j++){SCLOCK=0;SCLOCK=1;if(DOUT==0)temp1=temp1<<1;else{temp1=temp1<<1;temp1=temp1+0x01;}if(j==7||j==15||j==23){ printf("%02BX",temp1);temp1=0x00;}}
CS=1;}void read(readtime) //The subroutine read 200 data from the data register
int readtime;
{unsigned char temp1;
int i,j;temp1=0x00;
for(i=0;i<readtime;i++){ while(DRDY);writetoreg(0x44);CS=0;for(j=0;j<24;j++){SCLOCK=0;SCLOCK=1;if(DOUT==0)temp1=temp1<<1;else{temp1=temp1<<1;temp1=temp1+0x01;}if(j==7||j==15||j==23){ printf("%02BX",temp1);temp1=0x00;}}printf("\n");CS=1;}printf("\n\n\n");
}
AD7718控制代码的设计原理和实现细节:
#include<stdio.h>
#include<aduc832.h> // 包含ADuC832微控制器的寄存器定义文件
解释:包含标准I/O库用于串口打印,以及ADuC832微控制器的特殊功能寄存器定义文件。
sbit CS=0x085; // 片选信号 (P0.5)
sbit DIN=0x0B4; // 串行数据输入 (P3.4)
sbit DOUT=0x0B5; // 串行数据输出 (P3.5)
sbit DRDY=0x0B3; // 数据就绪信号 (P3.3)
sbit RESET=0x084; // 复位信号 (P0.4)
sbit SCLOCK=0x0A7;// 串行时钟 (P2.7)
int sig; // 全局状态标志
解释:使用sbit关键字定义AD7718的控制引脚:
- 地址0x085对应P0.5(片选)
- 0x0B4对应P3.4(数据输入)
- 0x0B5对应P3.5(数据输出)
- 0x0B3对应P3.3(数据就绪中断)
- 0x084对应P0.4(硬件复位)
- 0x0A7对应P2.7(串行时钟)
- sig变量用于中断状态标志
void int0_int() interrupt 0 {sig=0; // 中断触发时清除标志return;
}
解释:外部中断0服务程序。当DRDY引脚变低(数据就绪)时触发,将sig标志设为0通知主程序。
void main()
{int tim; // 延时计数器
解释:主函数开始,声明延时计数器变量。
/* Set up UART */T3CON = 0x082; // 定时器3控制:1000 0010 T3FD = 0x02D; // 波特率重装值SCON = 0x052; // 串口控制:0101 0010
解释:配置UART串口通信:
- T3CON=0x82:定时器3作为波特率发生器,模式2
- T3FD=0x2D:设置波特率(如9600)
- SCON=0x52:串口模式1(8位UART),允许接收
tim=1000; // 初始化延时计数器/* PRECONFIGURE...*/RESET=0; // 拉低复位引脚while(tim--); // 延时保持复位状态RESET=1; // 释放复位
解释:硬件复位AD7718。保持RESET低电平约1000个周期(具体时间取决于CPU频率),完成芯片复位。
SCLOCK=1; // 时钟空闲高电平DIN=1; // 数据线默认高DOUT=1; // 数据线默认高CS=1; // 取消片选DRDY=1; // 初始化状态
解释:初始化SPI控制线状态。符合SPI总线空闲状态要求(时钟高,数据线高)。
printf("\n"); // 输出换行符(测试串口)
解释:发送换行符验证串口是否正常工作。
writetoreg(0x03); // 写通信寄存器:选择FILTER寄存器writetoreg(0x45); // 写滤波器寄存器:0100 0101
解释:配置滤波器寄存器:
- 0x03:通信寄存器命令,表示下一个操作对象是滤波器寄存器
- 0x45:设置滤波器参数(输出数据速率和滤波器特性)
writetoreg(0x02); // 写通信寄存器:选择ADC控制寄存器writetoreg(0x0F); // 写控制寄存器:0000 1111
解释:配置ADC控制寄存器:
- 0x02:通信寄存器命令,选择ADC控制寄存器
- 0x0F:设置单极性模式、2.56V量程、AIN1输入通道
IT0=1; // 边沿触发中断EA=1; // 全局中断使能EX0=1; // 外部中断0使能
解释:配置中断系统:
- IT0=1:外部中断0为下降沿触发
- EA=1:开启总中断
- EX0=1:开启外部中断0(连接DRDY)
sig=1; // 设置等待标志while(sig); // 等待DRDY中断
解释:等待第一次数据就绪中断,确保ADC初始化完成。
writetoreg(0x01); // 选择模式寄存器writetoreg(0x06); // 系统零点校准while(DRDY); // 等待校准完成
解释:执行零点校准:
- 0x01:选择模式寄存器
- 0x06:启动系统零点校准
- while(DRDY):等待校准完成(DRDY变低)
printf("system zero-scale calibration finished.\n");sig=1; // 重置标志while(sig); // 等待中断
解释:打印校准完成信息,等待下一次数据就绪中断。
writetoreg(0x01); // 选择模式寄存器writetoreg(0x07); // 系统满量程校准while(DRDY); // 等待校准完成printf("system full-scale calibration finished.\n");
解释:执行满量程校准(流程同零点校准)。
writetoreg(0x01); // 选择模式寄存器writetoreg(0x03); // 连续转换模式
解释:设置连续转换模式(0x03),ADC开始持续采样。
// 读取各寄存器值用于验证writetoreg(0x40); // 读状态寄存器readfromreg(8);// ...类似读取其他寄存器
解释:读取并打印关键寄存器值(状态、模式、控制等),用于调试和配置验证。
read(200); // 读取200个采样数据
}
解释:主程序最终任务:连续读取200个24位采样值。
SPI通信函数详解:
void writetoreg(unsigned char byteword)
{unsigned char temp;int i;CS=0; // 使能芯片temp=0x80; // 1000 0000 掩码for(i=0;i<8;i++){DIN = (temp & byteword) ? 1 : 0; // 提取最高位SCLOCK=0; // 时钟下降沿SCLOCK=1; // 上升沿锁存数据temp >>= 1; // 右移掩码}CS=1; // 禁用芯片
}
设计原理:
- MSB优先的SPI通信
- 通过掩码(temp)逐位提取数据
- 在时钟上升沿锁存数据
- 完整8位数据传输后释放片选
void readfromreg(int bytenumber)
{int j;unsigned char temp1 = 0;CS=0; // 使能芯片for(j=0;j<bytenumber;j++){SCLOCK=0; // 准备时钟SCLOCK=1; // 上升沿读取数据temp1 <<= 1; // 左移腾出位置if(DOUT) temp1 |= 0x01; // 设置最低位// 每8位打印一次if(j%8 == 7) {printf("%02X",temp1);temp1=0;}}CS=1; // 禁用芯片
}
设计原理:
- 时钟上升沿采样数据
- 左移拼接数据位
- 每8位组成一个字节并打印
- 支持读取任意位数(8/16/24等)
void read(int readtime)
{for(int i=0;i<readtime;i++){while(DRDY); // 等待数据就绪writetoreg(0x44); // 选择数据寄存器CS=0;// 读取24位数据for(int j=0;j<24;j++){SCLOCK=0;SCLOCK=1; // 上升沿读取// 数据拼接逻辑if(j%8 == 7) printf("%02X",temp); // 每8位打印}printf("\n"); // 完成一个采样CS=1;}
}
设计原理:
- 等待DRDY变低(数据就绪)
- 发送0x44命令选择数据寄存器
- 读取24位转换结果
- 每8位作为一字节打印(共3字节)
- 循环读取指定次数
关键设计思想:
- 精确时序控制:通过直接操作寄存器实现硬件级SPI时序
- 中断驱动:利用DRDY信号触发中断提高效率
- 校准流程:严格的零点和满量程校准确保精度
- 模块化设计:读写操作封装为独立函数
- 调试支持:通过串口输出关键状态信息
- 低位优先处理:适合AD7718的MSB-first通信协议
- 状态机管理:通过通信寄存器实现多寄存器访问
这段代码完整展示了如何通过8051单片机控制高精度24位ADC,涉及硬件接口、通信协议、校准流程和数据处理等关键技术,是嵌入式数据采集系统的典型实现。