Написал консольное приложение на Visual Studio c++ и возникла проблема в приеме данных Arduino Uno. Данные, вроде как, отправляется, но ардуино не реагирует на них... если отправлять команды из монитора порта ардуино, то все работает и загораются диоды rx и xi, когда я отправляю команды из приложения, то загорается только диод xi... так же происходит, когда я меняю настройку NL (добавления новой строки) на любую другую в мониторинге порта... Очень хочу разобраться в проблеме, но никак не могу найти решение... очень прошу помощи. Код (C++): #include "stdafx.h" #include <iostream> #include <cstdlib> #include <Windows.h> #include <string> #include "conio.h" #include "io.h" #include <locale.h> #pragma package(smart_init) #pragma resource "*.dfm" #pragma hdrstop #include <io.h> // Для работы с файлами #include <fcntl.h> // Для работы с файлами #include <sys\stat.h> // Для работы с файлами using namespace std; //============================================================================= //..................... Объявления глобальных переменных ...................... //============================================================================= HANDLE hCOM; // Дескриптор порта int handle; //дескриптор для работы с файлом с помощью библиотеки <io.h> bool fl=0; //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно) OVERLAPPED overlapped; //будем использовать для операций чтения (см. поток ReadThread) OVERLAPPED overlappedwr; //будем использовать для операций записи unsigned long counter; //счётчик принятых байтов, обнуляется при каждом открытии порта #define BUFSIZE 255 // Ёмкость буфера приемо-передачи unsigned char bufwrHEX[BUFSIZE] = {1}; // передающий буфер для обмена в HEX unsigned char bufrdHEX[sizeof(bufwrHEX)]; // приёмный буфер для обмена в HEX bool stopfl = false; // флаг остановки цикла передачи данных bool Read_done = true; // флаг окончания чтения информации от ведомого bool slave_mode = false; // флаг работы программы в режиме slave HANDLE info_read; // сигнальное событие, показывающее прочитана ли информация из порта unsigned long Timer_cycles = 0; // переменная количества циклов таймера для счета времени по таймеру unsigned long Bytes_received = 0; // число принятых байт за один пуск unsigned long Bytes_written = 0;// число записанных байт в порт за один пуск bool show_info = false; // флаг вывода информации на экран //============================================================================= //.............................. Объявления функций ........................... //============================================================================= void COM_Open(void); // Открыть порт void COM_Setting(void); // Инициализировать порт void COM_Close(void); // Закрыть порт void ReadPrinting(void); // Создание потока void command(void); //============================================================================= //.............................. Объявления потоков ........................... //============================================================================= HANDLE reader; // Дескриптор потока чтения из порта HANDLE writer; // Дескриптор потока записи в порт HANDLE MainThr; //============================================================================= //............................... Тело программы .............................. //============================================================================= int main() { setlocale(LC_ALL,"Rus"); // Подключения языка char prov; int a; string str; COM_Open(); // Функция открытия порта COM_Setting(); // Функция инициализации порта DWORD WINAPI WriteThread(LPVOID); DWORD WINAPI ReadThread(LPVOID); do { printf("===============================\n"); cout<<"Введите 'n' для завершения ввода\n"; cin>> prov; printf("===============================\n"); cout<<"Введите команду!\n"; cout<<"===============================\n"<<endl; cin>>str; cout<<"==========значения в буффере до очистки программного передающего буффера:==========\n"<<endl; cout<<bufwrHEX<<endl; cout<<bufrdHEX<<endl; cout<<"===============================\n"<<endl; memset(bufwrHEX,0,BUFSIZE); // Очистить программный передающий буфер, чтобы данные не накладывались друг на друга cout<<"==========значения в буффере после очистки программного передающего буффера:==========\n"<<endl; cout<<bufwrHEX<<endl; cout<<bufrdHEX<<endl; PurgeComm(hCOM, PURGE_TXCLEAR); // Очистить передающий буфер порта cout<<"==========значения в буффере после очистки передающего буффера порта:==========\n"<<endl; cout<<bufwrHEX<<endl; cout<<bufrdHEX<<endl; strcpy((char*)bufwrHEX, str.c_str()); // Занести в программный передающий буфер строку из переменной str cout<<"===============================\n"<<endl; cout<<"==========значения в буффере после передачи в него команды:==========\n"<<endl; cout<<bufwrHEX<<endl; cout<<bufrdHEX<<endl; ResumeThread(writer); // Активировать поток записи данных в порт cout<<"==========значения в буффере после отправки команды:==========\n"<<endl; cout<<bufwrHEX<<endl; cout<<bufrdHEX<<endl; } while (prov != 'n'); printf("===============================\n"); printf("Для выхода введите 100!\n"); printf("===============================\n"); printf("Поле ввода команд: "); cin >> a; if(a=100); printf("===============================\n"); { COM_Close(); } }
Код (C++): //----------------------------------------------------------------------------- //......................... поток ReadThead и WriteThead....................... //----------------------------------------------------------------------------- DWORD WINAPI ReadThread(LPVOID) { COMSTAT comstat; //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов DWORD btr, temp, mask, signal; //переменная temp используется в качестве заглушки overlapped.hEvent = CreateEvent(NULL, true, true, NULL); //создать сигнальный объект-событие для асинхронных операций SetCommMask(hCOM, EV_RXCHAR); //установить маску на срабатывание по событию приёма байта в порт //SetCommMask(hCOM, EV_TXEMPTY); while(1) //пока поток не будет прерван, выполняем цикл { WaitCommEvent(hCOM, &mask, &overlapped); //ожидать события приёма байта (это и есть перекрываемая операция) signal = WaitForSingleObject(overlapped.hEvent, INFINITE); //приостановить поток до прихода байта if(signal == WAIT_OBJECT_0) //если событие прихода байта произошло { if(GetOverlappedResult(hCOM, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent if((mask & EV_RXCHAR)!=0) //если произошло именно событие прихода байта { ClearCommError(hCOM, &temp, &comstat); //нужно заполнить структуру COMSTAT btr = comstat.cbInQue; //и получить из неё количество принятых байтов if(btr) //если действительно есть байты для чтения { ReadFile(hCOM, bufrdHEX, btr, &temp, &overlapped); //прочитать байты из порта в буфер программы counter+=btr; // увеличиваем счётчик байт за все время работы программы Bytes_received+=btr; // счетчик принятых байт за один пуск SetEvent(info_read); // устанавливаем событие прочтения информации в сигнальное положение if (slave_mode) { // транслируем приянтое отправителю если в режиме slave memcpy(bufwrHEX,bufrdHEX,sizeof(bufrdHEX)); ResumeThread(writer); //активировать поток записи данных в порт } // if (slave_mode) memset(bufrdHEX, 0, BUFSIZE); //очистить буфер (чтобы данные не накладывались друг на друга) } // if(btr) } // if((mask & EV_RXCHAR)!=0) } // if(signal == WAIT_OBJECT_0) } // while(1) } /*DWORD WINAPI WriteThread(LPVOID) { DWORD temp, signal; //temp - переменная-заглушка overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL); //создать событие while(1) { PurgeComm(hCOM, PURGE_TXCLEAR); //очистить передающий буфер порта WriteFile(hCOM, bufwrHEX, sizeof(bufwrHEX), &temp, &overlappedwr); //записать байты в порт (перекрываемая операция!) signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE); //приостановить поток, пока не завершится перекрываемая операция WriteFile if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(hCOM, &overlappedwr, &temp, true))) //если операция завершилась успешно { Bytes_written += sizeof(bufwrHEX); // если единичный запуск, то выведем информацию на форму if (show_info) { Bytes_written = 0; } SuspendThread(writer); } } }*/ DWORD WINAPI WriteThread(LPVOID) { DWORD temp, signal; //temp - переменная-заглушка overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL); //создать событие while(1) { WriteFile(hCOM, bufwrHEX, strlen((char*)bufwrHEX), &temp, &overlappedwr); //записать байты в порт (перекрываемая операция! signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE); //приостановить поток, пока не завершится перекрываемая операция WriteFile if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(hCOM, &overlappedwr, &temp, true))) //если операция завершилась успешно { Bytes_written += sizeof(bufwrHEX); printf("\nПередача прошла успешно\n"); //вывести сообщение об этом в строке состояния } else { printf("Ошибка передачи\n"); //иначе вывести в строке состояния сообщение об ошибке } if (show_info) { Bytes_written = 0; } SuspendThread(writer); } }
Код (C++): //============================================================================= //............................... Описание функций ............................ //============================================================================= void COM_Open() { DCB dcb; COMMTIMEOUTS timeouts; hCOM = CreateFile(TEXT("COM3"),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED, NULL); if (hCOM == INVALID_HANDLE_VALUE) { printf("Ошибка открытия COM-порта (error %d)\n", GetLastError()); printf("===============================\n"); } if (hCOM != INVALID_HANDLE_VALUE) { printf("COM3 успешно открыт!\n"); printf("===============================\n"); } else { printf("COM-порт не доступен\n"); printf("===============================\n"); } getch (); return; } void COM_Setting() { COMMTIMEOUTS CommTimeOuts; DCB dcbSerialParams = {0}; SetupComm(hCOM, 2000, 2000); GetCommState(hCOM, &dcbSerialParams); dcbSerialParams.DCBlength=sizeof(dcbSerialParams); // В первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры // Считать структуру DCB из порта if (!GetCommState(hCOM, &dcbSerialParams)) // Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { printf("Не удалось считать параметры COM-порта\n"); COM_Close(); return; } else { printf("Параметры COM-порта считаны:\n"); printf("===============================\n"); _tprintf( TEXT("\nBaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d\n"), dcbSerialParams.BaudRate, dcbSerialParams.ByteSize, dcbSerialParams.Parity, dcbSerialParams.StopBits ); printf("\n===============================\n"); } //__________________________________________________________________________________________ //___________________________________Параметры COM-порта____________________________________ //__________________________________________________________________________________________ dcbSerialParams.BaudRate=CBR_57600; dcbSerialParams.ByteSize=8; //задаём 8 бит в байте dcbSerialParams.StopBits=ONESTOPBIT; //задаём один стоп-бит dcbSerialParams.Parity=NOPARITY; //отключаем проверку чётности dcbSerialParams.fBinary = TRUE; //включаем двоичный режим обмена dcbSerialParams.fOutxCtsFlow = FALSE; //выключаем режим слежения за сигналом CTS dcbSerialParams.fOutxDsrFlow = FALSE; //выключаем режим слежения за сигналом DSR dcbSerialParams.fDtrControl = DTR_CONTROL_DISABLE; //отключаем использование линии DTR dcbSerialParams.fDsrSensitivity = FALSE; //отключаем восприимчивость драйвера к состоянию линии DSR dcbSerialParams.fNull = FALSE; //разрешить приём нулевых байтов dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE; //отключаем использование линии RTS dcbSerialParams.fAbortOnError = FALSE; //отключаем остановку всех операций чтения/записи при ошибке if(!SetCommState(hCOM, &dcbSerialParams)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { printf("Ошибка в установке параметров COM-порта\n"); COM_Close(); } else { printf("Параметры COM порта успешно загружены:\n"); printf("===============================\n"); _tprintf( TEXT("\nBaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d\n"), dcbSerialParams.BaudRate, dcbSerialParams.ByteSize, dcbSerialParams.Parity, dcbSerialParams.StopBits ); printf("\n===============================\n"); } //__________________________________________________________________________________________ //___________________________________Параметры таймаутов____________________________________ //__________________________________________________________________________________________ CommTimeOuts.ReadIntervalTimeout = 0; //таймаут между двумя символами CommTimeOuts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения CommTimeOuts.ReadTotalTimeoutConstant = 0; //константа для общего таймаута операции чтения CommTimeOuts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи CommTimeOuts.WriteTotalTimeoutConstant = 0; //константа для общего таймаута операции записи //записать структуру таймаутов в порт if(!SetCommTimeouts(hCOM, &CommTimeOuts)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COM_Close(); printf("Не удалось установить параметры timeouts\n"); printf("===============================\n"); return; } else { printf("Параметры timeouts установлены\n"); printf("===============================\n"); } //__________________________________________________________________________________________ //_____________________________Настройка записи в файл______________________________________ //__________________________________________________________________________________________ SetupComm(hCOM,2000,2000); //установить размеры очередей приёма и передачи handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE); if(handle == - 1) //если произошла ошибка открытия файла { printf("Не удалось установить параметры timeouts\n"); printf("Ошибка открытия файла\n"); } else { printf("Файл открыт успешно\n"); printf("===============================\n"); } PurgeComm(hCOM, PURGE_RXCLEAR); //очистить принимающий буфер порта reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL); //создаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0) writer = CreateThread(NULL, 0, WriteThread, NULL, CREATE_SUSPENDED, NULL); //создаём поток записи в остановленном состоянии (предпоследний параметр = CREATE_SUSPENDED) getch (); return; } void COM_Close() { if(writer) //если поток записи работает, завершить его; проверка if(writer) обязательна, иначе возникают ошибки { TerminateThread(writer,0); CloseHandle(overlappedwr.hEvent); //нужно закрыть объект-событие CloseHandle(writer); printf("Поток записи завершен!\n"); } if(reader) //если поток чтения работает, завершить его; проверка if(reader) обязательна, иначе возникают ошибки { TerminateThread(reader,0); CloseHandle(overlapped.hEvent); //нужно закрыть объект-событие CloseHandle(reader); printf("Поток чтения завершен!\n"); } if(hCOM != INVALID_HANDLE_VALUE) { CloseHandle(hCOM); //закрыть порт hCOM=0; //обнулить переменную для дескриптора порта close(handle); //закрыть файл, в который велась запись принимаемых данных handle=0; //обнулить переменную для дескриптора файла printf("COM-порт закрыт!\n"); } getch (); return; } //============================================================================= //............................... Конец программы ............................. //=============================================================================
Попробуйте при отправке на ардуино выводить на экран коды символов того, что отправляете и сверить с тем, что должно быть (см. ascii-таблицу). Светодиод xi это tx? ещё можете взять 2 usb-uart кабеля, соединить и воткнуть в комп и проверить, что отправляет ваша программа другой программой). Дебаг программ на пк должен быть проще, т.к. вы в любой момент можете вывести переменные на экран или в режиме отладки смотреть их значения...
Да, xi это tx... Я, к примеру, отправляю 20 и в поток записывается 20... и отправляется 20...но вот обратно я ничего не получаю...по крайней мере, буфер чтения ничего не выводит, а должен получать в ответ ту же команду... Но опять же, так же происходит и в мониторе порта, если я не выбираю параметр NL (новая строка)...
Новая строка это символ "\n" (номер в ascii-таблице "10"). У вас он в программе на пк отправляется? И ещё "20" это 2 символа "2" и "0"? аски-таблица
я отправлял команду STXNULLLF....но это похоже на бред...честно, я без понятия, как это сделать...я бы не полез на форум, но уже больше недели пытаюсь это сделать и ничего не могу найти...
Можете привести лог программы, что тут происходит. (желательно в кодах) Сколько символов в bufwrHEX (ведь, он хранит то, что потом отправляется?) Параметры com-порта проверены? Приведите лог-программы из терминала, в котором работает весь процесс. Напишите на ардуино программку которая по программному юарту отправляет данные на пк(другой ком порт) и мониторьте обычным терминалом.