51单片机 关于快速的ADC和保存数据的问题

时间:2022-11-28 09:49:59
    传感器检测到震动后给出脉冲,要求将其波形模拟出来。
我用STC12C5160S2单片机,将未知的电压波形连续ADC后,UART发至电脑。
电压波形我用AD扫描后后发送。
    有以下问题:
1,ADC时间为90个时钟周期,这90个时钟周期用来保存ADC的数据,足够。但是若还要UART发送,不行。
2,若在有波形时保存ADC的数据,没有波形时UART发送,我尝试编了程序,数据会乱。
    有什么解决方法请给出,若全盘推翻我的方案也可给出。谢谢。

程序如下:

程序中,一直在进行ADC,并且使能其中断。
int i=0;
int j1,j2;
uchar dat[]; 
void adc_isr() interrupt 5 using 1    //AD中断服务函数
{
    ADC_CONTR &= !ADC_FLAG;         //Clear ADC interrupt flag
    if(ADC_RES>0)//AD转换的结果在ADC_RES中 >0表示有电压     我也尝试了将此处的0提高了一些
    {
        dat[i]=ADC_RES;
        i++;
    }

    ADC_CONTR = ADC_START;    //ADC启动
}
main()
{
    j1=i;
    for(;j2<j1;j2++)
    {
        UART_send(dat[j2]);
    }
}

10 个解决方案

#1


1. 只要UART通信波特率能够保证每次采样的数据及时发送出去就不会有问题。
2. 你这个程序也太不严谨,dat[]就不考虑溢出的可能性吗?数组下标应当添加溢出后的复位处理,否则数据必然乱。

#2


1)如果出现j2<j1,那么程序就停止运行了?
2)当你连续发送字节前,需要根据TX标志,判断字节是否已经从串口移位出去了
3)根据你的波特率,计算一下你发送每帧数据所要的时间,如果时间够,可以将UART_send(dat[j2])  直接放在dat[i]=ADC_RES语句后,加快速度;
4)一般情况下,串口速度比较慢,所以应该加长采样间隔,定时进行A/D转换,每次都发送出去;
5)不想丢失A/D数据,就要加入判断,无用的数据不保存,有用的数据保存到一个大数组中(加上上限限制);发送时,判断TX标志,并顺序发送数组数据;

#3


必须保证采样的数据与发送的数据不同时进行

#4


你可以不使用中断,读一个数据发送一个,都在main中进行。
如果对实时性要求不是很高,可以读1024个数据存起来,再发送。

#5


    多谢各位 我有了一想法,试出来后给各位看结果。
还会有后续的问题...

#6


该回复于2011-12-05 10:22:41被版主删除

#7


UART口很慢的。。。

#8


你传输速度跟不上采样速度那能有什么办法,降低采样频率是最直接的办法

adc的值超过8位的话,可以拼起来发送,能稍微节省点传输时间

还有就是楼主的代码实在……就算方法对了,也会出其他问题的

#9


    1 STC的快速ADC的时间为70-470个时钟周期,可调。470个时钟周期为50us左右;而UART发送数据时间约为1ms;应注意:STC12C5A的ADC时钟为内部RC时钟。只能在ADC采样完成后就对数据进行发送,只能对数据进行保存。在所有数据采集完后再发送。
    2 我采用的方法是:
        2.1 连续进行ADC;
        2.2 当ADC结果:ADC_RES>1后对数据保存;仍然进行ADC。
        2.3 当ADC_RES<1,停止ADC,UART发送数据。
    2 此种方法下,若用ADC中断来进行数据处理会很麻烦。所以就用轮询方式进行ADC。
    3 我进行了计算:一个信号周期的时间<10ms。最多可以采200个数据。
以下是我的程序:
    任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!
#include "reg51.h"
#include "intrins.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;

sfr ADC_CONTR   =   0xBC;           //ADC control register
sfr ADC_RES     =   0xBD;           //ADC high 8-bit result register
sfr ADC_LOW2    =   0xBE;           //ADC low 2-bit result register
sfr P1ASF       =   0x9D;           //P1 secondary function control register

#define ADC_POWER   0x80            //ADC power control bit
#define ADC_FLAG    0x10            //ADC complete flag
#define ADC_START   0x08            //ADC start control bit
#define ADC_SPEEDLL 0x00            //420 clocks
#define ADC_SPEEDL  0x20            //280 clocks
#define ADC_SPEEDH  0x40            //140 clocks
#define ADC_SPEEDHH 0x60            //70 clocks

void InitUart();
void InitADC();
void SendData(BYTE dat);
void Delay(WORD n);
void ADC();
void SaveResult(WORD i);
void Sendwei(WORD dat);
WORD GetResult();

WORD i,j,dat;
BYTE shuju[502][2];

//任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!

