百度空间 | 百度首页 
 
查看文章
 
AD7705的源程序
2009-06-30 10:24
------------AD7705头文件开始-------------------
#ifndef _AD7705_H
#define _AD7705_H

//通讯寄存器地址定义
#define     WR_SETUP_REG        0x10   //选中写设置寄存器
#define     RD_SETUP_REG        0x18   //选中写设置寄存器
#define     WR_CLOCK_REG     0x20   //选中写时钟寄存器
#define RD_DATA_REG         0x38   //选中数据寄存器读
#define     WR_OFFSET_REG      0x60   //选中写offset寄存器
#define     RD_OFFSET_REG      0x68   //选中读offset寄存器
#define     WR_FULL_REG        0x70   //选中写full scale寄存器
#define     RD_FULL_REG        0x78   //选中读full scale寄存器

#define     SYS_ZERO_CALI     0x80   //系统零校准模式
#define     SYS_FULL_CALI     0xC0   //系统满量程校准模式

#define ZERO_CALIBRATION    0x00 //系统零校准
#define FULL_CALIBRATION    0x01 //系统满量程校准

//CLOCK寄存器设置,无分频,50HZ输出更新速率
#define CLOCK_REG_SET    0X04

//函数声明
void reset_AD7705(void);

unsigned char read_AD7705_byte(void);
unsigned int   read_AD7705_word(void);
unsigned long int read_AD7705_dword(void);

void write_AD7705_byte(unsigned char data);
void write_AD7705_word(unsigned int data);
void write_AD7705_dword(unsigned long int data);

void ReadData7705(unsigned int *const pdata);
void AD7705_calibration(void);
void start_AD7705(void);

#endif

-----------AD7705主文件开始--------------
#include <util/delay.h>
#include <avr/eeprom.h>
#include "ad7705.h"
#include "main.h"
#include "crc16.h"
#include "Usart.h"

//针对四个量程的设置寄存器的设置内容
//(1)对于单极性V级别输入0-5V、0-20mA、0-10V这三个量程,输入范围为0-2V,无极性,增益为1,缓冲模式--0-2V
//(2)对于双极性V级别输入+-2.5V、+-5V这两个量程,输入范围为+-1V,双极性,增益为2,缓冲模式--+-2V
//(3)对于双精度mV级别输入+-500mV,增益为4,双极性,缓冲模式--+-2V
//(4)对双精度mV级别+-50mV,增益为32,双极性,缓冲模式--+-1.6V
//----MD1(0)    MD0(0)    G2(0)    G1(0)    G0(0)    B/U(0)    BUF(0)    FSYNC(0)--------------------//
const unsigned char text_of_setup[4]={0X06,0X0A,0X12,0X2A}; //缓冲模式,数字滤波同步

extern volatile unsigned char   command[7];    //校准命令全局数组
extern volatile unsigned char   scale;         //记录系统量程
extern volatile unsigned char   NO_CALI_TYPE; //未校准类型
extern volatile unsigned long   int ZS,GS;    //当前量程的校准系数
extern volatile unsigned char   time_count;    //超时标志

//----------------------------------------------------------------------------
//函数:reset_AD7705
//功能:AD7705串行接口失步后将其复位。复位后要延时500us再访问
//参数:无
//返回:无
//变量:无
//备注:无
//----------------------------------------------------------------------------
void reset_AD7705(void)
{
      unsigned char i;
     
      AD_DIN1;
      for( i=0; i<36; i++ )
      {
          AD_CLK0;
          asm("nop");
          asm("nop");
          asm("nop");         
          AD_CLK1;
          asm("nop");
          asm("nop");
          asm("nop");         
      }     
      _delay_us(30);
}

//------------------------------------------------------------------------------------------
//函数:read_AD7705_byte
//功能:从AD7705读一个字节的数据
//参数:无
//返回:读到的一字节数据
//变量:无
//备注:无
//------------------------------------------------------------------------------------------
unsigned char read_AD7705_byte(void)
{
      unsigned char data = 0;
      unsigned char i = 0;
     
      for( i=0; i<8; i++ )
      {
          data <<= 1;
          AD_CLK0;         
          asm("nop");
          asm("nop");
          asm("nop");
          if(AD_DOUT)
          {
              data++;
          }
          AD_CLK1;         
          asm("nop");
          asm("nop");
          asm("nop");
      }     
      return data;    
}

