OpenEdv-开源电子网

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

串口数据接收过快时,检查包头校验位的代码就会报错,发慢一地就不会

[复制链接]

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
发表于 2019-5-28 08:26:39 | 显示全部楼层 |阅读模式
3金钱
可能两条数据间隔太短,串口一次把多条当一条处理了,轻问各位大佬有什么办法解决

检验的

检验的

串口二等待接收任务

串口二等待接收任务
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
757
金钱
757
注册时间
2015-10-27
在线时间
180 小时
发表于 2019-5-28 08:38:55 | 显示全部楼层
试着用一下空闲中断+DMA接收,如果数据接收很快,把每次接收的数据都先做缓存再处理。数据处理不要放在中断
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2018-9-6
在线时间
37 小时
发表于 2019-5-28 08:40:47 | 显示全部楼层
本帖最后由 IoTCatcher 于 2019-5-28 08:45 编辑

buff[512]这个数组, 升级成支持FIFO功能.然后每次app处理就在fifo里面取一位, 校验是不是头, 在开始取后面的数据.
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 08:50:58 | 显示全部楼层
IoTCatcher 发表于 2019-5-28 08:40
buff[512]这个数组, 升级成支持FIFO功能.然后每次app处理就在fifo里面取一位, 校验是不是头, 在开始取后面 ...

请问这要怎么实现啊
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 08:52:06 | 显示全部楼层
g753388438 发表于 2019-5-28 08:38
试着用一下空闲中断+DMA接收,如果数据接收很快,把每次接收的数据都先做缓存再处理。数据处理不要放在中断

大概500ms一次没问题,100ms就有问题
回复

使用道具 举报

22

主题

271

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
405
金钱
405
注册时间
2019-3-21
在线时间
107 小时
发表于 2019-5-28 09:25:46 | 显示全部楼层
建议建一个环形缓冲区,,
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-28 09:26:26 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 08:52
大概500ms一次没问题,100ms就有问题

看你好像是中断一股脑接收,一次读取全部512处理,肯定有问题呀  既然有包头,读取两个包头之间的处理  要么就用空闲中断
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 10:03:50 | 显示全部楼层
nashui_sx 发表于 2019-5-28 09:26
看你好像是中断一股脑接收,一次读取全部512处理,肯定有问题呀  既然有包头,读取两个包头之间的处理   ...

[mw_shl_code=c,true]int UART_Read(int dev, unsigned char *buf, int size )
{
        int r_len;

        if( dev < 0 || dev >= UART_MAX ) return -1;
        if ( size <= 0 ) return 0;

        r_len = 0;

        while(uart_dev[dev].recv.Rd != uart_dev[dev].recv.Wr )
        {
                *buf = uart_dev[dev].recv.buf[uart_dev[dev].recv.Rd];
                uart_dev[dev].recv.Rd = (uart_dev[dev].recv.Rd+1) % BUFFER_LEN;
                buf++;
                if( ++r_len >= size ) return r_len;
        }

        return r_len;
}

