UART 接收数据较大时,怎么接收



  • uart就这样,你看发送那端可以分开两次发不,或者用别的串口协议传输数据



  • 你是用jlink调试的



  • @鱼的记忆 发送那端是别人的设备控制不了,是用Jlink调试的,打印口被用来传输数据了



  • 这个有点麻烦,这个只能富瑞坤内部人员,看可以解决不,分两次接收,我只会这种



  • 如果可以控制发送端,分包发送,两次接收,应该是没问题。谢谢你的帮忙



  • 找到解决办法了,接收中断改为半满,这样就有足够时间读取数据,不要在中断中打断点查看数据,这样也会导致接收不完整。具体做法如下
    串口初始化
    0_1617068878547_94a9dcdc-df40-4ba2-b1c1-24672afe74ca-image.png
    中断执行内容还是上面的图



  • 我不建议用芯片带FIFO来做接收中断,我从来都是自己做1个串口字节接收缓冲区,1个串口包处理缓冲区。这种结构对于1个叠包也基本够用了。
    attribute((weak)) attribute((section("ram_code"))) void uart0_isr_ram(void)
    {
    uint8_t int_id;
    uint8_t rx_byte;

    int_id = uart0_reg->u3.iir.int_id;
    
    if(int_id == 0x04 || int_id == 0x0c )   /* Receiver data available or Character time-out indication */
    {
        rx_byte = uart0_reg->u1.data;
        uart0_info.packet_timeout = 2;
    	if(1 == uart0_info.rxd_flg)
    	{
    		uart0_info.rxd_buf[uart0_info.rxd_ctr++] = rx_byte; //
    		if(uart0_info.rxd_ctr == uart0_info.rxd_len)
    		{   //收齐 处理包
    			uart0_info.rxd_ctr = 0;
    			uart0_info.rxd_flg = 0;
    			uart0_info.rxd_cmd_len = uart0_info.rxd_len; 
    			memcpy(uart0_info.rxd_cmd_buf, uart0_info.rxd_buf, uart0_info.rxd_len); 
    			evt.event_id = 0;            //串口0 事件
    			os_msg_post(uart01_task_id,  &evt);
    		}
    		else if(3==uart0_info.rxd_ctr)
    		{
    		    uart0_info.rxd_len = rx_byte + 4;//后面字节包的长度
    		}
    		else ;
    	}
    	else //== 0
    	{
    		if(0xA7 == rx_byte) //协议包头
    		{
    			uart0_info.rxd_flg = 1; //开启接收
    			uart0_info.rxd_ctr = 1; //接收字节计数
    			uart0_info.rxd_buf[0] = rx_byte;
    		}			
    	}		
    }
    if(int_id == 0x06)
    {
        volatile uint32_t line_status = uart0_reg->lsr;
    }
    if(int_id == 0x02)
    {	
       if(uart0_info.txd_ctr < uart0_info.txd_len[uart0_info.txd_busy_index]) //判断当前包是否发送完毕
       {   
    	   uart0_reg->u1.data     = uart0_info.txd_buf[uart0_info.txd_busy_index][uart0_info.txd_ctr++];
       }
       else //发完一包 休息或继续下一包
       {
    		uart0_info.txd_len[uart0_info.txd_busy_index] = 0;     //清除发送包长度 表示空的 可以重新组装			
    		if(uart0_info.txd_len[uart0_info.txd_emptypp_index]>0) //有包要发 则继续
    		{
    			if(0==uart0_info.txd_busy_index) {  
    				uart0_info.txd_busy_index    = 1;
    				uart0_info.txd_emptypp_index = 0;
    			}
    			else {  	
    				uart0_info.txd_busy_index    = 0; 	
    			    uart0_info.txd_emptypp_index = 1;
    			}			 				                           
    			uart0_info.txd_ctr  = 1;
    			uart0_reg->u1.data  = 0xA7; // 
    		}
    		else
    		{
    			uart0_reg->u2.ier.eti  = 0;   //关闭发送中断 避免这个MCU 产生发送空中断,STC51则不必 关不掉(因为51发送跟接收中断开关共用,而你不可能关闭接收中断)
    			uart0_info.tx_busy = IDLE;
    		}		   
       }
    }
    

    }



  • 修改接收中断处理函数,另外收到第一个byte开启硬件定时器做超时处理,收到下一个byte后reload定时器初值保证不产生中断,在间隔一定时间不收到产生超时中断,这个时间要以当前波特率下的的一byte传输数据留下余量。即使用超时成帧机制,再处理一帧数据



  • @赢娶姗姗 挺好的,值得学习学习,感谢



  • @zj4068 现在的使用和这个方法类似



  • 自己多想方法,原厂只是demo而已,我把发送函数也做了处理。目前demo是使用无中断发送。好处比较简单,不好的地方数据超多,会比较占用时间。使用填好发送缓冲我数据后,发送第一个字节启动tx串口中断,后续在发送中断中完成,发完后关闭发送中断。相对高效,如果原厂可以开放dma会更高效。



  • @zj4068 没错的 发送中断方式 比查询方式 会更少阻塞CPU一些。 DMA有的话更好, 中断发送方式更加通用,8位机基本没DMA,有的32位也没有串口发送 DMA呢