RS232_c++

Introduction

The purpose of this article is to describe how to interface to serial port on Win32. The serial port can be implemented by several techniques such as ActiveX, access I/O and file operation. This article explains the use of serial port on Win32 platform by file operation technique. The programmer can use kernel32.lib library that is provided with the Microsoft Visual C++ Version 6.0. In Microsoft Windows (2000, Me, XP and 95/98), serial port can be treated as a file. Therefore it's possible to open a serial port by using Windows file-creating function.

This article explains not only about serial port communication but also how to implement multi-tasking that can apply with our project "serial port" application. The reason why the software (serial communication) will be implemented with multi-tasking method is that the serial communication application has to handle work with more than one task at the same time. For example data-reading task, data-sending task, GUI task etc.

These topics describe the basic operation of interfacing a serial port on Win32:

Initial/Open serial port communication.

Receive/Send data

Design approach

Initial/Open serial port

The first step in opening a serial port is initiation or setting a serial port's configuration. The purpose of this is to create the serial port agent. All throughout the article we are going to use a file handle as serial port agent.

Creating a port handle

The serial port's handle is a handle that can be used to access the object of serial port. The function that is used to create the serial port handle is the CreateFile function. The following code shows the function that is used to create a handle:

Collapse
handlePort_ = CreateFile(portName,  // Specify port device: default "COM1"

GENERIC_READ | GENERIC_WRITE, // Specify mode that open device.

0, // the devide isn't shared.

NULL, // the object gets a default security.

OPEN_EXISTING, // Specify which action to take on file.

0, // default.

NULL); // default.

As figure 2 shows, portName = "COM1": the portName is a variable that is declared by const char*. It is used to specify port name that wants to create a serial port handle.

 

Figure 2: CreateFile function

 

Restoring a configuration

The restoration of serial port configuration is getting current configuration at control device. The configuration of serial port includes parameters that are used for setting a serial communications device.

The GetCommState function is used to get the current device-control and then fills to a device-control block (a DBC structure) with the current control settings for a specified communications device. The following code shows the function that is used to get the current control device:

Collapse
// Get current configuration of serial communication port.

if (GetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Get configuration port has problem.");
return FALSE;
}
Modifying a configuration

When you already have serial port configuration in the DBC format, you have to modify parameters a bit. Following code shows the parameters modified:

Collapse
// Assign user parameter.

config_.BaudRate = dcb.BaudRate; // Specify buad rate of communicaiton.

config_.StopBits = dcb.StopBits; // Specify stopbit of communication.

config_.Parity = dcb.Parity; // Specify parity of communication.

config_.ByteSize = dcb.ByteSize; // Specify byte of size of communication.
  • DWORD BaudRate:

    Current baud rate (default = 9600)

  • BYTE StopBits:

    0,1,2 = 1, 1.5, 2 (default = 0)

  • BYTE Parity:

    0-4= no, odd, even, mark, space (default = 0)

  • BYTE ByteSize:

    Number of bits/byte, 4-8 (default = 8)

Note: Recommend that programmers use default value for typical communication. As shown in figure 3, Watch Dialog Box shows the default values that are used for typical communication.

 

Figure 3: Serial port configuration

 

Storing a configuration

The next step is the storage of new configuration that is modified already into device control. Call SetCommState API function to store the configuration. The SetCommState function configures a communications device according to the specifications in a device-control block (a DBC structure). The function reinitializes all hardware and control settings, but it does not empty output or input queues. Following code shows storage of a new configuration:

Collapse
if (SetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Set configuration port has problem.");
return FALSE;
}
Setting a Time-Out communication

The final step in serial port opening is setting communication Time-out by using the COMMTIMEOUTS data-structure and calling SetCommTimeouts function. The code below shows setting time-out of communication:

Collapse
// instance an object of COMMTIMEOUTS.

COMMTIMEOUTS comTimeOut;
// Specify time-out between charactor for receiving.

comTimeOut.ReadIntervalTimeout = 3;
// Specify value that is multiplied

// by the requested number of bytes to be read.

comTimeOut.ReadTotalTimeoutMultiplier = 3;
// Specify value is added to the product of the

// ReadTotalTimeoutMultiplier member

comTimeOut.ReadTotalTimeoutConstant = 2;
// Specify value that is multiplied

// by the requested number of bytes to be sent.

comTimeOut.WriteTotalTimeoutMultiplier = 3;
// Specify value is added to the product of the

// WriteTotalTimeoutMultiplier member

comTimeOut.WriteTotalTimeoutConstant = 2;
// set the time-out parameter into device control.

SetCommTimeouts(handlePort_,&comTimeOut);
ReadIntervalTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters on the communications line. During a ReadFile operation, the time period begins when the first character is received. If the interval between the arrival of any two characters exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used.

A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received.

ReadTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is multiplied by the requested number of bytes to be read.

ReadTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier member and the requested number of bytes.

A value of zero for both the ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members indicates that total time-outs are not used for read operations.

WriteTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.

WriteTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is added to the product of the WriteTotalTimeoutMultiplier member and the number of bytes to be written.

A value of zero for both the WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant members indicates that total time-outs are not used for write operations.

Note: After the user has set the time-out of communication without any error, the serial port has opened already.

Sending data

Most of data transmission of serial port is done as writing a file. Programmer can apply file operation functions for sending data to serial port. The WriteFile function is a function used to send data in serial port communication.

Collapse
if (WriteFile(handlePort_,   // handle to file to write to

outputData, // pointer to data to write to file

sizeBuffer, // number of bytes to write

&length,NULL) == 0) // pointer to number of bytes written

