在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

OpenHarmony源碼剖析之ACE(JavaScript運行環境初始化)

OpenAtom OpenHarmony ? 來源:51CTO ? 作者:張亮亮 ? 2021-11-18 10:40 ? 次閱讀

張亮亮

深圳開鴻數字產業發展有限公司

簡介

JS UI 框架引擎ACE全稱 Ability Cross-platform Environment,是 OpenHarmony 標準系統上的UI框架。ACE:結合了 OpenHarmony 系統的基礎組件 Ability,開源 jsframework 框架,開源 js 引擎 quickjs,開源跨平臺 UI 框架 flutter,開源渲染引擎 skia 以及各種平臺能力 API 等共同構筑了 OpenHarmony 標準系統 javacript 應用開發的基礎。

1.1 OpenHarmony 架構圖

9b9230c6-47d2-11ec-b939-dac502259ad0.png

1.2 ACE UI框架引擎圖

9cadf030-47d2-11ec-b939-dac502259ad0.png

1.3 ACE 主要構成

1. JavaScript前端框架

目前 OpenHarmony 標準系統采用主流的類 Web 范式,對開源的 Weex 框架中的 jsframework 做定制化,采用 ts 開發,主要包括編程模型 MVVM、組件、API、頁面路由以及事件處理。

2. JavaScript引擎

目前 OpenHarmony 標準系統使用的是開源 quickjs 引擎,提供 JS 語言運行時和執行上下文,提供 js 的解析和 jsframework 的加載。

3. 中間轉換層

中間轉換層也就是 JS 橋接層,實現前端開發框架到 UI 后端引擎和 JS 引擎的對接。

4. 聲明式UI后端引擎

C++構建的UI后端引擎,包括 UI 組件、布局視圖、動畫事件、自繪制選軟管線。

5. 渲染引擎

目前 OpenHarmony 標準系統復用了開源跨平臺 UI 框架 flutter 引擎提供基礎的圖形渲染能力。

6. 平臺適配層

目前 OpenHarmony 標準系統的適配層完成了 OpenHarmony 平臺和 IDE 的 previewer 的適配,將平臺依賴聚焦到平臺相關的畫布、通用線程以及事件處理機制等少數接口上,為跨平臺提供相應的基礎設施,實現跨平臺一致化的 UI 渲染。

7. 能力擴展層

為擴展 ACE 能力提供的插件機制,平臺其他子系統可以利用插件機制開發相關能力的 js 接口,為應用層提供相應的能力支持。通過 napi 提供引擎無關的插件實現機制,保證接口的 ABI 兼容性。

基礎知識

2.1 代碼結構
/foundation/ace/ace_engine├── adapter                       # 平臺適配目錄│   ├── common|   ├── ohos                      # ohos平臺適配目錄│   └── preview                   # IDE preview平臺適配目錄├── frameworks                    # 框架代碼│   ├── base                      # 基礎庫│   ├── bridge                    # 前后端對接層│   └── core                      # 聲明式UI后端引擎目錄/third_party/jsframework          # JavaScript前端框架/third_party/quickjs              # JavaScript引擎/third_party/flutter#flutterengine提供跨平臺自渲染引擎

2.2 ACE框架類圖

9ce025a0-47d2-11ec-b939-dac502259ad0.png

(點擊圖片查看高清大圖) 2.3 線程模型

ACE JS 應用啟動時會創建一系列線程,形成獨立的線程模型,以實現高性能的渲染流程。

Platform線程:當前平臺的主線程,也就是應用的主線程,主要負責平臺層的交互、應用生命周期以及窗口環境的創建。

JS線程:JS 前端框架的執行線程,應用的 JS 邏輯以及應用 UI 界面的解析構建都在該線程執行。

UI線程:引擎的核心線程,組件樹的構建以及整個渲染管線的核心邏輯都在該線程:包括渲染樹的構建、布局、繪制以及動畫調度。

GPU線程:現代的渲染引擎,為了充分發揮硬件性能,都支持 GPU 硬件加速,在該線程上,會通過系統的窗口句柄,創建 GPU 加速的 OpenGL 環境,負責將整個渲染樹的內容光柵化,直接將每一幀的內容渲染合成到該窗口的 Surface 上并送顯。

