解决Python串口接收无标识不定长数据

 更新时间:2023年09月06日 14:56:58   作者:我我我只会printf  
这篇文章主要介绍了解决Python串口接收无标识不定长数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Python串口接收无标识不定长数据

python串口读取数据可以使用:

  • serial.read(n) n为读取数据个数,无参则读取一个
  • serial.readline() 读取到\n,读不到则阻塞直到读取到\n

在接收不定长数据时,没有n可以指定,接收数据也未必有\n,python又没有串口空闲中断,但是可以用延时来解决。

import serial
from time import sleep
ser = serial.Serial(port="COM5",baudrate=9600,timeout=0.5)
if ser.isOpen() :
    print("open")
    while True :
        n = ser.inWaiting()
        if n :
            sleep(0.1)
            n = ser.inWaiting()
            data = ser.read(n)
            print(data)
else:
    print(" not open")
ser.close()

接收可以单开一个线程,在接收到数据后延时0.1s再查询当前缓冲区数据个数,第一次查询并不接收,所以不会清除缓存。

相当于接收到数据后,延时0.1s后再取数据。

也就是下位机发送的数据需要在0.1s内发送完成,发送间隔大于0.1s。

这个时间应该根据下位机发送来定。

注意:

上位机与下位机数据收发时序需考虑

串口接收不定长数据的问题

这个通用的方法,其实原理就是传输两个字节间是否超过了指定时间,如果超过了一定的时间,就认为是接收完一帧数据了。

首先我们要知道,串口是接收一个字节,就会发生一次中断,如果一帧数据包含10个字节,就会发生10次中断。

在接收一个字节以后,会紧跟着接收下一个字节,如果时间超了一定值,就代表一帧数据已经发完了

比如.

波特率为9600,8位(数据位)+2位(开始位+停止位)=10位 :每个串口中断时间为10位 *(1000/9600),那么传一个字节1MS左右,

/*----------------------------------*/
/*-------- 定时器3 操作函数 --------*/
/*----------------------------------*/
void t3int() interrupt 19 using 1          //中断入口
{
if(uart2Ri_start){
 uart2Ri_start_time++;
  if(uart2Ri_start_time>12){
	uart2Ri_start=0;
	uart2Ri_start_time=0;
	uart2Ri_frame_flat=1;
	uart2Ri_cnt=0;
	}
  }
 	time_ms_pwm++;	
	time500ms_tmp1++;
		//时间点切换计时
		//脉冲宽度调制	
		if(time_ms_pwm <= pwm){
			OE =0;
		}else{
			OE =1;
			if(time_ms_pwm >= 14 ){
				time_ms_pwm =0;
				OE =1;
			}
		}
		RunLed++;
		if(RunLed>200){
			RunLed=0;
		RunState=~RunState;
		}
}
/*----------------------------
 串口中断2 中断服务程序
-----------------------------*/
#define S2RI  0x01              //S2CON.0
#define S2TI  0x02              //S2CON.1
#define S2RB8 0x04              //S2CON.2
#define S2TB8 0x08              //S2CON.3
char Count=0;
int uart1TimeOut=0;
char data1;
void Uart2() interrupt 8 using 1
{
	   unsigned char dat =0;                            //暂存接收的数据   
    //接收操作
    if (S2CON & S2RI){
			 S2CON &= 0xfe;
		   uart2Ri_start=1;                           //串口接收开始计时
    if(uart2Ri_cnt<uart2Ri_maxCnt){
		    rxd_buf[uart2Ri_cnt++]=S2BUF;
		   }
		else
		{
		uart2Ri_cnt=uart2Ri_maxCnt;
		}
			 uart2Ri_start_time=0;
		}
    if (S2CON & S2TI)
    {
        S2CON &= ~S2TI;         //清除S2TI位
        busy = 0;               //清忙标志
    }
}
 
 unsigned char time_ms =9;
