串口读取
python使用Serial模块读取串口数据

python使⽤Serial模块读取串⼝数据前⾔ pyserial 模块封装了对串⼝的访问,兼容各种平台。
使⽤模块安装pip install pyserial初始化import serialser = serial.Serial('com1', 9600, timeout=1)ser = serial.Serial("/dev/ttyUSB0", 9600, timeout=0.5) # 使⽤USB连接串⾏⼝ser = serial.Serial("/dev/ttyAMA0", 9600, timeout=0.5) # 使⽤树莓派的GPIO⼝连接串⾏⼝ser = serial.Serial(1, 9600, timeout=0.5)# winsows系统使⽤com1⼝连接串⾏⼝ser = serial.Serial("com1", 9600, timeout=0.5)# winsows系统使⽤com1⼝连接串⾏⼝ser = serial.Serial("/dev/ttyS1", 9600, timeout=0.5)# Linux系统使⽤com1⼝连接串⾏⼝不同平台下初始化对象属性name——设备名字port——读或者写端⼝baudrate——波特率bytesize——字节⼤⼩parity——校验位stopbits——停⽌位timeout——读超时设置writeTimeout——写超时xonxoff——软件流控rtscts——硬件流控dsrdtr——硬件流控interCharTimeout——字符间隔超时对象常⽤⽅法ser.isOpen()——查看端⼝是否被打开ser.open() ——打开端⼝ser.close()——关闭端⼝ser.read()——从端⼝读字节数据。
默认1个字节ser.read_all()——从端⼝接收全部数据ser.write("hello")——向端⼝写数据ser.readline()——读⼀⾏数据ser.readlines()——读多⾏数据in_waiting()——返回接收缓存中的字节数flush()——等待所有数据写出flushInput()——丢弃接收缓存中的所有数据flushOutput()——终⽌当前写操作,并丢弃发送缓存中的数据。
micropython uart 读取格式

Micropython是一种精简的Python解释器,专门用于微控制器和嵌入式系统。
它提供了一种方便的方式来编写和运行Python代码,并且可以轻松地与传感器、执行器和其他外部设备进行通信。
在Micropython中,UART(Universal AsynchronousReceiver/Transmitter)是一种常用的串行通信接口,用于将微控制器与其他设备连接起来。
在本文中,我们将探讨如何使用Micropython来读取和处理UART接收到的数据。
1. 确定串口配置在使用Micropython读取UART数据之前,首先需要确定串口的配置参数。
这些参数包括波特率、数据位、停止位和校验位等。
在Micropython中,可以通过调用`machine.UART`类来设置串口的配置,例如:```pythonuart = machine.UART(1, baudrate=9600, bits=8, parity=None, stop=1)```在这个例子中,我们创建了一个名为`uart`的串口对象,将其连接到第一个UART接口,并将波特率设置为9600,数据位设置为8位,停止位设置为1位,校验位设置为None。
2. 读取串口数据一旦串口被配置好,就可以开始读取接收到的数据了。
在Micropython中,可以使用`uart.read()`方法来从串口中读取指定长度的数据,例如:```pythondata = uart.read(10)```在这个例子中,我们从串口中读取了10个字节的数据,并将其赋值给名为`data`的变量。
需要注意的是,如果串口暂时没有接收到足够的数据,`uart.read()`方法会一直阻塞直至接收到指定长度的数据或者超时。
3. 处理串口数据一旦从串口中读取到数据,就可以对其进行进一步的处理了。
根据接收到的数据格式的不同,处理方法也会有所不同。
一种常见的情况是接收到的数据是ASCII格式的字符串,可以直接对其进行解析和处理,例如:```pythondata_str = data.decode('utf-8')```在这个例子中,我们将接收到的字节数据解码为UTF-8格式的字符串,并将其赋值给名为`data_str`的变量。
python读取串口数据的示例