void main()
{
    BYTE k;
    Delay(1);

    InitUart();                  
    InitADC(); 
    i=0;
    while (1)
    {
ADC(); 
if(ADC_RES > 0x00)    // ADC值第一次  > 0 0100 =4
{
SaveResult(i);  //保存第一次ADC>4的值
i++;
k=1;
while(k)
{
ADC();
if(ADC_RES > 0x01)
{
SaveResult(i);
i++;
if(i>=300)//
{
SendData('E');
SendData('x');
SendData('c');
SendData('e');
SendData('e');
SendData('d');
SendData('!');
k=0;
}
}
else k=0;
}

SendData('R');
SendData(':');
SendData('i');
SendData('=');
Sendwei(i);
SendData(' ');
for(j=0;j<i;j++)
{
dat = shuju[j][0];
dat = (dat<<2) + ( (shuju[j][1]) & 0x03) ;
Sendwei(dat);
SendData(' ');
}
i=0;
SendData('!');
SendData(' ');

}
    } 

}

void Sendwei(WORD i)
{
BYTE qian,bai,shi,ge;
qian = i/1000;
bai = i%1000/100;
shi = i%1000%100/10;
ge = i%10;
if(qian>0)
{
SendData(qian+0x30);
SendData(bai+0x30);
SendData(shi+0x30);
SendData(ge+0x30);
}
else if(bai>0)
{
SendData(bai+0x30);
SendData(shi+0x30);
SendData(ge+0x30);
}
else if(shi>0)
{
SendData(shi+0x30);
SendData(ge+0x30);
}
else  SendData(ge+0x30);
}

void SaveResult(WORD i)
{
shuju[i][0] = ADC_RES;
shuju[i][1] = ADC_LOW2;
}
WORD GetResult()
{
WORD dat;
dat = ADC_RES;
dat = (dat<<2) +  (ADC_LOW2 & 0x03);
return dat;
}
void ADC()
{
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;
    _nop_();                        //Must wait before inquiry
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
    ADC_CONTR &= ~ADC_FLAG;         //Close ADC
}
void InitUart()
{
    SCON = 0x50;                    //8 bit data ,no parity bit
TI = 1;
    TMOD = 0x20;                    //T1 as 8-bit auto reload
    TH1 = TL1 = 0xfd;  //Set Uart baudrate   9600 
    TR1 = 1;                        //T1 start running

}
void InitADC()
{
    P1ASF = 0xff;                   //Open 8 channels ADC function
    ADC_RES = 0;                    //Clear previous result
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(2);                       //ADC power-on and delay
}
void SendData(BYTE dat)
{
    while (!TI);                    //Wait for the previous data is sent
    TI = 0;                         //Clear TI flag
    SBUF = dat;                     //Send current data
}
void Delay(WORD n) //1-60ms
{
    WORD x;
    while (n--)
    {
        x = 5000;
        while (x--);
    }
}

任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!

#10


第一次发帖。请各位给出一件。3天后结贴。

#1


1. 只要UART通信波特率能够保证每次采样的数据及时发送出去就不会有问题。
2. 你这个程序也太不严谨,dat[]就不考虑溢出的可能性吗?数组下标应当添加溢出后的复位处理,否则数据必然乱。

#2


1)如果出现j2<j1,那么程序就停止运行了?
2)当你连续发送字节前,需要根据TX标志,判断字节是否已经从串口移位出去了
3)根据你的波特率,计算一下你发送每帧数据所要的时间,如果时间够,可以将UART_send(dat[j2])  直接放在dat[i]=ADC_RES语句后,加快速度;
4)一般情况下,串口速度比较慢,所以应该加长采样间隔,定时进行A/D转换,每次都发送出去;
5)不想丢失A/D数据,就要加入判断,无用的数据不保存,有用的数据保存到一个大数组中(加上上限限制);发送时,判断TX标志,并顺序发送数组数据;

#3


必须保证采样的数据与发送的数据不同时进行

#4


你可以不使用中断,读一个数据发送一个,都在main中进行。
如果对实时性要求不是很高,可以读1024个数据存起来,再发送。

#5


    多谢各位 我有了一想法,试出来后给各位看结果。
还会有后续的问题...

#6


该回复于2011-12-05 10:22:41被版主删除

#7


UART口很慢的。。。

#8


你传输速度跟不上采样速度那能有什么办法,降低采样频率是最直接的办法

adc的值超过8位的话,可以拼起来发送,能稍微节省点传输时间

还有就是楼主的代码实在……就算方法对了,也会出其他问题的

