嵌入式系统之ADC采样

news2024/11/26 17:40:31

         嵌入式系统往往会有模拟信号的采集,比如模拟传感器温度、压力、流量、速度、光强等模拟量,经过放大整形滤波电路后送给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); 
 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/740179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES 知识体系

https://www.easyice.cn/archives/367

【力扣算法03】之正则表达式匹配- python

文章目录 问题描述示例 1示例2示例3提示 思路分析代码分析完整代码运行效果及示例代码示例代码1运行结果示例代码2运行结果示例代码3运行结果 完结 问题描述 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 ‘.’ 和 ‘’ 的正则表达式匹配。 ‘.’ 匹配任意…

企业省时又省力:人工智能电话客服机器人的广泛应用

人工智能技术的崛起正深刻地改变着各个行业&#xff0c;其中之一便是客服领域。过去&#xff0c;人们常常在电话中与生硬的自动语音应答机打交道&#xff0c;这种体验常常令人沮丧。然而&#xff0c;随着人工智能电话客服机器人的广泛应用&#xff0c;企业不仅能够省时又省力&a…

MYSQL数据库系统期末试题及参考答案(2)

期末试题 : 一&#xff0c;创建数据库Game 二&#xff0c;数据表操作 1、创建表格players&#xff0c;记录游戏玩家信息&#xff1a; player_id&#xff1a;玩家ID&#xff0c;主键 player_name&#xff1a;玩家姓名&#xff0c;不能为空 age&#xff1a;年龄&#xff0c;必须…

Python数据分析常见Matplotlib SeaBorn图表

Matplotlib绘图 Matplotlib基本概念 Matplotlib&#xff1a;基于对象的思维构建的视觉符号。 每一个Axes&#xff08;坐标轴&#xff09;对象包含一个或者多个Axis(轴)对象&#xff0c;比如X轴、Y轴。 一个Figure&#xff08;画像&#xff09;是由一堆坐标轴对象组成的。 换…

2023中国数交会|美创科技获数字和软件服务行业两项大奖!

7月6日-9日&#xff0c;为期四天的2023中国国际数字和软件服务交易会&#xff08;简称&#xff1a;数交会&#xff09;圆满落幕。 作为国务院批准举办的国家级展会&#xff0c;本届数交会由商务部、科技部、中国贸促会和辽宁省政府主办&#xff0c;以“数字创新、融合发展”为主…

操作系统实战45讲|03.黑盒之中有什么、04.震撼的Linux全景图

03.黑盒之中有什么 黑盒之中有什么 从抽象的角度来看&#xff0c;内核就是计算机资源的管理者&#xff0c;管理资源是为了让应用使用资源。 计算机中的资源分为两类&#xff1a;硬件资源、软件资源&#xff1b; 硬件资源有以下这些&#xff1a; 总线&#xff0c;负责连接各种…

一个Transformer在尺度上适合多模态扩散的所有分布

文章目录 One Transformer Fits All Distributions in Multi-Modal Diffusion at Scale摘要本文方法实验结果 One Transformer Fits All Distributions in Multi-Modal Diffusion at Scale 摘要 本文提出了一个统一的扩散框架(UniDiffuser)来拟合一个模型中与一组多模态数据相…

Vue3+Vite+Pinia+Naive后台管理系统搭建之三:vue-router 的安装和使用

前言 如果对 vue3 的语法不熟悉的&#xff0c;可以移步 Vue3.0 基础入门快速入门。 如果对 vue-router 语法不熟悉的&#xff0c;可以移步Vue3 系列&#xff1a;vue-router。 1. 安装依赖 yarn add vue-router // or npm install vue-router 2. 构建 src/router/index.js …

对话式ai人工智能的主要好处有哪些

对话式 AI 是客户服务的一个重要且不断增长的组成部分&#xff0c;尤其是客户越来越多地采用的数字自助服务。 对话式 AI 可以在提高客户满意度 (CSAT) 方面发挥很重要的作用。在 IBM 于 2021 年进行的一项研究中&#xff0c;99% 的公司报告称&#xff0c;由于使用虚拟对话式 …

