乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      基于C語言的java串口通信程序

       山峰云繞 2022-05-24 發(fā)布于貴州

      目錄

      1.前言

      2.windows ?串口通信API

      3.JAVA-JNI ?java程序調(diào)用C++程序

      4.C/C++封裝 ?動(dòng)態(tài)運(yùn)行庫

      一、前言

      ??

      https://www.cnblogs.com/kadcyh/p/14389710.html



      寫這個(gè)博客主要是因?yàn)樽约合胗胘ava寫一個(gè)小小的后端服務(wù)器,其中要處理由51單片機(jī)傳送來的一些數(shù)據(jù)。單片機(jī)的數(shù)據(jù)由USB轉(zhuǎn)串口發(fā)送至上位機(jī),要處理這些數(shù)據(jù),就會(huì)用到windows提供一些API( Application Programming Interface,應(yīng)用程序接口 )。java在安裝了相關(guān)的包后,比如JNative.jar,可以直接用該包提供的接口來進(jìn)行調(diào)用windowsAPI。但是我才接觸java。而且整個(gè)作業(yè),我僅僅只要一部分來處理這個(gè)數(shù)據(jù)。安裝一個(gè)java包,實(shí)在是大可不必,所以就用C/C++來寫一個(gè)的終端,封裝一下放在java程序里面。

      二、windows串口通信API

      ??2.1 ? 工具VC++6.0

      ??2.2 ? 概述:windows操作系統(tǒng)的設(shè)備無關(guān)性將所有的外設(shè)都當(dāng)做文件來操作,那么我們寫串口通信就直接將串口當(dāng)做文件來讀寫。那么我們打開串口后一定要記得關(guān)閉,這個(gè)很重要

      ??2.3 ? 串口通信程序概述

      2.3.1 打開/關(guān)閉串口

      HANDLE WINAPI CreateFileW(
          LPCWSTR lpFileName,                 
          DWORD dwDesiredAccess,                        
          DWORD dwShareMode,                              //共享模式
          LPSECURITY_ATTRIBUTES lpSecurityAttributes,    //安全屬性
          DWORD dwCreationDisposition,                  //指定文件的動(dòng)作
          DWORD dwFlagsAndAttributes,                  //文件屬性---不指定就默認(rèn)為同步IO 
          HANDLE hTemplateFile                        //模板文件
          );
      
      BOOL WINAPI CloseHandle(
             HANDLE hObject
          );

      返回值:一個(gè)串口的句柄。
      參數(shù)解釋:
      lpFileName——串口名字。?當(dāng)為COM1~COM9的時(shí)候可以直接寫入但是大于10會(huì)有另外的寫法。以COM10為例:\.\COM10
      lpFileName——打開方式。?簡(jiǎn)單來說這個(gè)就是打開文件是讀還是寫。GENERIC_READ(讀)|GENERIC_WRITE(寫)。還有其它的兩個(gè)值,詳細(xì)請(qǐng)?jiān)诰庉嬈髦兄苯影聪翭12看看他們的定義。
      如果我們要定義一個(gè)同步IO的話,我們的打開方式必須要有讀動(dòng)作。
      dwShareMode指定該端口的共享屬性。?對(duì)于不能共享的串口,它必須設(shè)置為0。這就是文件與通信設(shè)備之間的主要差異之一。如果在當(dāng)前的應(yīng)用程序調(diào)用CreateFile()時(shí),另一個(gè)應(yīng)用程序已經(jīng)打開了串口,該函數(shù)就會(huì)返回錯(cuò)誤代碼,原因是兩個(gè)應(yīng)用程序不能共享一個(gè)端口。然而,同一個(gè)應(yīng)用程序的多個(gè)線程可以共享由CreateFile()返回的端口句柄,并且根據(jù)安全性屬性設(shè)置,該句柄可以被打開端口的應(yīng)用程序的子程序所繼承。
      dwCreationDisposition指定文件的動(dòng)作。?指定如果CreateFile()正在被已有的文件調(diào)用時(shí)應(yīng)采取的動(dòng)作。因?yàn)榇诳偸谴嬖?,fdwCreate必須設(shè)置成OPEN_EXISTING。該標(biāo)志告訴Windows不用企圖創(chuàng)建新端口,而是打開已經(jīng)存在的端口。
      調(diào)用該函數(shù)后,如果沒有穿件成功將會(huì)返回INVALID_HANDLE_VALUE。

      2.3.2 配置串口通信

      • (1)?當(dāng)我們?cè)O(shè)置同步IO通信的時(shí)候,需要設(shè)置一下通信超時(shí)。一般情況下,我們用GetCommTimeouts來獲得COMMTIMEOUTS結(jié)構(gòu)體,再利用SetCommTimeouts來寫入。

      BOOL WINAPI GetCommTimeouts(
          HANDLE hFile,
          LPCOMMTIMEOUTS lpCommTimeouts
          );
      
      BOOL WINAPI SetCommTimeouts(
          HANDLE hFile,
          LPCOMMTIMEOUTS lpCommTimeouts
          );

      COMMTIMEOUTS

      typedef struct _COMMTIMEOUTS {
          DWORD ReadIntervalTimeout;          /* 設(shè)置兩個(gè)字符之前的最大讀取時(shí)間 */
          DWORD ReadTotalTimeoutMultiplier;   /* 設(shè)置每個(gè)字符的讀取時(shí)間        */
          DWORD ReadTotalTimeoutConstant;     /* 設(shè)置所有字符讀取的最大時(shí)間    */
          DWORD WriteTotalTimeoutMultiplier;  /* 設(shè)置每個(gè)字符的寫入時(shí)間       */
          DWORD WriteTotalTimeoutConstant;    /* 設(shè)置所有字符的寫入時(shí)間      */
      } COMMTIMEOUTS,*LPCOMMTIMEOUTS;
      • (2)?設(shè)置波特率等相關(guān)參數(shù)
        仍然先用GetCommState得到DCB結(jié)構(gòu),修改其中的某些參數(shù)后再用SetCommState寫入DCB結(jié)構(gòu)。

      BOOL WINAPI GetCommState(
          HANDLE hFile,
          LPDCB lpDCB
          );
      BOOL WINAPI SetCommState(
          HANDLE hFile,
          LPDCB lpDCB
          );

      DCB數(shù)據(jù)結(jié)構(gòu)我們初級(jí)學(xué)者需要關(guān)注:波特率、校驗(yàn)位、停止位、發(fā)送數(shù)據(jù)位數(shù)。

      • (3)?設(shè)置緩沖區(qū)大小,根據(jù)程序要接收/發(fā)送的數(shù)據(jù)大小來決定。

      BOOL WINAPI SetupComm(
          HANDLE hFile,
          DWORD dwInQueue,
          DWORD dwOutQueue
          );
      • (4)?讀取/寫入數(shù)據(jù)

      BOOL WINAPI ReadFile(
          HANDLE hFile,
          LPVOID lpBuffer,                  //存放數(shù)據(jù)的緩沖區(qū)
          DWORD nNumberOfBytesToRead,       //一次想要讀入的數(shù)據(jù)長度
          LPDWORD lpNumberOfBytesRead,      //實(shí)際讀入的數(shù)據(jù)長度
          LPOVERLAPPED lpOverlapped      
          );
      
      BOOL WINAPI WriteFile(
          HANDLE hFile,
          LPCVOID lpBuffer,
          DWORD nNumberOfBytesToWrite,
          LPDWORD lpNumberOfBytesWritten,
          LPOVERLAPPED lpOverlapped
          );

      2.3.3 串口緩沖區(qū)配置

      在程序運(yùn)行的時(shí)候,應(yīng)該保證設(shè)置的緩沖區(qū)是“干凈”的。所以在讀數(shù)據(jù)或者寫數(shù)據(jù)之前,可以先清空一下緩沖區(qū)。

      //清空緩沖區(qū)
      BOOL WINAPI PurgeComm(
          HANDLE hFile,
          DWORD dwFlags
          );
      
      //清除錯(cuò)誤
      BOOL WINAPI ClearCommError(
          HANDLE hFile,
          LPDWORD lpErrors,
          LPCOMSTAT lpStat
          );

      2.4完整的讀串口代碼

      #include <stdio.h>`
      #include <windows.h>
      int Comm(int nBaud,int parity,int bytesize,int stopbits,int accdatalength,char rBuf[])
      {								//緩沖區(qū)
      	DWORD rSize = 0;
      	DWORD dwError;										//清除錯(cuò)誤
      	COMSTAT cs;				
      	COMMTIMEOUTS timeouts;								//超時(shí)數(shù)據(jù)結(jié)構(gòu)
      	DCB dcb;											//串口通信配置文件---用LPDCB類型會(huì)報(bào)錯(cuò)
      	HANDLE hCom;										//串口的句柄(實(shí)例)| the instance of com
      	hCom = CreateFile("COM3",							//串口的名字
      					   GENERIC_READ | GENERIC_WRITE,    //串口打開方式
      					   0,								//共享方式					
      					   NULL,							//安全屬性
      					   OPEN_EXISTING,					//指定文件的動(dòng)作
      					   0,								//文件屬性---不指定就默認(rèn)為同步IO
      					   NULL								//指向模板文件的句柄
      					   );
      	if(hCom == INVALID_HANDLE_VALUE)
      	{
      		return -1;
      	}
      ///////////////////////////////////////
      //同步IO需要設(shè)置讀數(shù)據(jù)超時(shí)
      //////////////////////////////////////
      	if(!(GetCommTimeouts(hCom,&timeouts)))		//獲的COMMTIMEOUTS結(jié)構(gòu)失?。?	{
      		CloseHandle(hCom);
      	}
      	timeouts.ReadIntervalTimeout = 1000;			//讀取每個(gè)字符之間的超時(shí)
      	timeouts.ReadTotalTimeoutMultiplier = 500;		//讀取一個(gè)字符的超時(shí)
      	timeouts.ReadTotalTimeoutConstant=5000;			//固定總超時(shí)
      	timeouts.WriteTotalTimeoutConstant = 0;			//寫入字符之間超時(shí)
      	timeouts.WriteTotalTimeoutMultiplier = 0;		//寫入字符總超時(shí)
      	if(!(SetCommTimeouts(hCom,&timeouts)))			//設(shè)置COMMTIMEOUTS結(jié)構(gòu)失敗
      	{
      		CloseHandle(hCom);
      	}
      ////////////////////////////////////////
      //設(shè)置緩沖區(qū)大小
      ///////////////////////////////////////
      	if(!SetupComm(hCom,500,500))				//設(shè)置讀寫緩沖區(qū)失敗
      	{
      		CloseHandle(hCom);
      	}
      //////////////////////////////////////
      //設(shè)置波特率等其它讀文件配置
      /////////////////////////////////////
      	if(GetCommState(hCom,&dcb)==0)			//獲得DCB數(shù)據(jù)失敗
      	{
      		CloseHandle(hCom);
      	}
      	//dcb.DCBlength = sizeof(DCB);
      	dcb.BaudRate = nBaud;					//波特率為4800
      	dcb.Parity = parity;					//校驗(yàn)方式為無校驗(yàn)
      	dcb.ByteSize = bytesize;						//數(shù)據(jù)位為8位
      	dcb.StopBits = stopbits;				//停止位為1位
      	if (!SetCommState(hCom,&dcb))			//設(shè)置串口通信配置項(xiàng)失敗
      	{
      		CloseHandle(hCom);
      	}
      
      //////////////////////////////////////
      //清除緩沖區(qū)
      /////////////////////////////////////
      	PurgeComm(hCom,PURGE_RXCLEAR|PURGE_TXCLEAR);
      ///////////////////////////////////////
      //清除錯(cuò)誤
      ///////////////////////////////////////
      	if(!(ClearCommError(hCom,&dwError,&cs)))
      	{
      		CloseHandle(hCom);
      	}
      ////////////////////////////////////////////
      //開始讀取緩沖口的數(shù)據(jù)
      ///////////////////////////////////////////
      
      	//讀取串口數(shù)據(jù)
      	if(INVALID_HANDLE_VALUE != hCom)
      	{
      		WriteFile
      		ReadFile(hCom,rBuf,accdatalength,&rSize,NULL);
      		printf("%d \n",rSize);
      		if(rSize)
      		{
      			CloseHandle(hCom);
      			return 1;
      			
      		}
      		else
      		{
      			CloseHandle(hCom);
      			return 0;
      		}
      	}
      	else
      	{
      		CloseHandle(hCom);
      		return 2;
      	}	
      }
      void main()
      {
      	int i;
      	char buf[18] = {0};
      	int a,b,c,d,e;
      	printf("請(qǐng)輸入相關(guān)參數(shù):");
      	scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
      	while(1)
      	{
      		if(Comm(a,b,c,d,e,buf)==1)
      		{
      			for(i=0;i<17;i++)
      			{
      				printf("%c ",buf[i]);
      			}
      			printf("\n");
      		}
      		else
      		{
      			printf("%d \n",Comm(a,b,c,d,e,buf));
      			break;
      		}
      	}
      	
      }

      運(yùn)行結(jié)果

      三、JAVA-JNI ?java程序調(diào)用C++程序

      ??參考博客
      ??在寫java程序調(diào)用C程序之前,寫過C#程序調(diào)用用C#封裝好的dll程序。然后,我以為,java程序調(diào)用C程序也可以直接把C封裝好的dll程序拿過來直接用就好。結(jié)果就是一直報(bào)錯(cuò)。那么接下來就是正確的調(diào)用方式。

      工具eclipse

      3.1

      ??首先在新建一個(gè)類,類的名字隨意。最好加上main()函數(shù)方便我們進(jìn)行模塊調(diào)試。在這個(gè)類里面。在這個(gè)類里面我們要自己定義將會(huì)用C/C++實(shí)現(xiàn)的函數(shù)。并且必須用到j(luò)ava提供的 System.loadLibrary()函數(shù)。如下:
      `

      public class Com {
      	
      	static {
      		System.loadLibrary("CommDLL");			//靜態(tài)語句塊,保證在創(chuàng)建該類的時(shí)候,該方法必須且只會(huì)調(diào)用一次。參數(shù)就是編寫的動(dòng)態(tài)庫名稱
      	}
      	public native int Comm(int nBaud,int parity,int bytesize,int stopbits,int accdatalength,String ComName,char[] rBuf);//將要用C/C++實(shí)現(xiàn)的函數(shù)
      	public static void main(String[] args) {
      	      int term = new Com().Comm(4800, 0, 8, 0, 17,"COM3", Buffer);
      			
      	}	
      }

      `
      注:native 關(guān)鍵字表示,這個(gè)函數(shù)為本地函數(shù)。盡管沒用java語言實(shí)現(xiàn),但它有自己的實(shí)體。

      3.2

      ??找到剛編寫的java源程序文件所在的位置。然后如下操作:

      ??注:馬賽克的位置是暫時(shí)還不該有的文件

      ??進(jìn)入控制臺(tái):

      ??輸入 javac -d ./ Com.java 。即是根據(jù)將java文件經(jīng)過編譯生成二進(jìn)制文件(class文件)

      ??輸入 javac -h ./ Com.java 生成相關(guān)的頭文件。

      ??注:如果報(bào)錯(cuò):'javac不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件。'?請(qǐng)參考相關(guān)博客添加相關(guān)的環(huán)境變量。參考博客。

      3.3

      ??在生成了相關(guān)的庫文件的編寫后。我們要用這個(gè)庫文件有兩種辦法。

      • 1:直接將生成的dll文件加入默認(rèn)的環(huán)境變量里面。( 但是不是很推薦這個(gè)辦法,因?yàn)槲覀兙帉懙膸欤瑑H僅只是在自己的程序上用一用。沒有很大的普適性。

      • 2:將生成的dll文件拷貝到自己源文件下面。同時(shí)配置一下自己的java程序。
        ?? 右鍵src--->properties--->Native Library--->Workspace

      3.4

      運(yùn)行代碼:

      public class Com {
      	
      	static {
      		System.loadLibrary("CommDLL");			//靜態(tài)語句塊,保證在創(chuàng)建該類的時(shí)候,該方法必須且只會(huì)調(diào)用一次。
      	}
      	public native int Comm(int nBaud,int parity,int bytesize,int stopbits,int accdatalength,String ComName,byte[] rBuf);
      	public static void main(String[] args) {
      		// TODO Auto-generated method stub
      		byte[] Buffer = new byte[18];
      		while(true)
      		{
      			int term = new Com().Comm(4800, 0, 8, 0, 17,"COM3", Buffer);
      			if(term==1)
      			{
      				for(int i=0;i<17;i++)
      				{
      					System.out.print(Buffer[i]+" ");
      					
      				}
      				System.out.println();
      			}
      		}
      		
      	}	
      }

      運(yùn)行結(jié)果

      四、C/C++封裝動(dòng)態(tài)運(yùn)行庫

      4.1:關(guān)于工具

      ??一開始用的工具是VC++6.0,盡管工具有點(diǎn)老,但是它足夠小。動(dòng)態(tài)庫編好了,在eclipse上面運(yùn)行的時(shí)候,出現(xiàn)了錯(cuò)誤,大致意思就是:“32位的動(dòng)態(tài)庫,沒有辦法在64位的設(shè)備上面”。 如果,我還想繼續(xù)使用這個(gè)動(dòng)態(tài)庫,已知的解決辦法就是:下載一個(gè)32位的java ? JDK包。但是,相比配置一個(gè)可以運(yùn)行32位的環(huán)境,我更加傾向于編譯生成一個(gè)64位的動(dòng)態(tài)運(yùn)行庫。然后,我就把代碼粘到了VS上面。一般寫代碼我不太喜歡在VS上面,雖然它的功能很強(qiáng)太,但是我的電腦負(fù)載它真的很費(fèi)力。

      4.2 用JNI編寫本地函具體步驟

      ?? * 1:建立DLL程序:文件--->新建--->項(xiàng)目--->windows桌面--->動(dòng)態(tài)鏈接庫

      4.2 代碼細(xì)節(jié)

      ?? * 1:新建一個(gè)頭文件,把在第三節(jié)里面生成的頭文件內(nèi)容復(fù)制粘貼過來。




      ?? * 2:具體cpp文件實(shí)現(xiàn)。
      當(dāng)我把VC里面的代碼直接粘貼過來的時(shí)候,就直接報(bào)錯(cuò)了。const char* 不可以轉(zhuǎn)換為LPCWSTR。我想強(qiáng)制轉(zhuǎn)化成LPCSTTR那肯定不可以的,但是強(qiáng)制轉(zhuǎn)化為wchar *這個(gè)是可以的。因?yàn)閳?bào)錯(cuò)的原因就是函數(shù)createFile()想要的文件名字應(yīng)該是寬字符傳進(jìn)去的。但是當(dāng)時(shí)我只解用了將普通字符轉(zhuǎn)成寬字符的函數(shù) MultiByteToWideChar ,不了解兩種字符的可以自行百度一下。用了這個(gè)函數(shù)后報(bào)錯(cuò)沒有了。
      但是,為了程序的健壯性我決定,把串口的名字暴露出來。然后新的問題出現(xiàn)了,當(dāng)我想為了適應(yīng)之前的程序,把串口的名字當(dāng)中字符數(shù)組傳進(jìn)來的時(shí)候。java程序又報(bào)錯(cuò),所以編譯器太智能了也讓人傷心。Java這邊發(fā)現(xiàn)的我傳入的就是一串字符,馬上要求我把參數(shù)改成字符串類型。那也沒辦法,我沒有能力自己開發(fā)一個(gè)IDE,所以就把string 傳了進(jìn)去。但是,我們知道C語言其實(shí)沒有stirng這種類型,后來我又加了一點(diǎn)C++的代碼,這樣才勉強(qiáng)有了字符串這種類型。好吧,用函數(shù)把jstring 類型在轉(zhuǎn)成寬字符類型。經(jīng)過這次的修改,代碼可以單獨(dú)在VS里面跑起來了。
      VS單獨(dú)運(yùn)行代碼:

      #include <iostream>
      #include<stdlib.h>
      #include<windows.h>
      using std::string;
      int Comm(int nBaud, int parity, int bytesize, int stopbits, int accdatalength,string comName, char rBuf[])
      {
      	DWORD rSize = 0;
      	DWORD dwError;										//清除錯(cuò)誤
      	COMSTAT cs;
      	COMMTIMEOUTS timeouts;								//超時(shí)數(shù)據(jù)結(jié)構(gòu)
      	DCB dcb;											//串口通信配置文件---用LPDCB類型會(huì)報(bào)錯(cuò)
      	HANDLE hCom;										//串口的句柄(實(shí)例)| the instance of com
      //////////////////////////////////////////////////////////////////////
      //將string轉(zhuǎn)換為LPCWSTR類型
      //////////////////////////////////////////////////////////////////////
      	int len = comName.length();
      	WCHAR buffer[256];
      	///////memset原型---extern void *memset(void *buffer, int c, int count) buffer:為指針或是數(shù)組,c:是賦給buffer的值,count:是buffer的長度.//////
      	memset(buffer, 0, sizeof(buffer));		//作用是在一段內(nèi)存塊中填充某個(gè)給定的值,它是對(duì)較大的結(jié)構(gòu)體或數(shù)組進(jìn)行清零操作的一種最快方法
      	MultiByteToWideChar(CP_ACP, 0, comName.c_str(), (len+1), buffer, sizeof(buffer) / sizeof(buffer[0]));
      	printf("%d\n", buffer[0]);
      	hCom = CreateFile(buffer,							//串口的名字
      		GENERIC_READ | GENERIC_WRITE,    //串口打開方式
      		0,								//共享方式					
      		NULL,							//安全屬性
      		OPEN_EXISTING,					//指定文件的動(dòng)作
      		0,								//文件屬性---不指定就默認(rèn)為同步IO
      		NULL								//指向模板文件的句柄
      	);
      	if (hCom == INVALID_HANDLE_VALUE)
      	{
      		return -1;
      	}
      	///////////////////////////////////////
      	//同步IO需要設(shè)置讀數(shù)據(jù)超時(shí)
      	//////////////////////////////////////
      	if (!(GetCommTimeouts(hCom, &timeouts)))		//獲的COMMTIMEOUTS結(jié)構(gòu)失??!
      	{
      		CloseHandle(hCom);
      	}
      	timeouts.ReadIntervalTimeout = 1000;			//讀取每個(gè)字符之間的超時(shí)
      	timeouts.ReadTotalTimeoutMultiplier = 500;		//讀取一個(gè)字符的超時(shí)
      	timeouts.ReadTotalTimeoutConstant = 5000;			//固定總超時(shí)
      	timeouts.WriteTotalTimeoutConstant = 0;			//寫入字符之間超時(shí)
      	timeouts.WriteTotalTimeoutMultiplier = 0;		//寫入字符總超時(shí)
      	if (!(SetCommTimeouts(hCom, &timeouts)))			//設(shè)置COMMTIMEOUTS結(jié)構(gòu)失敗
      	{
      		CloseHandle(hCom);
      	}
      	////////////////////////////////////////
      	//設(shè)置緩沖區(qū)大小
      	///////////////////////////////////////
      	if (!SetupComm(hCom, 500, 500))				//設(shè)置讀寫緩沖區(qū)失敗
      	{
      		CloseHandle(hCom);
      	}
      	//////////////////////////////////////
      	//設(shè)置波特率等其它讀文件配置
      	/////////////////////////////////////
      	if (GetCommState(hCom, &dcb) == 0)			//獲得DCB數(shù)據(jù)失敗
      	{
      		CloseHandle(hCom);
      	}
      	//dcb.DCBlength = sizeof(DCB);
      	dcb.BaudRate = nBaud;					//波特率為4800
      	dcb.Parity = parity;					//校驗(yàn)方式為無校驗(yàn)
      	dcb.ByteSize = bytesize;						//數(shù)據(jù)位為8位
      	dcb.StopBits = stopbits;				//停止位為1位
      	if (!SetCommState(hCom, &dcb))			//設(shè)置串口通信配置項(xiàng)失敗
      	{
      		CloseHandle(hCom);
      	}
      
      	//////////////////////////////////////
      	//清除緩沖區(qū)
      	/////////////////////////////////////
      	PurgeComm(hCom, PURGE_RXCLEAR | PURGE_TXCLEAR);
      	///////////////////////////////////////
      	//清除錯(cuò)誤
      	///////////////////////////////////////
      	if (!(ClearCommError(hCom, &dwError, &cs)))
      	{
      		CloseHandle(hCom);
      	}
      	////////////////////////////////////////////
      	//開始讀取緩沖口的數(shù)據(jù)
      	///////////////////////////////////////////
      
      		//讀取串口數(shù)據(jù)
      	if (INVALID_HANDLE_VALUE != hCom)
      	{
      		ReadFile(hCom, rBuf, accdatalength, &rSize, NULL);
      		printf("%d \n", rSize);
      		if (rSize)
      		{
      			CloseHandle(hCom);
      			return 1;
      
      		}
      		else
      		{
      			CloseHandle(hCom);
      			return 0;
      		}
      	}
      	else
      	{
      		CloseHandle(hCom);
      		return 2;
      	}
      }
      void main()
      {
      	int i;
      	char buf[18] = { 0 };
      	int a, b, c, d, e;
      	char ComName[6];
      	printf("請(qǐng)輸入相關(guān)參數(shù):");
      	std::cin >> a >> b >> c >> d >> e>>ComName;
      	while (1)
      	{
      		int t = Comm(a, b, c, d, e, ComName, buf);
      		if (t == 1)
      		{
      			for (i = 0; i < 17; i++)
      			{
      				printf("%c ", buf[i]);
      			}
      			printf("\n");
      		}
      		else
      		{
      			printf("%d\n", t);
      			break;
      		}
      	}
      
      }
      • 3:JNI中基本類型的處理
        ??完成這個(gè)作業(yè)之前我只是知道有JNI這個(gè)知識(shí)點(diǎn),但是確實(shí)沒有系統(tǒng)的學(xué)習(xí)過。但是我就自己學(xué)的一點(diǎn)點(diǎn)東西可以總結(jié)一下。java里面的基礎(chǔ)類型可以放到C/C++里面使用但是像數(shù)組之類的數(shù)據(jù)類型,必須有Java認(rèn)同的類型稍作處理,才可以在C/C++的環(huán)境里面運(yùn)行。具體請(qǐng)參考:參考博客這片博客好像是sun官網(wǎng)的中翻,值得參考。

      • 4:成功的DLL源代碼:

      #include "pch.h"
      #include "comm.h"
      #include <iostream>
      #include <stdlib.h>
      #include <windows.h>
      using std::string;
      /////////////////////////////////////////////////////////////////////////
      //
      JNIEXPORT jint JNICALL Java_Com_Comm(JNIEnv* env, jobject, jint nBaud, jint parity, jint bytesize, jint stopbits, jint accdatalength,jstring comName, jbyteArray rBuf)
      {	DWORD rSize = 0;
      	DWORD dwError;										//清除錯(cuò)誤
      	COMSTAT cs;
      	COMMTIMEOUTS timeouts;								//超時(shí)數(shù)據(jù)結(jié)構(gòu)
      	DCB dcb;											//串口通信配置文件---用LPDCB類型會(huì)報(bào)錯(cuò)
      	HANDLE hCom;										//串口的句柄(實(shí)例)| the instance of com
      	BYTE rBuffer[255];
      //////////////////////////////////////////////////////////////////////
      //將jstring轉(zhuǎn)換為LPCWSTR類型
      //////////////////////////////////////////////////////////////////////
      	WCHAR* buffer = (WCHAR*)env->GetStringChars(comName,NULL);
      	hCom = CreateFile(buffer,							//串口的名字
      		GENERIC_READ | GENERIC_WRITE,    //串口打開方式
      		0,								//共享方式					
      		NULL,							//安全屬性
      		OPEN_EXISTING,					//指定文件的動(dòng)作
      		0,								//文件屬性---不指定就默認(rèn)為同步IO
      		NULL								//指向模板文件的句柄
      	);
      	if (hCom == INVALID_HANDLE_VALUE)
      	{
      		return -1;
      	}
      	///////////////////////////////////////
      	//同步IO需要設(shè)置讀數(shù)據(jù)超時(shí)
      	//////////////////////////////////////
      	if (!(GetCommTimeouts(hCom, &timeouts)))		//獲的COMMTIMEOUTS結(jié)構(gòu)失??!
      	{
      		CloseHandle(hCom);
      	}
      	timeouts.ReadIntervalTimeout = 1000;			//讀取每個(gè)字符之間的超時(shí)
      	timeouts.ReadTotalTimeoutMultiplier = 500;		//讀取一個(gè)字符的超時(shí)
      	timeouts.ReadTotalTimeoutConstant = 5000;			//固定總超時(shí)
      	timeouts.WriteTotalTimeoutConstant = 0;			//寫入字符之間超時(shí)
      	timeouts.WriteTotalTimeoutMultiplier = 0;		//寫入字符總超時(shí)
      	if (!(SetCommTimeouts(hCom, &timeouts)))			//設(shè)置COMMTIMEOUTS結(jié)構(gòu)失敗
      	{
      		CloseHandle(hCom);
      	}
      	////////////////////////////////////////
      	//設(shè)置緩沖區(qū)大小
      	///////////////////////////////////////
      	if (!SetupComm(hCom, 500, 500))				//設(shè)置讀寫緩沖區(qū)失敗
      	{
      		CloseHandle(hCom);
      	}
      	//////////////////////////////////////
      	//設(shè)置波特率等其它讀文件配置
      	/////////////////////////////////////
      	if (GetCommState(hCom, &dcb) == 0)			//獲得DCB數(shù)據(jù)失敗
      	{
      		CloseHandle(hCom);
      	}
      	//dcb.DCBlength = sizeof(DCB);
      	dcb.BaudRate = nBaud;					//波特率為4800
      	dcb.Parity = parity;					//校驗(yàn)方式為無校驗(yàn)
      	dcb.ByteSize = bytesize;						//數(shù)據(jù)位為8位
      	dcb.StopBits = stopbits;				//停止位為1位
      	if (!SetCommState(hCom, &dcb))			//設(shè)置串口通信配置項(xiàng)失敗
      	{
      		CloseHandle(hCom);
      	}
      
      	//////////////////////////////////////
      	//清除緩沖區(qū)
      	/////////////////////////////////////
      	PurgeComm(hCom, PURGE_RXCLEAR | PURGE_TXCLEAR);
      	///////////////////////////////////////
      	//清除錯(cuò)誤
      	///////////////////////////////////////
      	if (!(ClearCommError(hCom, &dwError, &cs)))
      	{
      		CloseHandle(hCom);
      	}
      	////////////////////////////////////////////
      	//開始讀取緩沖口的數(shù)據(jù)
      	///////////////////////////////////////////
      
      		//讀取串口數(shù)據(jù)
      	if (INVALID_HANDLE_VALUE != hCom)
      	{
      		ReadFile(hCom, &rBuffer, accdatalength, &rSize, NULL);
      		if (rSize)
      		{
      			jbyte* term;								//將RBuffer中的值賦給rBuf
      			term = env->GetByteArrayElements(rBuf,FALSE);
      			for (int i = 0; i < accdatalength; i++)
      			{
      				term[i] = rBuffer[i];
      			}
      			env->ReleaseByteArrayElements(rBuf,term, JNI_COMMIT);
      			CloseHandle(hCom);
      			return 1;
      
      		}
      	}
      	else
      	{
      		CloseHandle(hCom);
      		return 1;
      	}
      	env->ReleaseStringChars(comName,(jchar *)buffer);			//釋放空間
      	CloseHandle(hCom);
      	return 2;
      
      }

      注:代碼寫在自己新建的和頭文件同名的自己建立的源文件(.cpp)里面。

      4.3 配置

      在生成DLL文件之前,我們還必須做一些重要的配置。

      • 1:把java jdk里面的一些文件拷貝到DLL文件里面去。

      ??將框起來的三個(gè)頭文件復(fù)制到DLL源程序的文件里面。

      • 2:修改一下DLL項(xiàng)目的配置:

      右鍵項(xiàng)目 ---> 屬性--->VC++目錄--->包含目錄(把DLL程序所在的文件路徑添加進(jìn)去)

      最后,我們?cè)邳c(diǎn)擊生成。就OK啦。

      到此結(jié)束啦,希望可以幫助到你!

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多