一、首先。老規矩。配置好自己的vs環境和建立一個dll工程。
我的環境:
- vs2013
- win10
二、開始寫代碼
廢話不多說。因為自己之前搞這個的時候,很多都要積分才可以下載,我這里就把我的整個工程分享出來供大家使用。經過測試工程讀寫完全正常。我在之前有發了一篇博客記錄了讀寫的截圖。
https://blog.csdn.net/weixin_43673603/article/details/107681314
代碼的輸出輸入為十六進制轉換,你們可以根據自己的需要去重新寫一個接收到的數據格式轉換函數,就可以輸出自己想要的格式。
首先自己新建兩個文件,一個com.c。一個com.h。名字可以自己其吧,只不過后面自己要改下頭文件引用。
com.c內容(這個串口的配置文件)
#include "stdafx.h"
#include <stdio.h>
#include "Com.h"
//
// Construction/Destruction
//
CCom::CCom()
{
hPort = INVALID_HANDLE_VALUE;
memset(LineBuf, 0, sizeof(LineBuf));
dataLen = 0;
}
CCom::~CCom()
{
close();
}
/** 奇偶校驗 0-4 = no,odd,even,mark,space 每字節一位停止位 0,1,2 = 1, 1.5, 2 OpenPort( _T("com1:"), 4800, 8, 0, 1 ); */
BOOL CCom::open(LPTSTR lpszPortName,
DWORD baudRate,
BYTE byteSize,
BYTE parity,
BYTE stopBits)
{
if (hPort != INVALID_HANDLE_VALUE)
{
//::MessageBox(NULL, "hPort != INVALID_HANDLE_VALUE", "錯誤", MB_OK);
return FALSE;
}
//打開串口
hPort = CreateFile(lpszPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
//如果打開端口出錯, 返回FALSE
if (hPort == INVALID_HANDLE_VALUE)
{
//不能打開端口
DWORD errNum = GetLastError();
char buf[256];
sprintf(buf, "Unable to open port[%s] errCode[%d]!\n", lpszPortName, errNum);
//::MessageBox(NULL, buf, "Err code", MB_OK);
return FALSE;
}
//指定端口監測的事件集
SetCommMask(hPort, EV_ERR | EV_RXCHAR | EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY);
//分配設備緩沖區
SetupComm(hPort, 512, 32);
//初始化緩沖區中的信息
PurgeComm(hPort, PURGE_TXCLEAR | PURGE_RXCLEAR);
//配置串行端口
if (!InitDCB(baudRate, byteSize, parity, stopBits))
{
//::MessageBox(NULL, "配置串行端口", "錯誤", MB_OK);
return FALSE;
}
//設置端口超時值
if (!InitCommTimeouts())
{
//::MessageBox(NULL, "設置端口超時值", "錯誤", MB_OK);
return FALSE;
}
//設置端口上指定信號的狀態
// SETDTR: 發送DTR (data-terminal-ready)信號
// SETRTS: 發送RTS (request-to-send)信號
EscapeCommFunction(hPort, SETDTR);
EscapeCommFunction(hPort, SETRTS);
//clear( hPort );
PurgeComm(hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return TRUE;
}
DWORD CCom::write(TCHAR *buf, DWORD dwCharToWrite)
{
if (hPort == INVALID_HANDLE_VALUE)
return 0;
BOOL fWriteState;
DWORD dwBytesWritten;
//寫入數據
fWriteState = WriteFile(hPort,
buf,
dwCharToWrite * sizeof(TCHAR),
&dwBytesWritten,
NULL);
if (!fWriteState)
{
//不能寫數據
printf("Can't Write String to Com\n");
dwBytesWritten = 0;
}
return dwBytesWritten;
}
BOOL CCom::InitDCB(DWORD baudRate,
BYTE byteSize,
BYTE parity,
BYTE stopBits)
{
DCB PortDCB;
DWORD dwError;
PortDCB.DCBlength = sizeof (DCB);
//得到端口的默認設置信息
GetCommState(hPort, &PortDCB);
//改變DCB結構設置
PortDCB.BaudRate = baudRate; //波特率
PortDCB.ByteSize = byteSize; //每字節的位數 number of bits/byte, 4-8
PortDCB.Parity = parity; //奇偶校驗 0-4=no,odd,even,mark,space
PortDCB.StopBits = (stopBits == 2) ? 2 : 0; //每字節一位停止位 0,1,2 = 1, 1.5, 2
//根據DCB結構配置端口
if (!SetCommState(hPort, &PortDCB))
{
this->close();
//不能配置串行端口
dwError = GetLastError();
char buf[256];
sprintf(buf, "Unable to configure the serial port err:%d\n", dwError);
//::MessageBox(NULL, buf, "Err code", MB_OK);
return FALSE;
}
return TRUE;
}
BOOL CCom::InitCommTimeouts()
{
COMMTIMEOUTS CommTimeouts;
DWORD dwError;
//得到超時參數
GetCommTimeouts(hPort, &CommTimeouts);
//改變COMMTIMEOUTS結構設置
CommTimeouts.ReadIntervalTimeout = MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
CommTimeouts.WriteTotalTimeoutMultiplier = 10;
CommTimeouts.WriteTotalTimeoutConstant = 1000;
//設置端口超時值
if (!SetCommTimeouts(hPort, &CommTimeouts))
{
this->close();
//不能設置超時值
printf("Unable to set the time-out parameters\n");
dwError = GetLastError();
return FALSE;
}
return TRUE;
}
BOOL CCom::close()
{
if (hPort != INVALID_HANDLE_VALUE)
{
//關閉串口
CloseHandle(hPort);
hPort = INVALID_HANDLE_VALUE;
return TRUE;
}
else
{
return TRUE;
}
}
DWORD CCom::read(char * buf, DWORD size)
{
if (hPort == INVALID_HANDLE_VALUE)
return 0;
//從串口讀取數據
if (!ReadFile(hPort, buf, size, &size, NULL))
{
//不能從串口讀取數據
printf("Error in read from serial port\n");
size = 0;
}
return size;
}
int CCom::readSyn(char *buf, DWORD wCount, DWORD wWaitTickCount)
{
//讀滿 wCound 個字符
DWORD nReadCount = 0;
DWORD wTimeBegin = ::GetTickCount();
while (nReadCount < wCount)
{
int count = read(buf + nReadCount, wCount - nReadCount);
if (count < 0)
return -1;
if (count == 0)
{
if (wWaitTickCount > 0 && ::GetTickCount() - wTimeBegin > wWaitTickCount)
return 0;
//Sleep(1);
}
else
nReadCount += count;
}
return 1;
}
接下來是com.h文件(串口配置頭文件)
#include <windows.h>
class CCom
{
public:
BOOL open(LPTSTR lpszPortName,
DWORD baudRate,
BYTE byteSize,
BYTE parity,
BYTE stopBits); //打開串口
BOOL close(); //關閉串口
int readSyn(char * buf, DWORD wCount, DWORD wWaitTickCount = 0);
DWORD read(char * buf, DWORD size);
DWORD write(TCHAR *buf, DWORD dwBytesToWrite); //寫數據
CCom();
virtual ~CCom();
private:
HANDLE hPort;
char LineBuf[256];
DWORD dataLen;
BOOL InitDCB(DWORD baudRate,
BYTE byteSize,
BYTE parity,
BYTE stopBits); //配置串口
BOOL InitCommTimeouts(); //設置超時參數
};
工程原本的.c文件。我的工程叫UartComdll。所以這里叫UartComdll.c
// UartComdll.cpp : 定義 DLL 應用程序的導出函數。
//
#include "stdafx.h"
#include "Com.h"
#include <stdio.h>
#include <stdlib.h>
#include "UartCom.h"
#include <string.h>
#include <iostream>
using namespace std;
char* uartbuff;
void delay(unsigned int xms) // xms代表需要延時的毫秒數
{
unsigned int x, y;
for (x = xms; x>0; x--)
for (y = 110000; y>0; y--);
}
unsigned char Hex_buf[6]; //繼電器串口接收緩存
unsigned char MotorHex_buf[100]; //步進電機
unsigned char i = 0x01;
CCom gCom;
BOOL gbInit = false;
int gCurCom = 0;
TPackaMsg boradMes;
#define MSG_HEAD1 0xFF
#define MSG_HEAD2 0xFE
void UartClose(void)
{
if (gbInit)
{
gCom.close();
gbInit = false;
}
}
int UartInit(int nCom)
{
if (!gbInit || nCom != gCurCom)
{
char sNum[8] = { 0 };
char sComName[16] = "com";
strcat(sComName, _itoa(nCom, sNum, 10));
UartClose();
gbInit = gCom.open(sComName, 115200, 8, 0, 1);
if (gbInit)
{
gCurCom = nCom;
return 1;
}
return -1;
}
if (!gbInit)
return -1; //打開端口失敗
return 1;
}
void substring(char *s, char ch1, char ch2, char *substr)
{
while (*s && *s++ != ch1);
while (*s && *s != ch2) *substr++ = *s++;
*substr = '\0';
}
//繼電器串口控制發送函數
int ControlRelaytoUart( unsigned char buf){
unsigned char index;
unsigned char checkvalue;
Hex_buf[0] = 0xff;
Hex_buf[1] = 0xfe; //裝載串口一幀數據頭部
Hex_buf[2] = 0x01; //板子編號
Hex_buf[3] = buf; //繼電器
Hex_buf[4] = 0xde; //
checkvalue = 0;
for (index = 0; index < 5; index++){ checkvalue ^= Hex_buf[index]; }
Hex_buf[5] = checkvalue; //裝載尾部
gCom.write((TCHAR*)Hex_buf,sizeof(Hex_buf));
return 1;
}
int ControlRelay(int id, unsigned char controldata){ //接口調用發數據給串口
if (id == 1){//id是板子編號
ControlRelaytoUart(controldata);//進入串口發送數據函數
}
return 1;
}
void testrelay(unsigned char num){
for (i; i < 17; i++){
ControlRelay(1, num);
num = num + 0x01;
delay(10000);
}
}
接下來就是在工程原本的頭文件編寫了,引出來我們的封裝函數可以被第三方調用。
UartComdll.h
#ifndef _RS232DLL_H_
#define _RS232DLL_H_
#define Uart_API __declspec(dllexport)
#define player 4
extern "C" //輸出dll中的接口,為程序所用,也為自己的測試程序所用
{
Uart_API void UartClose(void);
Uart_API int UartInit(int nCom);
Uart_API int ControlRelay(int id, unsigned char controldata);
Uart_API void testrelay(unsigned char num);
}
#endif
自此,全部完成。我們只需要點擊

就可以得到我們的dll和lib。在你的工程debug目錄下的文件夾中就可以找到,有些是x64的,就要去x64中財可以找到。

至於怎么引用,可以看我下一篇博客。
https://blog.csdn.net/weixin_43673603/article/details/107855147
如果自己根據我的博客配置還不成功的,可能是自己調用的版本問題,注意版本一致, 這個是絕對可以運行成功的,如果實在看不懂,那你花點積分下載我的資源吧,我也救不你。哈哈哈哈~~·
資源地址:點擊下載
