打印
[AVR单片机]

usart中断,大侠搭救——怎么处理从USART中收到的数据帧?

[复制链接]
3733|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
rankfyang|  楼主 | 2009-9-8 20:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 rankfyang 于 2009-9-9 09:06 编辑

小弟先谢谢您的关注了!
存在的问题:在多个中断函数中的数据共享,怎么才能正确解析从串口接收到的数据帧?
具体阐述:
小弟在做ATemga128的一个系统时,共使用了三个中断函数,三个中断函数和主要功能如下:
第一个中断(“选择”按钮对应的中断):
#pragma interrupt_handler select_isr:iv_INT4
这个中断通过ATemga128的PE4脚接了一个按键,用来触发LCD界面的光标位置的变化。
第二个中断(“确认”按钮对应的中断):
#pragma interrupt_handler enter_isr:iv_INT5
这个中断外部接了一个按键,接到ATemga128的PE5,通过按键动作改变LCD界面的显示图像。在其中一个图像变化的界面中会将中断三中收到的数据实时显示出来,并且在当前界面
按动“确认”按钮就会将中断三送过来的数据保存到片内RAM中。
第三个中断:
(串口1数据传送中断,这个中断每隔500毫秒会接收到从串口发送过来的数据,中间调用的子函数都在下面三个子函数中。)
#pragma interrupt_handler usart1_rx_isr:iv_USART1_RXC
void usart1_rx_isr(void)
{
  float pressure;
float sink;

CLI();
storeReceivedChars(USART_RxDataBuf, 65);
copyRightData(USART_RxDataBuf, RxDProcessStk, 13);
  pressure = char4_floatLittleEndian(&RxDProcessStk[3]);
  sink = char4_floatLittleEndian(&RxDProcessStk[7]);
  printf("\n pressure = %f", pressure);
  printf("\n sink = %f", sink);
SEI();
}
这个中断函数用来接收从串口发送过来的数据并判断收到数据的准确性。如果收到的数据正确,我将这组收到的数据(包括两个浮点数)实时显示到LCD界面。中断三每隔500毫秒
从下位机收到一个包含以上涉及到的两个浮点数的数据帧。数据帧中有包括开始的起始标志,最后两个字节是校验字。如果每次起始标志和CRC校验结果都正确,则将当前接收到的
数据送到LCD显示。并且无论收发数据与否,都要在按动“确认”按钮按下之后将当前收到的正确数据保存到另外的存储空间。
可是小弟在处理的时候总是出现数据解析有问题,在希望按动“确认”按钮保存当前数据的时候总是将当前的数据冲断,致使读到的数据不正确,本来该从起始位开始读起的数据却从中途读起,致使报错!为什么会出现这种状况呀?

中断接收数据我是采用的以下三个子函数(三个子函数都定义在串口接收中断之前),:
//本子函数用于从USART1接收一个字符
unsigned char usart1_MCU_receiveCh(void)
{
   while( !(UCSR1A & (1<<RXC1)));   
   return UDR1;
}//验证没问题

//本子函数用于从USART1接收一个包含size个字符的字符数组中,
//参数接收一个同名的全局变量USART_RxDataBuf
//其中USART_RxDataBuf是一个有100个字节的
//采用循环记录的方式将数据写入
void storeReceivedChars(unsigned char *USART_RxDataBuf, unsigned char size)
{
  int i;
  
  writeBufPtr = USART_RxDataBuf;
  for(i = 0; i < size; i++)
  {
    *writeBufPtr = usart1_MCU_receiveCh();
writeBufPtr++;
if( (writeBufPtr - USART_RxDataBuf) == size )writeBufPtr = USART_RxDataBuf;
  }
}
//本函数用于将全局变量USART_RxDataBuf中的数据拷贝到另外一个存储空间中
//该存储空间是一个长度为length的字符数组(也是定义的一个全局变量)
//
void copyRightData(unsigned char *USART_RxDataBuf, unsigned char *RxDProcessStk, unsigned char length)
{
   unsigned char *srcRdPtr;
  unsigned char *dstWrPtr;
  int crcChkResult;
  int RxD_CRC;
  int i;
  
  srcRdPtr = USART_RxDataBuf;
  dstWrPtr = RxDProcessStk;
  while( (*srcRdPtr) != 0x55 )srcRdPtr++;
  while(  (*srcRdPtr) == 0x55  )
  {
      crcChkResult = do_crc(srcRdPtr, 11);
    RxD_CRC = chars2_intLittleEndian( srcRdPtr+11 );
    if( crcChkResult == RxD_CRC)
      {
      for(i = 0; i < length; i++)
            {
              *dstWrPtr = *srcRdPtr;
        dstWrPtr++;
        srcRdPtr++;
     }
     }
     }
}
//这个函数是用来处理小端模式下接收的数据,将接收到的数据帧中相应的字节还原成固有的浮点数
float char4_floatLittleEndian(unsigned char *charsArray)
{
unsigned char receivedArray[4];
int i;
float *finalResult;

for(i = 3; i > -1; i--, charsArray++)
  receivedArray = *charsArray;

finalResult = (float *)receivedArray;

return *finalResult;
}
小弟承望各位指教!先行谢过了!!!

相关帖子

沙发
NE5532| | 2009-9-8 22:16 | 只看该作者
没看懂你到底要问啥,不过建议一点,程序一句话不要写,找张白纸来画,用中文,不要用程序,画清楚了再动手。

使用特权

评论回复
板凳
xwj| | 2009-9-8 22:38 | 只看该作者
呵呵,LS正解

使用特权

评论回复
地板
rankfyang|  楼主 | 2009-9-9 09:11 | 只看该作者
2# NE5532
的确我也发现这个问题很难阐述清楚!
也就是每次我收到数据之后,要是再触发外部中断,整个系统就死机,界面也不能再刷新。

因为我是通过计算机和单片机组成的一个环路,串口调试工具发送数据到单片机串口,然后再将单片机串口收到的数据不做任何修改返回到串口调试工具的接收窗口,但是再通过按键触发中断2,传就调试工具那边再也收不到从单片机串口返回的数据了。

使用特权

评论回复
5
电脑圆圆| | 2009-9-11 08:44 | 只看该作者
1)串口处理函数过长,
2)一个按键按下去理论上最小时间也得20ms,中间漏掉多少数据
3)接收一个字节一次中断。哪有一个中断里轮询接收完所有数据,不死机才怪
4)unsigned char receivedArray[4];
float *finalResult;
receivedArray = *charsArray;
finalResult = (float *)receivedArray;


这语句貌似用法比较牛x

使用特权

评论回复
6
电脑圆圆| | 2009-9-11 08:44 | 只看该作者
1)串口处理函数过长,
2)一个按键按下去理论上最小时间也得20ms,中间漏掉多少数据
3)接收一个字节一次中断。哪有一个中断里轮询接收完所有数据,不死机才怪
4)unsigned char receivedArray[4];
float *finalResult;
receivedArray = *charsArray;
finalResult = (float *)receivedArray;


这语句貌似用法比较牛x

使用特权

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

本版积分规则

2

主题

3

帖子

1

粉丝