Serial programming - WIN32
От: scf37  
Дата: 14.04.07 08:32
Оценка:
Есть контроллер PIC16F84A c "обвязкой" и кабель для подключения к COM-порту. Нужно сделать обмен данными между компом и девайсом.
Проблема: подключено только два сигнала: RD и TD
Вопрос: Как получить и устанавливать состояние этих сигналов с user-mode? C++/Asm не проблема, но написанием дров никогда не занимался
Re: Serial programming - WIN32
От: uni Россия  
Дата: 14.04.07 12:15
Оценка:
Здравствуйте, 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>>
Re: Serial programming - WIN32
От: Macr0s Россия  
Дата: 16.04.07 07:01
Оценка:
Здравствуйте, 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.
Перед тем, как улучшиться, ситуация ухудшается. (из законов Мерфи)
Re: Serial programming - WIN32
От: iekmuf  
Дата: 28.04.07 18:10
Оценка:

подключено только два сигнала: 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
Re: Serial programming - WIN32
От: scf37  
Дата: 28.04.07 18:16
Оценка:
Спасибо всем за помощь.
Собственно, решение:

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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.