打印

AD数据转换问题,还请指教

[复制链接]
2587|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
barryyan|  楼主 | 2010-7-12 22:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
小弟最近在做一个AD降采样的算法。

在ISR中,采用连续转换模式,每采集一个数据就让FLAG=1,随后在MAIN函数中,进行降采样的算法,随后通过UART发到终端

为了缓解ISR与MAIN的速度之差,以及让AD值能够快速传递。现在我用的方法是,设置一个全局变量数组,将ISR中转换的数据写入数组,同时在main中读取数组的值。

当转换频率为8KHZ时,在ISR中,每转换一次AD值,就将转换的AD值放入全局数组a[500]中,随后让flag=1;

在Main中,等待flag==1,然后从数组中依次读取AD值。随后进行降采样运算,随后发送UART



但是现在发现由于ISR中,放入数组的速度比main中读取的速度快,过一段时间后,原来写入数组的AD值会被新的值覆盖。main来不急读原来的值,就读取新的值了。也就是说写入的指针比读取的指针快了500超过。这样的话,读取的数据就不对了

请问这个问题怎么解决?

相关帖子

沙发
centimetre| | 2010-7-12 22:48 | 只看该作者
用个ring buffer来做

www.cmtekchina.com

使用特权

评论回复
板凳
zchong| | 2010-7-13 12:18 | 只看该作者
如果采样过快,main来不及处理的话,ring buffer也不行呀

使用特权

评论回复
地板
barryyan|  楼主 | 2010-7-13 15:50 | 只看该作者
听取了一些大虾的建议,用标志位对Main和Isr进行标记和约束

这时候,的确不会遗漏数据了。

我把大致程序写出来,和大家讨论一下,定义了一个全局数组a[500]

main()
{
  寄存器配置;
  while(1)
  {
  if(flag==1) //等待AD中断完成标志
  {
  sum2=a[readpoint]*f(p); //a[readpoint]是从数组a中读取AD值
  readpoint++;
  if(readpoint>=500)
  {
  readpoint=0;
  }
  out=sum2/k;
  当中都是降采样算法...

  UART发送一个AD数据;

  flag=0; //flag=0
  }
  }
}

ISR
{
  if(AD中断)
  {
  if(flag==0) //等待main完成UART发送的标志
  {
  a[writepoint]=ADCDATA;
  writepoint++;
  if(writepoint>=500)
  {
  writepoint=0;
  }
  flag=1; // flag=1给main函数信号
  }  
}
}

正当我微笑之际,领导一句话让我又陷入了沉思。。。。

现在公司要求ADC的转换频率要为8KHZ,不能减少采样速度。

但是如果在ISR中添加if(flag==0)后,要等待main处理完才获取第二个AD值,那么它采样AD的频率应该低于8KHZ了吧?(感觉main限制了AD采样的速度)

不知道我理解的是否正确,ISR中AD的采样频率是否比8KHZ低了?

如果低于8KHZ的话,那就不能用这个方法了,还有其他好的方法吗?

还请各位多多指教,谢谢。

使用特权

评论回复
5
urliyong| | 2010-7-13 22:25 | 只看该作者
用一个变量表示采用个数,采ISR中采一个就加1,main中都一个就减去1,等于500就不采了,

使用特权

评论回复
6
barryyan|  楼主 | 2010-7-25 19:47 | 只看该作者
帮自己再顶一下。这个问题纠结了两个星期。

总是发现ISR中AD的8KHZ转换频率时,它的cnt1++数值比较大;

而在main中的cnt2++数值比cnt1++数值小,而且随着时间的增加相差越来越大。

我就不明白,为什么main中的速度比ADC转换频率的8KHZ速度还慢。

难道是因为在main中的UART每次要发送好几个字节导致速度降低? 我将UART设置成最高的256000了,速度应该很快的啊,还请指教

使用特权

评论回复
7
barryyan|  楼主 | 2010-7-26 15:40 | 只看该作者
我上午自己算了一下UART发送的时间和ADC转换的时间。

我把自己所理解的说一下,请各位大侠看看我理解的是否正确,谢谢。

(1)、ADC的转换频率是8KHZ,那么这样算起来,1秒ADC的值就会转换8000次,即adccount=8000
(2)、UART的波特率是256000,它的单位应该是 bits/秒

我现在假设每次通过UART 发送的数据是4个字节。(格式是"%d\r\n",%d对应数字11,后面两个各占一个字节),设置起始位和停止位各1位,那么4个字节就是 4*10 = 40bits (这里我不确定自己理解是否正确)

那么256000/40=6400,也就是说1秒能够发送6400次。

所以光这样看的话,ADC的转换速度就比main中的UART发送速度快,再加上main中还有一点算法在,增加了CPU的时间。

所以说ADC中断中的 adccount数值比 main中的 maincount数值大也就是很自然的事了。

不知道我这样想是否正确,还请各位赐教,不胜感激。

使用特权

评论回复
8
xinzha| | 2010-7-26 23:26 | 只看该作者
cpu的计算时间有办法和串口发送同时进行,就可以缩小到忽略不计,可是串口的数据发送速度远低于ad数据的产生速度,这是个绕不过去的坎儿,除非换接口。
spi,emi,i2c都比串口好用些。

使用特权

评论回复
9
barryyan|  楼主 | 2010-7-27 08:52 | 只看该作者
8# xinzha

你好,首先谢谢你的回复。

我突然发现自己漏说了一点:

采样24个数据为一组数据,另外用一个pointer作为数据的序号。24个数据通过平均算法后通过UART只发送3个数据。(pointer分别为8,16,24时,就通过UART发送)

也就是说ADC的转换频率虽然是8KHZ,但是实际让UART传送的数据频率只需1KHZ。
这样算起来的话,256000波特率的UART应该能满足条件的。也就是说main中的UART应该来得及处理的。

那这样来说的话,还是main函数中算法的问题,还不够简洁?

每次在main中while(1)的flag==1的条件内,要运算的时间消耗太多资源,从而导致ADC中的计数值远大于main中的计数值。

使用特权

评论回复
10
xinzha| | 2010-7-27 09:10 | 只看该作者
如果串口发送不能用中断做,那么可以改变串口发送的查询方式。
每次启动发送之后不去等待发送完成,而是在下次发送之前查询是否busy,这样做出来的效果类似于串口发送和cpu处理并行,前提是你要做好数据的管理。

使用特权

评论回复
11
barryyan|  楼主 | 2010-7-28 09:36 | 只看该作者
10# xinzha

你好,我现在那个芯片里,没有busy这个寄存器。

我现在用的是发送中断TX,在ISR中,当TX的buffer为空时,触发中断,并将flag=1

main中的UART发送程序中
for(i=0;i<number;i++)
{
COMTX= a;
while(flag==0);
flag=0;
}

但是同事说这个其实效率还不是很高。  说可以为要发送的字节建立一个BUFFER ,用读写指针去判断,如果两个位置不一样就进行发送,这个可行吗?

这个算什么方法呢?

使用特权

评论回复
12
xinzha| | 2010-7-28 14:58 | 只看该作者
可行,但是即使用读写指针你依然要去判断busy位或者中断,否则的话串口buffer就爆了。只去判断读写指针的前提是你保证发送buffer足够大,发送速度足够快,你获得数据的速度永远低于串口发送的速度。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

37

主题

137

帖子

0

粉丝