Есть контроллер PIC16F84A c "обвязкой" и кабель для подключения к COM-порту. Нужно сделать обмен данными между компом и девайсом.
Проблема: подключено только два сигнала: RD и TD
Вопрос: Как получить и устанавливать состояние этих сигналов с user-mode? C++/Asm не проблема, но написанием дров никогда не занимался
Здравствуйте, scf37, Вы писали:
S>Есть контроллер PIC16F84A c "обвязкой" и кабель для подключения к COM-порту. Нужно сделать обмен данными между компом и девайсом.
S>Проблема: подключено только два сигнала: RD и TD
S>Вопрос: Как получить и устанавливать состояние этих сигналов с user-mode? C++/Asm не проблема, но написанием дров никогда не занимался
Можно почитать книжку "Интерфейс RS-232. Связь между компьютером и микроконтроллером", А.Ю. Кузьминов, 2006 г. Там подробно по этому поводу всё описано.
Также погуглить на тему: inpout32.dll, UserPort.
Можно посмотреть на телесисах проект DS1821 на Delphi, где с далласовским цифровым термомертом осуществляется связь посредством comapi32.dll.
Дрова уже написаны, нужно их только найти и использовать. Кое-где есть компоненты для Delphi и CBuilder'а, но я уже не помню их названий.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Здравствуйте, scf37, Вы писали:
S>Есть контроллер PIC16F84A c "обвязкой" и кабель для подключения к COM-порту. Нужно сделать обмен данными между компом и девайсом.
S>Проблема: подключено только два сигнала: RD и TD
S>Вопрос: Как получить и устанавливать состояние этих сигналов с user-mode? C++/Asm не проблема, но написанием дров никогда не занимался
Если сигнал RD используется только на чтение, а TD только н азапись, то в этом случае может помочь WriteFile и ReadFile. Юзер-мод, только правильно надо параметры порта выставить. Это делается при помощи CommAPI (GetCommState/SetCommState, GetCommTimeouts/SetCommTimeouts итд).
Если есть вариант поизвращаться с кабелем, то можно использовать DTR и/или RTS сигналы. Их из юзер-мода можно установить/снять используя EscapeCommFunction с параметрами SETDTR/CLRDTR и/или SETRTS/CLRRTS.
Перед тем, как улучшиться, ситуация ухудшается. (из законов Мерфи)
подключено только два сигнала: RD и TD
Нужно еще землю (GND) подключить. Т.е. RX, GND и TX платы соединяется с TX, GND и RX порта компа соответственно,
написанием дров никогда не занимался
Для посылки/отправки данных можно раблотать с портом, как с обычным файлом.
1) Открытие порта:
HANDLE hPort = CreateFile ("COM1", // Pointer to the name of the port
GENERIC_READ | GENERIC_WRITE,
// Access (read-write) mode
0, // Share mode
NULL, // Pointer to the security attribute
OPEN_EXISTING,// How to open the serial port
0, // Port attributes
NULL); // Handle to port with attribute
// to copy
2) Получение параметров порта:
DCB PortDCB;
// Get the default port setting information.
GetCommState (hPort, &PortDCB);
3) Изменение параметров
// Change the DCB structure settings.
PortDCB.BaudRate = CBR_19200; // Current baud
PortDCB.fBinary = TRUE; // Binary mode; no EOF check
PortDCB.fParity = FALSE;
PortDCB.fOutxCtsFlow = FALSE;
PortDCB.fOutxDsrFlow = FALSE;
PortDCB.fDtrControl = DTR_CONTROL_DISABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = FALSE;
PortDCB.fOutX = FALSE;
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_DISABLE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
PortDCB.XoffLim = 1024;
PortDCB.XonLim = 1;
PortDCB.XonChar = 0x41;
PortDCB.XoffChar = 0x42;
PortDCB.ErrorChar = 0x45;
PortDCB.EofChar = 0x46;
PortDCB.EvtChar = 0x56;
4) Установка параметров
if (!SetCommState (hPort, &PortDCB))
{
MessageBox (hMainWnd, TEXT("Невозможно сконфигурировать COM-порт"),
TEXT("Ошибка!"), MB_OK);
dwError = GetLastError ();
return false;
}
5) Получение/установка тайм-аутов для порта
COMMTIMEOUTS CommTimeouts;
GetCommTimeouts (hPort, &CommTimeouts);
// Change the COMMTIMEOUTS structure settings.
CommTimeouts.ReadIntervalTimeout = 10000;//MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 1; //0
CommTimeouts.ReadTotalTimeoutConstant = 25000;//0
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
// Set the time-out parameters for all read and write operations
// on the port.
if (!SetCommTimeouts (hPort, &CommTimeouts))
{
MessageBox (hMainWnd, TEXT("Невозможно установить тайм-ауты COM-порта"),
TEXT("Error"), MB_OK);
dwError = GetLastError ();
return false;
}
6) Очистка буферов порта (входного и выходного буфера) и установка их размеров.
// Clear in\out buffers
PurgeComm(hPort,PURGE_TXCLEAR||PURGE_RXCLEAR);
// Setup buffers size
SetupComm( hPort, 2048, 2048);
7) Оправка данных
DWORD dwError,
dwNumBytesWritten;
if (!WriteFile (hPort, // Port handle
(byte *)"Hello", // Pointer to the data to write
1, // Number of bytes to write
&dwNumBytesWritten, // Pointer to the number of bytes
// written
NULL)) // Must be NULL for Windows CE
{
// WriteFile failed. Report error.
dwError = GetLastError ();
return (false);
}
return (true);
8) Чтение данных. Здесь "aByte" — указатель на буфер, в который будем читать данные
DWORD dwBytesTransferred;
if (hPort != INVALID_HANDLE_VALUE)
{
// Re-specify the set of events to be monitored for the port.
SetCommMask (hPort, EV_RXCHAR);
ReadFile (hPort, aByte, 1, &dwBytesTransferred, 0);
if (dwBytesTransferred == 1) return (true);
}
return (false);
9) Закрытие порта
DWORD dwError;
if (hCommPort != INVALID_HANDLE_VALUE)
{
// Clear all events to be monitored for the port.
SetCommMask (hPort, 0);
// Close the communication port.
if (!CloseHandle (hCommPort))
{
dwError = GetLastError ();
return false;
}
else
{
hCommPort = INVALID_HANDLE_VALUE;
return true;
}
}
Вроде все. Если что не так — поправьте. Выдирал из класса рабочего проекта.
P.S. Про использованные функции и структуры — RTFM
Спасибо всем за помощь.
Собственно, решение:
class CPicComm
{
public:
CPicComm(std::string port)
{
hCom = CreateFile(port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hCom == INVALID_HANDLE_VALUE)
throw std::string("Невозможно открыть порт");
DCB dcb;
memset(&dcb, 0, sizeof(dcb));
dcb.BaudRate = CBR_110;
dcb.ByteSize = 8;
dcb.DCBlength = sizeof(DCB);
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fBinary = 1;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
if (!SetCommState(hCom, &dcb))
throw std::string("Невозможно настроить порт");
COMMTIMEOUTS cto;
memset(&cto, 0, sizeof(cto));
if (!SetCommTimeouts(hCom, &cto))
throw std::string("Невозможно настроить тайм-аут порта");
}
~CPicComm(void)
{
if (hCom != INVALID_HANDLE_VALUE)
CloseHandle(hCom);
}
//returns true if port is accessible
static bool verifyPort(std::string port)
{
HANDLE h = CreateFile(port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
return false;
CloseHandle(h);
return true;
}
void send(BYTE b)
{
send(&b, 1);
}
void send(BYTE b[], size_t count)
{
DWORD dw;
WriteFile(hCom, b, count, &dw, NULL);
if (dw != count)
throw std::string("Ошибка записи в порт");
}
BYTE recv()
{
BYTE b;
recv(&b, 1);
return b;
}
void recv(BYTE b[], size_t count)
{
DWORD dw;
ReadFile(hCom, b, count, &dw, NULL);
if (dw != count)
throw std::string("Ошибка чтения из порта");
}
private:
HANDLE hCom;
};
И часть прошивки:
sleep45: ; sleeps for 4.5 ms - half bit length (1000 ms / 110 bod / 2)
movlw 0x1D
movwf sleep_r1
sleep45_1:
clrf sleep_r2
sleep45_2:
decfsz sleep_r2
goto sleep45_2
decfsz sleep_r1
goto sleep45_1
return
;sends one byte from comm_reg
sendbyte:
; sending start-bit
bcf PORTB, 2
call sleep45
call sleep45
bsf STATUS, C
;we need to send 8 data bits AND stop-bit, which is now loaded to C
sendbyte_1l:
rrf comm_reg
btfss STATUS, C
bcf PORTB, 2
btfsc STATUS, C
bsf PORTB, 2
call sleep45
call sleep45
clrw
addwf comm_reg, w ;CF = 0, ZF = (commreg==0)
btfss STATUS, Z ;comm_reg=0 means we've done!
goto sendbyte_1l
return
; receives one byte to comm_reg
recvbyte:
btfsc PORTB, 1 ; waiting for startbit (0)
goto recvbyte
call sleep45
call sleep45
;first data bit starts here
movlw 0x80 ; we're putting '1' to bit7. it will appear in CF after 8 shifts
movwf comm_reg
recvbyte_l1:
call sleep45 ;skeeping halfbit
bcf STATUS, C
btfsc PORTB, 1 ; CF = PORTB1
bsf STATUS, C
rrf comm_reg
btfsc STATUS, C ;if initial '0x01' in CF now then we've done
goto recvbyte_exit
call sleep45 ;skeeping second halfbit
goto recvbyte_l1
recvbyte_exit:
call sleep45 ;second half of last bit
call sleep45 ;stopbit
call sleep45
return