//------------------------------------------------------------------------------------------
//函数:read_AD7705_word
//功能:从AD7705读一个字的数据,共16bit
//参数:无
//返回:读到的一字节数据
//变量:无
//备注:无
//------------------------------------------------------------------------------------------
unsigned int read_AD7705_word(void)
{
      unsigned int data = 0;
      unsigned char i = 0;
     
      for( i=0; i<16; i++ )
      {
          data <<= 1;
          AD_CLK0;         
          asm("nop");
          asm("nop");
          asm("nop");
          if(AD_DOUT)
          {
              data++;
          }
          AD_CLK1;         
          asm("nop");
          asm("nop");
          asm("nop");
      }     
      return data;    
}


//------------------------------------------------------------------------------------------
//函数:read_AD7705_dword
//功能:从AD7705读一个24的数据
//参数:无
//返回:读到的一字节数据
//变量:无
//备注:AD7705是一个16位AD
//------------------------------------------------------------------------------------------
unsigned long int read_AD7705_dword(void)
{
      unsigned long data = 0;
      unsigned char i = 0;
     
      for( i=0; i<24; i++ )
      {
          data <<= 1;
          AD_CLK0;         
          asm("nop");
          asm("nop");
          asm("nop");
          if(AD_DOUT)
          {
               data++;
          }
          AD_CLK1;         
          asm("nop");
          asm("nop");
          asm("nop");
      }     
      return data;    
}


//------------------------------------------------------------------------------------------
//函数:write_AD7705_byte
//功能:往AD7705写8位数据
//参数:IN - uint8_t   data,要写入AD7705的数据
//返回:无
//变量:无
//备注:无
//------------------------------------------------------------------------------------------
void write_AD7705_byte(unsigned char data)
{
      for(unsigned char i=0; i<8; i++)
      {
          AD_CLK0;
          if(data&0x80)
              AD_DIN1;
          else
              AD_DIN0;         
          asm("nop");
          asm("nop");
          asm("nop");
          AD_CLK1;         
          asm("nop");
          asm("nop");
          asm("nop");
          data <<= 1;
      }     
      AD_DIN1;     
}

//------------------------------------------------------------------------------------------
//函数:write_AD7705_dword
//功能:往AD7705写24位数据,因为AD7705是24位的器件
//参数:IN - int32_t   data,要写入AD7705的数据
//返回:无
//变量:无
//备注:无
//------------------------------------------------------------------------------------------
void write_AD7705_dword(unsigned long int data)
{
     for(unsigned char i = 0; i<24; i++)
     {
          AD_CLK0;
          if(data&0x800000)
              AD_DIN1;
          else
              AD_DIN0;         
          asm("nop");
          asm("nop");
          asm("nop");
          AD_CLK1;         
          asm("nop");
          asm("nop");
          asm("nop");
          data <<= 1;
      }     
      AD_DIN1;
}

//------------------------------------------------------------------------------------------
//函数:AD7705_calibration
//功能:根据cali_type的值对AD7705进行系统0校正或系统满量程校正,并将各校正值和校正标志存入
//       EEPROM,数据保存为双备份。数据块格式为: 内部0校正值(4byte), 内部满量程校正值(4byte),
//          系统0校正值(4byte), 系统满量程校正值(4byte), 系统0校正标志(1byte),系统满量程校正标志
//       (1byte),CRC16校验值(2byte),共20byte。
//参数:IN - uint8_t board, 0 - 对主板进行校正,1-对副板进行校正
//         IN - uint8_t range, 需要校正的量程
//       IN - uint8_t cali_type, 校正类型,ZERO_CALIBRATION- 0校正;
//            FULL_CALIBRATION - 满量程校正
//返回:返回-1表示校准失败,非0表示校正成功,并返回相应的索引值
//变量:无
//备注:做满量程校正前必须先做零校正
//------------------------------------------------------------------------------------------
//校准命令格式    
//STX     Data Long     Command Code     Parameter     CheckSum     ETX
//0x55     数据长度(2)     量程指示     00H/01H         CRC16(2)     0x0D
//
//校准过程中要用到Command[]的数据,所以校准之前要关掉串口接收中断

