嵌入式系统之ADC采样
嵌入式系统往往会有模拟信号的采集,比如模拟传感器温度、压力、流量、速度、光强等模拟量,经过放大整形滤波电路后送给ADC芯片,将电信号转转变成离散的数字量这个过程称之为AD采样,AD采样应用广泛,普遍遵循采样率3倍于信号变化频率的法则,也就是说我们采样的时间延迟在1/3信号变化延迟即可得到完美的信号变化特征。
嵌入式系统往往会有模拟信号的采集,比如模拟传感器温度、压力、流量、速度、光强等模拟量,经过放大整形滤波电路后送给ADC芯片,将电信号转转变成离散的数字量这个过程称之为AD采样,AD采样应用广泛,普遍遵循采样率3倍于信号变化频率的法则,也就是说我们采样的时间延迟在1/3信号变化延迟即可得到完美的信号变化特征。
通常情况下,A/D转换一般要经过取样、保持、量化及编码4个过程
根据A/D转换器的原理可将A/D转换器分成两大类。一类是直接型A/D转换器,将输入的电压信号直接转换成数字代码,不经过中间任何变量;另一类是间接型A/D转换器,将输入的电压转变成某种中间变量(时间、频率、脉冲宽度等),然后再将这个中间量变成数字代码输出。
广泛应用的主要有三种类型:逐次逼近式A/D转换器、双积分式A/D转换器、V/F变换式A/D转换器。
逐次逼近式(SAR)A/D转换器(SAR)的基本原理是:将待转换的模拟输入信号与一个推测信号进行比较,根据二者大小决定增大还是减小输入信号,以便向模拟输入信号逼进。推测信号由D/A转换器的输出获得,当二者相等时,向D/A转换器输入的数字信号就对应的时模拟输入量的数字量。这种A/D转换器一般速度很快,但精度实用常规精度要求。
双积分式A/D转换器的基本原理是:先对输入模拟电压进行固定时间的积分,然后转为对标准电压的反相积分,直至积分输入返回初始值,这两个积分时间的长短正比于二者的大小,进而可以得出对应模拟电压的数字量。这种A/D转换器的转换速度较慢,但精度较高。由双积分式发展为四重积分、五重积分等多种方式,在保证转换精度的前提下提高了转换速度。
Σ-Δ型AD由积分器、比较器、1位D/A转换器和数字滤波器等组成。原理上近似于积分型,将输入电压转换成时间(脉冲宽度)信号,用数字滤波器处理后得到数字值。电路的数字部分基本上容易单片化,因此容易做到高分辨率。主要用于音频和测量。这种转换器的转换精度极高,达到16到24位的转换精度,价格低廉,弱点是转换速度比较慢,比较适合用于对检测精度要求很高但对速度要求不是太高的检验设备。
V/F转换器是把电压信号转换成频率信号,由良好的精度和线性,而且电路简单,对环境适应能力强,价格低廉。适用于非快速的远距离信号的A/D转换过程。
MAX197芯片是Maxim公司推出的具有12位测量精度的高速A/D转换芯片,多量程(±10V,±5V,0~10V,0~5V)、8通道、12位高精度的A/D转换器。它采用逐次逼近工作方式,有标准的微机接口。
只需单一电源供电,且转换时间很短(6us),具有8路输入通道,还提供了标准的并行接口——8位三态数据I/O口,可以和大部分单片机直接接口,使用十分方便。
MAX197与其它A/D芯片不同之处在于它的很多硬件功能都是利用内部控制字来实现的,如通道选择、模拟信号量程、极性等。MAX197的输出数据采用无符号二进制模式(单极性输入方式)或二进制补码形式(双极性输入方式)。当CS和RD都有效时,HBEN为低电平,低8位数据被读出,HBEN为高电平,复用的高4位被读出,另外4位保持低电平(在单极性方式下),或另外4位为符号位(在双极性方式下)。
正确进行采集转换并读取数据的前提是必须正确设置控制字以及MAX197的各种控制信号。进行数据采集转换前都对MAX197进行初始化,以便确定其采集转换的通道、量程和极性等。
程序的编写可以采用查询和中断两种方式,其中查询方式是在查询相应的标志成立时,执行读取;而中断则通过把MAX197的INT引脚连接到单片机的外部中断引脚来实现。
以下是在pic32下采用MAX197进行多通道ADC采样的程序驱动,支持ucos-ii,可以实现自定义协议上位机实时通信在PC上展示实时的采样信号波形图,实际应用中,你还需要将数字信号转换成物理数值,这个就是典型的标定问题,以后我们接着讲。
//************************************************************
//Copyright(C)2010
// MAX197驱动源文件
//文件名称:MAX197DRIVER.c
//文件标识:(内参)
//摘 要:
// 1.配合头文件使用;
// 2.硬件参考作品;
// 3.
//
//当前版本:1.0
//作 者:xxd
//完成日期:2010.6.17
//
//取代版本:无
//原 作 者:无
//完成日期:无
//
//硬件说明:
//
// MAX197_Data ----------- PE0-7 (0-3--->adc 8-11复用)
// MAX197_CS ----------- PMCS2/RD10,nADCS
// MAX197_WR ----------- PMWR/RD4,nWR
// MAX197_RD ----------- PMRD/RD5,nRD
// MAX197_HBEN ----------- ETXEN/RD6,HBEN
// MAX197_INT ----------- CN19/RD13,ADINT
//
//使用查询法检测AD转换完毕
//***********************************************************
#define MAX197_GLOBALES
#include "MAX197DRIVER.h"
#define ADC_INT_MASK _PORTD_RD13_MASK
#define MAX197_INT (_RD13)//==ADC_INT_MASK)
//#define ADC_INT_BIT_IN_IDLE 0x2000 //BIT13为1,转换结束后此位为0,如果本引脚变化此值也需要变
//读写高低位引脚 ,高时读高4位,低时读低8位
#define MAX197_HBEN_LO _LATD6=0
//片选信号,低有效
#define MAX197_CS_LO _LATD10=0
//写信号,低有效
#define MAX197_WR_LO _LATD4=0
//读信号,低有效
#define MAX197_RD_LO _LATD5=0
#define MAX197_HBEN_HI _LATD6=1
#define MAX197_CS_HI _LATD10=1
#define MAX197_WR_HI _LATD4=1
#define MAX197_RD_HI _LATD5=1
//ADC Data Port 8Bit out 12Bit in PE0-3 复用作为高4位
//数据端口使用PORT E低8位
//数据端口输入输出方向设置
#define ADC_PORT_OUT TRISE=0x00
#define ADC_PORT_IN TRISE=0xFF
#define ADC_DATA_IN PORTE //直接读端口E
#define ADC_DATA_OUT LATE //写端口的寄存器
//#define USE_ADCINT 1 //采用中断读取的模式
//#define USE_ADCTIMER 1 //采用定时器中断采样
#define PRESCALE 64
#define TOGGLES_PER_SEC 200//10ms
#define ADC_TIMER_TICK (GetPeripheralClock()/TOGGLES_PER_SEC/PRESCALE)
//#ifdef USE_ADCINT
#define ADCIDLE_FLAG 0x01
static ADC ADCDrv[1];
//#endif
//*******************************************
//函数名称:void InitMAX197(void)
//函数功能:MAX197初始化
//形式参数:无
//行参说明:无
//返回参数:无
//使用说明:无
//*******************************************
void InitMAX197(void)
{
INT8U i,err;
ADC *pdev=NULL;
PORTSetPinsDigitalIn(IOPORT_D, BIT_13);
PORTSetPinsDigitalIn(IOPORT_E, BIT_0|BIT_1|BIT_2|BIT_3|BIT_4|BIT_5|BIT_6|BIT_7);
PORTSetPinsDigitalOut(IOPORT_D,BIT_4|BIT_5|BIT_6|BIT_10);
MAX197_CS_HI;
MAX197_WR_HI;
MAX197_RD_HI;
MAX197_HBEN_HI;
//本程序暂时采用IO查询的方式读取采样值
// 使用中断法时进行下列初始化,同时还要补充中断处理函数,这个函数并没有在该驱动中写明.
// ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
for(i=0;i<MAXADCCHANNELNUM;i++)
{
FRING_INIT (&pdev->adcchannel[i].adcin_id, NELEMENTS(pdev->adcchannel[i].adc_data));
pdev->adcchannel[i].nChannelID=i;
pdev->adcchannel[i].samplerate=2;//2毫秒一次,采样频率,以1ms为单位,可以通过应用程序设置
pdev->adcchannel[i].samplecounter=0; //采样时间间隔计数器,系统中断里更新,到达采样频率值时,触发采样函数
pdev->adcchannel[i].sampledot=ADC_DOT; //一次物理量计算值的点数,不得大于ADC_DOT即10个点,缓冲区里有这么多数据时通知应用程序取数并计算平均值
pdev->adcchannel[i].bStart=FALSE;
pdev->adcchannel[i].adcin_id.data=&pdev->adcchannel[i].adc_data[0];
pdev->adcchannel[i].semadcdataok=OSSemCreate(0);//通道间切换互斥保护
}
#ifdef USE_ADCINT
CNCON =_BIT(15); //CNCONjicun /* Enable the change notice module */
ConfigCNPullups(CN19_PULLUP_ENABLE); /* Enable a weak pull-up corresponding to the CN pin */
//dummy_read = PORTD; /* Perform a dummy read to clear any mismatch conditions */
EnableCN19; /* Enable change notice pin 19, tied to our push button */
mCNClearIntFlag();
/* Clear the int flag just in case it was triggered */
ConfigIntCN(CHANGE_INT_ON| CHANGE_INT_PRI_3); /* Enable CN interrupts at priority level 3 */
#endif
pdev->flagadcready=OSFlagCreate(ADCIDLE_FLAG,&err);//通道间切换互斥保护
pdev->init = TRUE;
#ifdef USE_ADCTIMER
//timer2用于adc定时采样
//Clear interrupt flag
mT2ClearIntFlag();
// Setup Timer 3
OpenTimer2(T2_ON |T2_SOURCE_INT | T2_PS_1_64, ADC_TIMER_TICK);
// set up the timer interrupt with a priority of 2
ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2|T2_INT_SUB_PRIOR_1);
mT2IntEnable(1);
/*
T2CON = 0x0; // Stop Timer and clear control register
T2CONSET = 0x0020; // Set prescaler at 1:64, internal clock source
TMR2 = 0x0; // Clear timer register
PR2 = ADC_TIMER_TICK; // Load period register
T2CONSET = 0x8000; // Start Timer
mT2SetIntPriority(1);
mT2IntEnable(1);
*/
#endif
}
/*
//根据补码进行转换
#if ((Vref_RANG== Vref_RANG_10_10)||(Vref_RANG== Vref_RANG_5_5))//双极性
// 2|FS|
//1LSB=-------------
// 4096
//-FS-----+FS (-5---+5/-10---+10)
void ADC_RAW_CONV_VOLT(INT16S adcraw,FP32 *rdata)
{
FP32 adc_volt=0.0f;
INT16S adc_raw=adcraw;
if((adc_raw&BIT_MASK_HI(11))==BIT_MASK_HI(11))
{
adc_raw=adc_raw-(MANPIAN-1);
}
adc_volt=(FP32)((FP32)(adc_raw*ADC_REF_VCC)/(MANPIAN));
*rdata=adc_volt;
}
#else //单极性
// FS
//1LSB=-------------
// 4096
//FS(5/10)
void ADC_RAW_CONV_VOLT(INT16S adcraw,FP32 *rdata)
{
*rdata=(FP32)(adcraw*ADC_REF_VCC/(MANPIAN));
}
#endif
*/
//*******************************************
//函数名称:void MAX197SampleVolteWithInterAcq(INT8U ucChannel)
//函数功能:MAX197以内部获取方式采集电压
//形式参数:INT8U ucChannel
//行参说明:输入通道号,取值范围:0~7
//返回参数:无
//使用说明:
//MAX197寄存器设置:
// 控制字格式:
// D7(MSB) D6 D5 D4 D3 D2 D1 D0(LSB)
// PD1 PD0 ACQMOD RNG BIP A2 A1 A0
// 控制字说明:
// PD1,PD0 ----- 选择时钟和掉电模式
// ACQMOD ----- 0:内部获取模式;1:外部获取模式
// RNG ----- 选择满幅输入电压
// BIP ----- 选择输入极性
// A2,A1,A0 ----- 选择输入通道
//
// PD1,PD0 ----- 00:一般模式/外部时钟
// 01:一般模式/内部时钟
// 10:Standby Power-Down/时钟不受影响
// 11:Full Power-Down (FULLPD)/时钟不受影响
//
// RNG,BIP ----- 00: 0V ~ +5V
// 01:-5V ~ +5V
// 10: 0V ~ +10V
// 11:-10V~ +10V
//
// A2,A1,A0 ----- 000:CH0
// 001:CH1
// 010:CH2
// 011:CH3
// 100:CH4
// 101:CH5
// 110:CH6
// 111:CH7
//*******************************************
int MAX197SampleVolteWithInterAcq(INT8U ucChannel,FP32 *sampvalue)
{
FP32 voltvalue,voltvalue1;
INT16U status=0,Cnt=500;
INT16U i;
INT8U err;
INT16S ConverValTemp =0;
ADC *pdev=NULL;
OS_FLAGS adcflag;
pdev=&ADCDrv[0];
INT8U temp =ACQMOD_INT| Vref_RANG | ucChannel;//内部获取模式,内部时钟,输入范围0~5V外部定义
pdev->nCurChannel=ucChannel;
writeByteto_MAX197(temp);
while(MAX197_INT&&Cnt--); //等待转换结束
ConverValTemp = ReadByteFrom_MAX197();
#ifdef CONVERT_TO_VOLT
ADC_RAW_CONV_VOLT(ConverValTemp,sampvalue);
voltvalue=*sampvalue;
#else
*sampvalue=voltvalue=0;
#endif
return ConverValTemp;
}
int MAX197SampleVolteWithInterAcqUseSampleRate(INT8U ucChannel,INT16S *adcRaw,FP32 *sampvalue,INT8U *adcHiByte,INT8U *adcLoByte)
{
FP32 voltvalue,voltvalue1;
INT16U status=0,Cnt=500;
INT8U err,i;
INT16S ConverValTemp =0;
ADC *pdev=NULL;
OS_FLAGS adcflag;
pdev=&ADCDrv[0];
INT8U temp =ACQMOD_INT| Vref_RANG | ucChannel;
//采用内部采样步进计数器实现采样频率控制,采样间隔时间
if(pdev->adcchannel[ucChannel].bStart)//本通道如果采样启动,则进入采样时序
{
if(pdev->adcchannel[ucChannel].samplecounter++>=pdev->adcchannel[ucChannel].samplerate)
{
//采样频率到,触发采样
pdev->adcchannel[ucChannel].samplecounter=0;
pdev->nCurChannel=ucChannel;
writeByteto_MAX197(temp);
}
else return 0;
}
else return 0;
while(MAX197_INT&&Cnt--); //等待转换结束
*adcRaw=ConverValTemp = ReadByteFrom_MAX197_1(adcHiByte,adcLoByte);
#ifdef CONVERT_TO_VOLT
// *sampvalue=voltvalue=ADC_LSB(ConverValTemp);
ADC_RAW_CONV_VOLT(ConverValTemp,sampvalue);
voltvalue=*sampvalue;
#else
*sampvalue=voltvalue=0;
#endif
//FRING_GETC(&pdev->adcchannel[pdev->nCurChannel].adcin_id,voltvalue1);
FRING_PUTC(&pdev->adcchannel[ucChannel].adcin_id,voltvalue);
if(FRING_COUNT(&pdev->adcchannel[ucChannel].adcin_id)>=pdev->adcchannel[ucChannel].sampledot)
OSSemPost(pdev->adcchannel[ucChannel].semadcdataok);
//采样数据读取完毕,设置ADC空闲标志,以进行下一次采样
// OSFlagPost(pdev->flagadcready, ADCIDLE_FLAG,OS_FLAG_SET,&err);
return 1;
}
//1 busy 0 ok
int StartADCWithInterAcq(INT8U ucChannel)
{
INT8U err;
ADC *pdev=NULL;
OS_FLAGS adcflag;
INT8U temp =ACQMOD_INT| Vref_RANG | ucChannel;//内部获取模式,内部时钟,输入范围0~5V外部定义
pdev=&ADCDrv[0];//只有一个ADC芯片
//if(OSSemAccpet(pdev->semadcready,0,&err);
//adcflag = OSFlagAccept(pdev->flagadcready, // 调用等事件标志组函数
// ADCIDLE_FLAG,
// OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME,
// &err);
//adcflag = OSFlagAccept(pdev->flagadcready, // 调用等事件标志组函数
adcflag = OSFlagPend(pdev->flagadcready, // 调用等事件标志组函数
ADCIDLE_FLAG,
OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME,
10,
&err);
if(adcflag!=ADCIDLE_FLAG) return 1;
//可以进行采样则清标识,启动采样
OSFlagPost(pdev->flagadcready,
ADCIDLE_FLAG,
OS_FLAG_CLR,
&err);
pdev->nCurChannel=ucChannel;
writeByteto_MAX197(temp);
return 0;
/*
OSSemPend(pdev->adcchannel[ucChannel].semadcdataok,0,&err);
//ReadADCValue
if(FRING_COUNT(&pdev->adcchannel[ucChannel].adcin_id)>0)
{
FRING_GETC(&pdev->adcchannel[ucChannel].adcin_id,value);
*sampvalue=value;
}
*/
}
//由应用程序调用,等待采样点数足够后计算
void WaitReadNumsADCComplete(INT8U ucChannel,FP32 *sampvalue,INT16U to,INT8U *perr,BOOLEAN bWaitMode)
{
INT8U i;
ADC * pdev=NULL;
float MaxValue=-10.0f,MinValue=10.0f;
float TotalValue=0.0f;
float tempvalue=0.0f;
pdev=&ADCDrv[0];
if(!bWaitMode)
{
if(OSSemAccept(pdev->adcchannel[ucChannel].semadcdataok)==0)
{
*perr=OS_ERR_TIMEOUT;
return;
}
*perr=OS_ERR_NONE;
}
else
{
OSSemPend(pdev->adcchannel[ucChannel].semadcdataok,to,perr);
if(*perr!=OS_ERR_NONE) return;
}
//ReadADCValue
for(i=0;i<pdev->adcchannel[ucChannel].sampledot;i++)
{
if(FRING_COUNT(&pdev->adcchannel[ucChannel].adcin_id)>0)
{
FRING_GETC(&pdev->adcchannel[ucChannel].adcin_id,tempvalue);
//*sampvalue=value;
if( tempvalue<MinValue )
MinValue=tempvalue;
if( tempvalue>MaxValue )
MaxValue=tempvalue;
TotalValue+=tempvalue;
}
else
break;
}
if(i>2)
*sampvalue=(TotalValue-MaxValue-MinValue)/(i-2);
else if(i>0) *sampvalue=(TotalValue)/(i);
else
{
*sampvalue=0;
FRING_FLUSH(&pdev->adcchannel[ucChannel].adcin_id);
*perr=OS_ERR_TIMEOUT;
}
}
void ReadADCValue()
{
INT8U err;
ADC * pdev=NULL;
INT16S ConverValTemp =0;
FP32 voltvalue,voltvalue1;
ConverValTemp = ReadByteFrom_MAX197();
//voltvalue=ADC_LSB(ConverValTemp);
ADC_RAW_CONV_VOLT(ConverValTemp,&voltvalue);
pdev=&ADCDrv[0];
//FRING_GETC(&pdev->adcchannel[pdev->nCurChannel].adcin_id,voltvalue1);
FRING_PUTC(&pdev->adcchannel[pdev->nCurChannel].adcin_id,voltvalue);
if(FRING_COUNT(&pdev->adcchannel[pdev->nCurChannel].adcin_id)>=pdev->adcchannel[pdev->nCurChannel].sampledot)
OSSemPost(pdev->adcchannel[pdev->nCurChannel].semadcdataok);
//采样数据读取完毕,设置ADC空闲标志,以进行下一次采样
OSFlagPost(pdev->flagadcready, ADCIDLE_FLAG,OS_FLAG_SET,&err);
}
//*******************************************
//函数名称:void MAX197SampleVolteWithExterAcq(INT8U ucChannel)
//函数功能:MAX197以外部获取方式采集电压
//形式参数:INT8U ucChannel
//行参说明:输入通道号,取值范围:0~7
//返回参数:无
//使用说明:
//MAX197寄存器设置:
// 控制字格式:
// D7(MSB) D6 D5 D4 D3 D2 D1 D0(LSB)
// PD1 PD0 ACQMOD RNG BIP A2 A1 A0
// 控制字说明:
// PD1,PD0 ----- 选择时钟和掉电模式
// ACQMOD ----- 0:内部获取模式;1:外部获取模式
// RNG ----- 选择满幅输入电压
// BIP ----- 选择输入极性
// A2,A1,A0 ----- 选择输入通道
//
// PD1,PD0 ----- 00:一般模式/外部时钟
// 01:一般模式/内部时钟
// 10:Standby Power-Down/时钟不受影响
// 11:Full Power-Down (FULLPD)/时钟不受影响
//
// RNG,BIP ----- 00: 0V ~ +5V
// 01:-5V ~ +5V
// 10: 0V ~ +10V
// 11:-10V~ +10V
//
// A2,A1,A0 ----- 000:CH0
// 001:CH1
// 010:CH2
// 011:CH3
// 100:CH4
// 101:CH5
// 110:CH6
// 111:CH7
//*******************************************
int MAX197SampleVolteWithExterAcq(INT8U ucChannel,FP32 *sampvalue)
{
INT16 i=0;
INT32 ConverValTemp;
INT8U temp = ACQMOD_EXT| Vref_RANG | ucChannel;//ACQMOD=1,外部获取模式,内部时钟,输入范围0~5V外部定义
writeByteto_MAX197(temp);
while(MAX197_INT); //等待转换结束
ConverValTemp = ReadByteFrom_MAX197();
#ifdef CONVERT_TO_VOLT
//*sampvalue=ADC_LSB(ConverValTemp);
ADC_RAW_CONV_VOLT(ConverValTemp,sampvalue);
#else
*sampvalue=0;
#endif
return ConverValTemp;
}
void writeByteto_MAX197(unsigned char Dat)
{
//PORTSetPinsDigitalOut(IOPORT_E, BIT_0|BIT_1|BIT_2|BIT_3|BIT_4|BIT_5|BIT_6|BIT_7);
ADC_PORT_OUT;
MAX197_CS_LO;
asm("nop");
MAX197_WR_LO;
asm("nop");
ADC_DATA_OUT=Dat;
asm("nop");
MAX197_CS_HI;
asm("nop");
MAX197_WR_HI;
ADC_PORT_IN;
}
INT16S ReadByteFrom_MAX197()
{
INT16S ADCDat;
INT8U hi_byte;
INT8U low_byte;
ADC_PORT_IN;
ADCDat=0;
hi_byte=low_byte=0;
MAX197_HBEN_HI;
asm("nop");
MAX197_CS_LO;
asm("nop");
asm("nop");
MAX197_RD_LO;
asm("nop");
asm("nop");
asm("nop");
hi_byte = ADC_DATA_IN;
asm("nop");
MAX197_HBEN_LO;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
low_byte = ADC_DATA_IN;
ADCDat=(hi_byte&0x0F);
ADCDat <<= 8;
ADCDat |= low_byte;
MAX197_RD_HI;
asm("nop");
MAX197_CS_HI;
return ADCDat;
}
INT16S ReadByteFrom_MAX197_1(INT8U *adcHiByte,INT8U *adcLoByte)
{
INT16S ADCDat;
INT8U hi_byte;
INT8U low_byte;
ADC_PORT_IN;
ADCDat=0;
hi_byte=low_byte=0;
MAX197_HBEN_HI;
asm("nop");
MAX197_CS_LO;
asm("nop");
asm("nop");
MAX197_RD_LO;
asm("nop");
asm("nop");
asm("nop");
*adcHiByte=hi_byte = ADC_DATA_IN;
asm("nop");
MAX197_HBEN_LO;
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
*adcLoByte=low_byte = ADC_DATA_IN;
ADCDat=(hi_byte&0x0F);
ADCDat <<= 8;
ADCDat |= low_byte;
MAX197_RD_HI;
asm("nop");
MAX197_CS_HI;
return ADCDat;
}
//调用ADC采样触发,根据配置的采样频率,最快每一毫秒采样一次,并将结果存储在buffer,
//直到采样到足够的点数后通知应用程序取数据并计算
void ADC_Sample()
{
INT8U i;
// static int i=0;
ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
for(i=0;i<MAXADCCHANNELNUM;i++)
{
if(pdev->adcchannel[i].bStart)//本通道如果采样启动,则进入采样时序
{
if(pdev->adcchannel[i].samplecounter++>=pdev->adcchannel[i].samplerate)
{
//采样频率到,触发采样
pdev->adcchannel[i].samplecounter=0;
if(StartADCWithInterAcq(i)==1)
{
//i--;
}
}
}
}
}
void ADCSampleReset()
{
}
BOOLEAN GetADCChannelStatus(INT8U nChannel)
{
ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
if(pdev!=NULL)
return (pdev->adcchannel[nChannel].bStart);
else
return FALSE;
}
//启动或停止某物理通道采样 ,有应用程序控制
void ADC_Sample_Config(INT8U nChannel,INT32U samplerate,INT8U sampledot,BOOLEAN bstart)
{
INT8U err;
ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
if(samplerate>=1)
pdev->adcchannel[nChannel].samplerate=samplerate;
if((sampledot>=3)&&(sampledot<=ADC_DOT))
pdev->adcchannel[nChannel].sampledot=sampledot;
//清空缓冲区
FRING_FLUSH(&pdev->adcchannel[nChannel].adcin_id);
//清信号量
OSSemSet(pdev->adcchannel[nChannel].semadcdataok,0,&err);
pdev->adcchannel[nChannel].bStart=bstart;
}
//暂停采样
void ADC_Pause(INT8U nChannel)
{
ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
pdev->adcchannel[nChannel].bStart=FALSE;
}
//启动采样,必须先配置通道,不然将采用默认值进行采样
void ADC_Start(INT8U nChannel)
{
INT8U err;
ADC *pdev=NULL;
pdev=&ADCDrv[0];//只有一个ADC芯片
//清空缓冲区
FRING_FLUSH(&pdev->adcchannel[nChannel].adcin_id);
//清信号量
OSSemSet(pdev->adcchannel[nChannel].semadcdataok,0,&err);
pdev->adcchannel[nChannel].bStart=TRUE;
}
/*******************************************************************************
* Function Name : TIMx_IRQHandler
* Description : This function handles TIMx Update interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
#ifdef USE_IRQ_MAC
void __attribute__( (interrupt(ipl1), vector(8))) BSP_TIM2ISR( void );
#endif
void TIM2_IRQHandler(void)
{
mT2ClearIntFlag();
#ifdef USE_ADCTIMER
ADC_Sample();
#endif
}
/*
*********************************************************************************************************
* BSP_CNHandler()
*
* Description: This function handles change notice interrupts.
*
* Arguments : None
*
* Returns : None
*
* Notes : Each push of the user push button will actually generate 2 interrupts, as there will actually be
* two changes of state with the IO pin. However, since the second generation occurs as the pin returns
* to its original state there is no simple way to reliably detect which pin generated this interrupt.
* In this implementation only the initial change notice interrupt is serviced.
*********************************************************************************************************
*/
#ifdef USE_IRQ_MAC
void __attribute__( (interrupt(ipl1), vector(26))) BSP_CNISR( void );
#endif
void ADC_CNHandler (void)
{
CPU_INT32U reg_val;
reg_val = PORTD; /* Read register to clear change notice mismatch condition */
if ((reg_val & ADC_INT_MASK) == 0) {
ReadADCValue(); /* Insert your application code here */ /* Insert your application code here */
}
mCNClearIntFlag();
}
BOOLEAN GetSampleValue(INT8U nchannel,FP32* fVoltValue)
{
INT8U err,adchiByte,adcloByte;
INT16U adcRaw;
FP32 adc_value,adc_value1;
if(nchannel>=MAXADCCHANNELNUM) return FALSE;
do{
if(GetADCChannelStatus(nchannel))
{
if(MAX197SampleVolteWithInterAcqUseSampleRate(nchannel,&adcRaw,&adc_value1,&adchiByte,&adcloByte))
{
}
//由应用程序调用,查询采样点数足够后计算
WaitReadNumsADCComplete(nchannel,fVoltValue,10,&err,FALSE);
if(err==OS_ERR_NONE)
{
//超级终端中显示
return TRUE;
}
//else return FALSE;
//OSTimeDly(1);
//DelayNS()
BSP_Dly(100);
}
else return FALSE;
}while(1);
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)