C++ Primer Plus(四)

完整閱讀C++ Primer Plus 

  系統重新學習C++語言部分,記錄重要但易被忽略的,關鍵但易被遺忘的。

 

友元、異常和其他

  1、拋出異常類時,雖然catch的是一個引用,但是也會產生一次拷貝,因為當拋出異常的函數在棧解退的過程中會會調用異常類的析構函數,異常類將不復存在。

  2、如果有一個異常類層次結構,應該這樣排列catch塊:將捕獲位於層次結構最下面的異常類的catch語句放在最前面,將捕獲基類異常的catch語句放在最後面。拋出異常的順序要與catch塊相反。

  3、在catch語句中使用基類對象時,將捕獲所有的派生類對象,但派生類特性將被剝去,因此將使用虛方法的基類版本。

  4、 將dynamic_cast用於引用時,由於沒有與空指針對應的引用值,因此無法使用特殊的引用值來表示失敗,當請求不正確時,將引發bad_cast的異常。

  5、reinterpret_cast運算符並不支持所有的類型轉換,例如,可以將指針類型轉換為足以存儲指針的整數,但不能將指針轉換為更小的整型或浮點型。另一個限制是,不能將函數指針和數據指針互相轉換。

 

string類和標準模板庫

  6、使用new分配內存時,可以使用auto_ptrunique_ptrshared_ptr、但只有unique_ptr有使用new[]和delete[]的版本。

  7、在unique_ptr為右值時,可以將其賦值給shared_ptr,模板shared_ptr包含一個顯式構造函數,可以用於將右值unique_ptr轉換為shared_ptr。

  8、對於所有內置的算術運算符、關係運算符和邏輯運算符,STL都提供了等價的函數符(仿函數)。

  9、valarray模板類重載了許多運算符,可以直接參与大多數數值運算;slice類可用作數組索引,它接受三個值初始值:起始索引、索引數、跨距。

1 valarry<double> arr(10);
2 arr[slice(1,4,3)] = 10;

  slice(1,4,3)創建的對象表示選擇4個索引,這可以將arr的第1、4、7、10個元素都設置為10。

  10、迭代器類型

Input iterator(輸入迭代器)  讀,不能寫;只支持自增運算
Output iterator(輸出迭代器) 寫,不能讀;只支持自增運算
Forward iterator(前向迭代器) 讀和寫;只支持自增運算
Bidirectional iterator(雙向迭代器) 讀和寫;支持自增和自減運算
Random access iterator(隨機訪問迭代器) 讀和寫;支持完整的迭代器算術運算

 

輸入、輸出和文件

  11、對於標準錯誤輸出,是沒有緩衝區的。

  12、在使用cout時,可以使用成員函數width()設置下一次輸出時的字段寬度,默認右對齊並以空格填充空白字段,當字段寬度不足時,C++不對截斷輸出寬度;使用成員函數fill()用來填充空白字段;使用成員函數precision()來設置浮點數輸出精度;成員函數setf()與unsetf()提供了更豐富的輸出格式設置方法,但使用標準控制符將更加簡單。

  13、對於cin的get()方法和getline()方法來說,如果沒有讀取到任何字符(getline()將換行符視為一個字符),則設置failbit;如果讀取了最大數目的字符,但行中還有其他字符,getline()將設置failbit

  14、cin的peak()方法可以查看輸入流中的下一個字符,gcount()方法可以返回最後一個非格式化抽取方法讀取的字符數,putback()方法可以將字符插入到輸入字符串中。

  15、fstream類中的方法seekg()和seekp()分別將輸入指針和輸出指針移到指定的文件位置,事實上,由於fstream類使用緩衝區來存儲中間數據,因此指針指向的是緩衝區中的位置,而不是實際的文件。

  16、fstream類中的方法tellg()和tellp()方法分別返回輸入流、輸出流當前指針的位置,對於fstream對象,輸入輸出指針將一前一后地移動,因此它們的返回值相同。但對於使用istream對象來管理輸入流,而使用ostream對象來管理同一個文件的輸出流,則輸入指針和輸出指針將彼此獨立的移動。

  17、關於如何生成臨時文件,使用tmpnam()可以生產TMP_NAM個不同的文件名,其中每個文件名包含的字符不超過L_tmpnam個。

  18、C++庫還提供了sstream族(包含ostringstream類和istringstream類),它們使用相同的接口提供程序和string對象之間的IO。

 

探討C++新標準

  19、新標準引入的移動語義,用來修飾六個特殊函數的default關鍵字,用來刪除任意成員函數的delete關鍵字,以及使用類似初始化列表的方式在一個構造函數中使用另一個構造函數(被稱為委託構造),以及使用using 類名::函數名,使基類所有的非特殊成員函數對派生類可以用(繼承構造函數),以及显示聲明重寫(覆蓋)某個虛函數的標識符override,以及禁止派生類覆蓋特定的虛函數標識符final

  20、C++11引入lambda表達的主要目的是能夠將類似於函數的表達式用作接受函數指針或函數符的函數的參數。

  21、C++提供了多個包裝器對象,用於給其他編程接口提供更一致或更合適的接口。C++11提供了包括模板bind(替代bind1st和bind2nd)men_fn(將成員函數作為常規函數傳遞)reference_wrapper(創建行為像引用但可被複制的對象)以及funtion(以統一的方式處理多種類似於函數的形式,使用模板時可減少可執行代碼的規模)

  22、正確使用遞歸實現可變參數模板

  23、C++11增加了對并行編程的支持,以及相當多的新增庫等。

 

附錄

  24、C++允許定義指向類成員(包括數據和函數)的指針,這種語法需要使用到成員解除引用運算符(* 、->*)。

  25、C++11新增了alignof運算符,它接受一個類型作為參數,返回這個類型的對齊方式;noexcept關鍵字用於指出函數不會引發異常,它也可以用作運算符,判斷表達式是否可能引發異常,不引發返回true。

  26、STL提供了豐富的全局函數,包括查詢,排序,複製等一系列算法。

  

  2020年6月2日,星期二,凌晨2點01分,首次完整讀完這本書,共勉。

  學如逆水行舟,不進則退;心似平原放馬,易縱難收。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

