📄 ads1241drv.c
字号:
#include "ADS1241Drv.h"
#include "stdio.h"
#include "hal_types.h"
#define SET 1
#define CLEAR 0
#define RESET 0
/* for gain=128 */
#define OneUE 518.5 //GAIN=128 ACR.2 = 1 ACR=0x04,but 518.5 can't be modified,otherwise, the ADS result is constant
#define ratioEVB 1.4946 // final value = OneUE/ratio
#define ratio 1.4924
/* for gain=64 */
// #define OneUE 389.0155 //GAIN=64 maxim range is +/-20000 ACR.2 = 1 ACR=0x04,but 518.5 can't be modified,otherwise, the ADS result is constant
#define N 6 // number of samples to be average
struct CHINFO Chan[3];
uint8 AcqData[12];
/*****************************************************************************
******************* UART0 SPI & ADC DataReady Pin***************************
*****************************************************************************/
extern unsigned char spi_xfer(unsigned char out);
void spi_select(void);
void spi_deselect(void);
void ADS1241_SleepWait(uint16 duration);
#define spi_in spi_xfer
#define spi_out spi_xfer
// spi_xfer - Exchange bytes with the SPI port
//
// Here is the workhorse routine for this module. spi_xfer will initiate a
// data transfer on the SPI port. Since the SPI protocol is an 'exchange'
// protocol, a read and a write operation are identical.
//
// On input, byte contains the byte value to send OUT the SPI port.
// On exit, the byte shifted in is the return value
//
/*
unsigned char spi_xfer(unsigned char out)
{
// Shift a byte out, wait for result, return shifted in byte
U1DBUF = out;
while (!rxFlag){}
rxFlag=FALSE; // Wait until SPI Tx empty & Rx Full
return (b);
}
*/
//
// spi_in and spi_out only differ in the way they report the action to the
// user. On a non-debug system, spi_xfer is the real routine to work with
//
//
// The following two worker routines select and deselect the EEPROM. By
// raising and lowering the CS line. If you wire up the SPI port differently,
// then put the code in here that maintains the CS line for the EEPROM.
//
void spi_select(void)
{
// Lower the CS line
CS = CLEAR; // set SS low
}
void spi_deselect(void)
{
// Raise the CS line
CS = SET;
}
void CS1241_SndComm(unsigned char CMD, unsigned char RegName, unsigned char RegValue)
{
unsigned char OUTBYTE;
OUTBYTE=CMD;
if(OUTBYTE==CS1241_WREG){
OUTBYTE=OUTBYTE+RegName;
}
spi_out(OUTBYTE);
if(OUTBYTE==(CS1241_WREG+RegName)) {
spi_out(0);
spi_out(RegValue);
}
}
unsigned char CS1241_ReadReg(unsigned char RegName)
{
unsigned char OUTBYTE,dummy=0;
OUTBYTE=CS1241_RREG+RegName;
dummy=spi_out(OUTBYTE);
dummy=spi_out(0);
dummy=spi_out(0);
return dummy;
}
void CS1241_Setup(void)
{
// unsigned char RegValue;
unsigned char i;
for (i=0;i<3;i++)
{
Chan[i].available=CLEAR;
Chan[i].type=NEGHALF;
}
spi_select();
CS1241_SndComm(CS1241_RESET,0,0);
CH1EXEN ; // channel 1 bridge EXC enable
CS1241_SndComm(CS1241_WREG,CS1241_DIO,CH1SEL); // AD704 Muliplex Set to Channel 1
CS1241_SndComm(CS1241_WREG,CS1241_DIR,0);
CS1241_SndComm(CS1241_WREG,CS1241_IOCON,0xC0); // AIN7&AIN6 are defined as D7&D6, for output control ADG709 EX1-3 select,others for ADC input
CS1241_SndComm(CS1241_WREG,CS1241_MUX,CHCOMN|CH1P);
// CS1241_SndComm(CS1241_WREG,CS1241_MUX,CH1P|CHCOMN);
// CS1241_SndComm(CS1241_WREG,CS1241_ACR,0x00);
CS1241_SndComm(CS1241_WREG,CS1241_ACR,0x04|DR15); // ACR.2=1 AVDD=3.3 Vref<=2.5
/* Read Register Value example
RegValue = CS1241_ReadReg( CS1241_ACR );
printf("ACR Value = %bx\n",RegValue);
RegValue = CS1241_ReadReg( CS1241_IOCON );
printf("IOCON Value = %bx\n",RegValue);
*/
// DRDY =0 before this command
CS1241_SndComm(CS1241_GCALSELF,0,0); // DRDY jumps to high for 500ms and go back to low and stay at low forever
while(!ADS1241_DataReady){} // wait here for DRDY low to High
while (ADS1241_DataReady){} /* wait for DRDY high to low */
CS1241_SndComm(CS1241_WREG,CS1241_SETUP,GAIN128);
// CS1241_SndComm(CS1241_WREG,CS1241_SETUP,BDMASK|GAIN128);//pga=128 with burnout current source for testing full bridge channel valid only
CS1241_SndComm(CS1241_OCALSELF,0,0);
while(!ADS1241_DataReady){}
while(ADS1241_DataReady){}; // wait for interrupt
// printf("cs1241 selfcal end up!\n");
CS1241_Sleep();
}
/**********************************************************
Function Name: CS1241_ADC
Function: do one time ADC convert
input:none
output: ADC RAW data
*********************************************************/
int32 CS1241_ADC(void)
{
unsigned char i=0;
union ADC_Data Result;
CS1241_SndComm(CS1241_RDATA,0,0);
Result.buf[3]=0;
// here the storage is different than MSC1210,buf[0] stores the LSB. MSB first
for(i=3;i>0;i--){
Result.buf[i-1] = spi_out(0);
// printf("Result.buf[%bx]=%bx \n",i,Result.buf[i]);
}
if(Result.buf[2]>0x7f){Result.buf[3]=0xff;}
return Result.dat;
}
/**********************************************************
Function Name: CS1241_SetChannel
Function: configure CS1241's register according to Channel's config
let channel ready for ADC convert
input:channel number, Bridge type
output: none
*********************************************************/
void CS1241_SetChannel(char ChanNum, char Btype)
{
uint8 PosInput,NegInput;
uint8 ChanSel;
switch(ChanNum)
{
case 0: CH1EXEN; // enable EX1,disable EX2,EX3
ChanSel=CH1SEL;
PosInput=CH1P;
NegInput=CH1N;
break;
case 1: CH2EXEN; // enable EX2,disable EX1,EX3
ChanSel=CH2SEL;
PosInput=CH2P;
NegInput=CH2N;
break;
case 2: CH3EXEN; // enable EX3,disable EX1,EX2
ChanSel=CH3SEL;
PosInput=CH3P;
NegInput=CH3N;
break;
default: break;
}
if(Btype==NEGHALF){ // if Half Bridge Configuration
NegInput=CHCOMN;
}
else if(Btype==POSHALF){ // if Half Bridge Configuration
PosInput=CHCOMN;
}
CS1241_SndComm(CS1241_WREG,CS1241_DIO,ChanSel); // Select Channel
CS1241_SndComm(CS1241_WREG,CS1241_MUX,NegInput|PosInput); // Select Postive Input and Negative Input Pins
ADS1241_SleepWait(5); //delay 5 mS
}
/**********************************************************
Function Name: CS1241_GetData
Function: do one time sensor Raw test
input:none
output: sensor Raw data(in physical unit)
*********************************************************/
signed long CS1241_GetData(void)
{
uint8 i;
float ADC_AVG;
signed long RawData[N];
for(i=0;i<4;i++){
while(!ADS1241_DataReady){}
while(ADS1241_DataReady){}
RawData[0]=CS1241_ADC();
}
ADC_AVG=0;
for(i=0;i<N;i++){
//WAIT FOR DATA READY SIGNAL FALLING EDGE
while(!ADS1241_DataReady){}
while(ADS1241_DataReady){}
// WAIT END
RawData[i]=CS1241_ADC();
ADC_AVG= ADC_AVG+RawData[i];
}
ADC_AVG = ADC_AVG/N;
ADC_AVG=ADC_AVG/((float)OneUE*(float)ratio);
return ((signed long)ADC_AVG);
}
/**********************************************************
Function Name: CS1241_ValidateChan
Function: find channal availability and Bridge Type
Method: First do Negative Half Test!if True,then HALF
bridge exist on this channel, if FALSE,the
channel is empty. then do Positive Half Bridge
Test for all channels with HALF bridge exist,
if TRUE,the another half Brige also exists,then it is
a FULL bridge.
*********************************************************/
void CS1241_ValidateChan(void)
{
uint8 i;
signed long Result;
// CS1241_SndComm(CS1241_WREG,CS1241_SETUP,GAIN128);
// CS1241_SndComm(CS1241_WREG,CS1241_SETUP,BDMASK|GAIN128); // for Full Bridge Test,enable Burnout current Source
/* ABC half bridge TEST */
for (i=0;i<3;i++){
CS1241_SetChannel(i,NEGHALF);
Result=CS1241_GetData();
if((Result<10300)&&(Result>-10300))
{
Chan[i].available=TRUE;
Chan[i].type=NEGHALF;
}
else {
Chan[i].available=FALSE;
}
}
/* ADC half brdige TEST for channles which already have ABC half bridge exist*/
for (i=0;i<3;i++){
if(Chan[i].available==TRUE)
{
/* ADC half brdige TEST */
CS1241_SetChannel(i,POSHALF);
Result=CS1241_GetData();
if((Result<10300)&&(Result>-10300))
{
Chan[i].available=TRUE;
Chan[i].type=FULL;
}
}
}
}
/**********************************************************
Function Name: CS1241_ScanChan
Function: Get One Channel Data according to this Channel's Config
the Config data get from ValidateChan
Input: Channel Number 0-3
Output: Unbalanced data
*********************************************************/
signed long CS1241_ScanChan(char ChanNum)
{
signed long Result=0;
if(Chan[ChanNum].available){
if(Chan[ChanNum].type==FULL)
{
CS1241_SetChannel(ChanNum,FULL);
}
else
{
CS1241_SetChannel(ChanNum,NEGHALF);
}
Result=CS1241_GetData();
}
return Result;
}
/**********************************************************
Function Name: CS1241_DoTest
Function: Get all Channels Data,and do balance,and flash
Data structure,called by High Level Logic level
responding to a data request
Input: TestType--unbalance/balance
Output: none
*********************************************************/
void CS1241_DoTest(char TestType)
{
uint8 i,*pBuf;
float ACQdata;
pBuf = AcqData;
CS1241_WakeUp();
if(TestType==UNBALANCE){
pBuf = AcqData;
CS1241_ValidateChan();
for(i=0;i<3;i++){
if(Chan[i].available) {
ACQdata = CS1241_ScanChan(i);
// ACQdata/= (float)ratio;
Chan[i].iniData.dat=(signed long)ACQdata;
}
else {
Chan[i].iniData.dat=0x7fffffff;
}
*pBuf++=Chan[i].iniData.buf[0];
*pBuf++=Chan[i].iniData.buf[1];
*pBuf++=Chan[i].iniData.buf[2];
*pBuf++=Chan[i].iniData.buf[3]; // buf[3] is MSB,valid data should be 0(Positive) or 0xff(Negative)
}
}
else{
pBuf = AcqData;
for(i=0;i<3;i++){
if(Chan[i].available) {
ACQdata = CS1241_ScanChan(i);
// ACQdata/= (float)ratio;
Chan[i].Data.dat=(signed long)ACQdata;
Chan[i].Data.dat=Chan[i].Data.dat-Chan[i].iniData.dat;
}
else {Chan[i].Data.dat=0x7fffffff;}
*pBuf++=Chan[i].Data.buf[0];
*pBuf++=Chan[i].Data.buf[1];
*pBuf++=Chan[i].Data.buf[2];
*pBuf++=Chan[i].Data.buf[3]; //buf[3] is MSB,valid data should be 0(Positive) or 0xff(Negative)
}
}
CS1241_Sleep();
}
void CS1241_Sleep(void)
{
CHEXDIS; // disable all output of mic5205-2.5 to save power
CS1241_SndComm(CS1241_SLEEP,0,0);
}
void CS1241_WakeUp(void)
{
CS1241_SndComm(CS1241_WAKEUP,0,0);
}
void ADS1241_SleepWait(uint16 duration)
{
while (duration--)
{
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -