• 正文
    • 一線通的具體協(xié)議
    • 一線通解析方法
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

聊聊兩輪車行業(yè)的一線通,AI加持

5小時前
288
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

現(xiàn)在很多廠家都支持一線通的通信協(xié)議,控制器呀,儀表呀,BMS呀,通通的提供了一線通的接口,這幾乎成了兩輪車行業(yè)的一個標(biāo)準(zhǔn)了。

第一次看到一線協(xié)議蠻驚訝的,因為這居然是一個國際標(biāo)準(zhǔn),比如:


似乎每一家的協(xié)議文檔的第一部分,都聲稱自己采用的是國際標(biāo)準(zhǔn)SIF通信協(xié)議。

這么看來,我們不得不了解一下,這個大名鼎鼎的國際標(biāo)準(zhǔn)是個什么標(biāo)準(zhǔn),哪幾個組織聯(lián)合發(fā)布的。

我?guī)痛蠹宜堰^了,Google搜索記錄一共3頁,除了像上面那樣介紹自家協(xié)議的引用外,關(guān)于SIF國際標(biāo)準(zhǔn)的關(guān)鍵字都是醫(yī)學(xué),或者視頻行業(yè)的詞條??磥鞧oogle也是孤陋寡聞了,GPT也是干瞪眼。

我翻到了自行車電動車協(xié)會發(fā)布的團(tuán)標(biāo),里面引用了一線通,并沒有說明一線通是什么國際標(biāo)準(zhǔn),只是簡單介紹了其通信架構(gòu)。

從上面的一線通架構(gòu)中,可以看出,這個一線通主要是一發(fā)多收的半雙工機制。跟半個Uart一樣。我之前為了方便,也是采用一根線做Uart通信,只不過我的MCU支持Tx和Rx調(diào)換一下,因此可以做到收發(fā)一體。

一線通的具體協(xié)議

相信很多朋友第一次接觸單線通信都是從DS18B20開始的,這是一種單總線結(jié)構(gòu),它支持主機發(fā)送查詢命令,然后接收各個子設(shè)備的信息。

那么兩輪車的這個一線通呢?其實就是砍掉一半,主機只發(fā)送,不接受,就像串口uart的Tx一樣,自己按照固定的波特率發(fā)送,線上的所有監(jiān)聽者按照協(xié)定的波特率接收。

區(qū)別在于,uart的電平高代表1,電平低代表0,這里指的TTL電平。而一線通該表了這個策略,它使用了固定周期,不同占空比PWM波形來表示0和1。

 

這樣抗干擾的能力就強了很多,看上去也很眼熟是不是? 這跟我們常常使用的彩色LED,WS2812的通信非常的相似,下圖是WS2812的時序波形圖。

其實它們都是采用的單極性歸零碼,歸零碼是一種數(shù)字信號編碼方式,在每個時鐘周期內(nèi),信號電平都會返回到零電平。

與WS2812所不同的是,一線通采用的同步機制并不是一長段的低電平,而是一長段的低電平后面跟上一個高電平,這樣有一個好處,就是可以讓通信更健壯,兼容性更佳。

有了同步幀和數(shù)據(jù)幀的定義,然后再把每一個數(shù)據(jù)周期定義下來,我們就可以接收到整個完整的數(shù)據(jù)包了,這里,一線通的數(shù)據(jù)周期定義為12*8bit,也就是在同步幀后,持續(xù)的接收96個bit。

一線通解析方法

網(wǎng)絡(luò)上看到很多解析一線通的方法,所示配置一個定時器,不斷地讀取GPIO的電平進(jìn)行采樣,然后根據(jù)個數(shù)來計算電平的持續(xù)時間,通用性還是可以的,只不過進(jìn)入中斷的次數(shù)比較多,不過抗干擾會比較好。

我使用的單片機都是有外部中斷的,所以我決定采用中斷配合定時器計時的方法來接收一線通數(shù)據(jù)。只需要定義兩個邊沿都觸發(fā),然后再觸發(fā)中斷里面根據(jù)觸發(fā)源,或者再次讀取一下IO電平就可以判斷出上一次計時器中的計時是高電平還是低電平。