IO線程:主要為了異步的文件 IO 讀寫,同時該線程會創建一個離屏的 GL 環境,這個環境和 GPU 線程的 GL 環境是同一個共享組,可以共享資源,圖片資源解碼的內容可直接在該線程上傳生成 GPU 紋理,實現更高效的圖片渲染。

Javascript運行環境初始化

3.1 時序圖

9d28c008-47d2-11ec-b939-dac502259ad0.png

(點擊圖片查看高清大圖)

3.2 源碼解析

1.OnStart()

  • AceAbility繼承自Ability,當應用啟動時首先應用程序框架會調用AceAbility的生命周期函數OnStart();

  • 通過Ability的api獲取Hap包的路徑,通過讀取配置文件manifest.json獲取應用程序配置的前端的類型;

  • 當前我們只關注JS前端,目前支持的前端類型包括enum class FrontendType { JSON, JS, JS_CARD, DECLARATIVE_JS };

  • 根據前端類型調用ACE核心聚合類AceContainer的靜態方法CreateContainer,這個類是ACE框架平臺適配層的核心類,接下來的前端核心類和JS引擎的創建都是在其中完成的。

//foundationaceace_engineadapterpreviewentranceace_ability.cppvoid AceAbility::OnStart(const Want& want){    ...        //獲取打包的js bundle文件,取出配置文件,獲取前端類型    auto packagePathStr = GetBundleCodePath();    auto moduleInfo = GetHapModuleInfo();    if (moduleInfo != nullptr) {        packagePathStr += "/" + moduleInfo->name + "/";    }    FrontendType frontendType = GetFrontendTypeFromManifest(packagePathStr);
    // create container    //創建AceContainer:內部初始化時創建了js線程,load了js engine,創建了JsFrontend    Platform::CreateContainer(        abilityId_, frontendType, this,        std::make_unique([this]() {            TerminateAbility();        }));    ...    ...
    //運行page    Platform::RunPage(        abilityId_, Platform::GetContainer(abilityId_)->GeneratePageId(),        parsedPageUrl, want.GetStringParam(START_PARAMS_KEY));
    ...}
2. CreateContainer
  • 在AceContainer::CreateContainer中,首先創建了AceContainer對象;

  • 在構造函數中創建了FlutterTaskerExecutor對象用于多線程的任務管理;

  • 此處主要關注JS線程的創建和初始化,在InitJsThread()中創建了JS線程并獲取保存了jsRunner_用于JS任務的派發;

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::CreateContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback){    auto aceContainer = AceType::MakeRefPtr(instanceId, type, aceAbility, std::move(callback));    AceEngine::Get().AddContainer(instanceId, aceContainer);    auto front = aceContainer->GetFrontend();    if (front) {        front->UpdateState(Frontend::ON_CREATE);        front->SetJsMessageDispatcher(aceContainer);    }}
AceContainer::AceContainer(int32_t instanceId, FrontendType type, AceAbility* aceAbility,    std::unique_ptr callback) : instanceId_(instanceId), type_(type), aceAbility_(aceAbility){    ACE_DCHECK(callback);    //創建和初始化FlutterTaskerExecutor用于封裝管理Flutter ACE中涉及的多個線程:platform,UI,JS,GPU,IO,統一post任務到各線程執行    auto flutterTaskExecutor = Referenced::MakeRefPtr();    //初始化platform線程,將flutter platform線程的TaskerRunner適配到ohos平臺主線程的EventRunner    flutterTaskExecutor->InitPlatformThread();    //初始化JS線程,這個線程用于解析JS,不歸flutter管理,因此是單獨在ACE里使用的    flutterTaskExecutor->InitJsThread();    //taskExector_封裝了所有線程任務調度的接口,因此會傳給Frontend用于JS前端解析任務和PipelineContext后端渲染UI和GPU IO相關    taskExecutor_ = flutterTaskExecutor;    if (type_ != FrontendType::DECLARATIVE_JS) {        //zll:初始化前端        InitializeFrontend();    }
    platformEventCallback_ = std::move(callback);}