void AD7705_calibration(void)
{
      //记录读取EEPROM的次数
      unsigned char readtimes =0;
     
      //记录上位机发送的校准量程类型
      unsigned char cali_scale =0;
     
      //读取24位校准系数的临时变量
      unsigned long int temp =0;
     
      //临时的校准系数数组,存放格式ZSL、ZSM、ZSH;GSL、GSM、GSH;CRCL、CRCH
      //并在校准结束时作为参数传递给TXOUT()函数,发送校准系数给上位机
      unsigned char coefficient[8] ={0}; //test[8]={0};
     
      //16位校验和的临时变量
      unsigned int crcvalue =0;
     
      AD_CS1;
     
      cali_scale = command[2]; //获取上位机发送的要校准的量程类型
       
      //读取EEPROM的第一份校准系数
      eeprom_busy_wait();
      eeprom_read_block( &coefficient[0], (void*)(ADDR_EEPROM_1+(cali_scale-1)*10), 8 );
      crcvalue = checksum( &coefficient[0], 6 ); //将6个值调用CRC校验函数得到校验
      if( (coefficient[7]*256+coefficient[6]) != crcvalue )
      {
          readtimes++;        
      }
     
      //如果校准系数不可用则读取第二份
      if( 1 == readtimes )
      {
          eeprom_busy_wait();
          eeprom_read_block( &coefficient[0], (void*)(ADDR_EEPROM_2+(cali_scale-1)*10), 8 );
          crcvalue = checksum( &coefficient[0], 6 ); //将6个值调用CRC校验函数得到校验
          if( (coefficient[7]*256+coefficient[6]) != crcvalue )
          {
              readtimes++;             
          }
      }
     
      //如果校准系数不可用则读取第三份
      if( 2 == readtimes )
      {
          eeprom_busy_wait();
          eeprom_read_block( &coefficient[0], (void*)(ADDR_EEPROM_3+(cali_scale-1)*10), 8 );         
      }
     
      ADDR409_MASK; //切换到第一通道进行校准
     
      AD_CS0;
      _delay_us(5);
      reset_AD7705();
     
      //CLOCK寄存器设置,无分频,50HZ输出更新速率
      write_AD7705_byte( WR_CLOCK_REG );
      write_AD7705_byte( CLOCK_REG_SET );
     
      if( ZERO_CALIBRATION == command[3] ) //校准命令为零校准
      {
          //写设置寄存器,选择零校准
          write_AD7705_byte( WR_SETUP_REG );
          write_AD7705_byte( text_of_setup[cali_scale-1] | SYS_ZERO_CALI );
         
          //等待校准完成,系统校准延时时间
          start_timer0();
          while( time_count < time_sys_cali );
          stop_timer0();
         
          while( AD_DRDY );//若将滤波器同步位FSYNC置为1,AD_DRDY信号将不会变低,这里将一直是死循环
          
          //读OFFSET寄存器
          write_AD7705_byte( RD_OFFSET_REG );
          temp = read_AD7705_dword();
          
          if( cali_scale == scale)
          {
              ZS = temp; //如果是当前量程零校准还要更新ZS
              //如果是当前量程的校准,还要将NO_CALI_TYPE赋值为1表示已经经过零校准
              //更新上电没有校准时readEEPROM()函数的运行状态
              NO_CALI_TYPE = NO_FULL_CALIBRATION;            
          }     
         
          coefficient[0] = (unsigned char)( temp%256 );
          coefficient[1] = (unsigned char)( (temp/256)%256 );
          coefficient[2] = (unsigned char)( (temp/65536)%256 );
      }
      else if( FULL_CALIBRATION == command[3] )//系统满量程校准
      {
         
          //计算ZS,一定要作强制类型转换,否则将出现错误
          temp = (unsigned long int)(coefficient[0]) + (unsigned long int)(coefficient[1])*256
               + (unsigned long int)(coefficient[2])*65536;         
         
          //将ZS写入到AD7705的OFFSET寄存器         
          write_AD7705_byte( WR_OFFSET_REG );
          write_AD7705_dword( temp );         
         
          //写设置寄存器,选择满量程校准
          write_AD7705_byte( WR_SETUP_REG );
          write_AD7705_byte( text_of_setup[cali_scale-1] | SYS_FULL_CALI );         
         
          //等待校准完成,系统校准延时时间
          start_timer0();
          while( time_count < time_sys_cali );
          stop_timer0();
         
          while( AD_DRDY );//若将滤波器同步位FSYNC置为1,AD_DRDY信号将不会变低,这里将一直是死循环
         
          //读FULL寄存器
          write_AD7705_byte( RD_FULL_REG );
          temp = read_AD7705_dword();
         
          if( cali_scale == scale )
          {
              GS = temp; //如果是当前量程满量程校准还要更新GS
              //如果是当前量程的校准,还要将NO_CALI_TYPE赋值为2表示已经经过零校准
              //更新上电没有校准的情况,让readEEPROM()函数退出循环状态
              NO_CALI_TYPE = ALREADY_CALIBRATION;             
          }     
         
          coefficient[3] = (unsigned char)( temp%256 );
          coefficient[4] = (unsigned char)( (temp/256)%256 );
          coefficient[5] = (unsigned char)( (temp/65536)%256 );
      }
      else
      {
          AD_CS1;
          _delay_us(5);
          return;
      }
     
      AD_CS1;
      _delay_us(5);
      
      crcvalue = checksum(&coefficient[0],6); //将6个校准值调用CRC校验函数得到校验码     
      coefficient[6] = (unsigned char)(crcvalue%256);//取校验值的高8位和低8位
      coefficient[7] = (unsigned char)(crcvalue/256);
     
      //保存第一份校准系数
      eeprom_busy_wait();
      eeprom_write_block( &coefficient[0], (void*)(ADDR_EEPROM_1+(cali_scale-1)*10), 8 );
     
      //保存第二份校准系数
      eeprom_busy_wait();
      eeprom_write_block( &coefficient[0], (void*)(ADDR_EEPROM_2+(cali_scale-1)*10), 8 );  
     
      //保存第三份校准系数
      eeprom_busy_wait();
      eeprom_write_block( &coefficient[0], (void*)(ADDR_EEPROM_3+(cali_scale-1)*10), 8 );
     
      Txout( &coefficient[0] );//输出校准数据给上位机
     
      return;     
}


