基於stm32的2FSK數據機設計

2021-07-13 03:23:00 字數 3774 閱讀 8521

筆者的專業是通訊工程,通訊領域內數據機的設計大多數用的都是硬體電路,但是鑑於筆者對程式設計情有獨鍾(其實筆者還是懂一點電路設計知識的~),所以最終決定用stm32來設計,純程式設計實現。看起來高大上,但實際做起來不難,不過有挺多東西要考慮的,所以還是花了筆者乙個星期的時間。

廢話不多說,先來介紹下什麼是調製解調,什麼是2fsk。

在通訊系統中,包含有豐富的低頻分量的訊號稱為基帶訊號,在傳輸距離較近時,基帶訊號可以直接傳輸。但是如果要實現較遠距離的傳輸時,需要用到調製技術,也就是用較高頻率的載波與基帶訊號進行結合,然後發射出去,接收方接收到訊號後,再通過一系列方法把基帶訊號還原出來。

上面只是乙個簡單地介紹,實際上調製解調過程要更複雜得多,涉及到模擬調製和數字調製,am,fm,ask,fsk,psk,qam等調製方式和相干解調,非相干解調等解調方式,還要考慮碼間串擾,誤位元速率等傳輸效能的問題。在這裡筆者不打算一一介紹,畢竟以程式設計為主。筆者僅對數字調製中的2fsk調製原理做乙個簡單的說明。

2fsk是利用載波的頻率變化來傳遞數字資訊。在基帶訊號的控制下,2fsk由兩個不同頻率的正弦波組合而成,具體的調製過程如下:

圖1 調製過程

好了,接下來開始進入數據機的設計階段。

總的設計思路如下:

圖2 數據機的設計

首先是基帶訊號的產生,它也是我們要調製和解調的目標。基帶訊號由一連串隨機的碼元序列構成,為了模擬隨機的碼元序列,筆者用定時器設計8位的pn碼序列,碼元速率為2000b/s。定時器3定時0.5ms,每進入一次中斷,變數num加一,設定一次io引腳電平,8位pn碼只需設定8次,然後num清零。

接下來要產生載波,載波就是正弦波無疑。這裡筆者的載波頻率要求是4khz和8khz。正弦波的產生用的是stm32的dma+dac+tim2。

正弦波的資料用正弦波資料發生器產生,取樣點數64,精度12位,儲存在sine12bit陣列,但是傳送給dma的正弦波資料不是這些原始的資料,而是將這些資料進行了進一步的處理:

為什麼要這麼處理呢?在講到dac的配置時還會再提到這一點,在這裡先不做解釋。經過處理後的正弦波資料可以直接傳送到dma通道,等tim2的觸發時間一到,就可以依次把資料給到dac,轉換成正弦波輸出。筆者用dac通道2(對應pa5引腳)輸出波形,所以需要使能和配置dma2通道4,dma的配置如下:

tim2和dac的配置如下:

這裡筆者把兩個模組的配置同時放在乙個初始化函式裡面,只是圖個方便,在官方例程裡是將dac和dma的配置放在一起。這段**有兩個地方需要注意:一是tim2計數模式設為向下計數,二是使能了dac的輸出快取。設為向下計數是為了在兩個正弦波頻率切換時不會因為計數溢位而出現問題,在fsk產生環節裡還會詳細說到這一點;使能輸出快取是因為stm32的dac在輸出快取關閉時輸出阻抗太大,帶負載能力弱,在輸入捕獲時正弦波嚴重失真,故需要開啟輸出快取,但同時也存在乙個問題:使能輸出快取後,dac沒辦法使輸出達到0,這就使得原始正弦波的峰值資料丟失,導致底部失真。於是我們需要用上面的**對原始正弦波資料做乙個處理——先乘上8除以10防止峰值超過12位精度的最大值4096(不能直接乘上0.8,因為陣列儲存的資料必須是整形),然後再加上500,將正弦波資料整體抬高。

生成正弦波後自然是要把兩個正弦波組合在一起形成fsk訊號,這個組合當然不是隨意組合,是要在基帶訊號的控制下進行。**在主函式執行,如下:

while(1)迴圈裡if語句判斷基帶訊號的碼元序列,「1」對應8khz載波,「0」對應4khz載波。通過改變tim2的自動重裝載暫存器(arr)的值實現兩個載波的頻率切換。解釋一下這裡為什麼選擇140和280:取樣64個點,8khz對應的dac轉換速率為8000*64hz,那麼tim2就要每隔8000/64/72 000 000 = 1/140s觸發一次dac,故tim2的arr值為140;同樣的,4khz對應的arr值為280。在這裡還要注意:tim2的計數模式應配置為向下計數。一般例程都會把定時器配置為向上計數,但用在這裡會出現乙個問題:在基帶訊號由0變為1時,fsk訊號也要相應的從4khz正弦波跳變到8khz正弦波。我們知道向上計數模式是tim2->cnt暫存器從0開始計數,一直計到arr的值,進入中斷,然後重新清零,繼續計數直到又達到arr設定的值。。。假設fsk訊號在4khz正弦波時tim2->cnt一度計數到140以上(此時arr的值為280),突然基帶訊號變為1,fsk訊號由4khz正弦波變為8khz,arr值被設定為140,這時候cnt暫存器將一直往上計數,永遠不會停止,直到溢位(arr暫存器為16位)。實際上筆者在除錯時,當基帶訊號為「1「,輸出的fsk訊號為一條直線。把計數模式改為向下計數,問題解決。

經過上述一番折騰,調製總算是搞定了,來看看效果:

圖3 調製效果

接下來就是解調。筆者用了兩次解調才把基帶訊號完整復現出來。先來看看初步解調**,用的是tim1的輸入捕獲模組,tim1屬於高階定時器,和通用定時器的**還是有些地方不一樣的,比如輸入捕獲中斷函式名為tim1_cc_irqhandler()

選擇輸入捕獲是因為對於fsk訊號來說,它由兩個不同頻率的正弦波組成,stm32預設的高電平在2v以上,低電平在0.8v以下。通過測量從上公升沿到下降沿這段時間,與閾值100us比較(4khz的正弦波半個週期為125us,8khz的正弦波半個週期為62.5us),大於100者碼元即為「0」,反之則為「1」。

在這裡筆者小小地偷了個懶——沒有配置tim1的更新中斷,而只是配置了捕獲中斷。這是鑑於筆者的tim1初始化為:

看到了吧,0xffff,多大的數~其實也不大,只不過對於我們要捕獲的fsk訊號來說它避免了更新中斷對捕獲造成的影響,也就是說當我們捕獲到下降沿時得到的tim1->ccr1暫存器的值就是我們想得到的時間,與計數值溢位多少次並無關係。注意:當捕獲的波形頻率較高時可以這麼做,但是如果波形頻率較低時最好使能更新中斷,在更新中斷裡儲存中斷次數,得到的結果更準確。

然而這只是我們初步解調出來的結果,由於4khz與8khz之間的過渡帶影響,最終得到的碼元序列「1」的持續時間長於碼元為「0」的持續時間,訊號的碼速率不是2000b/s,所以我們需要進行二次解調。

圖4 初次解調效果(黃:基帶訊號 藍:初次解調訊號)

二次解調的關鍵在於定時器tim5的同步作用。筆者用tim5定時2khz,在初步解調訊號的邊沿處先延時150us,然後開始同步,通過判斷初步解調訊號的碼元序列,得到二次解調訊號的碼元。

圖5 有延時的二次解調過程示例圖

在tim1中斷函式裡面:

在這裡為什麼要延時150us呢?為何不在初步解調訊號的邊沿處就開始同步呢?這是考慮到初步解調訊號高電平持續的時間比低電平的長,如果不延時,則可能出現低電平碼元誤判。

圖6 無延時的二次解調示例圖

接下來就是定時器5的中斷服務函式:

圖7 二次解調結果(黃:基帶訊號 藍:二次解調訊號)

由於tim5的2khz時鐘的同步作用,得到的二次解調訊號能完整地復現基帶訊號,實現解調。至此,整個2fsk調製解調系統設計完成。

ARM開發(2)基於STM32的蜂鳴器

基於stm32的蜂鳴器 一 蜂鳴器原理 1.1 本實驗實現1個蜂鳴器間隔1s鳴叫。1.3 開發環境 mdk5 庫函式版本開發 jlink 二 實驗步驟 2.1 beep.h ifndef beep h define beep h include sys.h define beep pbout 10 ...

基於STM32的串列埠通訊

序列通訊一般是以幀格式傳輸資料,即一幀一幀的傳輸,每一幀都含有起始訊號,資料資訊以及停止資訊等。資料各個位同時傳輸,速度快,但是占用引腳資源多。eg led1602 資料按位順序傳輸,占用引腳資源少,但是速度相對較慢。一位一位傳輸 bit iic spi 串列埠通訊 單工,半雙工,全雙工 同步通訊 ...

基於STM32的恆流源設計

本設計以stm32f103rct6為主控晶元,利用mos管的恆流區特點,設計恆流源。設計電流範圍為1 300ma。基本原理圖 q2為n溝道mos管,在正常工作情況下,運放與mos管之間構成深度負反饋,使得輸入控制電壓與vr虛短,近似相等。這可以得到負載電流 3.1.電源 電路圖如圖所示 電源由 12...