带有128KB缓存的AD7606模拟采集板
01简介
构建多路16bit的AD采集器,并可以进行高速缓存,对于采集静态电压,还是动态波形都非常有利。在23LC1024四线访问数据
博文中介绍了对扩展SPI接口RAM(128kB)的四线制高速访问的方法。在AD7606八通道AD采集模块测试
博文中给出了基于AD7606芯片的AD采集电路模块的测量。在博文扩展32KRAM的STC8H8K信号采集版
中给出了利用WiFi-UART模块,实现采集数据的高速无线传送。
▲ 插图|来自网络
下面给出了该系统的设计以及相关调试结果。
02电路系统设计
1. 电路设计
就在23LC1024四线访问数据
的基础上1,增加WiFi接口,完成模块的设计。
▲ 电路原理图
铺设PCB适合于单面PCB快速制版。
▲ PCB图
03电路测试
1.硬件测试
在正式下载程序之前,对电路施加5V工作电源,测量对应的静态工作电流,LM1117输出的3.3V电压信号。
1)对单片机的硬件配置
参考在“23LC1024四线访问数据
”中对单片机的配置,设置单片机IRC工作频率为35MHz.
▲ 通电后的电路
下位机中的响应交互程序代码片段为,这是用来测试23LC1024串行SPI接口的RAM功能。
else IFARG0("rm") {
ucChar = LC1024ReadMode();
printf("LC1024 mode:%bx\r\n", ucChar);
} else IFARG0("wm") {
sscanf(SDA(1), "%bx", &ucChar);
LC1024WriteMode(ucChar);
ucChar = LC1024ReadMode();
printf("LC1024 mode:%bx\r\n", ucChar);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
通过使用rd, wr来对23L1024进行读写测试。,验证读写正常。
2.测试AD转换功能
交互代码如下:
} else IFARG0("data") {
AD7606Convert();
AD7606ReadData(nAD, 4);
for(i = 0; i < 8; i ++) {
printf("%d ", nAD[i]);
}
printf("\r\n");
} else IFARG0("datamean") {
sscanf(SDA(1), "%d", &nSize);
if(nSize == 0) nSize = 1;
for(i = 0; i < 8; i ++) lnADSigma[i] = 0;
for(i = 0; i < nSize; i ++) {
AD7606Convert();
AD7606ReadData(nAD, 4);
for(j = 0; j < 8; j ++)
lnADSigma[j] += nAD[j];
}
for(i = 0; i < 8; i ++) {
printf("%d ", (int)(lnADSigma[i] / nSize));
}
printf("\r\n");
} else IFARG0("rangeon") {
ON(AD7606_RANGE);
} else IFARG0("rangeoff") {
OFF(AD7606_RANGE);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
▲ 连接有AD7606测试系统
- 使用data:获取当前采样一次的数值;
- 使用datamean:获取相近采集平均数据。命令: datamean , 其中参数你标示采集数据平均的结果。
- rangeon: 设置采集电压范围 ± 10 V \pm 10V ±10V。
- rangeoff:设置采集电压范围: ± 5 V \pm 5V ±5V。
3.测试中断内采集
使用Timer2实现10kHz的中断频率。在其中断程序里完成AD7606的8路16bit数据采集,并存储在23LC1024中。
1) 设置Timer2
//==============================================================================
#if TIME2_INT_EN
//------------------------------------------------------------------------------
void Timer2Init(void) {
AUXR |= 0x04;
T2L = 0x54;
T2H = 0xF2;
IE2 |= 0x4; // 7:ETKSU1 6:ET4: 5:ET3: 4:ES4: 3:ES3, 2:ET2, 1:ESPI, 0:ES2
AUXR |= 0x10;
//--------------------------------------------------------------------------
g_nTimer2IntCount = 0;
}
void Timer2ISR(void) interrupt 12 using 1 {
int nAD[8];
unsigned char * p;
unsigned char i;
g_nTimer2IntCount ++;
//----------------------------------------------------------------------
if(g_ucADSampleFlag) {
AD7606Convert();
AD7606ReadData(nAD, 4);
p = (unsigned char *)nAD;
LC1024WriteBegin(g_ucAdd2, g_ucAdd1, g_ucAdd0);
for(i = 0; i < 16; i ++)
LC1024Write(*(p ++));
LC1024ReadWriteEnd();
g_ucAdd0 += 16;
if(g_ucAdd0 == 0) {
g_ucAdd1 ++;
if(g_ucAdd1 == 0)
g_ucAdd2 ++;
}
}
}
#endif // TIME2_INT_EN
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
在STC8G指令中,上述使用unsigned char 的指针来访问int数字,将相应的8个short整型数据写入SPI接口的23LC1024内部。在C51中是按照Big-Endian
模式存储数据的。所以在通过bytes回复int16的过程中,是高字节在前,低字节在后。
▲ Big-Endian vs. Little-Endian
2) 测量转换时间
在实验“AD7606八通道AD采集模块测试
”中,测量了AD7606转换函数AD7606Convert的执行时间大约为 T A D = 4.17 μ s T_{AD} = 4.17\mu s TAD=4.17μs。
通过测量LC1024的片选信号CS信号可以测量LC1024写入16个字节所需要的时间。在23LC1024四线访问数据
中给出了LC1024的片选信号在PIN1。
▲ 测量LC1024的CS信号,确定写入16个字节所需要的时间
LC1024连续写入16个字节(AD7606转换的8个16bitAD结果)所需要的时间为: T W R = 24.3 μ s T_{WR} = 24.3\mu s TWR=24.3μs.。
那么在Timer2的10k中断的时间 T i n t = 100 μ s T_{{\mathop{\rm int}} } = 100\mu s Tint=100μs内,所需要执行的AD转换和存储所需要的总时间大约为: T T 2 = T A D + T W R = 4.17 + 24.3 = 28.47 μ s T_{T2} = T_{AD} + T_{WR} = 4.17 + 24.3 = 28.47\mu s TT2=TAD+TWR=4.17+24.3=28.47μs
占用中断时间大太阳30%的时间。
3)修改UART1优先级
由于TImer2占用了30% 的时间,就影响了UART1通过460800波特率接收对应的上位机的指令,出现了丢失字符的现象。
需要通过修改Timer2,UART1的优先级来进行调整。使得UART1能够中断Timer2接收上位机的指令。
STC8G内部的中断源定义如下图所示。总共分为4个中断优先级别。0:为最低,3:为最高优先级。
▲ STC8G 内部中断源的定义
UART1的优先级是由IP,IPH中的4bit定义; Timer2的优先级始终为0(最低)。
▲ UART,TIMER2
通过将IP,IPH中的PS,PSH修改成1, 定义为优先级为3(最高),就可以使得UART1中断Timer2完成串行命令的接受el。
▲ 确定串口优先级的IP,IPH寄存机对应的位定义
在原来的C51Basic中UARInit()函数中增加如下代码,对其中IP, IPH修改其中的bit4。
//--------------------------------------------------------------------------
#if UART1_INT_EN
IP |= 0x10; // Set Serial1 Interrupt prority as 3
IPH |= 0x10;
g_ucUART1BufferHead = g_ucUART1BufferTail = 0;
g_ucTIFlag = 0;
ES = 1;
#endif // UART1_INT_EN
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
修改完之后,便可以解决原来接收上位机指令丢失字符的问题了。
4. 获取采集的信号波形
在串口命令中增加了如下控制命令,可以获得AD采集到的波形信号。
▲ 采集的信号波形,使用示波器观察到的
▲ 获得采集后的信号波形
更换三角波形:
▲ 输入三角波形
▲ AD7606采集到的三角形好的波形
} else IFARG0("showad") {
nSize = 0x100;
ucChannel =1 ;
if(STD_NUM > 1) sscanf(SDA(1), "%d", &nSize);
if(STD_NUM > 2) sscanf(SDA(2), "%bd", &ucChannel);
STOP_SAMPLE;
//----------------------------------------------------------------------
lnAddress = GetADAddress();
lnAddress -= nSize * 16;
ucAdd2 = (unsigned char)(lnAddress >> 16);
ucAdd1 = (unsigned char)(lnAddress >> 8);
ucAdd0 = (unsigned char)lnAddress;
LC1024ReadBegin(ucAdd2, ucAdd1, ucAdd0);
for(i = 0; i < nSize; i ++) {
pData = (unsigned char *)nAD;
for(j = 0; j < 16; j ++)
*(pData ++) = LC1024ReadByte();
for(j = 0; j < ucChannel; j ++)
printf("%d ", nAD[j]);
}
LC1024ReadWriteEnd();
printf("\r\n" );
START_SAMPLE;
} else IFARG0("showadbin") {
nSize = 0x100;
ucChannel =1 ;
if(STD_NUM > 1) sscanf(SDA(1), "%d", &nSize);
if(STD_NUM > 2) sscanf(SDA(2), "%bd", &ucChannel);
STOP_SAMPLE;
//----------------------------------------------------------------------
lnAddress = GetADAddress();
lnAddress -= nSize * 16;
ucAdd2 = (unsigned char)(lnAddress >> 16);
ucAdd1 = (unsigned char)(lnAddress >> 8);
ucAdd0 = (unsigned char)lnAddress;
LC1024ReadBegin(ucAdd2, ucAdd1, ucAdd0);
for(i = 0; i < nSize; i ++) {
pData = (unsigned char *)nAD;
for(j = 0; j < 16; j ++) SendChar(LC1024ReadByte());
}
LC1024ReadWriteEnd();
START_SAMPLE;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
下面的代码是不带Buffer版本的外部命令。它可以连续读取AD7606转换的数值。
具体实现是通过 C51-Ver2:NoBuffer。
if(strcmp("hello", (char *)STD_ARG[0]) == 0)
printf("%s is ready !\r\n", VERSION_STRING);
else IFARG0("ad") {
sscanf(SDA(1), "%d", &nNumber);
sscanf(SDA(2), "%d", &nChannel);
sscanf(SDA(3), "%d", &nWaitTime);
g_ucWaitMS = 0;
for(i = 0; i < nNumber; i ++) {
while(g_ucWaitMS != nWaitTime);
g_ucWaitMS = 0;
AD7606Convert();
AD7606ReadData(nData, 4);
for(j = 0; j < nChannel; j ++) {
nNum = nData[j];
SendChar((unsigned char)(nNum >> 8));
SendChar((unsigned char)nNumber);
}
}
}
else IFARG0("adtext") {
sscanf(SDA(1), "%d", &nNumber);
sscanf(SDA(2), "%d", &nChannel);
sscanf(SDA(3), "%d", &nWaitTime);
g_ucWaitMS = 0;
for(i = 0; i < nNumber; i ++) {
while(g_ucWaitMS != nWaitTime);
g_ucWaitMS = 0;
AD7606Convert();
AD7606ReadData(nData, 4);
for(j = 0; j < nChannel; j ++) {
nNum = nData[j];
printf("%d ", nNum);
}
}
} else IFARG0("ad5v") {
OFF(AD7606_RANGE);
} else IFARG0("ad10v") {
ON(AD7606_RANGE);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
04结论
经过测试,基于AD7606的八路AD采样板基本上达到了设计要求,可以用于之后的信号处理的实验。
文章来源: zhuoqing.blog.csdn.net,作者:卓晴,版权归原作者所有,如需转载,请联系作者。
原文链接:zhuoqing.blog.csdn.net/article/details/105980787
- 点赞
- 收藏
- 关注作者
评论(0)