文章鋪墊
我為什么要編碼
- 開發(fā)的產(chǎn)品有一個功能妓忍,需要用模擬信號對數(shù)字信息進行編碼處理磷账,編碼完成后缝裁,通過模擬量傳遞到另一個設備,然后另一個設備該信號進行解碼 治拿。這里面就有兩步轉(zhuǎn)換和兩步逆轉(zhuǎn)換:
- 發(fā)射端:將數(shù)字信息轉(zhuǎn)化數(shù)字二進制編碼信號摩泪,將數(shù)字編碼信號轉(zhuǎn)化為模擬信號。
- 接收端:模擬信號轉(zhuǎn)化為數(shù)字編碼信號劫谅,將數(shù)字編碼信號解碼為數(shù)字信息见坑。
- 對數(shù)字信號編碼模擬信號是如何轉(zhuǎn)化為數(shù)字信號的問題嚷掠,在此文章中不提及。
正文
常用的編碼方式
- 本來是不需要介紹這一小節(jié)鳄梅,不過筆者在網(wǎng)上查找該編碼的詳細介紹時叠国,感覺講的都不是很清楚,要么就是不夠簡練戴尸,廢話一堆粟焊,要么就是太簡練,到了看不懂的程度孙蒙,筆者有時候都在懷疑作者自己有沒有搞明白项棠。
- 兩種編碼的統(tǒng)一之處:頻率穩(wěn)定的時鐘源(下圖時序圖中的虛線)
- 參考圖
圖片來自網(wǎng)絡,點擊可查看來源 - 曼徹斯特編碼
- 文字敘述:時鐘源之間如果是上升沿挎峦,則表示0香追,下降沿則表示1。當然坦胶,你也可以反過來透典。
- 規(guī)律:看兩個虛線之間,如果是下降顿苇,對應的數(shù)字信號欄就是1峭咒,反之為0。
圖片來自網(wǎng)絡纪岁,點擊可看來源
- 差分曼徹斯特編碼
- 時鐘源開始信號為標準凑队,如果在虛線處保持電平,則表示為1幔翰,如果在虛線處發(fā)生了翻轉(zhuǎn)漩氨,則表示為0。
- 規(guī)律:數(shù)字信號欄遗增,第一個數(shù)字為1叫惊,左側(cè)虛線對應的差分編碼電平?jīng)]有反轉(zhuǎn),第二個數(shù)字是0做修,左側(cè)虛線信號發(fā)生了反轉(zhuǎn)霍狰,如此進行。
圖片來自上上圖統(tǒng)一網(wǎng)絡蚓耽,筆者做了些粗暴的編輯
使用差分曼徹斯特編碼的好處
- 在無法提供準確渠牲,且穩(wěn)定的系統(tǒng)時鐘的情況下旋炒,采用該編碼,只需要區(qū)分1倍時鐘長度和2倍時鐘長度签杈。
- 延續(xù)上一項瘫镇,設備的發(fā)射端和接收端不再需要協(xié)商一個標準的傳輸速率(比如通信里面常用的波特率)鼎兽,發(fā)射端只需要在數(shù)據(jù)的開頭,隨意發(fā)射一段相對固定頻率的信號铣除,作為1倍時鐘長度谚咬,接收端則可以計算出2倍時鐘長度
算法優(yōu)化
- 上文說道,曼徹斯特編碼只需要1倍時鐘長度和2倍時鐘長度的區(qū)分尚粘,就可以對數(shù)據(jù)進行編碼择卦,這種說法是有前提的,不知道細心的讀者發(fā)現(xiàn)了沒有郎嫁。差分曼徹斯特編碼秉继,沒有反轉(zhuǎn)的情況用0表示,有反轉(zhuǎn)的情況用1表示泽铛。那么如果出現(xiàn)連續(xù)多個0的情況尚辑,電平可能一直不會發(fā)生反轉(zhuǎn),這時候還需要區(qū)分3倍時鐘長度盔腔,4倍杠茬,甚至更多......
- 于是還是要引出IBM公司于1983年發(fā)明的8B/10B方式。應用該方法弛随,大大彌補了連續(xù)多個0出現(xiàn)的情況瓢喉,數(shù)據(jù)的傳輸速率和準確性都有了比較大的提高。
- 8B/10B編碼枚舉量太撵幽,下圖給出4B/5B的編碼灯荧,感受一下即可:
附上C語言代碼
- 編碼
說明:該編碼的代碼是項目里面的源代碼片段,有一些別的算法影子夾雜在里面盐杂,主要是有8B/10B的編碼算法和容差處理逗载,強烈建議看看就行了,不要copy链烈。
/*曼徹斯特差分編碼
輸入: str0:原始二進制數(shù)據(jù)
no_flip_len:無翻轉(zhuǎn)的數(shù)據(jù)長度
輸出: str1:二進制流數(shù)據(jù)
bit_len:二進制數(shù)據(jù)長度
*/
void Dif_Manchester1(u8* str0, u8* str1,u16 no_flip_len,u8* bit_len)
{
u16 avg=0;
u16 count=1;
u16 count_0=0;
u16 j=0;
avg = averge_range(str0);
while(count<no_flip_len)
{
if(!(*str0^*(++str0)))
{
count++;
}else
{
if((count%avg)>(avg*2/3))//此處做了容差處理
{
count_0 = (count / avg)+1;
}else
{
count_0 = (count / avg);
}
if(count_0 >= 2)//此處做了8B/10B編碼處理
{
str1[j] = 0;
j += 1;
}
str1[j] = 1;
j += 1;
count = 1;
}
}
*bit_len = j - 1;
}
- 解碼就不寫了厉斟,理解了算法,代碼只是體力活
CrekerLi强衡,2017年9月2日修改以前的筆記擦秽。