澳洲野火燒破千人家園 雪梨收災難性警告

摘錄自2019年11月11日ETtoday 綜合報導

澳洲東部森林野火自8日起延燒多日,造成3人死亡、數十人受傷以及上千人失去家園,仍在燃燒的上百處火場燒掉了至少150棟的住宅。當局指出,恐怕連雪梨及周邊地區也會受影響,12日將迎接「災難性」野火威脅。

外電報導,新南威爾斯州(New South Wales)及昆士蘭州(Queensland)等地接連傳出災情,當局派出將近1300名消防員也沒能撲滅燒了4天的大火,只能宣布災區進入「緊急狀態」,並警告人口最多的雪梨地區,高溫恐飆破攝氏37度,要面臨「災難性」(catasrophic)的野火威脅。

這也是澳洲2009年推出新的「火情危險評級制度」(Fire Danger Rating,分為中等、高、非常高、嚴重、極高及災難性)後,雪梨第一次面臨「災難性」等級,預計12日雪梨會出現攝氏37度高溫、強風、乾燥等,不排除比澳洲東部當初被野火襲擊時更嚴重。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

增近四倍 2015年Q1中國純電動車銷量達1.54萬輛

近日,中國汽車工業協會發佈最新統計資料顯示,今年第一季,中國汽車銷售達615.3萬輛,與去年同期相比增長3.9%,但相較去年同期9.2%的增幅,下滑明顯。此外新能源汽車產銷分別為2.73萬輛和2.66萬輛,與去年同期相比分別增長2.9倍和2.8倍。   其中,純電動車型銷售1.54萬輛,與去年同其相比增長3.7倍;插電式混合動力車型銷售1.12萬輛,與去年同期相比增長2.1倍。與新能源汽車相比,傳統車型銷量增幅卻明顯回落。根據資料,一季度乘用車共銷售530.51萬輛,與去年同其相比增長8.95%,增幅比去年同期回落1.14個百分點。在乘用車四類車型中,轎車銷量與去年同期相比下滑0.4%。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

推薦一種通過刷leetcode來增強技術功底的方法

背景

如果前人認為這個一種學習提高或者檢驗能力的成功實踐。而自己目前又沒有更好的方法,那就不妨試一試。

而不管作為面試官還是被面試者,編碼題最近越來越流行。而兩種角色都需要思考的問題是希望考察什麼能力,通過什麼題目,需要達到怎樣的程度可以說明面試者具有了這樣的能力。

而要找到上面這些問題的答案,比較好的方式除了看一些理論性文章和接受培訓之外,自己動手刷一刷leetcode切身實踐一下不失為一個不錯的方式。而既然要花精力去做這件事情,那就需要解決一個問題:我從中可以獲得什麼提高。以下是個人的一些經驗和感受。

 

收益

對底層有了更深入的了解和思考

leetcode一些常見題也是平時工作中常用的一些底層數據結構的實現方法。 

先舉個大家使用比較多的算法:LRU(最近最少使用),在Java的實現中實現特別簡單。只是使用了LinkedHashMap這種數據結構。而如果看一些開源包里LRU的實現,發現也是這樣實現的。實際上動手實現一遍,LRU就再也不會忘了。

再舉個數據結構的例子:字典樹又叫前綴樹。它是搜索和推薦的基礎。標準點的定義是:

字典樹又稱單詞查找樹,Tire樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高。

因為之前做過搜索引擎,一直也對這塊很有興趣,所以對它底層知識的補充對個人而言,感覺深度有增加。

 

  

養成評估時空開銷的習慣

我刷leetcode必看官方解答里估算的時間和空間複雜度。這也是作為一個架構師的必備基本能力。

數組、哈希這些因為數據的位置不需要進行查找,只需要算數計算就可以得到,所以它們的時間複雜度是O(1)。

鏈表如果直接在頭部或者尾部插入,因為不需要查找,所以時間複雜度也是O(1),但是定位的話因為涉及查找,按遍歷查找來算是log(n)。所以對於jdk1.7之前,hashmap底層採用的是數組+鏈表的數據結構。所以如果不算哈希衝突和擴容的話,獲取和插入數據的時間複雜度是O(1);如果出現了哈希衝突,則插入因為是頭部插入,時間複雜度還是O(1);獲取時間複雜度因為涉及先查找,所以是O(n),這個n代表衝突的數量。

對於在有序數據中進行查找,因為可採用二分查找等優化,時間複雜度可降到log(n).

對於遞歸調用,如果遞歸方法內進行2次調用。對於層數n來說,時間複雜度是2的n次方。舉個例子就是一個數等於前面兩個數之和。當然,如果是前面3個數之和,不進行優化的情況下時間複雜度就是3的n次方。

對於一個n*m的二維數組等需要進行嵌套循環遍歷的,時間複雜度是O(n*m),有個特殊情況是n*m,這時候時間複雜度是n的平方。

對於全排列的情況,時間複雜度是O(n!)。

 

代碼簡化的方法

 

我習慣的一種學習方法是先做題,有了一定自己的總結和思考之後,再看書學習別人的總結思考方法。對於刷leetcode相關性高,也比較受認可的書是《Cracking the Coding interview(6th)》,中文版翻譯是《程序員面試金典》。這本書對於面試官和面試者來說讀了都會有一定的收穫。

 

我讀了這本書,對我印象最深的是介紹了兩種代碼優化的方法:BUD和BCR。

 

BUD 

BUD是瓶頸、不必要工作、重複工作 三個詞組首字母的縮寫。

 

作者提出拿到一道編程題,可先嘗試用暴力解法將題目寫出來,之後找到解法的性能瓶頸,針對瓶頸進行優化,之後在去掉不必要的工作,最後去掉重複的工作。