#9


    1 STC的快速ADC的时间为70-470个时钟周期,可调。470个时钟周期为50us左右;而UART发送数据时间约为1ms;应注意:STC12C5A的ADC时钟为内部RC时钟。只能在ADC采样完成后就对数据进行发送,只能对数据进行保存。在所有数据采集完后再发送。
    2 我采用的方法是:
        2.1 连续进行ADC;
        2.2 当ADC结果:ADC_RES>1后对数据保存;仍然进行ADC。
        2.3 当ADC_RES<1,停止ADC,UART发送数据。
    2 此种方法下,若用ADC中断来进行数据处理会很麻烦。所以就用轮询方式进行ADC。
    3 我进行了计算:一个信号周期的时间<10ms。最多可以采200个数据。
以下是我的程序:
    任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!
#include "reg51.h"
#include "intrins.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;

sfr ADC_CONTR   =   0xBC;           //ADC control register
sfr ADC_RES     =   0xBD;           //ADC high 8-bit result register
sfr ADC_LOW2    =   0xBE;           //ADC low 2-bit result register
sfr P1ASF       =   0x9D;           //P1 secondary function control register

#define ADC_POWER   0x80            //ADC power control bit
#define ADC_FLAG    0x10            //ADC complete flag
#define ADC_START   0x08            //ADC start control bit
#define ADC_SPEEDLL 0x00            //420 clocks
#define ADC_SPEEDL  0x20            //280 clocks
#define ADC_SPEEDH  0x40            //140 clocks
#define ADC_SPEEDHH 0x60            //70 clocks

void InitUart();
void InitADC();
void SendData(BYTE dat);
void Delay(WORD n);
void ADC();
void SaveResult(WORD i);
void Sendwei(WORD dat);
WORD GetResult();

WORD i,j,dat;
BYTE shuju[502][2];

//任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!

void main()
{
    BYTE k;
    Delay(1);

    InitUart();                  
    InitADC(); 
    i=0;
    while (1)
    {
ADC(); 
if(ADC_RES > 0x00)    // ADC值第一次  > 0 0100 =4
{
SaveResult(i);  //保存第一次ADC>4的值
i++;
k=1;
while(k)
{
ADC();
if(ADC_RES > 0x01)
{
SaveResult(i);
i++;
if(i>=300)//
{
SendData('E');
SendData('x');
SendData('c');
SendData('e');
SendData('e');
SendData('d');
SendData('!');
k=0;
}
}
else k=0;
}

SendData('R');
SendData(':');
SendData('i');
SendData('=');
Sendwei(i);
SendData(' ');
for(j=0;j<i;j++)
{
dat = shuju[j][0];
dat = (dat<<2) + ( (shuju[j][1]) & 0x03) ;
Sendwei(dat);
SendData(' ');
}
i=0;
SendData('!');
SendData(' ');

}
    } 

}

void Sendwei(WORD i)
{
BYTE qian,bai,shi,ge;
qian = i/1000;
bai = i%1000/100;
shi = i%1000%100/10;
ge = i%10;
if(qian>0)
{
SendData(qian+0x30);
SendData(bai+0x30);
SendData(shi+0x30);
SendData(ge+0x30);
}
else if(bai>0)
{
SendData(bai+0x30);
SendData(shi+0x30);
SendData(ge+0x30);
}
else if(shi>0)
{
SendData(shi+0x30);
SendData(ge+0x30);
}
else  SendData(ge+0x30);
}

void SaveResult(WORD i)
{
shuju[i][0] = ADC_RES;
shuju[i][1] = ADC_LOW2;
}
WORD GetResult()
{
WORD dat;
dat = ADC_RES;
dat = (dat<<2) +  (ADC_LOW2 & 0x03);
return dat;
}
void ADC()
{
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START;
    _nop_();                        //Must wait before inquiry
    _nop_();
    _nop_();
    _nop_();
    while (!(ADC_CONTR & ADC_FLAG));//Wait complete flag
    ADC_CONTR &= ~ADC_FLAG;         //Close ADC
}
void InitUart()
{
    SCON = 0x50;                    //8 bit data ,no parity bit
TI = 1;
    TMOD = 0x20;                    //T1 as 8-bit auto reload
    TH1 = TL1 = 0xfd;  //Set Uart baudrate   9600 
    TR1 = 1;                        //T1 start running

}
void InitADC()
{
    P1ASF = 0xff;                   //Open 8 channels ADC function
    ADC_RES = 0;                    //Clear previous result
    ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
    Delay(2);                       //ADC power-on and delay
}
void SendData(BYTE dat)
{
    while (!TI);                    //Wait for the previous data is sent
    TI = 0;                         //Clear TI flag
    SBUF = dat;                     //Send current data
}
void Delay(WORD n) //1-60ms
{
    WORD x;
    while (n--)
    {
        x = 5000;
        while (x--);
    }
}

任何问题/疑问/对数据处理有更好办法/... 都可提出,谢谢!

#10


第一次发帖。请各位给出一件。3天后结贴。