由于本次项目之中使用的线长为40米的倾角传感器,需要对于其频率输出存在要求,如何测试其频率如下所示:
如上所示相应的软件,软件中存在一句如果设置后不保存,则存在传感器断电后设置还原。在实际设计接口的时候,发现这款软件即便是设置后进行了保存,如果连续开关断电时间过长,还是会存在断电还原的情况,因此,在测试代码之中需要写出对于初始状态的判断。
初始状态的时候,假设波特率为9600,当然也可能开始的时候已经设置为115200,
协议如下所示,首先需要设置为00应答模式,才可以需要重新设置串口的信息。
下面是对于初始波特率是否为9600进行判断,我这个地方是进行了8次判断,看看是否能够写入输出,如果不是重新设置为115200。
//默认为9600的时候,进行对话模式
char command_R4[] = { 0x77, 0x05, 0x00, 0x0C, 0x00, 0x11 };
if (!WriteFile(hSerial, command_R4, sizeof(command_R4), &bytesWritten4, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
bool exists = false; // 标志位,记录元素是否存在
int falsecount = 0;
// 循环遍历数组
while (!exists) {
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
for (int i = 0; i < sizeof(dataReceived); i++) {
if (dataReceived[i] == 0xFFFFFF8C) {
exists = true; // 元素存在,设置标志位为true
std::cout << "应答模式配置成功!" << std::endl;
//std::this_thread::sleep_for(std::chrono::milliseconds(400000));
break; // 跳出for循环
}
}
if (!exists) {
falsecount++;
if (falsecount >= 8)//说明原有配置是115200波特率
{
dcbSerialParams.BaudRate = CBR_115200;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::cout << "Error setting serial port state." << std::endl;
CloseHandle(hSerial);
return 1;
}
timeouts.ReadIntervalTimeout = 500;
timeouts.ReadTotalTimeoutConstant = 500;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.WriteTotalTimeoutConstant = 500;
timeouts.WriteTotalTimeoutMultiplier = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
std::cout << "Error setting timeouts." << std::endl;
CloseHandle(hSerial);
return 1;
}
}
if (!WriteFile(hSerial, command_R4, sizeof(command_R4), &bytesWritten4, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
std::cout << "元素不存在,继续执行某条语句..." << std::endl;
// 可以在这里添加需要执行的语句
}
}
上面代码为什么要进行反复的输入,判断输出的原因是因为在实际的测试的情况下,写入一次可能会出现返回数据不正确的情况,因此需要一个标志位去表明协议已经写入正确。
在给定的配套软件之中,设置的这个位置按钮就是进行协议的写入,但是按一次偶尔会出现没有生效,因此,这个地方进行反复判断功能。
一个准确的报文帧数据应该是如下所示:
正常的报文帧数据应该是0x77 0x10 0x00 0xFFFF84开头,一个数据的大小是17bytes,
那就以一个实际的案例进行读出,设置波特率为115200,应答模式为100Hz输出。
可以见到并不是0x77 0x10 0x00 0xFFFF84开头,原因在于当设置完成自动输出模式之后,其将返回的帧数据与角度数据结合到了一起。
可以见到返回数据帧的大小为6bytes,因此这个地方需要将返回数据帧大小设置为6bytes+17bytes = 23bytes。
读取数据是从6 + 5 = 11byte开始读取。也就是FFFFFF84后面的一位开始读取。也就是response_R[11-1]位开始读取。
可以见到数据正常。
一开始我是想要在页面上写一个读写的功能进行频率的输出,但是存在问题,发现写一帧然后读一帧的数据是非常慢的,因为BWS2000系列倾角传感器是半双工的倾角传感器,不建议那样用,但是我看给的官方软件上存在这样一句话:
我不是特别的理解,既然是半双工的倾角传感器,自动输出模式不是更好一些吗????但是我还是用自动输出模式吧。
注意:设置好之后,不能够直接进行读取,否则会出现问题,也就是出现频率不正确。
原因是因为设置好之后,传感器并不是处于稳定的状态,导致读出频率与设置频率不一致,在采集之前需要加入一个延时函数:
然后在代码之中,通过对比前后输出的时间差别,查看是否输出的频率正确。
可以见到是正确的,也就是说倾角传感器40米线长的情况下,115200波特率的情况下,可以正常输出,打完收工,接下来就是设计线程的过程。
测试代码如下所示:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
double convertStringToDouble(const std::string& str) {
double result;
std::istringstream stream(str);
stream >> result;
return result;
}
int main() {
HANDLE hSerial;
DCB dcbSerialParams = { 0 };
COMMTIMEOUTS timeouts = { 0 };
DWORD bytesRead, bytesRead1, bytesWritten, bytesWritten1, bytesWritten2, bytesWritten3, bytesWritten4, bytesWritten5, response_R1;
char command_R[] = { 0x77, 0x04, 0x00, 0x04, 0x08 };//读X、Y轴角度 发送命令: 77 04 00 04 08
char response_R[34];
double Sensor_Angle_RX0;
double Sensor_Angle_RY0;
char dataReceived[34];
wchar_t portName[] = L"\\\\.\\COM10"; // Note the 'L' before the string
hSerial = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSerial == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
std::cout << "Serial port not available." << std::endl;
}
return 1;
}
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
std::cout << "Error getting serial port state." << std::endl;
CloseHandle(hSerial);
return 1;
}
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::cout << "Error setting serial port state." << std::endl;
CloseHandle(hSerial);
return 1;
}
timeouts.ReadIntervalTimeout = 500;
timeouts.ReadTotalTimeoutConstant = 500;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.WriteTotalTimeoutConstant = 500;
timeouts.WriteTotalTimeoutMultiplier = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
std::cout << "Error setting timeouts." << std::endl;
CloseHandle(hSerial);
return 1;
}
//默认为9600的时候,进行对话模式
char command_R4[] = { 0x77, 0x05, 0x00, 0x0C, 0x00, 0x11 };
if (!WriteFile(hSerial, command_R4, sizeof(command_R4), &bytesWritten4, NULL)) {
std::cout << "第一次9600的对话模式配置失败" << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "第一次9600的对话模式数据读取失败." << std::endl;
CloseHandle(hSerial);
return 1;
}
std::cout << "第一次初始波特率:" << dcbSerialParams.BaudRate << std::endl;
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
bool exists = false; // 标志位,记录元素是否存在
int falsecount = 0;
// 循环遍历数组
while (!exists) {
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
for (int i = 0; i < sizeof(dataReceived); i++) {
if (dataReceived[i] == 0x77 && dataReceived[i+3] == 0xFFFFFF8C) {
exists = true; // 元素存在,设置标志位为true
std::cout << falsecount << std::endl;
std::cout << "应答模式配置成功!" << std::endl;
//std::this_thread::sleep_for(std::chrono::milliseconds(400000));
break; // 跳出for循环
}
}
if (exists)
{
break;
}
if (!exists) {
falsecount++;
if (falsecount >= 2)//说明原有配置是115200波特率
{
dcbSerialParams.BaudRate = CBR_115200;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::cout << "Error setting serial port state." << std::endl;
CloseHandle(hSerial);
return 1;
}
timeouts.ReadIntervalTimeout = 500;
timeouts.ReadTotalTimeoutConstant = 500;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.WriteTotalTimeoutConstant = 500;
timeouts.WriteTotalTimeoutMultiplier = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
std::cout << "Error setting timeouts." << std::endl;
CloseHandle(hSerial);
return 1;
}
}
if (!WriteFile(hSerial, command_R4, sizeof(command_R4), &bytesWritten4, NULL)) {
std::cout << "115200的对话模式配置失败." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "115200的对话模式回复失败." << std::endl;
CloseHandle(hSerial);
return 1;
}
}
}
//设置频率为115200
char command_R1[] = { 0x77, 0x05, 0x00, 0x0B, 0x04, 0x14 };//115200
if (!WriteFile(hSerial, command_R1, sizeof(command_R1), &bytesWritten1, NULL))
{
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL))
{
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
exists = false;
while (!exists)
{
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
for (int i = 0; i < sizeof(dataReceived); i++) {
if (dataReceived[i] == 0x77 &&dataReceived[i+3] == 0xFFFFFF8B) {//设置成功
exists = true; // 元素存在,设置标志位为true
std::cout << "115200波特率配置成功!" << std::endl;
break; // 跳出for循环
}
}
if (exists)
{
break;
}
if (!exists) {
if (!WriteFile(hSerial, command_R1, sizeof(command_R1), &bytesWritten1, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
std::cout << "重复配置115200波特率" << std::endl;
// 可以在这里添加需要执行的语句
std::this_thread::sleep_for(std::chrono::milliseconds(4000));
}
}
//00-11:应答模式 05-50Hz 04-25Hz
//06-100 05-50 04-25
char command_R3[] = { 0x77, 0x05, 0x00, 0x0C, 0x05, 0x16 };//50Hz
if (!WriteFile(hSerial, command_R3, sizeof(command_R3), &bytesWritten3, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
exists = false;
while (!exists) {
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
for (int i = 0; i < sizeof(dataReceived); i++) {
if (dataReceived[i] == 0x77 && dataReceived[i+3] == 0xFFFFFF8C) {//设置成功
exists = true; // 元素存在,设置标志位为true
std::cout << "50Hz配置成功!" << std::endl;
break; // 跳出for循环
}
}
if (exists)
{
break;
}
if (!exists) {
if (!WriteFile(hSerial, command_R3, sizeof(command_R3), &bytesWritten3, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
std::cout << "元素不存在,继续执行某条语句..." << std::endl;
// 可以在这里添加需要执行的语句
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(2004));
std::cout << "波特率:" << dcbSerialParams.BaudRate << std::endl;
// 设置角度输出频率模式 77 05 00 0C 06(100Hz 05 50Hz 04 25Hz) 11 100Hz
std::cout << " " << std::endl;
std::cout << "开始采集 " << std::endl;
int i = 0;
const int interval = 40;
while (1)
{
auto startTime = std::chrono::high_resolution_clock::now();
/*if (!WriteFile(hSerial, command_R, sizeof(command_R), &bytesWritten, NULL)) {
std::cout << "Error writing to serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}
*/
ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL);
/*
if (!ReadFile(hSerial, dataReceived, sizeof(dataReceived), &bytesRead, NULL)) {
std::cout << "Error reading from serial port." << std::endl;
CloseHandle(hSerial);
return 1;
}*/
for (int i = 0; i < sizeof(dataReceived); i++) {
printf("%02X ", dataReceived[i]);
}
//std::cout << "dadasdafasf" << std::endl;
int flag;
for (int i = 0; i < sizeof(dataReceived); i++) {
if (dataReceived[i] == 0x77 && dataReceived[i + 1] == 0x10 && dataReceived[i + 2] == 0x00 && dataReceived[i + 3] == 0xFFFFFF84)
{
flag = i;
break;
}
}
std::cout << "" << std::endl;
//std::this_thread::sleep_for(std::chrono::milliseconds(4000));
//x轴
// Given hexadecimal values
int hexValues[] = { dataReceived[flag + 5] & 0xFF, dataReceived[flag + 6] & 0xFF, dataReceived[flag + 7] & 0xFF };
int hexValues1[] = { dataReceived[flag + 9] & 0xFF, dataReceived[flag + 10] & 0xFF, dataReceived[flag + 11] & 0xFF };
int numValues = sizeof(hexValues) / sizeof(hexValues[0]);
std::stringstream ss;
ss << std::setfill('0') << std::setw(2) << std::hex << hexValues[0];
for (int i = 1; i < numValues; i++) {
ss << "." << std::setw(2) << std::hex << hexValues[i];
}
std::string resultString = ss.str();
std::string inputString = resultString;
std::string outputString;
size_t firstDotIndex = inputString.find('.');
size_t secondDotIndex = inputString.find('.', firstDotIndex + 1);
if (firstDotIndex != std::string::npos && secondDotIndex != std::string::npos) {
outputString = inputString.substr(0, secondDotIndex) + inputString.substr(secondDotIndex + 1);
}
else {
outputString = inputString;
}
double resultDouble = std::stod(outputString);
if (dataReceived[flag + 4] == 0x00)
{
Sensor_Angle_RX0 = resultDouble;
}
else
{
Sensor_Angle_RX0 = -resultDouble;
}
std::cout << "x轴角度" << Sensor_Angle_RX0 << std::endl;
//Y轴
int numValues1 = sizeof(hexValues1) / sizeof(hexValues1[0]);
std::stringstream ss1;
ss1 << std::setfill('0') << std::setw(2) << std::hex << hexValues1[0];
for (int i = 1; i < numValues1; i++) {
ss1 << "." << std::setw(2) << std::hex << hexValues1[i];
}
std::string resultString1 = ss1.str();
std::string inputString1 = resultString1;
std::string outputString1;
size_t firstDotIndex1 = inputString1.find('.');
size_t secondDotIndex1 = inputString1.find('.', firstDotIndex1 + 1);
if (firstDotIndex1 != std::string::npos && secondDotIndex1 != std::string::npos) {
outputString1 = inputString1.substr(0, secondDotIndex1) + inputString1.substr(secondDotIndex1 + 1);
}
else {
outputString1 = inputString1;
}
double resultDouble1 = std::stod(outputString1);
if (dataReceived[flag + 8] == 0x00)
{
Sensor_Angle_RY0 = resultDouble1;
}
else
{
Sensor_Angle_RY0 = -resultDouble1;
}
std::cout << "y轴: " << Sensor_Angle_RY0 << std::endl;
// 计算执行代码所花费的时间
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast(endTime - startTime);
// 计算需要延迟的时间
int delay = interval - duration.count();
//std::cout << delay << std::endl;
if (delay == interval)
{
std::cout << "频率正确" << std::endl;
}
else if (delay > 0) {
// 延迟执行
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
std::cout << "频率正确" << std::endl;
}
else if (delay < 0)
{
std::cout << "时间不够:(ms)***************************************:" << delay << std::endl;
}
//std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
getchar();
CloseHandle(hSerial);
return 0;
}
上面的代码是了两帧数据的选取,将两帧之中的数据提取一帧数据,则设定的时间为原来频率的一半。