0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java調(diào)用C/C++動(dòng)態(tài)庫(kù)dll操作串口實(shí)例

CHANBAEK ? 來(lái)源:嵌入式大本營(yíng) ? 作者:小小飛飛哥 ? 2023-05-23 15:41 ? 次閱讀

大家好,今天分享的是使用C/C++編寫(xiě)一個(gè)讀取串口數(shù)據(jù)的代碼,然后將其編譯成Windows下的動(dòng)態(tài)鏈接庫(kù)(.dll文件),然后寫(xiě)一個(gè)簡(jiǎn)單的java demo來(lái)調(diào)用C/C++接口

眾所周知,java開(kāi)發(fā)項(xiàng)目會(huì)比較方便,尤其是在一些大型項(xiàng)目中,java開(kāi)發(fā)效率會(huì)比較高,但是一些底層的東西和一些追求效率的東西,依然會(huì)傾向使用C/C++,這是他們不可替代的優(yōu)勢(shì)。所以有時(shí)會(huì)需要兩者混合起來(lái),C/C++完成一部分較底層的功能,提供接口給java調(diào)用。

由于本人主要是從事嵌入式相關(guān),對(duì)java也不是很熟,所以今天主要是把整個(gè)流程過(guò)一遍,把整個(gè)流程打通,搞清楚如何制作動(dòng)態(tài)庫(kù),如何被java調(diào)用即可。關(guān)于動(dòng)態(tài)庫(kù)的內(nèi)容,還可以參考我之前的文章。

還有就是今天所有的操作都是在命令行中完成,不會(huì)使用任何IDE ,這也符合我們嵌入式開(kāi)發(fā)的習(xí)慣,能用命令行就沒(méi)必要去安裝臃腫的IDE軟件,所以大家需要先在自己的DOS窗口中安裝好必要的工具,g++用于編譯c++代碼,安裝java的jdk以提供java環(huán)境,另外把nmake路徑添加到環(huán)境變量中就可以使用Makefile了。

一、編寫(xiě)cpp功能函數(shù)

這一部分就是具體的功能實(shí)現(xiàn),比如在本次中,我們需要讀取串口數(shù)據(jù),那么至少涉及四個(gè)接口:打開(kāi)串口,設(shè)置波特率等參數(shù),讀取數(shù)據(jù),關(guān)閉串口。我們需要使用c++代碼把這四個(gè)接口的具體實(shí)現(xiàn)寫(xiě)出來(lái),新建一個(gè)文件夾,用于存放文件,在里面新建一個(gè)dllApi.cpp和dllApi.h文件。

dllApi.h:

#ifndef DLLAPI_H
#define DLLAPI_H
#include 
#include 
#include 
#include 
using namespace std;
class ComHelper  {
public:
    // bool Open(void);      //打開(kāi)串口
    void DLL_API_Set(int baud);    //設(shè)置串口信息
    char* DLL_API_Read(char str[],int length);
    bool DLL_API_Close(void);
    bool DLL_API_OPEN(void);
};

dllApi.cpp:

#include "dllApi.h"
HANDLE  hCom ;
bool ComHelper::DLL_API_OPEN(void)
{
    int num;
    const char* com="COM";
    char buf[100]={0};
    cout<<"請(qǐng)輸入要打開(kāi)的串口號(hào),輸入1打開(kāi)COM1"<

這里面主要是涉及兩個(gè)很重要的函數(shù),CreateFile 和 ReadFile 函數(shù),這兩個(gè)函數(shù)是Windows下的API,可以直接調(diào)用,關(guān)于具體的函數(shù)功能及用法,這里暫時(shí)不討論,其實(shí)和linux下的驅(qū)動(dòng)是很類(lèi)似的。

二、編寫(xiě)一個(gè)java的demo

Java2cpp.java :

public class Java2cpp
{
static
{
System.loadLibrary("javaCallcpp");
}


public native boolean DLL_OPEN();
public native void DLL_Set(int baud);    //設(shè)置串口信息
public native String DLL_Read(char str[],int length);
public native boolean DLL_Close();


public static void main(String args[])
{


    System.out.println("code test....");
    boolean ret;
    char buf[]={0};
    String str;
    Java2cpp com = new Java2cpp();
    ret=com.DLL_OPEN();
    if(!ret)
    {
        System.out.println("打開(kāi)串口失敗");
        return;
    }
    System.out.println("打開(kāi)串口成功");
    com.DLL_Set(115200);
    while(true)
    {
        str=com.DLL_Read(buf, 100);
        System.out.println(str);
    }
}
}

這里主要注意兩個(gè)點(diǎn),一個(gè)是使用System.loadLibrary( "javaCallcpp" );導(dǎo)入了一個(gè)庫(kù),這個(gè)庫(kù)的名字是javaCallcpp 也就是說(shuō)待會(huì)兒我們要生成一個(gè)javaCallcpp.dll的文件。第二點(diǎn)是public native boolean DLL_OPEN ();等幾個(gè)API。

使用native關(guān)鍵字說(shuō)明這個(gè)方法是原生函數(shù),也就是這個(gè)方法是用C/C++語(yǔ)言實(shí)現(xiàn)的,并且被編譯成了DLL,由java去調(diào)用。使用native關(guān)鍵字說(shuō)明這個(gè)方法是原生函數(shù),也就是這個(gè)方法是用C/C++語(yǔ)言實(shí)現(xiàn)的,并且被編譯成了DLL,由java去調(diào)用。這些函數(shù)的實(shí)現(xiàn)體在DLL中,JDK的源代碼中并不包含,你應(yīng)該是看不到的。對(duì)于不同的平臺(tái)它們也是不同的。這也是java的底層機(jī)制,實(shí)際上java就是在不同的平臺(tái)上調(diào)用不同的native方法實(shí)現(xiàn)對(duì)操作系統(tǒng)的訪問(wèn)的。

這個(gè)時(shí)候還沒(méi)有dll文件,因此有了第三步:

三、生成dll文件

首先進(jìn)入到文件目錄,在命令行中使用

javac -h ./ Java2cpp.java

命令生成Java2cpp.h文件,這個(gè)頭文件是不可修改的,大概長(zhǎng)這樣

圖片

接下來(lái)新建一個(gè)Java2cpp.cpp文件,在這個(gè)文件中調(diào)用第一步中實(shí)現(xiàn)的接口

Java2cpp.cpp :

#include "Java2cpp.h"
#include "dllApi.h"
JNIEXPORT jboolean JNICALL Java_Java2cpp_DLL_1OPEN
  (JNIEnv *, jobject)
{
    ComHelper com;
    bool var=0;
    var=com.DLL_API_OPEN();
    return var;
}


JNIEXPORT void JNICALL Java_Java2cpp_DLL_1Set
  (JNIEnv *, jobject, jint baud)
{
    ComHelper com;
    com.DLL_API_Set(115200);
    return;
}


JNIEXPORT jstring JNICALL Java_Java2cpp_DLL_1Read
  (JNIEnv * env, jobject, jcharArray ay, jint)
{
    char array[1024];
    char* buf=array;
    int len=strlen(buf);

    jstring ret;
    ComHelper com;
    com.DLL_API_Read(array,100);


    //將char[] 轉(zhuǎn)化為jstring
    //定義java String類(lèi) strClass
     jclass strClass = (env)->FindClass("Ljava/lang/String;");
     //獲取java String類(lèi)方法String(byte[],String)的構(gòu)造器,用于將本地byte[]數(shù)組轉(zhuǎn)換為一個(gè)新String
    jmethodID ctorID = (env)->GetMethodID(strClass, ", "([BLjava/lang/String;)V");
    //建立byte數(shù)組
    jbyteArray bytes = (env)->NewByteArray((jsize)strlen(buf));
    //將char* 轉(zhuǎn)換為byte數(shù)組
    (env)->SetByteArrayRegion(bytes, 0, (jsize)strlen(buf), (jbyte*)buf);
    //設(shè)置String, 保存語(yǔ)言類(lèi)型,用于byte數(shù)組轉(zhuǎn)換至String時(shí)的參數(shù)
    jstring encoding = (env)->NewStringUTF("gbk"); 
    //將byte數(shù)組轉(zhuǎn)換為java String,并輸出
    ret= (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding);
    return ret;
}


JNIEXPORT jboolean JNICALL Java_Java2cpp_DLL_1Close
  (JNIEnv *, jobject)
{
    bool ret;
    ComHelper com;
    ret=com.DLL_API_Close();
    return ret;
}

實(shí)際上你也可以直接在這里實(shí)現(xiàn)具體的功能代碼,這樣就省掉第一步了,不過(guò)為了一個(gè)分層的思想,更方便維護(hù),還是不要省掉第一步比較好。

在這個(gè)文件中,使用#include "dllApi.h" 來(lái)調(diào)用第一步中的接口,然后這個(gè)文件是被java程序調(diào)用的,這里要稍微注意一下數(shù)據(jù)類(lèi)型的轉(zhuǎn)化。 比如char[] 轉(zhuǎn)化為jstring。

然后在命令行中將前面的dllApi.cpp 和這個(gè)Java2cpp.cpp同時(shí)編譯成dll文件。

g++ -shared -fPIC Java2cpp.cpp dllApi.cpp -o javaCallcpp.dll -I "F:\\Program Files\\Java\\jdk-11.0.12\\include"  -I "F:\\Program Files\\Java\\jdk-11.0.12\\include\\win32"

圖片

這樣在目錄中就出現(xiàn)了javaCallcpp.dll文件。

圖片

四、編譯并運(yùn)行java程序

在命令行中輸入

javac Java2cpp.java

生成Java2cpp.class文件,.class文件就是java編譯后的可執(zhí)行文件

最后在命令行中輸入

java Java2cpp  //注意沒(méi)有.class后綴

就可以運(yùn)行java程序了。

圖片

這樣就成功實(shí)現(xiàn)了java調(diào)用dll庫(kù),我們也可以將上面那些命令寫(xiě)成Makefile文件,和linux下的Makefile是一樣的,只不過(guò)在Windows下不是make命令,而是nmake,使用時(shí)需要將nmake的路徑添加到系統(tǒng)環(huán)境變量中。

圖片

圖片

總結(jié):

1、編寫(xiě)cpp具體的功能接口代碼

2、編寫(xiě)java程序,使用native關(guān)鍵字聲明調(diào)用本地接口

3、javac -h (在舊版本中直接使用javah)生成頭文件,根據(jù)頭文件編寫(xiě)對(duì)應(yīng)cpp源文件

4、使用g++ 編譯生成.dll文件

5、使用javac xxx.java生成xxx.class文件并執(zhí)行

當(dāng)然如果不習(xí)慣使用命令行,也可以結(jié)合Visual Studio 和 Eclipse 兩個(gè)IDE進(jìn)行操作,在這里不做闡述。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • WINDOWS
    +關(guān)注

    關(guān)注

    3

    文章

    3521

    瀏覽量

    88317
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2952

    瀏覽量

    104477
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1540

    瀏覽量

    76059
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2100

    瀏覽量

    73453
  • 動(dòng)態(tài)庫(kù)

    關(guān)注

    0

    文章

    16

    瀏覽量

    6216
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Qt創(chuàng)建動(dòng)態(tài)庫(kù)C#調(diào)用,通過(guò)回調(diào)完成交互

    動(dòng)態(tài)庫(kù)(dll),給C#加載調(diào)用,并且還需要設(shè)置回調(diào),方便C#知道Qt運(yùn)行時(shí),輸出內(nèi)部的一些實(shí)時(shí)
    的頭像 發(fā)表于 09-09 11:37 ?4471次閱讀
    Qt創(chuàng)建<b class='flag-5'>動(dòng)態(tài)</b><b class='flag-5'>庫(kù)</b>給<b class='flag-5'>C</b>#<b class='flag-5'>調(diào)用</b>,通過(guò)回調(diào)完成交互

    C/ C++/ Java 程序設(shè)計(jì)經(jīng)典教程》

    C語(yǔ)言的標(biāo)準(zhǔn)庫(kù) 1.9 重要的軟件發(fā)展趨勢(shì):面向?qū)ο蟮募夹g(shù) 1.10 C++語(yǔ)言以及C++編程 1.11 Java語(yǔ)言以及
    發(fā)表于 11-13 11:22

    JAVAC++區(qū)別

    指針來(lái)直接訪問(wèn)內(nèi)存無(wú)指針,并且增添了自動(dòng)的內(nèi)存管理功能,從而有效地防止了cc++語(yǔ)言中指針操作失誤,如野指針?biāo)斐傻南到y(tǒng)崩潰。但也不是說(shuō)JAVA沒(méi)有指針,虛擬機(jī)內(nèi)部還是使用了指針,只
    發(fā)表于 04-11 15:19

    LabVIEW調(diào)用visual studio C#生成的動(dòng)態(tài)鏈接庫(kù)dll文件

    1)visual studio C#生成動(dòng)態(tài)鏈接庫(kù)dll文件2)LabVIEW通過(guò)構(gòu)造器調(diào)用C#
    發(fā)表于 07-23 23:18

    JAVAC++區(qū)別

    來(lái)直接訪問(wèn)內(nèi)存無(wú)指針,并且增添了自動(dòng)的內(nèi)存管理功能,從而有效地防止了cc++語(yǔ)言中指針操作失誤,如野指針?biāo)斐傻南到y(tǒng)崩潰。但也不是說(shuō)JAVA沒(méi)有指針,虛擬機(jī)內(nèi)部還是使用了指針,只是外
    發(fā)表于 10-10 14:50

    請(qǐng)問(wèn)各位labview大佬關(guān)于調(diào)用dll動(dòng)態(tài)鏈接庫(kù)的問(wèn)題

    我最近學(xué)習(xí)labview的dll動(dòng)態(tài)庫(kù)調(diào)用,我用的vs2017來(lái)編譯c++并生成dll文件,但是
    發(fā)表于 03-10 18:43

    JavaC++的區(qū)別

    來(lái)直接訪問(wèn)內(nèi)存無(wú)指針,并且增添了自動(dòng)的內(nèi)存管理功能,從而有效地防止了cc++語(yǔ)言中指針操作失誤,如野指針?biāo)斐傻南到y(tǒng)崩潰。但也不是說(shuō)JAVA沒(méi)有指針,虛擬機(jī)內(nèi)部還是使用了指針,只是外
    發(fā)表于 09-13 16:02

    labview 動(dòng)態(tài)調(diào)用 C# 生成的dll

    目的: 用labview動(dòng)態(tài)調(diào)用C#生成的dll問(wèn)題:目前知道可以用.net的構(gòu)造器調(diào)用,但是該方式不像“
    發(fā)表于 01-04 15:47

    Tcl/Tk命令與C/C++的集成研究

    針對(duì) Tcl/Tk 腳本中需要調(diào)用C/C++函數(shù)的問(wèn)題,簡(jiǎn)要說(shuō)明了Tcl/Tk 命令的運(yùn)行機(jī)理,給出了一個(gè)使用Tcl/Tk 命令來(lái)調(diào)用C/
    發(fā)表于 08-26 09:47 ?36次下載

    C++動(dòng)態(tài)鏈接庫(kù)的創(chuàng)建和調(diào)用

    動(dòng)態(tài)連接庫(kù)的創(chuàng)建步驟: 一、創(chuàng)建Non-MFC DLL動(dòng)態(tài)鏈接庫(kù) 1、打開(kāi)File —> New —> Project選項(xiàng),選擇Win3
    發(fā)表于 11-24 18:13 ?7次下載

    什么是DLL (動(dòng)態(tài)連接庫(kù))

    什么是DLL (動(dòng)態(tài)連接庫(kù)) DLL動(dòng)態(tài)連接庫(kù)),既然是
    發(fā)表于 11-28 14:51 ?1.5w次閱讀

    C語(yǔ)言與C++相互調(diào)用

    ? ? 1CC++相互調(diào)用 在一個(gè)嵌入式系統(tǒng)中大部分的底層和驅(qū)動(dòng)層更多的是采用C語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā),而上層應(yīng)用、服務(wù)更多的采用C++等高級(jí)語(yǔ)言
    的頭像 發(fā)表于 01-18 11:05 ?3267次閱讀
    <b class='flag-5'>C</b>語(yǔ)言與<b class='flag-5'>C++</b>相互<b class='flag-5'>調(diào)用</b>

    LABVIEW調(diào)用C# DLL實(shí)例分享

    LABVIEW調(diào)用C# DLL實(shí)例分享
    發(fā)表于 01-04 11:20 ?105次下載

    java上位機(jī)開(kāi)發(fā)(c庫(kù)調(diào)用)

    所有的動(dòng)態(tài)語(yǔ)言,包括在java在內(nèi),一般都會(huì)提供一個(gè)調(diào)用c庫(kù)的方法。java語(yǔ)言的出現(xiàn)是在上個(gè)世
    發(fā)表于 05-09 10:00 ?0次下載
    <b class='flag-5'>java</b>上位機(jī)開(kāi)發(fā)(<b class='flag-5'>c</b><b class='flag-5'>庫(kù)</b><b class='flag-5'>調(diào)用</b>)

    CC++編寫(xiě)環(huán)境下LabVIEW如何調(diào)用動(dòng)態(tài)庫(kù)?

    C語(yǔ)言編寫(xiě)的動(dòng)態(tài)鏈接庫(kù)相比,不同的地方在于extern int “C” __declspec(dllexport) add(int x,int y) 這一導(dǎo)出語(yǔ)句,在
    發(fā)表于 06-11 09:15 ?7402次閱讀
    <b class='flag-5'>C</b>和<b class='flag-5'>C++</b>編寫(xiě)環(huán)境下LabVIEW如何<b class='flag-5'>調(diào)用</b><b class='flag-5'>動(dòng)態(tài)</b><b class='flag-5'>庫(kù)</b>?