int UART_Write( int dev, unsigned char *buf, int size )
{
#if OS_CRITICAL_METHOD == 3
        OS_CPU_SR  cpu_sr = 0;
#endif

        int w_len;

        if( dev < 0 ||dev >= UART_MAX ) return -1;
        if ( size <= 0 ) return 0;

        w_len = 0;

        while(uart_dev[dev].send.Rd != ((uart_dev[dev].send.Wr+1)%BUFFER_LEN))
        {
                uart_dev[dev].send.buf[uart_dev[dev].send.Wr] = *buf;
                uart_dev[dev].send.Wr = ( uart_dev[dev].send.Wr + 1 )%BUFFER_LEN;

                w_len++;
                if ( w_len >= size ) break;
                buf++;
        };
    #if 0
    if(DEV_UART3 == dev)
    {
        printf("^^^%d,%d^^^\r\n",uart_dev[dev].send.Rd,uart_dev[dev].send.Wr);
    }
    #endif

        OS_ENTER_CRITICAL();
        if ( uart_dev[dev].send.State == SEND_IDLE )
                {
                OS_EXIT_CRITICAL();

                uart_dev[dev].send.State = SENDING;
                //(*((volatile unsigned char *) uart_dev[dev].send.reg)) = uart_dev[dev].send.buf[uart_dev[dev].send.Rd];
                switch(dev)
                {
                case DEV_UART1:
                        USART_SendData(USART1,uart_dev[dev].send.buf[uart_dev[dev].send.Rd]);
                        #if 1
                        USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
                        #endif
                        break;
                case DEV_UART2:
                        USART_SendData(USART2,uart_dev[dev].send.buf[uart_dev[dev].send.Rd]);
                        #if 1
                        USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
                        #endif
                        break;
                }

                return w_len;
        }
        OS_EXIT_CRITICAL();

        return w_len;
}


void USART1_IRQHandler(void)
{
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
                USART_ClearITPendingBit(USART1, USART_IT_RXNE);
                //接收数据
                //uart_dev[DEV_UART1].recv.buf[uart_dev[DEV_UART1].recv.Wr] = U1RBR;
                uart_dev[DEV_UART1].recv.buf[uart_dev[DEV_UART1].recv.Wr] = USART_ReceiveData(USART1);
                  uart_dev[DEV_UART1].recv.Wr = (uart_dev[DEV_UART1].recv.Wr +1)%BUFFER_LEN;
                  if(uart_dev[DEV_UART1].recv.Wr == uart_dev[DEV_UART1].recv.Rd ) {
                          uart_dev[DEV_UART1].recv.Rd = (uart_dev[DEV_UART1].recv.Rd +1)%BUFFER_LEN;
                  }
                //USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);


        }

        #if 1
        if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET){
        #else
        if(USART_GetITStatus(USART1, USART_IT_TC) != RESET){
                USART_ClearITPendingBit(USART1, USART_IT_TC);
        #endif
                //发送数据
                if(uart_dev[DEV_UART1].send.State == SENDING){
                        uart_dev[DEV_UART1].send.Rd = (uart_dev[DEV_UART1].send.Rd +1)%BUFFER_LEN;
                        if ( uart_dev[DEV_UART1].send.Rd == uart_dev[DEV_UART1].send.Wr) {
                                uart_dev[DEV_UART1].send.State = SEND_IDLE;
                        } else {
                                //U1THR = uart_dev[DEV_UART1].send.buf[uart_dev[DEV_UART1].send.Rd];
                                USART_SendData(USART1, uart_dev[DEV_UART1].send.buf[uart_dev[DEV_UART1].send.Rd]);
                        }
                }
                #if 1
                else{
                        USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
                }
                #endif
        }
}