這個經典的編程優化方法不只可應用於編程,還可應用於整個程序的優化,也是最常規的優化方法。

 

BCR

BCR是Best Conceivable Runtime的縮寫,意思是想知道自己可以優化到什麼程度,先估算可達到的最優情況。

比如:在一個無序數組中,查找兩個兩個相同的數。直覺來說如果找到這兩個數,最起碼需要將每個數都遍歷一遍,所以可達到的最優情況是O(n),無論怎麼優化,都不可能比這個更好。所以這就是優化的上限。

這本書里還介紹了其他的優化方法如:使用額外數據結構、通過構建測試用例、根據題目的限制和提示來尋找線索,大家看這本書的時候可以了解下。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

特斯拉將公布儲能電池計畫 F-貿聯可望受惠

特斯拉傳將於 4 月 30 日公布儲能電池計畫,市場推測,該計畫將包括住宅與公共規模市場,業界傳出,本來就是特斯拉重要夥伴的 F-貿聯,有機會獲新電力線訂單。而今年在特斯拉需求持續強勁,與 Type C 等外接式擴充介面的需求爆發下,法人預期,該公司今年營運將逐季走高,全年營收看增 15%。   F-貿聯首季營收 19.04 億元,年增 10%,創下歷年同期新高。而特斯拉傳出將於下周公布最新的儲能電池計畫,據市場傳言表示,貿聯本來就是特斯拉在電動車電池模組用線與超級充電樁的線束的主力供應商,未來不排除大型公共規模用儲能電池,將與現有充電站結合。而貿聯有機會順勢切入取得新產品,並以公用市場應用的電力線為主,近日有望已小量出貨。   法人預估,F-貿聯今年除來自特斯拉的需求成長外,另在其他車用佈局方面,包括全地形車大客戶全車線束、擴大歐美客戶於倒車雷達等新產品的開發;另外針對美國官方對公營單位節能環保的需求,也配合客戶開發出得以改裝現有車為電動車的配備裝置,隨未來該商業模式成型,貢獻將逐步擴大。  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

最新的一波Vue實戰技巧,不用則已,一用驚人

Vue中,不同的選項有不同的合併策略,比如 data,props,methods是同名屬性覆蓋合併,其他直接合併,而生命周期鈎子函數則是將同名的函數放到一個數組中,在調用的時候依次調用

Vue中,提供了一個api, Vue.config.optionMergeStrategies,可以通過這個api去自定義選項的合併策略。

在代碼中打印

console.log(Vue.config.optionMergeStrategies)

  

 通過合併策略自定義生命周期函數

背景

最近客戶給領導反饋,我們的系統用一段時間,瀏覽器就變得有點卡,不知道為什麼。問題出來了,本來想甩鍋到後端,但是瀏覽器問題,沒法甩鍋啊,那就排查吧。

後來發現頁面有許多定時器,ajax輪詢還有動畫,打開一個瀏覽器頁簽沒法問題,打開多了,瀏覽器就變得卡了,這時候我就想如果能在用戶切換頁簽時候將這些都停掉,不久解決了。百度裏面上下檢索,找到了一個事件visibilitychange,可以用來判斷瀏覽器頁簽是否显示。

有方法了,就寫唄

export default {
  created() {
    window.addEventListener('visibilitychange', this.$_hanldeVisiblityChange)
    // 此處用了hookEvent,可以參考小編前一篇文章
    this.$on('hook:beforeDestroy', () => {
      window.removeEventListener(
        'visibilitychange',
        this.$_hanldeVisiblityChange
      )
    })
  },
  methods: {
    $_hanldeVisiblityChange() {
      if (document.visibilityState === 'hidden') {
        // 停掉那一堆東西
      }
      if (document.visibilityState === 'visible') {
        // 開啟那一堆東西
      }
    }
  }
}

通過上面的代碼,可以看到在每一個需要監聽處理的文件都要寫一堆事件監聽,判斷頁面是否显示的代碼,一處兩處還可以,文件多了就頭疼了,這時候小編突發奇想,定義一個頁面显示隱藏的生命周期鈎子,把這些判斷都封裝起來

自定義生命周期鈎子函數

定義生命周期函數 pageHidden 與 pageVisible

import Vue from 'vue'

// 通知所有組件頁面狀態發生了變化
const notifyVisibilityChange = (lifeCycleName, vm) => {
  // 生命周期函數會存在$options中,通過$options[lifeCycleName]獲取生命周期
  const lifeCycles = vm.$options[lifeCycleName]
  // 因為使用了created的合併策略,所以是一個數組
  if (lifeCycles && lifeCycles.length) {
    // 遍歷 lifeCycleName對應的生命周期函數列表,依次執行
    lifeCycles.forEach(lifecycle => {
      lifecycle.call(vm)
    })
  }
  // 遍歷所有的子組件,然後依次遞歸執行
  if (vm.$children && vm.$children.length) {
    vm.$children.forEach(child => {
      notifyVisibilityChange(lifeCycleName, child)
    })
  }
}

// 添加生命周期函數
export function init() {
  const optionMergeStrategies = Vue.config.optionMergeStrategies
  // 定義了兩個生命周期函數 pageVisible, pageHidden
  // 為什麼要賦值為 optionMergeStrategies.created呢
  // 這個相當於指定 pageVisible, pageHidden 的合併策略與 created的相同(其他生命周期函數都一樣)
  optionMergeStrategies.pageVisible = optionMergeStrategies.beforeCreate
  optionMergeStrategies.pageHidden = optionMergeStrategies.created
}


// 將事件變化綁定到根節點上面
// rootVm vue根節點實例
export function bind(rootVm) {
  window.addEventListener('visibilitychange', () => {
    // 判斷調用哪個生命周期函數
    let lifeCycleName = undefined
    if (document.visibilityState === 'hidden') {
      lifeCycleName = 'pageHidden'
    } else if (document.visibilityState === 'visible') {
      lifeCycleName = 'pageVisible'
    }
    if (lifeCycleName) {
      // 通過所有組件生命周期發生變化了
      notifyVisibilityChange(lifeCycleName, rootVm)
    }
  })
}

應用

  1. main.js主入口文件引入
import { init, bind } from './utils/custom-life-cycle'

// 初始化生命周期函數, 必須在Vue實例化之前確定合併策略
init()

const vm = new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

// 將rootVm 綁定到生命周期函數監聽裏面
bind(vm)

  2. 在需要的地方監聽生命周期函數

export default {
  pageVisible() {
    console.log('頁面显示出來了')
  },
  pageHidden() {
    console.log('頁面隱藏了')
  }
}

  

provideinject,不止父子傳值,祖宗傳值也可以

Vue相關的面試經常會被面試官問道,Vue父子之間傳值的方式有哪些,通常我們會回答,props傳值,$emit事件傳值,vuex傳值,還有eventbus傳值等等,今天再加一種provideinject傳值,離offer又近了一步。(對了,下一節還有一種)

使用過React的同學都知道,在React中有一個上下文Context,組件可以通過Context向任意後代傳值,而Vueprovideinject的作用於Context的作用基本一樣

先舉一個例子

使用過elemment-ui的同學一定對下面的代碼感到熟悉

<template>
  <el-form :model="formData" size="small">
    <el-form-item label="姓名" prop="name">
      <el-input v-model="formData.name" />
    </el-form-item>
    <el-form-item label="年齡" prop="age">
      <el-input-number v-model="formData.age" />
    </el-form-item>
    <el-button>提交</el-button>
  </el-form>
</template>
<script>
export default {
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}
</script>

  

看了上面的代碼,貌似沒啥特殊的,天天寫啊。在el-form上面我們指定了一個屬性size="small",然後有沒有發現表單裏面的所有表單元素以及按鈕的 size都變成了small,這個是怎麼做到的?接下來我們自己手寫一個表單模擬一下

自己手寫一個表單

自定義表單custom-form.vue

<template>
  <form class="custom-form">
    <slot></slot>
  </form>
</template>
<script>
export default {
  props: {
    // 控製表單元素的大小
    size: {
      type: String,
      default: 'default',
      // size 只能是下面的四個值
      validator(value) {
        return ['default', 'large', 'small', 'mini'].includes(value)
      }
    },
    // 控製表單元素的禁用狀態
    disabled: {
      type: Boolean,
      default: false
    }
  },
  // 通過provide將當前表單實例傳遞到所有後代組件中
  provide() {
    return {
      customForm: this
    }
  }
}
</script>

  

在上面代碼中,我們通過provide將當前組件的實例傳遞到後代組件中,provide是一個函數,函數返回的是一個對象

自定義表單項custom-form-item.vue

沒有什麼特殊的,只是加了一個label,element-ui更複雜一些

<template>
  <div class="custom-form-item">
    <label class="custom-form-item__label">{{ label }}</label>
    <div class="custom-form-item__content">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    label: {
      type: String,
      default: ''
    }
  }
}
</script>

自定義輸入框 custom-input.vue

<template>
  <div
    class="custom-input"
    :class="[
      `custom-input--${getSize}`,
      getDisabled && `custom-input--disabled`
    ]"
  >
    <input class="custom-input__input" :value="value" @input="$_handleChange" />
  </div>
</template>
<script>
/* eslint-disable vue/require-default-prop */
export default {
  props: {
    // 這裏用了自定義v-model
    value: {
      type: String,
      default: ''
    },
    size: {
      type: String
    },
    disabled: {
      type: Boolean
    }
  },
  // 通過inject 將form組件注入的實例添加進來
  inject: ['customForm'],
  computed: {
    // 通過計算組件獲取組件的size, 如果當前組件傳入,則使用當前組件的,否則是否form組件的
    getSize() {
      return this.size || this.customForm.size
    },
    // 組件是否禁用
    getDisabled() {
      const { disabled } = this
      if (disabled !== undefined) {
        return disabled
      }
      return this.customForm.disabled
    }
  },
  methods: {
    // 自定義v-model
    $_handleChange(e) {
      this.$emit('input', e.target.value)
    }
  }
}
</script>

  


form中,我們通過
provide返回了一個對象,在
input中,我們可以通過
inject獲取
form中返回對象中的項,如上代碼
inject:['customForm']所示,然後就可以在組件內通過
this.customForm調用
form實例上面的屬性與方法了

在項目中使用

<template>
  <custom-form size="small">
    <custom-form-item label="姓名">
      <custom-input v-model="formData.name" />
    </custom-form-item>
  </custom-form>
</template>
<script>
import CustomForm from '../components/custom-form'
import CustomFormItem from '../components/custom-form-item'
import CustomInput from '../components/custom-input'
export default {
  components: {
    CustomForm,
    CustomFormItem,
    CustomInput
  },
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  }
}
</script>

  執行上面代碼,運行結果為:

<form class="custom-form">
  <div class="custom-form-item">
    <label class="custom-form-item__label">姓名</label>
    <div class="custom-form-item__content">
      <!--size=small已經添加到指定的位置了-->
      <div class="custom-input custom-input--small">
        <input class="custom-input__input">
      </div>
    </div>
  </div>
</form>

  

通過上面的代碼可以看到,input組件已經設置組件樣式為custom-input--small

inject格式說明

除了上面代碼中所使用的inject:['customForm']寫法之外,inject還可以是一個對象。且可以指定默認值

修改上例,如果custom-input外部沒有custom-form,則不會注入customForm,此時為customForm指定默認值

{
  inject: {
    customForm: {
      // 對於非原始值,和props一樣,需要提供一個工廠方法
      default: () => ({
        size: 'default'
      })
    }
  }
}

  

使用限制

1.provideinject的綁定不是可響應式的。但是,如果你傳入的是一個可監聽的對象,如上面的customForm: this,那麼其對象的屬性還是可響應的。

2.Vue官網建議provideinject 主要在開發高階插件/組件庫時使用。不推薦用於普通應用程序代碼中。因為provideinject在代碼中是不可追溯的(ctrl + f可以搜),建議可以使用Vuex代替。 但是,也不是說不能用,在局部功能有時候用了作用還是比較大的。

 

插槽,我要鑽到你的懷裡

插槽,相信每一位Vue都有使用過,但是如何更好的去理解插槽,如何去自定義插槽,今天小編為你帶來更形象的說明。

默認插槽

<template>
  <!--這是一個一居室-->
  <div class="one-bedroom">
    <!--添加一個默認插槽,用戶可以在外部隨意定義這個一居室的內容-->
    <slot></slot>
  </div>
</template>

  

<template>
  <!--這裏一居室-->
  <one-bedroom>
    <!--將傢具放到房間裏面,組件內部就是上面提供的默認插槽的空間-->
    <span>先放一個小床,反正沒有女朋友</span>
    <span>再放一個電腦桌,在家還要加班寫bug</span>
  </one-bedroom>
</template>
<script>
import OneBedroom from '../components/one-bedroom'
export default {
  components: {
    OneBedroom
  }
}
</script>

具名插槽

<template>
  <div class="two-bedroom">
    <!--這是主卧-->
    <div class="master-bedroom">
      <!---主卧使用默認插槽-->
      <slot></slot>
    </div>
    <!--這是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard"></slot>
    </div>
  </div>
</template>

  

<template>
  <two-bedroom>
    <!--主卧使用默認插槽-->
    <div>
      <span>放一個大床,要結婚了,嘿嘿嘿</span>
      <span>放一個衣櫃,老婆的衣服太多了</span>
      <span>算了,還是放一個電腦桌吧,還要寫bug</span>
    </div>
    <!--次卧,通過v-slot:secondard 可以指定使用哪一個具名插槽, v-slot:secondard 也可以簡寫為 #secondard-->
    <template v-slot:secondard>
      <div>
        <span>父母要住,放一個硬一點的床,軟床對腰不好</span>
        <span>放一個衣櫃</span>
      </div>
    </template>
  </two-bedroom>
</template>
<script>
import TwoBedroom from '../components/slot/two-bedroom'
export default {
  components: {
    TwoBedroom
  }
}
</script>

作用域插槽

<template>
  <div class="two-bedroom">
    <!--其他內容省略-->
    <div class="toilet">
      <!--通過v-bind 可以向外傳遞參數, 告訴外面衛生間可以放洗衣機-->
      <slot name="toilet" v-bind="{ washer: true }"></slot>
    </div>
  </div>
</template>

  

<template>
  <two-bedroom>
    <!--其他省略-->
    <!--衛生間插槽,通過v-slot="scope"可以獲取組件內部通過v-bind傳的值-->
    <template v-slot:toilet="scope">
      <!--判斷是否可以放洗衣機-->
      <span v-if="scope.washer">這裏放洗衣機</span>
    </template>
  </two-bedroom>
</template>  

插槽默認值

<template>
  <div class="second-hand-house">
    <div class="master-bedroom">
      <!--插槽可以指定默認值,如果外部調用組件時沒有修改插槽內容,則使用默認插槽-->
      <slot>
        <span>這裡有一張水床,玩的夠嗨</span>
        <span>還有一個衣櫃,有點舊了</span>
      </slot>
    </div>
    <!--這是次卧-->
    <div class="secondary-bedroom">
      <!--次卧使用具名插槽-->
      <slot name="secondard">
        <span>這裡有一張嬰兒床</span>
      </slot>
    </div>
  </div>
</template>

  

<second-hand-house>
    <!--主卧使用默認插槽,只裝修主卧-->
    <div>
      <span>放一個大床,要結婚了,嘿嘿嘿</span>
      <span>放一個衣櫃,老婆的衣服太多了</span>
      <span>算了,還是放一個電腦桌吧,還要寫bug</span>
    </div>
  </second-hand-house>

dispatchbroadcast,這是一種有歷史的組件通信方式

dispatch
broadcast是一種有歷史的組件通信方式,為什麼是有歷史的,因為他們是
Vue1.0提供的一種方式,在
Vue2.0中廢棄了。但是廢棄了不代表我們不能自己手動實現,像許多UI庫內部都有實現。本文以
element-ui實現為基礎進行介紹。同時看完本節,你會對組件的
$parent,
$children,
$options有所了解。

方法介紹

$dispatch: $dispatch會向上觸發一個事件,同時傳遞要觸發的祖先組件的名稱與參數,當事件向上傳遞到對應的組件上時會觸發組件上的事件偵聽器,同時傳播會停止。

$broadcast: $broadcast會向所有的後代組件傳播一個事件,同時傳遞要觸發的後代組件的名稱與參數,當事件傳遞到對應的後代組件時,會觸發組件上的事件偵聽器,同時傳播會停止(因為向下傳遞是樹形的,所以只會停止其中一個恭弘=叶 恭弘子分支的傳遞)。

$dispatch實現與應用

1. 代碼實現

 // 向上傳播事件
 // @param {*} eventName 事件名稱
 // @param {*} componentName 接收事件的組件名稱
 // @param {...any} params 傳遞的參數,可以有多個
 
function dispatch(eventName, componentName, ...params) {
  // 如果沒有$parent, 則取$root
  let parent = this.$parent || this.$root
  while (parent) {
    // 組件的name存儲在組件的$options.componentName 上面
    const name = parent.$options.name
    // 如果接收事件的組件是當前組件
    if (name === componentName) {
      // 通過當前組件上面的$emit觸發事件,同事傳遞事件名稱與參數
      parent.$emit.apply(parent, [eventName, ...params])
      break
    } else {
      // 否則繼續向上判斷
      parent = parent.$parent
    }
  }
}

// 導出一個對象,然後在需要用到的地方通過混入添加
export default {
  methods: {
    $dispatch: dispatch
  }
}  

2. 代碼應用

  • 在子組件中通過$dispatch向上觸發事件

    import emitter from '../mixins/emitter'
    export default {
      name: 'Chart',
      // 通過混入將$dispatch加入進來
      mixins: [emitter],
       mounted() {
         // 在組件渲染完之後,將組件通過$dispatch將自己註冊到Board組件上
        this.$dispatch('register', 'Board', this)
      }
    }
  • Board組件上通過$on監聽要註冊的事件

$broadcast實現與應用

1. 代碼實現

  //向下傳播事件
  // @param {*} eventName 事件名稱
  // @param {*} componentName 要觸發組件的名稱
  // @param  {...any} params 傳遞的參數
 
function broadcast(eventName, componentName, ...params) {
  this.$children.forEach(child => {
    const name = child.$options.name
    if (name === componentName) {
      child.$emit.apply(child, [eventName, ...params])
    } else {
      broadcast.apply(child, [eventName, componentName, ...params])
    }
  })
}

// 導出一個對象,然後在需要用到的地方通過混入添加
export default {
  methods: {
    $broadcast: broadcast
  }
}  

2. 代碼應用

在父組件中通過$broadcast向下觸發事件

import emitter from '../mixins/emitter'
export default {
  name: 'Board',
  // 通過混入將$dispatch加入進來
  mixins: [emitter],
  methods:{
  	//在需要的時候,刷新組件
  	$_refreshChildren(params) {
  		this.$broadcast('refresh', 'Chart', params)
  	}
  }
}

在後代組件中通過$on監聽刷新事件

export default {
  name: 'Chart',
  created() {
    this.$on('refresh',(params) => {
      // 刷新事件
    })
  }
}

總結

通過上面的例子,同學們應該都能對$dispatch$broadcast有所了解,但是為什麼Vue2.0要放棄這兩個方法呢?官方給出的解釋是:”因為基於組件樹結構的事件流方式實在是讓人難以理解,並且在組件結構擴展的過程中會變得越來越脆弱。這種事件方式確實不太好,我們也不希望在以後讓開發者們太痛苦。並且 $dispatch$broadcast 也沒有解決兄弟組件間的通信問題。“

確實如官網所說,這種事件流的方式確實不容易讓人理解,而且後期維護成本比較高。但是在小編看來,不管黑貓白貓,能抓老鼠的都是好貓,在許多特定的業務場景中,因為業務的複雜性,很有可能使用到這樣的通信方式。但是使用歸使用,但是不能濫用,小編一直就在項目中有使用。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

印尼蘇門答臘象身首異處慘死 象牙遭盜採

摘錄自2019年11月8日自由時報屏東報導

印尼保育官員今天表示,1頭列為極危(critically endangered)物種的蘇門答臘象屍體被發現,牠的頭被砍下且象牙被拔走,顯然是一宗盜獵案件。

蘇門答臘島廖內省(Riau)一名農園工人昨天發現這頭40歲公象腐爛的屍體。當地保育機關主管蘇哈尤諾(Suharyono)在聲明中說:「大象的頭被砍下,切斷的象鼻落在距離象身1公尺處。」當局正在追查犯案人士。

森林濫伐造成蘇門答臘象的天然棲地縮減,導致牠們和人類的衝突加劇。另一方面,蘇門答臘象象牙在野生動物黑市交易中價值連城。

去年在印尼亞齊省(Aceh)也發現一具顯然被毒死的蘇門答臘象屍體,當時牠的象牙也不見。印尼環境部估計,境內野生蘇門答臘象只剩不到2000頭。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

痞子衡嵌入式:利用i.MXRT1xxx系列ROM提供的FlexSPI driver API可輕鬆IAP

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT系列ROM中的FlexSPI驅動API實現IAP

  痞子衡的技術交流群里經常有群友提問: i.MXRT中的FlexSPI驅動API到底怎麼用啊?這個問題已經出現過好幾次了,本來痞子衡不打算專門為這個寫文章的,因為這部分內容在芯片手冊System Boot章節里的最後一節ROM APIs里其實介紹得非常詳細了,但是既然還是有不少朋友在問這個,看起來手冊里的內容藏得有點深,這麼好的東西被埋沒太可惜了,那麼今天痞子衡就跟大家再認真聊一聊。

一、ROM API簡介

1.1、API產生背景

  i.MXRT系列都是Flashless(沒有內置NVM)的芯片,所以BootROM必不可少。BootROM是個很特殊的東西,本質上它是一個完整的C代碼寫成的系統級App,這個系統級App專門用於從外部存儲器中加載用戶級App執行。簡單地說,BootROM就是PC機里的BIOS。

  BootROM代碼是存放在專門的ROM區域的(前面講i.MXRT系列沒有內置NVM,其實不夠準確,其實是有內部ROM空間的,只不過這個ROM區域用戶無法下載程序使用,因此等效於沒有NVM),ROM顧名思義Readonly,所以BootROM代碼只能隨着芯片一起Tapeout,代碼無法更改(其實也有ROM patch機制,以後再介紹)。

  ROM空間其實挺大的,從64KB到512KB不等,因芯片啟動功能複雜程度而異。下圖是i.MXRT1050系列的BootROM所佔空間,ROM起始地址是0x200000(起始地址在i.MXRT上都一樣),ROM大小為96KB(這是標準啟動功能所要的代碼長度。在i.MXRT1010上是64KB – 精簡啟動功能,在i.MXRT1170上是256KB – 複雜啟動功能)。

  BootROM代碼其實並沒有佔滿全部ROM空間,總有些剩餘空間(因為工藝原因,ROM空間都是8/16KB倍數),這部分空間浪費了着實可惜。如果我們能把SDK里的一些常用模塊驅動(比如WDOG)順便放進去供用戶調用,既充分利用ROM空間,也為用戶節省Flash空間,豈不是一舉兩得。此外,BootROM功能代碼中也有一些現成模塊驅動(比如各種啟動設備存儲器驅動接口)可以一併導出,這便是API由來。

1.2、API設計實現

  有了API想法,現在就是設計實現了。其實i.MXRT ROM API設計並不是重頭開始的,在這個MCU系列被主推之前,Kinetis系列也曾當紅過,Kinetis中也內置了ROM,並且提供了ROM API,痞子衡之前為此寫過一篇文章 《飛思卡爾Kinetis系列MCU啟動那些事(11)- KBOOT特性(ROM API)》。 i.MXRT ROM API設計思路完全復用了Kinetis ROM API的設計。

  API說到底就是一個個功能函數的結合,我們知道工程代碼都是由鏈接器自動分配的,因此每個函數實際鏈接地址是無法預期的(在鏈接文件里給每個函數分配固定地址鏈接這種方法不在考慮範疇,當函數數量眾多時,這種方法太麻煩),業界上一個比較通用的做法是定義成員是函數指針的結構體,i.MXRT ROM API就是採用的業界通用方式,下面bootloader_api_entry_t便是i.MXRT1060中API原型,g_bootloaderTree就是實例:

typedef struct
{
    const uint32_t version;
    const char *copyright;
    void (*runBootloader)(void *arg);
    const hab_rvt_t *habDriver;

    //!< FlexSPI NOR Flash API
    const flexspi_nor_driver_interface_t *flexSpiNorDriver;

    const nand_ecc_driver_interface_t *nandEccDriver;
    const clock_driver_interface_t *clockDriver;
    const rtwdog_driver_interface_t *rtwdogDriver;
    const wdog_driver_interface_t *wdogDriver;
    const stdlib_driver_interface_t *stdlibDriver;
} bootloader_api_entry_t;

// Bootloader API Tree
const bootloader_api_entry_t g_bootloaderTree = {
    .copyright = "Copyright 2018 NXP",
    .version = MAKE_VERSION(1, 0, 0),
    .runBootloader = run_bootloader,
    .habDriver = &hab_rvt,

    .flexSpiNorDriver = &g_flexspiNorDriverInterface,

    .nandEccDriver = &g_nandEccDriverInterface,
    .clockDriver = &g_clockDriverInterface,
    .rtwdogDriver = &g_rtwdogDriverInterface,
    .wdogDriver = &g_wdogDriverInterface,
    .stdlibDriver = &g_stdlibDriverInterface,
};

  從上面代碼我們可以看出,bootloader_api_entry_t成員好像並不是函數指針,是的,為了分組方便,bootloader_api_entry_t成員還是一個個結構體,它的這些結構體成員(比如flexspi_nor_driver_interface_t)才是真正包含一個個函數指針的結構體。API從功能來分一共提供了7類:HAB、FlexSPI NOR、NAND ECC、Clock、RT-WDOG、WDOG、stdlib。

  設計到這裏,我們通過g_bootloaderTree結構體常量就可以調用所有的API函數了,最後剩下的問題就是如何在ROM里找一個確定的地方保存隨機鏈接的g_bootloaderTree地址(只要4字節即可)。是的,還是Kinetis ROM API用的那個巧妙的方法,下面是BootROM工程的startup文件(Keil版),BootROM將g_bootloaderTree的地址放到了中斷向量表第8個向量的位置處(該向量為ARM Cortex-M未定義的系統向量),因此0x20001c處開始的4bytes便固定是g_bootloaderTree地址。

                PRESERVE8
                THUMB

; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
                IMPORT  |Image$$ARM_LIB_STACK$$ZI$$Limit|
                IMPORT  g_bootloaderTree

__Vectors       DCD     |Image$$ARM_LIB_STACK$$ZI$$Limit|
                DCD     Reset_Handler
                DCD     DefaultISR
                DCD     HardFault_Handler
                DCD     DefaultISR
                DCD     DefaultISR
                DCD     DefaultISR
                DCD     g_bootloaderTree
                DCD     0
                DCD     0
                DCD     0
                DCD     SVC_Handler
                DCD     DefaultISR
                DCD     0
                DCD     DefaultISR
                DCD     DefaultISR
		        ;; ...

1.3、API調用方法

  了解了前面介紹的ROM API產生背景與設計實現,它的調用方法就非常簡單了,以WDOG API調用為例,只需要如下簡單3句代碼:

// 找到API根結構體
#define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c)
// 定義WDOG模塊配置變量
wdog_config_t config;
// 調用API中WDOG_Init()
g_bootloaderTree->wdogDriver->WDOG_Init(WDOG1, config);

1.4、支持API的i.MXRT型號

  截止目前,i.MXRT1xxx系列一共出了7款型號,但並不是每個型號都開放了ROM API,最早誕生的三款型號(105x、1021、1015)就並沒有開放API(不是沒有API,而是沒有嚴格測試),其餘型號都支持API。

RT芯片型號 是否支持ROM API
i.MXRT117x 支持
i.MXRT1064 支持
i.MXRT106x 支持
i.MXRT105x 未開放
i.MXRT1021 未開放
i.MXRT1015 未開放
i.MXRT1011 支持

二、API之FlexSPI驅動

  前面鋪墊了太多ROM API設計細節,到這裏才算進入正題,本文其實主要是要跟大家聊如何利用API里的FlexSPI NOR驅動實現IAP。痞子衡在前面鋪墊那麼多的原因其實主要是想告訴大家,API里的每個驅動都是經過完善測試的,尤其是這個FlexSPI NOR驅動,更是經過了千錘百鍊,無論是易用性、運行穩定性還是Flash型號的支持度上都是首屈一指的。

  對於JESD216標準下的串行SPI接口Flash驅動,大家知道更多的可能是RT-Thread技術總監朱天龍大神的開源 SFUD 項目,但痞子衡告訴你,i.MXRT ROM API里的這個串行Flash驅動也毫不遜色(持續維護與優化了近6年,歷經多款MCU的ROM,是真正的產品級),只是不如開源項目那麼知名,不過它的源代碼也是開源在SDK里的(\SDK\middleware\mcu-boot\src\drivers\flexspi_nor),BSD-3-Clause許可證。

