分享TI LM3S811开发板使用心得 之高精度采集卡制作

2019-08-06 16:38发布

本帖最后由 lilihua0721 于 2011-11-30 21:51 编辑

   以下是我使用TI MCU制作高精度采集卡的全部资料,包括硬件搭建原理图、软见工程文件,液晶资料及ADS1211资料,详情请参考附件。
分别放在以下连续的8个楼层中,有不足的地方请大家指教!
效果图展示:


采集界面.jpg 采集结果显示.jpg 差分正向数据接3.3反向输入端接0.jpg
一、基于LM3S811ADS1211数据采集卡设计硬件部分(全部电路请参考附件)
对于硬件我是采用以前的做的一块ADS1211采集卡板跳线来完成实验的,目前并没有针对LM3S811设计PCB板,在这里给出测试原理图。
1、电源部分及ADS1211的外围电路设计:
在测量过程中,电源是影响测量精度大的因素,所以电源必须要稳定。
以下是我设计的电源部分及ADS1211的外围电路设计。 电源与ADS1211电路.JPG

2、ADS1211差分输入信号的隔离:
采用了LM324用于电压跟随,在此没有做放大(测试差分输入电压为0~5V
具体如下图:
差分隔离输入电路.JPG

3、串口通信电路:
考虑到通讯的距离及稳定性采用了MAX232转换为RS232电平,
具体参考如下: RS232连接电路.JPG

3、LM3S811ADS板接口连接: 接口部分.JPG

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
lilihua0721
1楼-- · 2019-08-06 19:32
本帖最后由 lilihua0721 于 2011-11-27 20:57 编辑

一、基于LM3S811ADS1211数据采集卡设计软件部分(完整工程文件请参照附件工程文件)
ADS1211读写流程.JPG
ADS1211读写流程
1、mian.c

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "ADS1211U.h"
#include "Type.h"
#include <stdio.h>
#include <string.h>
#include <math.h>

double UVal;//计算电压值,
char str[60];//存放显示字符串
INT32U ADdata; //24 AD转换器采集到的AD
INT32U  Value; //存放转换电压值放大10000倍的结果
INT16U  integer=0;// 待转换为字符串整数部分
INT16U  decimal=0;// 待转换为字符串小数部分
INT8U i=0; // 记录当前显示通道

#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

/**************************************************************************************
函数名: void UARTIntHandler(void)
  : 接受中断处理
  : 从接受FIFO中取出数据然后发送出去
  入:无

  出:无
  他:无
**************************************************************************************/

void UARTIntHandler(void)
{
INT32U ulStatus;

//
获取中断状态

ulStatus = UARTIntStatus(UART0_BASE, true);

//
清中断

UARTIntClear(UART0_BASE, ulStatus);

//
查接受FIFO是否存在数据

while(UARTCharsAvail(UART0_BASE))

{
//
从接受FIFO接受到数据后然后通过发送FIFO发送出去

UARTCharPutNonBlocking(UART0_BASE, UARTCharGetNonBlocking(UART0_BASE));

}

}
/*****************************************************************************
函数名: CreanLcd(INT16U
usColor,INT16U X0,INT16U Y0,INT16U X1,INT16U Y1)

  : 清指定区域的,用usColor颜 {MOD}对指定区域进行填充
  : 清液晶指定区域
  入:usColor填充颜 {MOD}
      X0 Y0第一点左上坐标
               X1
Y1
第一点右下坐标

  出:无
  他:无
*******************************************************************************/
void CreanLcd(INT16U
usColor,INT16U X0,INT16U Y0,INT16U X1,INT16U Y1)

{
INT8U
CmdData[6]={0xAA,0x64,0xCC,0x33,0xC3,0x3C};

INT8U
i=0;

//
发送帧头

for(i=0;i<2;i++)

{

UARTCharPutNonBlocking(UART0_BASE, CmdData);

}

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送填充颜 {MOD}

UARTCharPutNonBlocking(UART0_BASE, usColor>>8);

UARTCharPutNonBlocking(UART0_BASE, usColor);

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送左上LCD地址

UARTCharPutNonBlocking(UART0_BASE, X0>>8);

UARTCharPutNonBlocking(UART0_BASE, X0);

UARTCharPutNonBlocking(UART0_BASE, Y0>>8);

UARTCharPutNonBlocking(UART0_BASE, Y0);

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送右下LCD地址

UARTCharPutNonBlocking(UART0_BASE, X1>>8);

UARTCharPutNonBlocking(UART0_BASE, X1);

UARTCharPutNonBlocking(UART0_BASE, Y1>>8);

UARTCharPutNonBlocking(UART0_BASE, Y1);

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送帧尾及校验位

for(i=2;i<6;i++)

{

UARTCharPutNonBlocking(UART0_BASE, CmdData);

SysCtlDelay(SysCtlClockGet()/3000);

}

}

lilihua0721
2楼-- · 2019-08-06 23:36
本帖最后由 lilihua0721 于 2011-11-27 20:58 编辑

/**************************************************************************
函数名: void UARTSend(const INT8U *pucBuffer, INT32U ulCount,INT16U XAddr, INT16U YAddr)
  : 清指定区域的,用usColor颜 {MOD}对指定区域进行填充
  : 清液晶指定区域
  入:pucBuffer 字符串指针
ulCount
字符串个数

XAddr
YAddr
显示地址

  出:无
  他:无
*****************************************************************************/
void UARTSend(const INT8U *pucBuffer, INT32U ulCount,INT16U XAddr, INT16U YAddr)
{
INT8U
CmdData[6]={0xAA,0x54,0xCC,0x33,0xC3,0x3C};

INT8U
i=0;

//
发送帧头

for(i=0;i<2;i++)

{

UARTCharPutNonBlocking(UART0_BASE, CmdData);

}

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送写入LCD地址

UARTCharPutNonBlocking(UART0_BASE, XAddr>>8);

UARTCharPutNonBlocking(UART0_BASE, XAddr);

UARTCharPutNonBlocking(UART0_BASE, YAddr>>8);

UARTCharPutNonBlocking(UART0_BASE, YAddr);

SysCtlDelay(2*SysCtlClockGet()/3000);

//
发送显示内容

while(ulCount--)

{

UARTCharPutNonBlocking(UART0_BASE, *pucBuffer++);

SysCtlDelay(SysCtlClockGet()/3000);

}

//
发送帧尾及校验位

for(i=2;i<6;i++)

{

UARTCharPutNonBlocking(UART0_BASE, CmdData);
SysCtlDelay(SysCtlClockGet()/3000);
}

}
lilihua0721
3楼-- · 2019-08-07 02:59
本帖最后由 lilihua0721 于 2011-11-27 21:09 编辑

/******************************************************************************
函数名: void ADConversion_test(INT8U chn)
  : 测试24AD转换器的采样精度
  : 由于采集输入端电压范围为0~5V5V对应的满量程为0x7FFFFF
        故:差分输入电压值为:U = (5*AD)/0x7FFFFF ,可以知道U必然
              小于5V,乘10000后必然小于0xFFFF,所以执行以下操作不会越界

integer=(INT16U)(Value/10000);
//
取字符串的整数部分
decimal=(INT16U)(Value%10000);
//
取字符串的小数部分
  入:无
  出:无
  他:无
*****************************************************************************/
void ADConversion_test(INT8U chn)
{
if(chn>=4)

{

return ; //
通道有误,返回!

}

memset(str,0,60);

ADdata = ADCave_ADS1211(chn,3);

UVal=ADdata;

UVal=UVal*5;

UVal=UVal/0x7FFFFF;

Value = (INT32U)(UVal*10000);
//
double型数据强制转换为32位整型数据,并放大

//10000
integer=(INT16U)(Value/10000);
//
取字符串的整数部分

decimal=(INT16U)(Value%10000);
//
取字符串的小数部分

if(chn==0)

{

//
清显示区,显示第一通道时清显示区域(不是整个屏幕)

CreanLcd(0xFFFF,0x00,0x50,0x1C2,0xE0);

if(decimal<10)

sprintf(str,
第一通道检测:AD:0x%x 电压值:%d.000%dV",ADdata,integer,decimal);

else if(decimal<100)

sprintf(str,"
第一通道检测:AD:0x%x 电压值:%d.00%dV",ADdata,integer,decimal);

else if(decimal<1000)

sprintf(str ,"
第一通道检测:AD:0x%x 电压值:%d.0%dV",ADdata,integer,decimal);

else

sprintf(str ,"
第一通道检测:AD:0x%x 电压值:%d.%dV",ADdata,integer,decimal);

//
发送给串口屏进行显示

UARTSend((INT8U *)str, strlen(str),0x00,0x50);

}

else if(chn==1)

{
if(decimal<10)

sprintf(str,
第二通道检测:AD:0x%x 电压值:%d.000%dV",ADdata,integer,decimal);

else if(decimal<100)

sprintf(str,"
第二通道检测:AD:0x%x 电压值:%d.00%dV",ADdata,integer,decimal);

else if(decimal<1000)

sprintf(str ,"
第二通道检测:AD:0x%x 电压值:%d.0%dV",ADdata,integer,decimal);

else

sprintf(str ,"
第二通道检测:AD:0x%x 电压值:%d.%dV",ADdata,integer,decimal);

//
发送给串口屏进行显示

UARTSend((INT8U *)str, strlen(str),0x00,0x70);

}

else if(chn==2)

{

if(decimal<10)

sprintf(str,
第三通道检测:AD:0x%x 电压值:%d.000%dV",ADdata,integer,decimal);

else if(decimal<100)

sprintf(str,"
第三通道检测:AD:0x%x 电压值:%d.00%dV",ADdata,integer,decimal);

else if(decimal<1000)

sprintf(str ,"
第三通道检测:AD:0x%x 电压值:%d.0%dV",ADdata,integer,decimal)

else

sprintf(str ,"
第三通道检测:AD:0x%x 电压值:%d.%dV",ADdata,integer,decimal);

//
发送给串口屏进行显示

UARTSend((INT8U *)str, strlen(str),0x00,0x90);

}

else if(chn==3)

{

if(decimal<10)

sprintf(str,
第四通道检测:AD:0x%x 电压值:%d.000%dV",ADdata,integer,decimal);

else if(decimal<100)

sprintf(str,"
第四通道检测:AD:0x%x 电压值:%d.00%dV",ADdata,integer,decimal);

else if(decimal<1000)

sprintf(str ,"
第四通道检测:AD:0x%x 电压值:%d.0%dV",ADdata,integer,decimal);

else

sprintf(str ,"
第四通道检测:AD:0x%x 电压值:%d.%dV",ADdata,integer,decimal);

//
发送给串口屏进行显示

UARTSend((INT8U *)str, strlen(str),0x00,0xb0);

}

integer=0;

decimal=0;

}
nongfuxu
4楼-- · 2019-08-07 05:34
高精度是ADS1211吧,与LM3S811有什么关系.
ADS1211与任何一个单片机都完成同样功能--->高精度数据采集卡.
lilihua0721
5楼-- · 2019-08-07 08:19
 精彩回答 2  元偷偷看……
lilihua0721
6楼-- · 2019-08-07 08:29
本帖最后由 lilihua0721 于 2011-11-27 21:04 编辑

2、        ADS1211.c

#include "Type.h"         
#include "ADS1211U.h"         
#include "driverlib/sysctl.h"

/******************************
函数名: void Ads1211Init(void)
功  能: 初始化ADS1211U
说  明: 无
输  入:无
输  出:无
返  回:无
其  他:无
******************************/
void Ads1211Init(void)
{
   while(!ADS1211_DRDY());   
   while(ADS1211_DRDY());
//   delay5us(5) ;   
   /* 设置INSR写入4字节命令字CMR */
   WriteAds1211(0x64);         
   /* 设置输出REF及设置双极性 */
   WriteAds1211(0x52);           
   /* 选择半自动校准模式,增益PGA为1,通道3 */
   WriteAds1211(0x22);         
   /* 根据抽取率=fxin*TMR/(Fdata*512);计算抽取率 */
   WriteAds1211(0x81);         
   /* TMR设置为8;Fdata为1000;Fxin为10M,得到抽取率为312.5  20位有效位 */
   WriteAds1211(0x38);        
}

/************************************
函数名: void WriteAds1211(INT8U Dat)
功  能: 向ADS1211写入1字节数据
说  明: 无
输  入:Dat
输  出:无
返  回:无
其  他:无
*************************************/
void WriteAds1211(INT8U Dat){
  INT8U i,tmp;
  
  /* 移位 */
  tmp = Dat;
  for(i= 0;i< 8;i++){
    /* 模拟时钟高并保持一段时间 */
    ADS1211_SCLK_1();
        SysCtlDelay(2000*SysCtlClockGet()/30000);
    /* 获取数据 */
    if(tmp & 0x80)  ADS1211_SDIO_1();
    else            ADS1211_SDIO_0();
    /* 模拟时钟低并保持一段时间 */
    ADS1211_SCLK_0();
        SysCtlDelay(2000*SysCtlClockGet()/30000);
    /* 移位 */
    tmp <<= 1;
  }
}

/****************************************************
函数名: INT8U AdsReadData(tU32 *Dat,INT8U chn)
功  能: 读取ADS1211转换数据
说  明: 读取转换数据通过 Dat 进行返回
输  入:chn:通道号  0->3
输  出:Dat
返  回:0:成功
        1:失败
其  他:无
****************************************************/
INT8U AdsReadData(INT32U *Dat,INT8U chn)
{
  INT8U   i = 0;
  INT32U  Chr=0;  

  if(chn>3) return 1;
  while(!ADS1211_DRDY());     
  while(ADS1211_DRDY());
  WriteAds1211(0x05);
  switch (chn)
  {
    case 0:  
      WriteAds1211(0x20);
      break;
    case 1:
      WriteAds1211(0x21);                              
      break;           
    case 2:  
      WriteAds1211(0x22);
      break;   
    case 3:  
      WriteAds1211(0x23);
      break;   
    default:
      break;
  }
  while(!ADS1211_DRDY());   
  while(ADS1211_DRDY());
  WriteAds1211(0xc0);   // 读DOR寄存器中3个字节
  for(i=0;i<24;i++)
  {    // 读取数据
    ADS1211_SCLK_1();
        SysCtlDelay(2000*SysCtlClockGet()/30000);
    Chr <<= 1;
    ADS1211_SCLK_0();
        SysCtlDelay(2000*SysCtlClockGet()/30000);
    Chr += ADS1211_SDOUT()?1:0;
  }
  ADS1211_SCLK_0();          // ADS1211的SCLK清零
//  (*(INT32U_UNION*)&Chr).sBYTE.BHH = 0;
  *Dat =Chr;
  return 0 ;  
}
/**********************************************
函数名: void ADCmid(void)
功  能: 1路A/D转换函数(中值滤波)
说  明: 获取通道channel中值滤波后的A/D转换结果,
        返回该通道中值滤波后的A/D转换结果
输  入:channel: 通道号  0->3      
输  出:无
返  回:中值AD
其  他:无
***********************************************/
INT32U ADCmid_ADS1211(INT8U chn){
  INT32U i,j,k,tmp;
  
  tmp =0;
  if((!AdsReadData(&i,chn))&&
      (!AdsReadData(&j,chn))&&
      (!AdsReadData(&k,chn)))
  {
    if(i > j)
        {
      tmp = i;
      i   = j;
      j   = tmp;
    }
    if(k>i)
        {
      if (k >j)
             tmp = j;
      else      
             tmp = k;
    }
    else
        {
      tmp = i;
    }
  }            
  return tmp;
}

/**************************************
函数名: void ADCave(void)
功  能: 1路A/D转换函数(均值滤波)
说  明: 通道channel进行n次中值滤波,
        求和再作均值,得出均值滤波结
        果并返回该通道均值滤波后的A/D
        转换结果   
输  入:chn:通道号  0->3     
        n:中值滤波次数
输  出:无
返  回:无
其  他:均值AD
**************************************/
INT32U ADCave_ADS1211(INT8U chn,INT8U n)
{
  INT8U    i=0;
  INT32U   j=0;
  
  for (i=0; i<n; i++)
  {
    j += ADCmid_ADS1211(chn);
  }
  j = j/n;
  return j;
}
1、
ADS1211.h
部分

#ifndef _ADS1211U_H
#define _ADS1211U_H

#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "Type.h"

/* AD采集芯片端口定义 */
#define ADS1211_SCLK_1() (GPIOPinWrite(GPIO_PORTD_BASE,
                                                  GPIO_PIN_4, GPIO_PIN_4))
#define ADS1211_SCLK_0()(GPIOPinWrite(GPIO_PORTD_BASE,
                                                 GPIO_PIN_4,~GPIO_PIN_4))
#define ADS1211_SDIO_1() (GPIOPinWrite(GPIO_PORTD_BASE,
                                               GPIO_PIN_5, GPIO_PIN_5))
#define ADS1211_SDIO_0() (GPIOPinWrite(GPIO_PORTD_BASE,
                                                  GPIO_PIN_5,~GPIO_PIN_5))

#define  ADS1211_SDOUT() (GPIOPinRead(GPIO_PORTD_BASE,
                                                GPIO_PIN_6))
#define  ADS1211_DRDY() (GPIOPinRead(GPIO_PORTD_BASE,  GPIO_PIN_7))
/* 函数接口 */
void Ads1211Init(void) ;
void WriteAds1211(INT8U Dat);
INT8U AdsReadData(INT32U *Dat,INT8U chn);
INT32U ADCmid_ADS1211(INT8U chn) ;
INT32U ADCave_ADS1211(INT8U chn,INT8U n) ;
#endif
2、Type.h部分

#ifndef _TYPE_H
#define _TYPE_H
/* 类型定义 */
typedef unsigned char INT8U;/* 无符号8位数*/
typedef signed charINT8S;/* 有符号8位数*/
typedef unsigned short int INT16U;/* 无符号16位数 */
typedef signed short int INT16S; /* 有符号16位数 */
typedef unsigned long intINT32U;/* 无符号32位数 */
typedef signed long int INT32S;/* 有符号32位数 */
typedef float FP32; /* 单精度浮点数 */
typedef double FP64; /* 双精度浮点数 */
typedef unsigned char tBoolean;
#endif

一周热门 更多>