解决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编程中内置的NotImplemented类型的用法
这篇文章主要介绍了Python编程中内置的NotImplemented类型的用法,NotImplemented 是Python在内置命名空间中的六个常数之一,下文更多详细内容需要的小伙伴可以参考一下2022-03-03Django 用户登陆访问限制实例 @login_required
这篇文章主要介绍了Django 用户登陆访问限制实例 @login_required,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2020-05-05
最新评论