void USART2_IRQHandler(void)
{
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){
                USART_ClearITPendingBit(USART2, USART_IT_RXNE);
                //接收数据
                //uart_dev[DEV_UART1].recv.buf[uart_dev[DEV_UART1].recv.Wr] = U1RBR;
                uart_dev[DEV_UART2].recv.buf[uart_dev[DEV_UART2].recv.Wr] = USART_ReceiveData(USART2);
                  uart_dev[DEV_UART2].recv.Wr = (uart_dev[DEV_UART2].recv.Wr +1)%BUFFER_LEN;
                  if(uart_dev[DEV_UART2].recv.Wr == uart_dev[DEV_UART2].recv.Rd ) {
                          uart_dev[DEV_UART2].recv.Rd = (uart_dev[DEV_UART2].recv.Rd +1)%BUFFER_LEN;
                  }
                //USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
        }

        #if 1
        if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET){
        #else
        if(USART_GetITStatus(USART1, USART_IT_TC) != RESET){
                USART_ClearITPendingBit(USART1, USART_IT_TC);
        #endif
                //发送数据
                if(uart_dev[DEV_UART2].send.State == SENDING){
                        uart_dev[DEV_UART2].send.Rd = (uart_dev[DEV_UART2].send.Rd +1)%BUFFER_LEN;
                        if ( uart_dev[DEV_UART2].send.Rd == uart_dev[DEV_UART2].send.Wr) {
                                uart_dev[DEV_UART2].send.State = SEND_IDLE;
                        } else {
                                //U1THR = uart_dev[DEV_UART1].send.buf[uart_dev[DEV_UART1].send.Rd];
                                USART_SendData(USART2, uart_dev[DEV_UART2].send.buf[uart_dev[DEV_UART2].send.Rd]);
                        }
                }
                #if 1
                else{
                        USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
                }
                #endif
        }
[/mw_shl_code]
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 10:05:22 | 显示全部楼层
nashui_sx 发表于 2019-5-28 09:26
看你好像是中断一股脑接收,一次读取全部512处理,肯定有问题呀  既然有包头,读取两个包头之间的处理   ...

数据有一条是不定长的,大佬看看我的串口处理代码,同事给的
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 10:16:49 | 显示全部楼层
nashui_sx 发表于 2019-5-28 09:26
看你好像是中断一股脑接收,一次读取全部512处理,肯定有问题呀  既然有包头,读取两个包头之间的处理   ...

数据不定长
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-28 10:21:35 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 10:05
数据有一条是不定长的,大佬看看我的串口处理代码,同事给的

各种方案都能解决,看你是对旧代码大刀阔斧的改还是修修补补
大刀阔斧就用空闲中断,小改这个已经有fifo处理了,你usartproess先查询帧头位置,读取第二个帧头前的长度就好了
回复

使用道具 举报

3

主题

1155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7464
金钱
7464
注册时间
2015-1-15
在线时间
1368 小时
发表于 2019-5-28 10:31:48 来自手机 | 显示全部楼层
学习别人是怎么用fifo的,感觉对处理串口通信会有帮助
回复

使用道具 举报

1

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2018-9-6
在线时间
37 小时
发表于 2019-5-28 11:51:58 | 显示全部楼层
本帖最后由 IoTCatcher 于 2019-5-28 11:58 编辑
余怡帆℡ 发表于 2019-5-28 08:50
请问这要怎么实现啊
看了下你的串口读写, 已经有fifo功能了.app分析数据的时候, 一位一位取试试.
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 14:54:23 | 显示全部楼层
IoTCatcher 发表于 2019-5-28 11:51
看了下你的串口读写, 已经有fifo功能了.app分析数据的时候, 一位一位取试试.

是一位位检验的啊,就是发快了就会报错,包头错,校验码错,应该是乱了
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 14:56:06 | 显示全部楼层
nashui_sx 发表于 2019-5-28 10:21
各种方案都能解决,看你是对旧代码大刀阔斧的改还是修修补补
大刀阔斧就用空闲中断,小改这个已经有fifo ...

判断这个包头和下个包头都正确才会继续,否则指针后移,再判断,但是这一步就直接返回了,估计是没有后面的包头
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 15:02:25 | 显示全部楼层
1599064432 发表于 2019-5-28 09:25
建议建一个环形缓冲区,,

有没有简单点的方法大神
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 15:11:04 | 显示全部楼层
yklstudent 发表于 2019-5-28 10:31
学习别人是怎么用fifo的,感觉对处理串口通信会有帮助

急急急,这个串口驱动也不是我写的,麻烦说详细点
回复

使用道具 举报

5

主题

106

帖子

0

精华

高级会员

Rank: 4

积分
757
金钱
757
注册时间
2015-10-27
在线时间
180 小时
发表于 2019-5-28 15:16:37 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 08:52
大概500ms一次没问题,100ms就有问题

那你用空闲中断吧,每次接收完就处理没问题,但是不要在中断里处理数据
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 15:23:29 | 显示全部楼层
g753388438 发表于 2019-5-28 15:16
那你用空闲中断吧,每次接收完就处理没问题,但是不要在中断里处理数据

那要改串口驱动吧
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 16:20:53 | 显示全部楼层
各位大佬们,这个是一个控制主机的设备,两个串口一个连上位机一个连WiFi,WiFi那边发指令控制上位机开机读取上位机外设信息并应答,只有两条指令是需要单片机应答的,因为这个协议不是很完善,我也不能改,现在问题是我发需要单片机应答的指令500ms一条没问题,100ms一条,检查数据帧的代码就各种报错,我猜测是数据处理不及时,多条当一条处理的,急急急,谢谢大家
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 16:21:33 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 16:20
各位大佬们,这个是一个控制主机的设备,两个串口一个连上位机一个连WiFi,WiFi那边发指令控制上位机开机读 ...

我也是个新手,希望大家能解答详细点
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2019-5-28 16:38:56 | 显示全部楼层
100ms是个很慢很慢的速度了
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-28 16:42:27 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 16:20
各位大佬们,这个是一个控制主机的设备,两个串口一个连上位机一个连WiFi,WiFi那边发指令控制上位机开机读 ...

看代码接收已经有fifo了,你就是读取的时候别一次读这么多就好了,一次读一帧就够了
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 16:57:35 | 显示全部楼层
nashui_sx 发表于 2019-5-28 16:42
看代码接收已经有fifo了,你就是读取的时候别一次读这么多就好了,一次读一帧就够了

主要是有个不定长的帧,所以不能写死
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 16:58:13 | 显示全部楼层
edmund1234 发表于 2019-5-28 16:38
100ms是个很慢很慢的速度了

是啊,那个协议只有一字节包头就没了
回复

使用道具 举报

0

主题

36

帖子

0

精华

高级会员

Rank: 4

积分
688
金钱
688
注册时间
2018-9-6
在线时间
249 小时
发表于 2019-5-28 17:18:55 | 显示全部楼层
开两个缓存接收数据,只要有1个缓冲区接收到了一帧数据,就换另一个去缓存,把已经接收到的数据及时处理掉,然后等待数据接收
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 17:29:52 | 显示全部楼层
[mw_shl_code=c,true]void Uart2Process(void)
{
        u8 buff[512];                        /*Need Modify*/
        int buffLen  = 0;
        int frameLen = 0;
        int i;

        buffLen = UART_Read(DEV_UART2, &buff[frameLen], sizeof(buff));
               
        //printf("zzzzzzzzzzzzz");
        if(buffLen != 0)
        {
                frameLen += buffLen;
                if( frameLen > sizeof( buff ))
                {       
                        buffLen  = 0;
                        frameLen = 0;
                        printf("VVVVVVVVVVVVVV");
                }

                for(i = 0;i < frameLen;i++)
                {
                               
                        if((buff== FRAME_COMM_START) && (buff[i+8] == FRAME_COMM_START))
                                {
                                        if(0 != appCommRevDataCheck(&buff,frameLen-i))
                                        {
                                                printf("QQQQQQQQQQQQ");
                                                continue;
                                        }
                                        else
                                        {
                                                appCommRevDataDeal(buff[1],&buff,frameLen-i);
                                                buffLen  = 0;
                                                frameLen = 0;
                                        }
                                }
                }
        }[/mw_shl_code]
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-28 17:30:41 | 显示全部楼层
余怡帆℡ 发表于 2019-5-28 17:29
[mw_shl_code=c,true]void Uart2Process(void)
{
        u8 buff[512];                        /*Need Modify*/

改成这样解析不报错了,但是还是会卡顿,就是收几条才会有应答
回复

使用道具 举报

3

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2019-4-23
在线时间
26 小时
 楼主| 发表于 2019-5-29 13:45:09 | 显示全部楼层
谢谢各位的帮助,不是一次处理了多条数据。是处理的一条不完整数据报的错,
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-18 23:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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