void FlutterTaskExecutor::InitJsThread(bool newThread){    //創建并初始化JS線程,獲取保存js線程的TaskRunner    //JS線程是ACE平臺特有,不通過flutter創建管理    if (newThread) {        jsThread_ = std::make_unique(GenJsThreadName());        jsRunner_ = jsThread_->GetTaskRunner();    } else {        jsRunner_ = uiRunner_;    }}

3. JsFrontend

  • 完成JS線程的初始化后,如果前端類型不是DECLARATIVE_JS,會調用InitializeFrontend()對前端進行初始化。

  • 首先創建前端對象,Frontend::Create定義在js_frontend.cpp中,創建的是JsFrontend實例;

  • 然后通過JsEngineLoader::Get()動態加載QjsEngineLoader;

  • 再通過QjsEngineLoader創建QjsEngine并設置給JsFrontend;最后對JsFrontend對象做初始化;

  • JsFrontend是ACE框架從后端進入前端的唯一入口,AceAbility、AceContainer和JsFrontend是一一對應的關系;

//foundationaceace_engineadapterpreviewentranceace_container.cppvoid AceContainer::InitializeFrontend(){    if (type_ == FrontendType::JS) {        //目前Frontend::Create定義在js_frontend.cpp中,創建的是JsFrontend實例        frontend_ = Frontend::Create();        auto jsFrontend = AceType::DynamicCast(frontend_);        //創建并初始化js engine,此處是通過dlopen加載的qjs engine管理對象        jsFrontend->SetJsEngine(Framework::Get().CreateJsEngine(instanceId_));        ...    } else if (type_ == FrontendType::DECLARATIVE_JS) {        ...    } else {        ...    }    ACE_DCHECK(frontend_);    //初始化前端和js engine    frontend_->Initialize(type_, taskExecutor_);}
4. QjsEngine
  • 接下來我們繼續分析一下JS引擎管理對象的創建;

  • 首先通過dlopen動態加載libace_engine_qjs.z.so通過入口函數創建獲取QjsEngineLoader單例對象;

  • 然后通過QjsEngineLoader::CreateJsEngine()創建QjsEngine;

//foundationaceace_engineframeworksridgejs_frontendenginecommonjs_engine_loader.cpp//"libace_engine_qjs.z.so"動態庫的入口,在qjs_engine_loader.cpp中定義constexpr char JS_ENGINE_ENTRY[] = "OHOS_ACE_GetJsEngineLoader";constexpr char QUICK_JS_ENGINE_SHARED_LIB[] = "libace_engine_qjs.z.so";...const char* GetSharedLibrary(){    return QUICK_JS_ENGINE_SHARED_LIB;}JsEngineLoader& GetJsEngineLoader(const char* sharedLibrary){    void* handle = dlopen(sharedLibrary, RTLD_LAZY);    ...    //    auto loader = reinterpret_cast(entry());    ...
    return *loader;}...//通過加載動態鏈接庫的形式獲取qjs橋接模塊的入口函數并創建QjsEngineLoaderJsEngineLoader& JsEngineLoader::Get(){    static JsEngineLoader& instance = GetJsEngineLoader(GetSharedLibrary());    return instance;}
//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine_loader.cppRefPtr QjsEngineLoader::CreateJsEngine(int32_t instanceId) const{    return AceType::MakeRefPtr(instanceId);}
5. JS線程
  • 在完成了QjsEngine的創建并設置給JsFrontend后,調用JsFrontend::Initialize();

  • 這里主要完成了FrontendDelegateImpl對象的創建和初始化將對JS引擎的相關操作委派給這個對象;

  • 以及Post JS引擎初始化的任務到JS線程的TaskRunner的message queue;

//foundationaceace_engineframeworksridgejs_frontendjs_frontend.cppbool JsFrontend::Initialize(FrontendType type, const RefPtr& taskExecutor){    LOGI("JsFrontend initialize begin.");    type_ = type;    ACE_DCHECK(type_ == FrontendType::JS);    //創建并初始化FrontendDelegate對象,具體實現為FrontendDelegateImpl    InitializeFrontendDelegate(taskExecutor);    //在JS線程初始化js engine,真正的啟動JS引擎運行時并創建上下文    taskExecutor->PostTask(        [weakEngine = WeakPtr(jsEngine_), delegate = delegate_] {            auto jsEngine = weakEngine.Upgrade();            if (!jsEngine) {                return;            }            jsEngine->Initialize(delegate);        },        TaskExecutor::JS);
    LOGI("JsFrontend initialize end.");    return true;}