python读取串⼝数据的⽰例python3 读取串⼝数据 demo最近在写⼀个demo,zigbee串⼝连接树莓派,树莓派使⽤串⼝通信接受zigbee穿过来得值。
其中我是⽤的树莓派是3代B+,zigbee每隔三秒钟从串⼝输出数据。
下⾯是python串⼝通信,但是不是linux的,是我在windows上写的测试demo,python版本是3。
python串⼝读取数据# TODO 串⼝读取数据# Auther wjwimport serial # 导⼊串⼝包import time # 导⼊时间包ser = serial.Serial("COM3",115200,timeout = 5) # 开启com3⼝,波特率115200,超时5ser.flushInput() # 清空缓冲区def main():while True:count = ser.inWaiting() # 获取串⼝缓冲区数据if count !=0 :recv = ser.read(ser.in_waiting).decode("gbk") # 读出串⼝数据,数据采⽤gbk编码print(time.time()," --- recv --> ", recv) # 打印⼀下⼦time.sleep(0.1) # 延时0.1秒,免得CPU出问题if __name__ == '__main__':main()上边的代码就已经实现python串⼝读数了,但⼤部分还需要写⼊。
串⼝写⼊数据其实就是⼀个write⽅法,我开了⼀个线程,在线程⾥获取串⼝出来的数据,然后⼀个死循环每隔⼀秒发1,每隔⼀秒发0. import serialimport timeimport _thread # 导⼊线程包data_ser = serial.Serial("COM3",115200,timeout = 5)data_ser.flushInput()def get_data():while True:data_count = data_ser.inWaiting()if data_count !=0 :recv = data_ser.read(data_ser.in_waiting).decode("gbk")print(time.time()," --- data_recv --> ", recv)time.sleep(0.1)if __name__ == '__main__':_thread.start_new_thread(get_data,()) # 开启线程,执⾏get_data⽅法while 1:time.sleep(20)data_ser.write(b'1') # 发送⼆进制1time.sleep(20)data_ser.write(b'0') # 发送⼆进制0完成了,应该差不多就这样!树莓派⾃带python,但是默认是python2,可以两⾏命令修改默认python3sudo rm /usr/bin/pythonsudo ln -s /usr/bin/python3.4 /usr/bin/python以上就是python 读取串⼝数据的⽰例的详细内容,更多关于python 读取串⼝数据的资料请关注其它相关⽂章!。
单片机89C52RC串口读取am2320温湿程序

// AM 系列读IIC 使用范例//单片机:AT89S52 或STC89C52RC// 功能:串口发送温湿度数据波特率9600// 晶振:12M (用户系统时钟如不是12M 请更改相关宏定义及注释的延时时间)// 编译环境: Keil3// 公司:奥松电子//****************************************************************//#include "reg52.h"#include <intrins.h>#define USE_T2#define FOSC 12000000#define BAUD 9600//端口位定义,可修改sbit SDA=P1A0;sbit SCL=P"1;//内部数据定义#define IIC_Add 0xB8 //器件地址#define IIC_RX_Length 15unsigned char IIC_TX_Buffer[]={0x03,0x00,0x04}; // 读温湿度命令(无CRC 校验) unsigned char IIC_RX_Buffer[IIC_RX_Length] = {0x00};// 读回的温湿度unsigned char Uart_RX_Buffer[30] = {0x00}; unsigned char *String;unsigned char WR_Flag;//字符串定义#define S_Function "Function: 03 04"#define S_Temp "Temp:"#define S_RH "RH:"#define S_CRCT "CRC: True"#define S_CRCF "CRC: Wrong"#define S_Data "Data: "#define S_NotS "Sensor Not Connected"void Ack(void);void NoAck(void); void delay10us(void) // 这个延时函数要大于5US 以上_nop_(); _nop_(); _nop_();_nop_(); _nop_(); _nop_(); }void delay1ms(unsigned int t){unsigned int i;unsigned int j;for(j=t;j>0;j--) for(i=124;i>0;i--);}void InitUART(void) {unsigned int iTmpBaud;unsigned long lTmpBaud; iTmpBaud = 0;//首先选定定时器 2 作为波特率发生器 ,16位定时器 ,自动装载SCON = 0x50; //SM0 SM1 SM2 REN TB8 RB8 TI RI //0 1 0 1 0 00 0PCON = 0x00; //PCON 的地址是 87H, 这里 SMOD =0//TF2 EXF2 RCLK TCLK EXEN2 TR2 C(/T2) CP(/RL2) //0 0 1 1 0 0 0 // / / / / / / T2OE DCEN //0 0 0 0 0 0 0 0//fosc = 22.1184M,6T: 144, 设置波特率//(RCAP2H,RCAP2L) = 65536- fosc/(n*Baud) 。
readfile串口原理

