python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python串口接收无标识不定长数据

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

作者:我我我只会printf

这篇文章主要介绍了解决Python串口接收无标识不定长数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

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

在接收不定长数据时,没有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;
			}
}

总结

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

您可能感兴趣的文章:
阅读全文