支持源码的低代码核心工具,逻辑引擎

在现代企业管理中&#xff0c;决策扮演着至关重要的角色。然而&#xff0c;随着业务规模的扩大和数据量的增加&#xff0c;人工决策变得越来越困难和耗时&#xff0c;而且容易受到主观因素的影响。逻辑引擎的出现为企业提供了一种高效、准确的决策推理工具&#xff0c;能够以逻…

数字化转型迫在眉睫

在挑战商业世界现状并实现数字化转型时&#xff0c;一定程度的阻力是不可避免的。事实上&#xff0c;《福布斯》的一篇文章援引哈佛商学院的研究表明&#xff0c;70%的组织变革努力都失败了&#xff0c;“原因之一是高管们没有从足够多的人那里了解他们的计划和想法。”支持。”…

市面上的ipad国产触控笔怎么样?好用的电容笔合集

而对那些把IPAD当作学习工具的人而言&#xff0c;这个Apple Pencil绝对是不可或缺的。然而&#xff0c;苹果版本的Pencil却是昂贵得让许多人望而却步。因此&#xff0c;最佳方法是选择一个平替的电容笔。我是从几年前开始用IPAD的&#xff0c;也是一个数码爱好者&#xff0c;近…

AIGC行业周刊【2023-0709】【第六期】2023年世界人工智能大会大佬发言汇总

点击加入->【智子纪元-AIGC】技术交流群 一、大咖观点&#xff1a; 0709AI日报&#xff1a;2023年世界人工智能大会大佬发言汇总「5年内&#xff0c;人类程序员没了」&#xff0c;Stability AI老板大胆预测&#xff0c;一众大佬狂怼&#xff1a;大错特错&#xff0c;都懒得…

在vite创建的vue3项目中加载Cesium立体地形信息并调整初始化角度

在vite创建的vue3项目中加载Cesium立体地形信息并调整初始化角度 使用vite创建vue3项目 npm create vitelatestcd到创建的项目文件夹中 npm install安装Cesium npm i cesium vite-plugin-cesium vite -D配置 &#xff08;1&#xff09;在项目的vite.config.js文件中添加&#x…

算法训练营第三十一天||理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和

理论基础 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 这么说有点抽象&#xff0c;来举一个例子&#xff1a; 例如&#xff0c;有一堆钞票&#xff0c;你可以拿走十张&#xff0c;如果想达到最大的金额&#xff0c;你要怎么拿&#xff1f; 指定每次…

专项练习24

目录 一、选择题 1、JavaScript 中的数字在计算机内存中占多少个Byte&#xff1f; 2、请问以下JS代码会输出什么 二、编程题 1、以数字的形式返回数字参数向下取整的结果 一、选择题 1、JavaScript 中的数字在计算机内存中占多少个Byte&#xff1f; A、2 Byte B、4Byte C…

如何在购物 App 上实现商品快递物流信息的展示

前言 现如今&#xff0c;人们大多数会选择在手机购物App上进行购物&#xff0c;这样买东西很是便捷&#xff0c;不用出门就能买到全国各地甚至是国外的商品&#xff0c;下单之后只需要等待快递送达就可以了。一个购物APP&#xff0c;不可或缺的一个辅助功能就是&#xff0c;展…

GPT-4 验明真身的经典三连问:快速区分 GPT-3.5 与 GPT-4

GPT-4 验明真身的经典三连问&#xff1a;快速区分 GPT-3.5 与 GPT-4

华为VRP系统基础

系列文章目录 华为数通学习&#xff08;1&#xff09; 目录 一&#xff0c;什么是VRP? 二&#xff0c;VRP的发展 三&#xff0c;VRP的文件系统 3.1&#xff0c;系统文件:.cc结尾 ​编辑 3.2&#xff0c;配置文件&#xff1a;.cfg&#xff0c;.zip&#xff0c;.dat结尾 3.…