readfile串口原理
串口通信是一种用于在计算机或其他设备之间传输数据的常见方式。
readfile函数通常是用于在Windows平台上从串口读取数据的函数之一。
串口通信使用串行接口来传输数据,这意味着每个位都按顺序发送。
现在让我从多个角度来解释串口通信的原理和readfile函数的作用。
首先,串口通信使用串行接口传输数据,这意味着数据位按照顺序一个接一个地发送。
串口通信通常涉及两个设备,一个充当发送方,另一个充当接收方。
发送方将数据转换为串行数据流,并通过一根线路发送给接收方。
接收方接收到数据后,将其转换回并还原为原始数据。
串口通信通常涉及一些重要的参数,例如波特率(波特率决定了数据传输速度)、数据位(决定了每个字节的位数)、校验位(用于验证数据的正确性)、停止位(用于指示数据传输的结束)等。
这些参数需要在通信双方进行配置,以确保数据能够正确地传输和解析。
readfile函数是在Windows平台上用于从串口读取数据的函数
之一。
它允许应用程序从串口接收数据,并将其存储到指定的缓冲区中。
使用readfile函数需要指定串口句柄、缓冲区以及要读取的字节数等参数。
通过调用readfile函数,应用程序可以从串口接收数据,并进行进一步的处理和分析。
总之,串口通信是一种常见的数据传输方式,readfile函数是在Windows平台上用于从串口读取数据的函数之一。
通过理解串口通信的原理和readfile函数的作用,我们可以更好地理解和应用串口通信技术。
希望这些解释能够帮助你更好地理解串口通信和readfile函数的工作原理。
Linux_C_C++串口读写串口读写