//------------------------------------------------------------------------------------------
//函数:start_AD7705
//功能:先写offset寄存器,再写full scale寄存器,然后启动7705进行单次转换
//参数:uint8_t channel   -- 要进行A/D转换的通道号
//       uint8_t cali      -- 是第几次测量,电阻需要测量2次
//返回:无
//变量:无
//备注:
//------------------------------------------------------------------------------------------
void start_AD7705(void)
{
      reset_AD7705();
     
      //写OFFSET寄存器
      write_AD7705_byte( WR_OFFSET_REG );
      write_AD7705_dword( ZS );
     
      //写满量程校准寄存器
      write_AD7705_byte( WR_FULL_REG );
      write_AD7705_dword( GS );
     
      //CLOCK寄存器设置,无分频,50HZ输出更新速率
      write_AD7705_byte( WR_CLOCK_REG );
      write_AD7705_byte( CLOCK_REG_SET );
     
      //写设置寄存器
      write_AD7705_byte( WR_SETUP_REG );
      write_AD7705_byte( text_of_setup[scale-1] );
     
      start_timer0();
      while( time_count < time_read_data );//读取数据延时20ms左右,
      stop_timer0();
}

类别:编程开发 | 添加到搜藏 | 浏览() | 评论 (9)
 
最近读者:
 
网友评论:
1
2009-07-30 17:26 | 回复
看不太懂你的程序里面关于校准系数可不可用那一部分.直接读取需要的校准系数写入校准寄存器中不就可以了么?怎么还那么多转换.呵呵 只看懂一点点.不太懂c.只会汇编..
 
2
2009-07-30 21:09 | 回复
回复天玺:我也看不懂,呵呵,所以我就没有用它的,我也是自己写的,那部分没有什么用,我也看不懂!
 
3
2009-08-01 14:12 | 回复
回复mudh118:探讨个问题,现在我弄得个东西对精度要求不高,但是得得用一路差分,一路测电流.而且用的两个通道增益不一样一个增益为1,一个为128.可不可以每个通道只进行自校准,不进行系统校准啊.7705是不是里面应该有自己的系统校准系数啊.呵呵 现在还没有焊接调试,你试过么,交流下.现在手头资源较差,没有电压源也没有电流源..
 
4
2009-08-04 22:06 | 回复
回复天玺:我也是刚研究AD7705,好多也是不太明白,呵呵,希望你弄明白了告诉我一声,先谢谢了
 
5
2009-08-04 22:07 | 回复
回复天玺:完全是转人家的!我一点都不明白,但是我觉得他有好多东西都是没有用的
 
6
2009-08-11 18:28 | 回复
能不能给我分编完的呀?好用的
 
7
2009-08-13 21:50 | 回复
头文件是怎么定义的???我们没有那些头文件怎么用啊???
 
8
2009-08-14 08:14 | 回复
回复iiiiii:自己写,不要什么都靠人家,网上的东西,真正能用的太少了,完全好用的程序有几个人能上传到网上?我这也是转载人家的,自己修改后用!
 
9
2009-09-21 10:27 | 回复
回复mudh118:呵呵 才看到消息.我用汇编写的.基本ok.转换速度尚可.50hz还可以,500hz的话ad读数就差很多,还有如果对精度要求不是很高,系统校准可以不做.
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu