OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3820|回复: 24

串口中断接收问题

[复制链接]

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
发表于 2017-9-10 18:02:10 | 显示全部楼层 |阅读模式
10金钱
身边没有平台,直接手敲,见谅。串口调试过程中遇到的问题,望请答复!谢谢~
代码如下:
void UART4_IRQHandler(void)
{
  volatile u8 ch;
  u8 i;
  if(USART_GetITStatus(UART4,USART_IT_RXNE) != RESET)
  {
     ch = USART_ReceiveData(UART4);
     Delay_ms(10);  //别处定义
     a[i] = ch;  //数组定义在别处,全局变量
     printf("data = %d\n",a[i]);
     if(i++>50) i=0;
     USART_ClearITPendingBit(UART4,USART_IT_RXNE);
  }
}

应该没有拼写错误,有的话见谅,请略过。
按理来说,此处不应该有什么问题。但是现在有几处不明白,请大大们指教!
第一:串口接收到数据后,中断触发,ch接收值为发送的第一个字节,但是a[i] = ch; 这个赋值不成功,数组里全是0。
第二:我还有一个问题一直没有想明白,串口中断是一字节一字节接收的,当别处发10个字节时(肯定也是一字节一字节的发送,但是发送端不会考虑接收端有没有接收完成,它很快发完10个字节),
         我这边接收数据也是一字节一字节的接收(当第一个字节到来触发中断,接收数据),我想不明白的是接收完第一个字节后,后面的字节是怎么接收的(也是按照第一个字节那样接收的吗?)。
此外,如上所说,接收数据也是一字节一字节的接收,当接收10字节时,触发10此中断,那么printf("data = %d\n",a[i]); 应该打印10次。但是在线跑时,只打印一次是怎么回事?


啰嗦很多!请大家指教!不甚感激!


最佳答案

查看完整内容[请看2#楼]

单片机处理速度,比你的通讯速率快的多得多。不存在你处理不完又来一包数据。你想的太多了,按你说的情况,其实是新来的数据覆盖旧数据,串口不会给你缓存数据的
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2017-9-10 18:02:11 | 显示全部楼层
huangbo265419 发表于 2017-9-13 19:24
/*******************************************************************************
* Function Name  : ...

单片机处理速度,比你的通讯速率快的多得多。不存在你处理不完又来一包数据。你想的太多了,按你说的情况,其实是新来的数据覆盖旧数据,串口不会给你缓存数据的
我有故事,你有酒吗
回复

使用道具 举报

1

主题

20

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2017-4-8
在线时间
13 小时
发表于 2017-9-10 18:07:48 | 显示全部楼层
先把延时去掉再说,你非要延时10ms,数据早就发完了。
回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7560
金钱
7560
注册时间
2016-11-30
在线时间
643 小时
发表于 2017-9-11 09:43:29 | 显示全部楼层
中断里不要加延时和printf。
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-11 19:32:51 | 显示全部楼层
菜鸟L 发表于 2017-9-10 18:07
先把延时去掉再说,你非要延时10ms,数据早就发完了。

首先,谢谢!我会去掉延时。等调试的时候,我再把结果放上来~
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-11 19:33:57 | 显示全部楼层
lvkanger 发表于 2017-9-11 09:43
中断里不要加延时和printf。

首先,谢谢啊!我会把延时和printf去掉。等下次调试的时候,我再把结果放上来。
回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7560
金钱
7560
注册时间
2016-11-30
在线时间
643 小时
发表于 2017-9-12 09:41:26 | 显示全部楼层
你的i应该搞个全局变量才对吧?
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-13 19:24:08 | 显示全部楼层
/*******************************************************************************
* Function Name  : UART4_IRQHandler
* Description    : This function handles UART4 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void UART4_IRQHandler(void)   //485总线
{
        volatile u8 ch;
        
        if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
        {            
                ch = USART_ReceiveData(UART4);    //下一步:数据有了,怎么把它读出来,放到目的地
            
                USART_SendData(USART3, ch);        //接收到的数据重新发送到串口
            
                RecvBufPushChar(&Recv4Stru,ch);//将ch存入Recv4Stru中
                TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除定时器溢出中断
                TIM_SetCounter(TIM4,0);//当接收到一个新的字节,将定时器4复位为0,重新计时(相当于喂狗)
                TIM_Cmd(TIM4,ENABLE);//开始计时
                USART_ClearITPendingBit(UART4, USART_IT_RXNE);
        }               
}
第一个问题:数据现在是正常的。具体原因,我也无法解释(很可能是我调试的方法不对吧)。我直接将串口4接收的数据又从串口3发出去了,确实是接收到了。一包数据接收完后,我在Recv4Stru中看到的数据和串口3发出去的数据一样。
第二个问题:数据发送接收肯定是一个字节一个字节进行的。后续字节也是按照第一个中断触发那样接收。10个字节触发10次中断是肯定的,我没有看到10次打印,应该是中断里不适合放打印函数。
以上是关于,上问题的总结。
以下是一个新问题:串口数据接收完后,没来得及读出来,又来一包数据,我去读的时候是前一包数据?还是当前这包数据?


回复

使用道具 举报

15

主题

96

帖子

0

精华

高级会员

Rank: 4

积分
650
金钱
650
注册时间
2017-4-21
在线时间
151 小时
发表于 2017-9-14 20:34:56 | 显示全部楼层
你之前的函数其实把a[i]里面的i定义成全局变量也是可以的
回复

使用道具 举报

56

主题

520

帖子

0

精华

高级会员

Rank: 4

积分
964
金钱
964
注册时间
2014-11-18
在线时间
160 小时
发表于 2017-9-15 09:25:08 | 显示全部楼层
huangbo265419 发表于 2017-9-13 19:24
/*******************************************************************************
* Function Name  : ...

一开始的时候你犯了一个致命的错误.就是无论你接收多少数据.

你的i   永远为0.原因自己想.



自己选择的路,成家前走完。
回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7560
金钱
7560
注册时间
2016-11-30
在线时间
643 小时
发表于 2017-9-15 10:51:46 | 显示全部楼层
huangbo265419 发表于 2017-9-13 19:24
/*******************************************************************************
* Function Name  : ...

你肯定要搞一个缓存来缓存你的接收数据的,接收完成数据后要给主函数一个标志。去处理你缓存中的数据就可了。下一包数据和当前包的数据也是不影响的,因为数据缓存到什么位置是你可以自己进行控制的。只要设计好,不会有影响的。
回复

使用道具 举报

15

主题

46

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
283
金钱
283
注册时间
2014-11-21
在线时间
48 小时
发表于 2017-9-15 15:05:14 | 显示全部楼层
你在中断处理程序中执行打印,速度很慢,可能后面9个字节发送完了,你都还没打印完,而且还延时10ms。中断相应程序尽量做到代码量少,处理速度快
回复

使用道具 举报

3

主题

130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3132
金钱
3132
注册时间
2017-3-2
在线时间
324 小时
发表于 2017-9-15 15:53:44 | 显示全部楼层
等你下一包发过来的时候,前面一包早就被处理了,除非2包数据之间的时间非常的短,短到单片机都无法处理完一包数据
坚持不懈的努力!
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:28:18 | 显示全部楼层
aiyeba 发表于 2017-9-15 09:25
一开始的时候你犯了一个致命的错误.就是无论你接收多少数据.

你的i   永远为0.原因自己想.

局部变量的原因,每次进入函数的时候都会执行重新定义?
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:29:12 | 显示全部楼层
chengnnan 发表于 2017-9-14 20:34
你之前的函数其实把a里面的i定义成全局变量也是可以的

由于i局部变量的原因?每次都是a[0]
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:33:50 | 显示全部楼层
lvkanger 发表于 2017-9-15 10:51
你肯定要搞一个缓存来缓存你的接收数据的,接收完成数据后要给主函数一个标志。去处理你缓存中的数据就可 ...

嗯,我问的不是这个意思。我的意思是:数据来了,有串口中断标志,但是由于别的高优先级中断正在执行使得这次数据还没有到串口中断去接收,然后这时候串口又来一包数据,那么中断返回读的哪包数据?
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:35:25 | 显示全部楼层
来俩不甜的 发表于 2017-9-15 11:02
单片机处理速度,比你的通讯速率快的多得多。不存在你处理不完又来一包数据。你想的太多了,按你说的情况 ...

嗯,可能我表达不清除。我的意思是:数据来了,串口中断触发了,但是由于别的高优先级中断什么的使得这次中断被打断了,然后这时候串口又来一包数据,那么串口中断中读的哪包数据?
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:36:35 | 显示全部楼层
meimengxing2014 发表于 2017-9-15 15:53
等你下一包发过来的时候,前面一包早就被处理了,除非2包数据之间的时间非常的短,短到单片机都无法处理完 ...

嗯,串口处理是快,但是有其他中断的情况。我的意思是:数据来了,串口中断触发了,但是由于别的高优先级中断什么的使得这次中断被打断了,然后这时候串口又来一包数据,那么中断返回读的哪包数据?
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-15 17:44:15 | 显示全部楼层
顺便再贴一段读串口数据的代码:(以后自己要用了,就过来复制)
typedef struct
{
     uint8_t MaxLength;
    uint8_t Length;
    uint8_t Data[BUF_ARRAY_LEN]; //接收数据缓存区
}BUF_TypeDef;

typedef struct
{
     uint8_t      Total;
    uint8_t      Current;    /* write */
    uint8_t      Readidx;    /* read */
    BUF_TypeDef  Buffer[BUF_ROW_NUM];
}RECVBUF_TypeDef;  //接收数据缓存区

//ch = USART_ReceiveData(UART4); //数据有了,放到目的地
①:从串口读到数据后
/*将串口读取到的数据转到接收缓冲数组*/
uint8_t RecvBufPushChar(RECVBUF_TypeDef *RevBuf, uint8_t ch)
{
   uint8_t BufIdx = RevBuf->Current;                  //获取当前数组(第几行数组)
  uint8_t BufLen = RevBuf->Buffer[BufIdx].Length;    //获取当前数组长度
  if(RevBuf->Total >= BUF_ROW_NUM)   //判断接收缓冲区是否为满
  {
       return 0;
  }
  RevBuf->Buffer[BufIdx].Data[BufLen++] = ch;              //将字符放入当前数组中
  RevBuf->Buffer[BufIdx].Length = BufLen % BUF_ARRAY_LEN;   //数组长度+1
  return 1;
}
②:串口接收完最后一个字节后
/*将串口读取的最后一个字符转到接收缓冲区数组,并指向下一个数组*/
uint8_t RecvBufPushEndChar(RECVBUF_TypeDef *RevBuf/*, uint8_t ch*/)
{
//     RecvBufPushChar(RevBuf,ch);
    RevBuf->Current++;
    RevBuf->Current=RevBuf->Current%BUF_ROW_NUM;
    RevBuf->Total++;
    if(RevBuf->Total>=BUF_ROW_NUM)  //优化多次写数组超出设定值得BUG
   {
         RevBuf->Total=BUF_ROW_NUM;
   }   
    return 1;
}
③:数据转存到数组
/*读接收缓冲区的数据*/
uint8_t RecvBufGetData(RECVBUF_TypeDef *RevBuf, uint8_t *DataBuf, uint8_t Length)
{
     uint8_t DataLen=RevBuf->Buffer[RevBuf->Readidx].Length;
    uint8_t StrLen=Length>DataLen?DataLenength;

    RecvBufCopy(DataBuf,RevBuf->Buffer[RevBuf->Readidx].Data,StrLen);
    RecvBufReset(RevBuf,RevBuf->Readidx);  //清除当前数组内容

    RevBuf->Readidx ++; //指向下一组
    RevBuf->Readidx = RevBuf->Readidx % BUF_ROW_NUM;

    RevBuf->Total --; //标识数组容量增1
    if(RevBuf->Total>BUF_ROW_NUM)  //优化多次读数组超出设定值得BUG
    RevBuf->Total=0;
   
     return StrLen;
}
回复

使用道具 举报

3

主题

130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3132
金钱
3132
注册时间
2017-3-2
在线时间
324 小时
发表于 2017-9-15 18:36:12 | 显示全部楼层
huangbo265419 发表于 2017-9-15 17:36
嗯,串口处理是快,但是有其他中断的情况。我的意思是:数据来了,串口中断触发了,但是由于别的高优先级 ...

高优先级的中断处理完了,就会处理低优先级的中断,即使这样单片机也完全能处理得过来,你放心
坚持不懈的努力!
回复

使用道具 举报

56

主题

520

帖子

0

精华

高级会员

Rank: 4

积分
964
金钱
964
注册时间
2014-11-18
在线时间
160 小时
发表于 2017-9-15 19:51:58 | 显示全部楼层
meimengxing2014 发表于 2017-9-15 18:36
高优先级的中断处理完了,就会处理低优先级的中断,即使这样单片机也完全能处理得过来,你放心

不是像的这样的,串口在接收数据的时候最好不要被打断,否者会掉包的.

除非用的是DMA,这样就算被打断了,数据还在缓存区.
自己选择的路,成家前走完。
回复

使用道具 举报

3

主题

130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3132
金钱
3132
注册时间
2017-3-2
在线时间
324 小时
发表于 2017-9-15 22:17:50 | 显示全部楼层
aiyeba 发表于 2017-9-15 19:51
不是像的这样的,串口在接收数据的时候最好不要被打断,否者会掉包的.

除非用的是DMA,这样就算被打断了, ...

恩 ,是的,把串口中断优先级设置高些
坚持不懈的努力!
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2017-9-16 09:56:18 | 显示全部楼层
huangbo265419 发表于 2017-9-15 17:35
嗯,可能我表达不清除。我的意思是:数据来了,串口中断触发了,但是由于别的高优先级中断什么的使得这次 ...

只要你的中断处理函数按标准来,别带延时、别带printf。绝对没问题。cpu处理速度要多块有多快,比你想的还要快。波特率我最常用的就是9600、115200.你不相信自己算一下,串口真的很慢
我有故事,你有酒吗
回复

使用道具 举报

5

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
107
金钱
107
注册时间
2014-3-24
在线时间
19 小时
 楼主| 发表于 2017-9-30 17:56:16 | 显示全部楼层
放一个modbus的文档,备不时之需

Modbus协议规范(中文).pdf

4.51 MB, 下载次数: 171

回复

使用道具 举报

6

主题

64

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
320
金钱
320
注册时间
2017-10-14
在线时间
80 小时
发表于 2017-10-15 00:17:12 | 显示全部楼层
static  i
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-13 20:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表