邏輯很簡單,但是寫起來還得費點功夫,我肯定是想一兩分鐘搞定的,畢竟有AI加持了,誰還自己敲代碼呢。我把波形圖和GPIO中斷的函數(shù)喂給了AI。告訴他,將收到的96個數(shù)據(jù)存到一個12字節(jié)的數(shù)組里面。

還記得剛剛說的同步幀嗎? 同步幀后面有一個高電平的。我跟AI說,這個同步幀的高電平其實就是一個單位時間,后面跟來的數(shù)據(jù)幀都是按同步幀中高電平來計算的,這樣做,我們就可以一套代碼適用不同廠家的一線通了,AI絕對的聰明,同時他也肯定了我的理解。

瞅瞅,不單看明白了我的意圖,還給我增加了允許誤差,提高程序的健壯性,代碼也不含糊

voidone_wire_int_process(void){int?curr_level =?HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3);HAL_TIM_Base_Stop(&g_hTIMx);uint16_t?pulse_time = __HAL_TIM_GET_COUNTER(&g_hTIMx);
// 重新計時,準(zhǔn)備捕獲下一個電平? ? __HAL_TIM_SET_COUNTER(&g_hTIMx,?0);HAL_TIM_Base_Start(&g_hTIMx);
if?(curr_level ==?0)? ? {? ? ? ? last_high_time = pulse_time;? ? }else? ? {? ? ? ? last_low_time = pulse_time;? ? }
// 采集到一對高低電平后,直接解析if?(last_high_time)? ? {if?(state == WAIT_SYNC)? ? ? ? {if?((last_low_time > LOW_SYNC_MIN && last_low_time < LOW_SYNC_MAX) &&? ? ? ? ? ? ? ? (last_high_time > HIGH_SYNC_MIN && last_high_time < HIGH_SYNC_MAX))? ? ? ? ? ? {? ? ? ? ? ? ? ? t_unit = last_high_time;? ? ? ? ? ? ? ? state = RECEIVE_DATA;? ? ? ? ? ? ? ? bit_idx =?0;for?(int?i =?0; i <?12; i++)? ? ? ? ? ? ? ? ? ? data_buf[i] =?0;? ? ? ? ? ? }? ? ? ? }elseif?(state == RECEIVE_DATA)? ? ? ? {int?t1 = t_unit;int?t2 = t_unit *?2;int?tol1 =?TOLERANCE_INT(t1);int?tol2 =?TOLERANCE_INT(t2);// DATA(0): 低2T高1Tif?(abs(last_low_time - t2) < tol2 &&?abs(last_high_time - t1) < tol1)? ? ? ? ? ? {? ? ? ? ? ? ? ? data_buf[bit_idx /?8] <<=?1;? ? ? ? ? ? ? ? bit_idx++;? ? ? ? ? ? }// DATA(1): 低1T高2Telseif?(abs(last_low_time - t1) < tol1 &&?abs(last_high_time - t2) < tol2)? ? ? ? ? ? {? ? ? ? ? ? ? ? data_buf[bit_idx /?8] <<=?1;? ? ? ? ? ? ? ? data_buf[bit_idx /?8] |=?1;? ? ? ? ? ? ? ? bit_idx++;? ? ? ? ? ? }else? ? ? ? ? ? {? ? ? ? ? ? ? ? state = WAIT_SYNC;? ? ? ? ? ? }if?(bit_idx >= DATA_BITS_TOTAL)? ? ? ? ? ? {? ? ? ? ? ? ? ? state = WAIT_SYNC;// TODO 你可以在這里從數(shù)組獲取數(shù)據(jù)? ? ? ? ? ? }? ? ? ? }// 處理完一對高低電平后,必須立即清零? ? ? ? last_low_time =?0;? ? ? ? last_high_time =?0;? ? }}

上面是中斷里面的處理函數(shù),很多宏定義和變量初始化的部分,AI會幫我添加到頭文件,我這里就不拷貝了。

Cursor是真的棒,大家一定要多多體驗!

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

多年硬件從業(yè)經(jīng)驗,專注分享從研發(fā)到供應(yīng)鏈,再到精益制造過程中的經(jīng)驗和感悟!