{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}

Note: If the function succeeds, the return value is nonzero.

Receiving data

Most of data reception of serial communication is done as reading a file. Programmer can apply file operation functions for receiving data from serial port. The ReadFile function is the function that handles reading data in serial port communication.

Collapse
if (ReadFile(handlePort_,  // handle of file to read

inputData, // handle of file to read

sizeBuffer, // number of bytes to read

&length, // pointer to number of bytes read

NULL) == 0) // pointer to structure for data

{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}

Note: If the function succeeds, the return value is nonzero.

Closing a serial port

The serial port closing calls the CloseHandle API function to close handle of device control.

Collapse
if(CloseHandle(handlePort_) == 0)    // Call this function to close port.

{
AfxMessageBox("Port Closeing isn't successed.");
return FALSE;
}

Note: If the function succeeds, the return value is nonzero.

<think>好的,我现在要解决用户提到的这个C语言编译警告:“suggest parentheses around '+' inside '<<' [-Wparentheses]”。首先,我需要仔细看看用户提供的代码行: g_transmission_mode_info.duration = rs232_uart_queue_buf[6] << 8 + rs232_uart_queue_buf[7]; 用户的问题是关于运算符优先级导致的警告。我的思路是,先回忆C语言中运算符的优先级顺序。移位运算符(如<<和>>)的优先级通常比加法运算符低吗?这个时候可能用户在这里的表达式没有正确加括号,导致运算顺序不符合预期。 接下来,我需要确认运算符的优先级。根据C语言的标准,加法运算符(+)的优先级确实高于移位运算符(<<)。所以在这行代码中,编译器会先计算8 + rs232_uart_queue_buf[7],然后再进行左移操作。这显然和用户的意图不符,用户应该是想先把rs232_uart_queue_buf[6]左移8位,然后再加上rs232_uart_queue_buf[7]。这通常用于将两个字节合并成一个16位的整数,比如高位和低位字节的组合。 举个例子,假设rs232_uart_queue_buf[6]是0x12,rs232_uart_queue_buf[7]是0x34。按照用户当前的写法,实际上是0x12 << (8 + 0x34),也就是左移44位,这显然会导致结果错误,甚至未定义行为,因为移位超过变量长度。而正确的做法应该是(0x12 << 8) + 0x34,得到0x1234。 因此,问题出在运算符的优先级上,用户需要给移位操作加上括号,确保先移位后相加。编译器检测到这种情况,发现可能存在逻辑错误,所以发出警告提示用户加上括号,明确运算顺序。 接下来,我需要将这个问题用中文清晰地解释给用户,分步骤说明原因和解决方法。可能需要用例子来帮助用户理解,同时强调运算符优先级的重要性,以及为何编译器会给出这样的警告。此外,还可以提醒用户在其他类似情况下注意运算符优先级,避免类似的错误。 总结步骤应该是: 1. 指出运算符优先级的问题,加法先于移位。 2. 分析原代码的实际运算顺序,说明其错误。 3. 给出正确的写法,加上括号。 4. 举例说明错误和正确情况下的结果差异。 5. 提醒用户注意其他类似运算符的优先级问题。 在解释过程中,使用数学表达式时要注意格式,行内公式用$...$,独立公式用$$...$$,但根据用户要求,可能不需要太多复杂公式,重点在于清晰易懂。同时要确保LaTeX语法正确,避免错误。 现在需要检查是否有遗漏的地方,比如是否还有其他可能的运算符优先级问题需要注意,或者用户可能存在的其他疑问。例如,是否所有类似的移位和加法操作都需要括号?是的,因为加法和移位的优先级差异可能导致意外结果,建议在不确定时使用括号明确顺序。 最后,整理语言,确保结构清晰,逐步引导用户理解问题,并提供可靠的解决方案。</think>这个警告是由于C/C++中**运算符优先级**问题导致的。让我们逐步分析: 1. **问题根源**: 在表达式`rs232_uart_queue_buf[6] << 8 + rs232_uart_queue_buf[7]`中: - 加法运算符`+`的优先级**高于**移位运算符`<<`(详见下表) - 实际运算顺序变为:`rs232_uart_queue_buf[6] << (8 + rs232_uart_queue_buf[7])` | 运算符 | 优先级 | |--------|--------| | `+` | 更高 | | `<<` | 更低 | 2. **错误示例**: 假设: ```c rs232_uart_queue_buf[6] = 0x12; // 二进制 00010010 rs232_uart_queue_buf[7] = 0x34; // 二进制 00110100 ``` - **当前错误运算**:`0x12 << (8 + 0x34) = 0x12 << 60`(无意义,可能导致未定义行为) - **期望正确运算**:`(0x12 << 8) + 0x34 = 0x1200 + 0x34 = 0x1234` 3. **解决方案**: 添加括号明确运算顺序: ```c g_transmission_mode_info.duration = (rs232_uart_queue_buf[6] << 8) + rs232_uart_queue_buf[7]; ``` 4. **延伸建议**: - 当同时使用位操作和算术运算符时,建议始终用括号明确优先级 - 类似的优先级陷阱还包括:`&`/`|` 与 `==`/`!=` 的混用 - 可使用十六进制验证结果: ```c printf("Merged value: 0x%04X\n", (buf[6] << 8) | buf[7]); // 更安全的位操作写法 ``` 这个警告本质是编译器在提醒:"你的运算顺序可能不符合预期,请用括号明确意图"。这对处理网络协议、硬件寄存器等需要精确位操作的场景尤为重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值