6. jsframework
  • 在JS線程執行QjsEngine對象的初始化,初始化JS運行環境;

  • 初始化JS引擎運行時上下文和初始化JavaScript框架層jsframework;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppbool QjsEngine::Initialize(const RefPtr& delegate){    ACE_SCOPED_TRACE("QjsEngine::Initialize");    LOGI("Initialize");
    JSRuntime* runtime = nullptr;    JSContext* context = nullptr;
    // put JS_NewContext as early as possible to make stack_top in context    // closer to the top stack frame pointer of JS thread.    runtime = JS_NewRuntime();    if (runtime != nullptr) {        context = JS_NewContext(runtime);    }
    ...
    engineInstance_ = AceType::MakeRefPtr(delegate, instanceId_);    return engineInstance_->InitJsEnv(runtime, context);}
bool QjsEngineInstance::InitJsEnv(JSRuntime* runtime, JSContext* context){    ...    context_ = context;    //1.初始化js運行時,上下文    if (!InitJsContext(context_, MAX_STACK_SIZE, instanceId_, this)) {        LOGE("Qjs cannot allocate JS context");        EventReport::JS_ENGINE_INIT_ERR);        JS_FreeRuntime(runtime_);        return false;    }    ...    //2.加載JS Framework,初始化JS前端框架    //加載jsframework,js_framework和js_framework_size是quickjs編譯器編譯jsframework的ts生成的c文件    //quickjs通過JS_ReadObject讀取生成的cbytecode,并通過JS_EvalFunction(ctx, obj)執行相應的函數    //在這里最終調用的函數是jsframework/runtime/preparation/index.ts中的initFramework()函數    JSValue retVal = LoadJsFramework(GetQjsContext(), js_framework, js_framework_size, instanceId_);    bool result = JS_IsException(retVal) ? false : true;    if (context) {        JS_FreeValue(context, retVal);    }    ...
    return result;}
7. ACE模塊
  • 初始化JS引擎運行時上下文是在InitJsContext完成;

  • 其中初始化Ace模塊并將模塊導入JS運行時上下文中,為jsframework框架層提供了ACE功能相關的接口;

  • jsframework可以通過調用ACE模塊的接口完成Page上Dom元素到后端聲明式UI元素節點的創建;

  • 同時往JS運行時上下文全局對象掛載了日志打印的函數用于對接平臺日志打印功能;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cpp//ace模塊向js context暴露的函數,(js函數名,參數個數,對應的C函數)const JSCFunctionListEntry JS_ACE_FUNCS[] = {    JS_CFUNC_DEF_CPP("domCreateBody", 5, JsDomCreateBody),    JS_CFUNC_DEF_CPP("domAddElement", 9, JsDomAddElement),    JS_CFUNC_DEF_CPP("updateElementAttrs", 3, JsUpdateElementAttrs),    JS_CFUNC_DEF_CPP("updateElementStyles", 3, JsUpdateElementStyles),    JS_CFUNC_DEF_CPP("onCreateFinish", 0, JsOnCreateFinish),    JS_CFUNC_DEF_CPP("onUpdateFinish", 0, JsOnUpdateFinish),    JS_CFUNC_DEF_CPP("removeElement", 2, JsRemoveElement),    JS_CFUNC_DEF_CPP("callNative", 1, JsCallNative),    JS_CFUNC_DEF_CPP("callComponent", 3, JsCallComponent),    JS_CFUNC_DEF_CPP("loadIntl", 0, JsLoadIntl),    JS_CFUNC_DEF_CPP("loadLocaleData", 0, JsLoadLocaleData),#ifdef ENABLE_JS_DEBUG    JS_CFUNC_DEF_CPP("compileAndRunBundle", 4, JsCompileAndRunBundle),#endif};...