Linux C/C++串口读写串口简介串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。
常用的串口是RS-232-C 接口(又称EIA RS-232-C)它是在1970 年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。
它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25 个脚的DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。
传输距离在码元畸变小于4% 的情况下,传输电缆长度应为50 英尺。
Linux 操作系统从一开始就对串行口提供了很好的支持串口操作打开串口在Linux 下串口文件是位于/dev 下的串口一为/dev/ttyS0串口二为/dev/ttyS1设置串口最基本的设置串口包括波特率设置,效验位和停止位设置。
设置这个结构体很复杂,我这里就只说说常见的一些设置:波特率设置设置波特率的例子函数:/***@brief 设置串口通信速率*@param fd 类型 int 打开串口的文件句柄*@param speed 类型 int 串口速度*@return void*/int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400,B1200, B300, };int name_arr[] ={38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; void set_speed(int fd, int speed){int i;int status;struct termios Opt;tcgetattr(fd, &Opt);for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {if (speed == name_arr[i]) {/*** tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。
Linux串口读取GPS数据
nt gps::set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
if ( tcgetattr( fd,&oldtio) != 0)
{
perror("SetupSerial 1");
break;
}
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
{
if (strstr(buf, "GPGGA") != NULL)
parseData(buf);
}
}
// restore fd: tcsetattr...直接连接串口的设备需要在此恢复波特率
close(fd);
}
模板二
与其他的关于设备编程的方法一样,在Linux下,操作、控制串口也是通过操作起设备文件进行的。在Linux下,串口的设备文件是/dev/ttyS0或/dev/ttyS1等。因此要读写串口,我们首先要打开串口,然后根据GPS模块的配置参数对串口的波特率、校验、流控制等进行设置,这些参数设置均通过对termios结构中c_cflag的配置实现,串口配置部分函数如下:
$GPGGA,064746.000,4925.4895,N,00103.9255,E,1,05,2.1,-68.0,M,47.1,M,,0000*4F
串口写入和读取数据
串⼝写⼊和读取数据SerialPort类WriteComm 写串⼝函数DWORD CSerialPort::WriteComm(char *buf, DWORD dwLength){if(!IsOpen()){return0;}assert(buf != NULL);COMSTAT comStat;DWORD dwErrorFlags;if (!ClearCommError(m_hCom, &dwErrorFlags, &comStat) && dwErrorFlags > 0){PurgeComm(m_hCom, PURGE_TXABORT | PURGE_TXCLEAR);}OVERLAPPED osWrite;memset(&osWrite, 0, sizeof(OVERLAPPED));osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);BOOL bWriteStat = WriteFile(m_hCom, buf, dwLength, &dwLength, &osWrite);if(!bWriteStat){if(GetLastError() == ERROR_IO_PENDING){WaitForSingleObject(osWrite.hEvent, 2000);}else{dwLength = 0;}}return dwLength;}调⽤char buf[10]; //字符数组将字符串通过 strcpy 放⼊字符数组再向串⼝写⼊strcpy(buf,"1234");m_SerialPort.WriteComm(buf,4);MessageBox(_T("1234"));buf[0]=0x61; //将要发送的字符串或⼗六进制数据储存在char型字符数组中,利⽤WriteComm发送到串⼝m_SerialPort.WriteComm(buf,1);ReadCommDWORD CSerialPort::ReadComm(char *buf, DWORD dwLength){if(!IsOpen()){return0;}buf[0] = '\0';COMSTAT comStat;DWORD dwErrorFlags;if (!ClearCommError(m_hCom, &dwErrorFlags, &comStat) && dwErrorFlags > 0){PurgeComm(m_hCom, PURGE_RXABORT | PURGE_RXCLEAR);return0;}if(comStat.cbInQue == 0){return0;}DWORD dwBytesRead=0;BOOL bReadStat;dwBytesRead = min(dwLength - 1, (DWORD)comStat.cbInQue);OVERLAPPED osRead;memset(&osRead,0,sizeof(OVERLAPPED));osRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);DWORD dwByteOfRead = 0;bReadStat = ReadFile(m_hCom, buf, dwBytesRead, &dwByteOfRead, &osRead);if(!bReadStat){if(GetLastError() == ERROR_IO_PENDING){WaitForSingleObject(osRead.hEvent, 2000);// GetOverlappedResult(m_hCom, &osRead, &dwByteOfRead, FALSE) ;}}// PurgeComm(m_hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ////清空串⼝的接收缓冲区,必要性不⼤,但有保证作⽤?清空的话如果⼤数据会丢失buf[dwByteOfRead] = '\0';return dwByteOfRead;}调⽤char *pBuf=new char[10]; //定义⼀个char型字符数组,动态分配内存 memset(pBuf,0,10);m_SerialPort.ReadComm(pBuf,10);。
单片机485串口读写冲突
单片机485串口读写冲突单片机485串口读写冲突是指在使用串口进行数据通信时,由于读和写操作同时进行而造成的冲突现象。
这种冲突会导致数据发送或接收不完整,甚至造成通信失败。
在单片机中,485串口通信的读写冲突问题可以通过以下方法解决:1. 采用流程控制:可以通过硬件或软件的方式实现流控制,例如使用硬件流控制的方式,通过控制CTS(Clear To Send)和RTS(Request To Send)信号来进行数据的读写控制。
2. 设置读写优先级:通过设置读写优先级,可以确保在进行数据通信时,读操作和写操作不会同时进行。
可以根据不同的应用场景和需求,设置读写操作的优先级,从而避免冲突。
3. 缓冲区设计:在单片机中,可以通过设置发送缓冲区和接收缓冲区来避免读写冲突。
发送缓冲区用于存储待发送的数据,当串口空闲时,将数据从缓冲区发送出去;接收缓冲区用于存储接收到的数据,当数据接收完成后,再从缓冲区读取。
4. 使用中断:可以使用串口中断来实现数据的读取和写入。
通过设置中断触发条件和中断服务程序,当数据接收完成或发送缓冲区空闲时,触发中断进行相应的读写操作,从而避免读写冲突。
5. 使用互斥锁:可以通过使用互斥锁来实现对串口的互斥访问。
当一个任务正在进行读或写操作时,其他任务需要等待访问权限,从而确保同一时间只有一个任务能够进行读写操作,避免冲突发生。
除了以上的解决方法,还可以通过合理的软件设计和优化算法来尽可能减少读写冲突的发生,例如使用DMA(Direct Memory Access)方式进行数据传输,减轻单片机CPU的负担,提高效率。
另外,在设计和调试过程中,可以使用示波器等工具进行数据监测和分析,找出冲突问题的具体原因,并及时采取相应的措施进行修复。
在实际应用中,针对不同的场景和需求,可能需要结合多种方法来解决读写冲突问题,需要根据具体情况进行选择和调整。
同时,还需要进行充分的测试和验证,确保系统的稳定性和可靠性。
BT201蓝牙模块串口指定路径读取U盘和TF卡里面的TXT串口输出
1一、简介
芯片支持文件系统,所以可以很轻易的读取到U 盘或者TF 卡里面指定的文件内容。
目前我们扩展了读取TXT 文件的功能,实现的方式是初始化U 盘或者TF 卡的时候读取一次,正常播放音乐的时候就不会去读了
二、实现的方法AT+AR/00*/002*.
指定“00xxx”文件夹里面的002xxx.文件读取
AT+AR/00*/003*.
指定“00”文件夹里面的003xxx.文件读取1、原理参考5.1.6,这里不再说明。
发送此指令之后,芯片会停止当前的音乐播放。
2、串口会以16进制发送出去。
注意是一比一的发送。
注意上图的TXT 中0x41对应字符“A”。
其中0x42对字符”B”。
3、如果待读取的文件少于512个字节,则读取一次就退出了。
音乐此时也是停止的
4、如果待读取的文件大于512个字节。
为了方便用户使用,我们设置为512个字节读取一次,读完就串口转发出去再延时500ms,读取下一个512字节。
直到前部读完为止。
方便用户边收边存
1、这里文件类型不做要求,用户可以是txt,也可以是bin 或者其他都可以,这里以txt 作为举例说明
2、TXT 文件内容越多,耗时越长,实际的读取时间以测试为准。
其实读非常快,一次读512个字节,最多2ms
3、用户需要读取文件的时候,串口发送指令即可。
只在U 盘或者TF 卡初始化完成之后才有效
4、读取成功就会返回相对应的数据,如果读取失败或者文件不存在则返回错误ER6。
详见4.1.3
以上是实际测试的效果如上三个图。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在Linux下串口信息的读取有了一点心得体会。
1. 打开串口与其他的关于设备编程的方法一样,在Linux下,操作、控制串口也是通过操作起设备文件进行的。
在Linux下,串口的设备文件是/dev/ttyS0或/dev/ttyS1等。
因此要读写串口,我们首先要打开串口:char *dev = "/dev/ttyS0";//串口1int fd = open(dev,O_RDWR );//| O_NOCTTY | O_NDELAYif (-1 == fd){perror("Can't Open Serial Port");return -1;}elsereturn fd;2. 设置串口速度打开串口成功后,我们就可以对其进行读写了。
首先要设置串口的波特率:int speed_arr[] = { B38400,B19200,B9600,B4800,B2400,B1200,B300,B38400,B19200,B9600,B4800,B2400,B1200,B300,};int name_arr[] = {38400,19200,9600,4800,2400,1200,300,38400,19200,9600,4800,2400,1200,300,};void set_speed(int fd,int speed){int i;int status;struct termios Opt;tcgetattr(fd,&Opt);for (i= 0;i < sizeof(speed_arr)/ sizeof(int);i++){if (speed == name_arr){tcflush(fd,TCIOFLUSH);cfsetispeed(&Opt,speed_arr);cfsetospeed(&Opt,speed_arr);status = tcsetattr(fd,TCSANOW,&Opt);if (status != 0){perror("tcsetattr fd");return;}tcflush(fd,TCIOFLUSH);}}}3. 设置串口信息这主要包括:数据位、停止位、奇偶校验位这些主要的信息。
/***@brief 设置串口数据位,停止位和效验位*@param fd 类型int 打开的串口文件句柄*@param databits 类型int 数据位取值为7 或者8*@param stopbits 类型int 停止位取值为1 或者2*@param parity 类型int 效验类型取值为N,E,O,,S*/int set_Parity(int fd,int databits,int stopbits,int parity){struct termios options;if (tcgetattr(fd,&options)!= 0){perror("SetupSerial 1");return(FALSE);}options.c_cflag &= ~CSIZE;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);/*Input*/ options.c_oflag &= ~OPOST;/*Output*/switch (databits)/*设置数据位数*/{case 7:options.c_cflag |= CS7;break;case 8:options.c_cflag |= CS8;break;default:fprintf(stderr,"Unsupported data size\n");return (FALSE);}switch (parity){case 'n':case 'N':options.c_cflag &= ~PARENB;/* Clear parity enable */options.c_iflag &= ~INPCK;/* Enable parity checking */break;case 'o':case 'O':options.c_cflag |= (PARODD | PARENB);/* 设置为奇效验*/options.c_iflag |= INPCK;/* Disnable parity checking */ break;case 'e':case 'E':options.c_cflag |= PARENB;/* Enable parity */ options.c_cflag &= ~PARODD;/* 转换为偶效验*/ options.c_iflag |= INPCK;/* Disnable parity checking */ break;case 'S':case 's':/*as no parity*/options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;break;default:fprintf(stderr,"Unsupported parity\n");return (FALSE);}/* 设置停止位*/switch (stopbits){case 1:options.c_cflag &= ~CSTOPB;break;case 2:options.c_cflag |= CSTOPB;break;default:fprintf(stderr,"Unsupported stop bits\n");return (FALSE);}/* Set input parity option */if (parity != 'n')options.c_iflag |= INPCK;tcflush(fd,TCIFLUSH);options.c_cc[VTIME] = 0;/* 设置超时0 seconds*/options.c_cc[VMIN] = 13;/* define the minimum bytes data to be readed*/if (tcsetattr(fd,TCSANOW,&options)!= 0){perror("SetupSerial 3");return (FALSE);}return (TRUE);}在上述代码中,有两句话特别重要:options.c_cc[VTIME] = 0;/* 设置超时0 seconds*/options.c_cc[VMIN] = 13;/* define the minimum bytes data to be readed*/这两句话决定了对串口读取的函数read()的一些功能。
我将着重介绍一下他们对read ()函数的影响。
对串口操作的结构体是Struct{tcflag_t c_iflag;/*输入模式标记*/tcflag_t c_oflag;/*输出模式标记*/tcflag_t c_cflag;/*控制模式标记*/tcflag_t c_lflag;/*本地模式标记*/cc_t c_line;/*线路规程*/cc_t c_cc[NCCS];/*控制符号*/};其中cc_t c_line只有在一些特殊的系统程序(比如,设置通过tty设备来通信的网络协议)中才会用。
在数组c_cc中有两个下标(VTIME和VMIN)对应的元素不是控制符,并且只是在原始模式下有效。
只有在原始模式下,他们决定了read()函数在什么时候返回。
在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回。
控制符VTIME和VMIN之间有着复杂的关系。
VTIME定义要求等待的零到几百毫秒的时间量(通常是一个8位的unsigned char变量,取值不能大于cc_t)。
VMIN定义了要求等待的最小字节数(不是要求读的字节数——read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0.l 如果VTIME取0,VMIN定义了要求等待读取的最小字节数。
函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。
l 如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。
这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0.l 如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。
如果当调用read函数时可以得到数据,计时器马上开始计时。
如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。
函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。
不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。
l 如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。
同时,返回值0表示read函数不需要等待文件结束标志就返回了。
这就是这两个变量对read函数的影响。
我使用的读卡器每次传送的数据是13个字节,一开始,我把它们设置成options.c_cc[VTIME] = 150options.c_cc[VMIN] = 0;结果,每次读取的信息只有8个字节,剩下的5个字节要等到下一次打卡时才能收到。
就是由于这个原因造成的。
根据上面规则的第一条,我把VTIME取0,VMIN=13,也就是正好等于一次需要接收的字节数。
这样就实现了一次读取13个字节值。
同时,得出这样的结论,如果读卡器送出的数据为n个字节,那么就把VMIN=n,这样一次读取的信息正好为读卡器送出的信息,并且读取的时候不需要进行循环读取。
4. 读取数据有了上面的函数后,我设置了串口的基本信息,根据我们自己的实际情况,设置了相应的参数,就可以读取数据了。
void getcardinfo(char *buff){int fd;int nread,count=0;char tempbuff[13];char *dev = "/dev/ttyS0";//串口1fd = OpenDev(dev);set_speed(fd,9600);if (set_Parity(fd,8,1,'N')== FALSE){ printf("Set Parity Error\n");//return -1;}while (1)//循环读取数据{count=0;//sleep(5000);while(1){if((nread = read(fd,tempbuff,13))>0){//printf("\nLen %d\n",nread);memcpy(&buff[count],tempbuff,nread);count+=nread;}if(count==13){buff[count+1] = '\0';//printf("\n%s",buff);break;}}//break;}//return buff;close(fd);pthread_exit(NULL);//close(fd);// exit (0);}这是我原来的程序,其实把VMIN设置以后,可以改成:void getcardinfo(char *buff){int fd;int nread,count=0;char tempbuff[13];char *dev = "/dev/ttyS0";//串口1fd = OpenDev(dev);set_speed(fd,9600);if (set_Parity(fd,8,1,'N')== FALSE){printf("Set Parity Error\n");//return -1;}nread = read(fd,buff,13)close(fd);}5. 程序完整代码:#include /*标准输入输出定义*/#include /*标准函数库定义*/#include /*Unix 标准函数定义*/#include#include#include /*文件控制定义*/#include /*PPSIX 终端控制定义*/#include /*错误号定义*/#define FALSE -1#define TRUE 0/***@brief 设置串口通信速率*@param fd 类型int 打开串口的文件句柄*@param speed 类型int 串口速度*@return void*/int speed_arr[] = { B38400,B19200,B9600,B4800,B2400,B1200,B300,B38400,B19200,B9600,B4800,B2400,B1200,B300,};int name_arr[] = {38400,19200,9600,4800,2400,1200,300,38400,19200,9600,4800,2400,1200,300,};void set_speed(int fd,int speed){int i;int status;struct termios Opt;tcgetattr(fd,&Opt);for (i= 0;i < sizeof(speed_arr)/ sizeof(int);i++){if (speed == name_arr){tcflush(fd,TCIOFLUSH);cfsetispeed(&Opt,speed_arr);cfsetospeed(&Opt,speed_arr);status = tcsetattr(fd,TCSANOW,&Opt);if (status != 0){perror("tcsetattr fd");return;}tcflush(fd,TCIOFLUSH);}}}/***@brief 设置串口数据位,停止位和效验位*@param fd 类型int 打开的串口文件句柄*@param databits 类型int 数据位取值为7 或者8*@param stopbits 类型int 停止位取值为1 或者2*@param parity 类型int 效验类型取值为N,E,O,,S */int set_Parity(int fd,int databits,int stopbits,int parity){struct termios options;if (tcgetattr(fd,&options)!= 0){perror("SetupSerial 1");return(FALSE);options.c_cflag &= ~CSIZE;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);/*Input*/ options.c_oflag &= ~OPOST;/*Output*/switch (databits)/*设置数据位数*/{case 7:options.c_cflag |= CS7;break;case 8:options.c_cflag |= CS8;break;default:fprintf(stderr,"Unsupported data size\n");return (FALSE);}switch (parity){case 'n':case 'N':options.c_cflag &= ~PARENB;/* Clear parity enable */options.c_iflag &= ~INPCK;/* Enable parity checking */break;case 'o':case 'O':options.c_cflag |= (PARODD | PARENB);/* 设置为奇效验*/ options.c_iflag |= INPCK;/* Disnable parity checking */break;case 'e':case 'E':options.c_cflag |= PARENB;/* Enable parity */options.c_cflag &= ~PARODD;/* 转换为偶效验*/options.c_iflag |= INPCK;/* Disnable parity checking */ break;case 'S':case 's':/*as no parity*/options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;break;default:fprintf(stderr,"Unsupported parity\n");return (FALSE);}/* 设置停止位*/switch (stopbits){case 1:options.c_cflag &= ~CSTOPB;break;case 2:options.c_cflag |= CSTOPB;break;default:fprintf(stderr,"Unsupported stop bits\n");return (FALSE);}/* Set input parity option */if (parity != 'n')options.c_iflag |= INPCK;tcflush(fd,TCIFLUSH);options.c_cc[VTIME] = 0;/* 设置超时15 seconds*/options.c_cc[VMIN] = 13;/* define the minimum bytes data to be readed*/if (tcsetattr(fd,TCSANOW,&options)!= 0){perror("SetupSerial 3");return (FALSE);}return (TRUE);}/********************************************************************** 代码说明:使用串口一测试的,发送的数据是字符,但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号**********************************************************************/ /*********************************************************************/ int OpenDev(char *Dev){int fd = open(Dev,O_RDWR );//| O_NOCTTY | O_NDELAYif (-1 == fd){perror("Can't Open Serial Port");return -1;}elsereturn fd;}void getcardinfo(char *buff){int fd;int nread,count=0;char tempbuff[13];char *dev = "/dev/ttyS0";//串口1fd = OpenDev(dev);set_speed(fd,9600);if (set_Parity(fd,8,1,'N')== FALSE){ printf("Set Parity Error\n");//return -1;}while (1)//循环读取数据{count=0;//sleep(5000);while(1){if((nread = read(fd,tempbuff,13))>0){//printf("\nLen %d\n",nread);memcpy(&buff[count],tempbuff,nread);count+=nread;}if(count==13){buff[count+1] = '\0';//printf("\n%s",buff);break;}}//break;}//return buff;close(fd);pthread_exit(NULL);//close(fd);// exit (0);}。