/*******************************************************************
* 函数名 :  timer0_init
* 描述   : 1毫秒的中断。
* 参数   : ALL_INT_Enable -- 使能总中断
********************************************************************/
void tm0_isr() interrupt 1 using 1
{ 
		time_ms++;
		if(USART2_RX_STA & 0x40){
      uart_time_sta++;   //接收超时计时
			if( uart_time_sta >=12){
         // rx_cnt =0;
          USART2_RX_STA =0x80; //这里也清0了允许接收位
		 // USART2_485_Status_Rx_Tx=1;//接收发送标记位。
      }
		} 
}
 

以下是串口的部分,串口接收发送部分的调用过

 
#include "main.h"
#include "uart.h"
#include "protocol_process.h"
#include "stdio.h"
#define FOSC 11059200L          //系统频率
#define BAUD 115200               //串口波特率
//#define FOSC 11059200L          //系统频率
//#define BAUD 115200             //串口波特率
#define NONE_PARITY     0       //无校验
#define ODD_PARITY      1       //奇校验
#define EVEN_PARITY     2       //偶校验
#define MARK_PARITY     3       //标记校验
#define SPACE_PARITY    4       //空白校验
#define PARITYBIT EVEN_PARITY   //定义校验位
#define S2RI  0x01              //S2CON.0
#define S2TI  0x02              //S2CON.1
#define S2RB8 0x04              //S2CON.2
#define S2TB8 0x08              //S2CON.3
#define S2_S0 0x01              //P_SW2.0
bit busy;
//dong 2019-03-19
//unsigned char rx_max_len =256;
xdata unsigned char USART2_RX_BUF_test[ rx_max_len ];
xdata unsigned char USART2_RX_BUF[ rx_max_len ];
xdata unsigned char USART2_TX_BUF[ rx_max_len ];
unsigned char USART2_485_Status_Rx_Tx=0;
unsigned char USART2_RX_STA =0;    //位[7]-接收成功标志,位[6]-允许接收数据标志(包头正确标志) 
unsigned char uart_time_sta =0;    //用于串口接收计时
unsigned char rx_cnt =0;
void uart2_init(char ALL_INT_Enable)
{
    P_SW2 &= ~S2_S0;                 //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
       //P_SW2 |= S2_S0;             //S2_S0=1 (P4.6/RxD2_2, P4.7/TxD2_2)
    S2CON = 0x50;                    //8位可变波特率
    T2L = (65536 - (FOSC/4/BAUD));   //设置波特率及重装值
    T2H = (65536 - (FOSC/4/BAUD))>>8;
    AUXR |= 0x14;                    //T2为1T模式, 并启动定时器2
    IE2 = 0x01;                      //使能串口2中断
    if(ALL_INT_Enable){
      EA = 1; 
    }else{
      EA = 0; 
    }     
}
void UartInit(void)		//9600bps@11.0592MHz
{
  P_SW2 &= ~S2_S0;                 //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
	S2CON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x04;		//定时器2时钟为Fosc,即1T
	T2L = 0xE0;		//设定定时初值
	T2H = 0xFE;		//设定定时初值
	AUXR |= 0x10;		//启动定时器2
}
void SendData(unsigned char dat)  
{
    while (busy);          //等待前面的数据发送完成
    busy = 1;
    S2BUF = dat;                //写数据到UART2数据寄存器
}
void SendString(unsigned char *s, unsigned char len)   
{
    unsigned char i =0;
		for(i=0; i<len; i++){
			SendData(*s++);         //发送当前字符	
		}
}
/*----------------------------
发送串口数据
----------------------------*/
void SendData2(char dat)
{
    while (busy);               //等待前面的数据发送完成
   // ACC = dat;               //获取校验位P (PSW.0)
  S2BUF = dat;                //写数据到UART2数据寄存器
    busy = 1;
}
/*----------------------------
发送字符串
----------------------------*/
void SendString2(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
    SendData2(*s++);         //发送当前字符
    }
}
//重写putchar函数
char putchar(char c)
{
     SendData2(c);
    return c;
}
//用于485接收完成数据后再发送数据
void Uart2() interrupt 8 using 1 /* UART2 中断服务程序 */
{
    unsigned char dat =0;                               //暂存接收的数据 
    unsigned char checksum =0;
    unsigned char offset =0;
    //接收操作
   if ( (S2CON & S2RI)  && (USART2_485_Status_Rx_Tx==0 )){  //当USART2_STA_RX_TX:0时为485数据线空闲状态。
 //   if ( (S2CON & S2RI) ){  //当USART2_STA_RX_TX:0时为485数据线空闲状态。
			 USART2_485_Status_Rx_Tx=1;
       //S2CON &= ~S2RI;        //清除S2RI位
        S2CON &= 0xfe;          //清除S2RI位
        dat = S2BUF;		   
        //数据包接收是否允许标志位检测
			   USART2_RX_STA |= 0x40;
		   //完成时不接收,清0了才能接收数据,主函数查询处理完成后置1,并将接收数据缓存清空掉待下次接收。
				if( !(USART2_RX_STA & 0x80) ){ 
            uart_time_sta =0x00;       //连续每来一字节间隔时间清0,达到不过超时时间,过了超时时间置1 
            //USART2_RX_STA的第二个位允许接收数据标志检测
            if(USART2_RX_STA & 0x40){
                if(rx_cnt < rx_max_len){
                   USART2_RX_BUF[rx_cnt++] =dat;
        }
				else
				{
                //数据包接收完成
                //  rx_cnt =0;
								//	USART2_485_Status_Rx_Tx=1; //大于最大长度退出时接收标志位为0:空闲
                  USART2_RX_STA =0x80;
                  uart_time_sta =12;
        }
        }
				}
		    }
    //发送操作
    if (S2CON & S2TI){
        //  S2CON &= ~S2TI;         //清除S2TI位
        S2CON &= 0xfd;                                  //清除S2TI位
      //  S2BUF=checksum;
        busy = 0;                                  //清忙标志
    }
}
void clear_rx_buf()
{
			unsigned char i =0;
			for(i=0; i<rx_max_len; i++){
				USART2_RX_BUF[i] =0;
			}
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 解决Python 使用h5py加载文件,看不到keys()的问题

    解决Python 使用h5py加载文件,看不到keys()的问题

    今天小编就为大家分享一篇解决Python 使用h5py加载文件,看不到keys()的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-02-02
  • Flask自定义序列化超详细讲解

    Flask自定义序列化超详细讲解

    序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。php将数据序列化和反序列化会用到两个函数:serialize 将对象格式化成有序的字符串、unserialize 将字符串还原成原来的对象
    2022-11-11
  • pandas loc与iloc用法及区别

    pandas loc与iloc用法及区别

    本文主要介绍了pandas loc与iloc用法及区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • 在keras中实现查看其训练loss值

    在keras中实现查看其训练loss值

    这篇文章主要介绍了在keras中实现查看其训练loss值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • python opencv实现影像拼接

    python opencv实现影像拼接

    这篇文章主要介绍了python opencv实现影像拼接,主要包括内容又垂直影像拼接vconcat和水平影像拼接hconcat以及纵向拼接多个不同图片,下面详细的相关内容,需要的朋友可以参考一下
    2022-03-03
  • 浅析Python3中遍历目录的三种方法

    浅析Python3中遍历目录的三种方法

    在学习中,工作中,我们经常会说遍历一下当前目录咯,那么Python3中遍历目录的方法具体都有哪些呢并且如何操作呢,下面小编就来和大家简单聊聊吧
    2023-07-07
  • python flask解析json数据不完整的解决方法

    python flask解析json数据不完整的解决方法

    这篇文章主要介绍了python flask解析json数据不完整的解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • flask中的wtforms使用方法

    flask中的wtforms使用方法

    这篇文章主要介绍了flask中的wtforms使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Python jieba分词添加自定义词和去除不需要长尾词的操作方法

    Python jieba分词添加自定义词和去除不需要长尾词的操作方法

    这篇文章主要介绍了Python jieba分词如何添加自定义词和去除不需要长尾词,主要介绍jieba的基础用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Python利用subplots_adjust方法解决图表与画布的间距问题

    Python利用subplots_adjust方法解决图表与画布的间距问题

    这篇文章主要介绍了如何在使用python 的 matplotlib库绘图时, 使用subplots_adjust()方法来调整图表与画布之间的间距,以及图表与图表之间的间距,感兴趣的可以了解一下
    2022-04-04

最新评论