bool InitJsContext(JSContext* ctx, size_t maxStackSize, int32_t instanceId, const QjsEngineInstance* qjsEngineInstance){    ...        //將ace模塊注入到上下文中,使得jsframework可以通過注冊的接口調用ace的相關功能    // Inject ace native functions module    InitAceModules(ctx);
    JSValue globalObj, perfUtil;    globalObj = JS_GetGlobalObject(ctx);    perfUtil = JS_NewObject(ctx);
    InitJsConsoleObject(ctx, globalObj);
    JS_SetPropertyStr(ctx, perfUtil, "printlog", JS_NewCFunction(ctx, JsPerfPrint, "printlog", 0));    JS_SetPropertyStr(ctx, perfUtil, "sleep", JS_NewCFunction(ctx, JsPerfSleep, "sleep", 1));    JS_SetPropertyStr(ctx, perfUtil, "begin", JS_NewCFunction(ctx, JsPerfBegin, "begin", 1));    JS_SetPropertyStr(ctx, perfUtil, "end", JS_NewCFunction(ctx, JsPerfEnd, "end", 1));    JS_SetPropertyStr(ctx, globalObj, "perfutil", perfUtil);
    ...
    JSValue hiView;    hiView = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, hiView, "report", JS_NewCFunction(ctx, JSHiViewReport, "report", 2));    JS_SetPropertyStr(ctx, globalObj, "hiView", hiView);
    JSValue i18nPluralRules;    i18nPluralRules = JS_NewObject(ctx);    JS_SetPropertyStr(ctx, i18nPluralRules, "select", JS_NewCFunction(ctx, JsPluralRulesFormat, "select", 1));    JS_SetPropertyStr(ctx, globalObj, "i18nPluralRules", i18nPluralRules);        //將ace模塊導入到cxt指定的js 上下文中    const char* str = "import * as ace from 'ace';
"                      "var global = globalThis;
"                      "global.ace = ace;
"#ifdef ENABLE_JS_DEBUG                      "global.compileAndRunBundle = ace.compileAndRunBundle;
"#endif                      "global.callNative = ace.callNative;
";
    if (JS_CALL_FAIL == CallEvalBuf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE, instanceId)) {        LOGW("Qjs created JS context but failed to init Ace modules!");    }
    JS_FreeValue(ctx, globalObj);    return true;}

8. 初始化完成

  • 完成JS運行時上下文初始化之后,緊接著加載初始化jsframework,為JS應用程序提供javascript應用框架;

  • 這個地方使用quickjs的運行bytecode的方法,在編譯時通過qjsc(quickjs編譯器)將jsframework編譯成c文件;

  • c文件的內容就是一個bytecode的組數和數組大小,指定了jsframework的入口函數;

  • 在這里對應jsframework/runtime/preparation/index.ts 中的initFramework()完成jsframework的初始化;

  • jsframework初始化完成的工作主要包括掛載到js運行時上下文全局對象上提供給native調用的jsframework函數,注冊到jsframework的ACE提供的模塊及其中的方法和jsframework提供的與native一一對應的組件及其方法;

//foundationaceace_engineframeworksridgejs_frontendenginequickjsqjs_engine.cppJSValue LoadJsFramework(JSContext* ctx, const uint8_t buf[], const uint32_t bufSize, int32_t instanceId){    ACE_SCOPED_TRACE("LoadJsFramework");
    LOGI("Qjs loading JS framework");    //等同于調用jsframework/runtime/preparation/index.ts 中的initFramework()    JSValue ret = CallReadObject(ctx, buf, bufSize, true, instanceId);    if (JS_IsException(ret)) {        LOGD("Qjs loading JSFramework failed!");        QjsUtils::JsStdDumpErrorAce(ctx, JsErrorType::LOAD_JS_FRAMEWORK_ERROR, instanceId);    }
    return ret;}