2.1 FlexSPI驅動原型

  flexspi_nor_driver_interface_t便是FlexSPI NOR驅動的原型,尋常的讀寫擦功能自然不在話下,除此以外,API裏面還有一個非常厲害的xfer()函數,這個函數可以用來實現其他定製化的Flash操作函數,有興趣的朋友可以進一步去研究。

typedef struct
{
    uint32_t version;
    status_t (*init)(uint32_t instance, flexspi_nor_config_t *config);
    status_t (*program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t dst_addr, const uint32_t *src);
    status_t (*erase_all)(uint32_t instance, flexspi_nor_config_t *config);
    status_t (*erase)(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t lengthInBytes);
    status_t (*read)(uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t addr, uint32_t lengthInBytes);
    void (*clear_cache)(uint32_t instance);
    status_t (*xfer)(uint32_t instance, flexspi_xfer_t *xfer);
    status_t (*update_lut)(uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, uint32_t seqNumber);
    status_t (*get_config)(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option);
} flexspi_nor_driver_interface_t;

2.2 FlexSPI驅動使用示例

  FlexSPI驅動使用基本三步走,先調用get_config()獲取完整FlexSPI模塊配置,然後調用init()函數去初始化FlexSPI以及訪問Flash獲取SFDP表信息,最後就是調用Flash操作函數(比如erase())。

// 找到API根結構體
#define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c)

// 定義FlexSPI, Flash配置變量
flexspi_nor_config_t config;
serial_nor_config_option_t option;
option.option0.U = 0xC0000008; // QuadSPI NOR, Frequency: 133MHz
uint32_t instance = 0;

// 調用API中get_config()函數
g_bootloaderTree->flexSpiNorDriver->get_config(instance, &config, &option);
// 調用API中init()函數
g_bootloaderTree->flexSpiNorDriver->init(instance, &config);
// 調用API中erase()函數
g_bootloaderTree->flexSpiNorDriver->erase(instance, &config, 0x40000, 0x1000);

2.3 FlexSPI驅動特點

  因為FlexSPI NOR驅動API來自於BootROM,因此其在使用上有一些小小的限制,也算是其特點吧。FlexSPI驅動API里並沒有提供Flash連接的Pinmux配置,其Pinmux配置已經寫死在init()函數中,就是ROM支持啟動的FlexSPI PORTA上的那些pin(片選是SS0)。

  在上面的使用示例代碼中,你會看到option.option0.U = 0xC0000008代碼,這算是FlexSPI驅動最大的特點了,這是一個簡化的option配置word(其原型可在芯片手冊里找到),通過這個簡化的option,用戶可以輕鬆配置來訪問不同廠商的Flash,下面是常用的Flash模式配置值。

• QuadSPI NOR - Quad SDR Read: option0 = 0xc0000008 (133MHz)
• QuadSPI NOR - Quad DDR Read: option0 = 0xc0100003 (60MHz)
• HyperFLASH 1V8: option0 = 0xc0233009 (166MHz)
• HyperFLASH 3V0: option0 = 0xc0333006 (100MHz)
• MXIC OPI DDR (OPI DDR enabled by default): option=0xc0433008(133MHz)
• Micron Octal DDR: option0=0xc0600006 (100MHz)
• Micron OPI DDR: option0=0xc0603008 (133MHz), SPI->OPI DDR
• Micron OPI DDR (DDR read enabled by default): option0 = 0xc0633008 (133MHz)
• Adesto OPI DDR: option0=0xc0803008(133MHz)

2.4 FlexSPI驅動用作IAP

  IAP其實就是在App中實現Flash擦寫,單純從技術上來說並不是一個很難的東西。但i.MXRT上很多時候App代碼本身也在同一片Flash里執行(也叫XIP),而市面上很多Flash都是不支持RWW(Read-While-Write)的,這就導致一個問題,當你調用Flash操作函數去擦寫Flash時,CPU又需要繼續去Flash獲取指令,違反了RWW,因此你只能把Flash相關操作函數全部放在RAM中去執行(這涉及分散加載了,對於初級嵌入式用戶來說稍微有點難)。

  現在我們有了ROM API,FlexSPI驅動代碼體全部都在ROM空間里,並不佔用Flash空間,因此不存在RWW問題,真是天然為IAP而生,再也不用再管什麼分散加載這麼麻煩的事了。

三、FlexSPI API業界應用

  最後再介紹一下i.MXRT FlexSPI API在業界的應用,這個API其實並不小眾,目前已被主流IDE和調試工具用作i.MXRT Flash下載算法。

3.1 用於IAR下載算法

  如果你的IAR版本夠新,能夠支持i.MXRT1060等型號,隨便打開一個i.MXRT1060 SDK工程,在工程Option里找到Debugger,然後進入Flashloader配置,你會看到頁面里有Extra parameters一欄,在下面的解釋里有這個參數的示例,它就是前面2.3節里介紹的option0。有了這種方式設計的Flash下載算法,你再也不用手動更新下載算法文件去支持不同的Flash了,改參數就行了。

3.2 用於J-Link下載算法

  目前最新的Jlink驅動里的下載算法也是基於ROM API的,痞子衡有一個開源項目,收集了i.MXRT所有型號的下載算法源代碼工程,其中jlink算法是最全的,其他IDE算法還在陸續完善中。

https://github.com/JayHeng/imxrt-tool-flash-algo

  至此,i.MXRT系列ROM中的FlexSPI驅動API實現IAP痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時發布到我的 博客園主頁、CSDN主頁、微信公眾號 平台上。

微信搜索”痞子衡嵌入式“或者掃描下面二維碼,就可以在手機上第一時間看了哦。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心