//third_partyjsframework
untimepreparationinit.tsexport function initFramework(): void {  for (const serviceName in i18n) {    service.register(serviceName, i18n[serviceName]);  }  for (const serviceName in dpi) {    service.register(serviceName, dpi[serviceName]);  }  //jsframework提供的可供Ace native在QjsEngine對象中調用的TS方法  const globalMethods: GlobalInterface = {    'createInstance': globalApi.createInstance,    'registerModules': globalApi.registerModules,    'appDestroy': globalApi.appDestroy,    'appError': globalApi.appError,    'destroyInstance': globalApi.destroyInstance,    'getRoot': globalApi.getRoot,    'callJS': globalApi.callJS  };  //注冊modules,這些modules是ACE module提供的,調用這些模塊的方法,會通過調用注冊到qjs_engine的ace模塊中的callNative方法  //會最終通過ace module的callNative調用到qjs_engine中的JsCallNative-->JsHandleModule-->然后調用對應的native方法  // registerModules and registerComponents  ModulesInfo.forEach(modules => {    globalMethods['registerModules'](modules);  });    //注冊components組件,對組件方法的調用,最終會通過ace module的callComponent調用到qjs_engine中的JsCallComponent  ComponentsInfo.forEach((name) => {    if (name && name.type && name.methods) {      NativeElementClassFactory.createNativeElementClass(        name.type,        name.methods      );    }  });  //全局方法,這些方法可以被Qjs engine通過JS_GetPropertyStr(ctx, globalObj, "methodNamge")獲取并調用,從而實現了從native到js的調用  for (const methodName in globalMethods) {    global[methodName] = (...args: any) => {      const res: any = globalMethods[methodName](...args);      if (res instanceof Error) {        Log.error(res.toString());      }      return res;    };  }}

總結

以上內容首先對 OpenHarmony 標準系統上 JS UI 框架引擎 ACE 的邏輯架構及相關模塊進行了簡單的介紹,給出了 ACE 架構中相關模塊涉及的部分類的類圖,結合本次重點分析的 Javascript 運行環境初始化的時序圖詳細分析了 Javascript 運行環境初始化的整個流程。

本文首發自:https://harmonyos.51cto.com/posts/7908
編輯:jq


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JS
    JS
    +關注

    關注

    0

    文章

    78

    瀏覽量

    18330
  • ui
    ui
    +關注

    關注

    0

    文章

    205

    瀏覽量

    21603
  • OpenHarmony
    +關注

    關注

    26

    文章

    3795

    瀏覽量

    17650

原文標題:OpenHarmony源碼解析之ACE(JavaScript運行環境初始化)

文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    使用PyQt5自動初始化OpenVINO?環境出現報錯怎么解決?

    編寫了一個程序以使用 PyQt5 自動初始化OpenVINO?環境:從 PyQt5 導入 QtWidgets 導入操作系統 #import時間 導入系統 如果__name__
    發表于 03-07 06:35

    STM32CubeMX用于STM32配置和初始化C代碼生成

    電子發燒友網站提供《STM32CubeMX用于STM32配置和初始化C代碼生成.pdf》資料免費下載
    發表于 02-26 17:32 ?655次下載

    EE-359:ADSP-CM40x啟動時間優化和器件初始化

    電子發燒友網站提供《EE-359:ADSP-CM40x啟動時間優化和器件初始化.pdf》資料免費下載
    發表于 01-13 16:33 ?0次下載
    EE-359:ADSP-CM40x啟動時間優化和器件<b class='flag-5'>初始化</b>

    EE-88:使用21xx編譯器在C中初始化變量

    電子發燒友網站提供《EE-88:使用21xx編譯器在C中初始化變量.pdf》資料免費下載
    發表于 01-13 15:54 ?0次下載
    EE-88:使用21xx編譯器在C中<b class='flag-5'>初始化</b>變量

    OMAP5912多媒體處理器初始化參考指南

    電子發燒友網站提供《OMAP5912多媒體處理器初始化參考指南.pdf》資料免費下載
    發表于 12-17 16:20 ?0次下載
    OMAP5912多媒體處理器<b class='flag-5'>初始化</b>參考指南

    STM32F407 MCU使用SD NAND?不斷電初始化失效解決方案

    STM32F407微控制器單元(MCU)與SD NAND的結合提供了強大的存儲解決方案。然而,不斷電初始化失效問題可能會導致系統穩定性和數據完整性受損。我們將STM32F407與SD NAND集成時可能遇到的初始化問題,并提供專業的解決方案。
    的頭像 發表于 12-11 10:51 ?691次閱讀
    STM32F407 MCU使用SD NAND?不斷電<b class='flag-5'>初始化</b>失效解決方案

    基于旋轉平移解耦框架的視覺慣性初始化方法

    精確和魯棒的初始化對于視覺慣性里程計(VIO)至關重要,因為不良的初始化會嚴重降低姿態精度。
    的頭像 發表于 11-01 10:16 ?727次閱讀
    基于旋轉平移解耦框架的視覺慣性<b class='flag-5'>初始化</b>方法

    TMS320C6000 McBSP初始化

    電子發燒友網站提供《TMS320C6000 McBSP初始化.pdf》資料免費下載
    發表于 10-26 10:10 ?0次下載
    TMS320C6000 McBSP<b class='flag-5'>初始化</b>

    ESP-BOX 智能藥盒源碼解析(續)

    藥盒基本概述請參考上一篇文章源碼解析主函數部分___main/main.c●初始化NVS:初始化非易失性存儲(NVS),如果需要擦除和重新初始化NVS,會進行相應處理。●檢查百度API
    的頭像 發表于 10-10 08:01 ?598次閱讀
    ESP-BOX 智能藥盒<b class='flag-5'>源碼</b>解析(續)

    Keil中變量不被初始化方法

    有些時候在我們的應用過程中要求變量有連續性,或者現場保留,例如Bootloader跳轉,某種原因的復位過程中我們有些關鍵變量不能被初始化,在不同的編譯環境下有不同的設置,本文就這個操作做總結,分別
    的頭像 發表于 08-30 11:47 ?1094次閱讀
    Keil中變量不被<b class='flag-5'>初始化</b>方法

    瀚海微SD NAND應用之SD協議存儲功能描述2 初始化命令

    初始化和識別過程: 總線激活后,主機啟動卡初始化和識別過程。 初始化過程從SD SEND OP COND (ACMD41)開始,通過設置其操作條件和OCR中的HCS位。HCS (Host
    的頭像 發表于 07-22 10:54 ?563次閱讀
    瀚海微SD NAND應用之SD協議存儲功能描述2 <b class='flag-5'>初始化</b>命令

    STM32H750在-40℃環境下程序在串口初始化階段跑飛了怎么處理?

    STM32H750,主頻設置為400MHz,常溫下可以正常工作,低溫-40℃時,程序在初始化階段跑飛,用仿真器連接進行調試,單步運行在串口初始化函數處報錯: Target
    發表于 07-04 06:35

    VSCode里ESP-IDF初始化報錯和亂碼怎么解決?

    在VSCode里配置了espidf的開發環境,測試前幾個官方example的時候都能正常運行。但是自從調試了cmake例程以后,打開vscode、espidf在初始化之后總會報錯(如下),并且跳轉到esp-idf的安裝界面。有時
    發表于 06-11 06:48

    初始化IO口為外部中斷線的時候,最先初始化的會被后初始化的覆蓋掉為什么?

    初始化IO口為外部中斷線的時候,比如GPIOA6與GPIOB6先后初始化為外部中斷,最先初始化的會被后初始化的覆蓋掉,不知道是為什么?
    發表于 05-14 08:26

    鴻蒙OpenHarmony【創建工程并獲取源碼

    在通過DevEco Device Tool創建OpenHarmony工程時,可自動下載相應版本的OpenHarmony源碼
    的頭像 發表于 04-19 21:40 ?532次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【創建工程并獲取<b class='flag-5'>源碼</b>】
    主站蜘蛛池模板: 五月天婷五月天综合网在线 | 国产精品电影一区 | www.色在线观看| 色吧在线观看 | 久久久久久人精品免费费看 | 色综合美国色农夫网 | 亚洲国产精品婷婷久久久久 | 男子扒开美女尿口做羞羞的事 | 亚洲国产成人精彩精品 | 日本aaaaa特黄毛片 | 在线成人精品国产区免费 | 一区二区三区在线免费 | 国产男女免费视频 | 日本一区二区高清免费不卡 | 免费在线观看一级毛片 | 小泽玛利亚厕所大喷水 | 日韩美女拍拍免费视频网站 | 国产无遮挡床戏视频免费 | 色综合欧美 | 97色在线视频 | 511韩国理论片在线观看 | 天天摸天天看天天爽 | 二级黄的全免费视频 | 国内精品久久久久影 | 91成人午夜性a一级毛片 | 操欧美女人 | 在线免费视频你懂的 | 久久骚 | 国产成人在线影院 | 日韩精品免费一级视频 | 一级毛片在播放免费 | 特级毛片视频在线 | 三级在线免费 | 毛片在线看免费版 | 黄色小网站在线观看 | 国产女乱淫真高清免费视频 | 美女视频很黄很暴黄是免费的 | 天天综合视频网 | 国产 日韩 欧美 高清 | 国产精品视频色拍拍 | 亚洲视频在线一区二区 |