動(dòng)與調(diào)試避坑)
簡(jiǎn)介AD9959開(kāi)發(fā)資源包面向STM32嵌入式開(kāi)發(fā)者與電子工程師提供圍繞ADI高性能DDS芯片AD9959的完整信號(hào)發(fā)生方案涵蓋可直接移植的驅(qū)動(dòng)代碼、技術(shù)資料與電路原理圖適用于頻率特性測(cè)試、多路信號(hào)發(fā)生等實(shí)際工程場(chǎng)景。壓縮包共223個(gè)文件大小約11.97MB主體為C源文件、頭文件和Keil MDK工程文件基于STM32F10x標(biāo)準(zhǔn)外設(shè)庫(kù)包含定時(shí)器、RCC、ADC、I2C、SPI等模塊配置代碼同時(shí)附有PDF原理圖與設(shè)計(jì)文檔、hex燒錄文件及編譯調(diào)試過(guò)程文件可在工程中直接打開(kāi)、編譯和燒錄便于對(duì)照源碼逐行理解DDS控制流程。目前已有4581人學(xué)習(xí)/瀏覽是同類(lèi)DDS開(kāi)發(fā)資料中較為完整的打包方案。借助包內(nèi)代碼可掌握通過(guò)GPIO或SPI接口配置AD9959頻率、相位和幅度的寄存器操作方法原理圖則呈現(xiàn)電源管理、濾波與信號(hào)調(diào)理電路的設(shè)計(jì)要點(diǎn)配套資料中的頻率特性測(cè)試案例和底層驅(qū)動(dòng)工程組織方式能為實(shí)際項(xiàng)目開(kāi)發(fā)、排錯(cuò)與二次開(kāi)發(fā)提供直接參考。1 一套能直接落地的四通道DDS工程AD9959不只是寫(xiě)個(gè)頻率字調(diào)過(guò)AD9959的人多半有這種體驗(yàn)看數(shù)據(jù)手冊(cè)覺(jué)得寄存器就那么幾個(gè)寫(xiě)個(gè)SPI把頻率字懟進(jìn)去就完事結(jié)果上電后示波器上看不到波形或者四路輸出相位亂跳。這個(gè)工程資源真正解決的問(wèn)題是把“原理圖設(shè)計(jì)、寄存器配置、STM32驅(qū)動(dòng)代碼”三段鏈路一次打通拿到手就能照著自己畫(huà)板子、燒程序、出波形。它適合三類(lèi)人要做多通道信號(hào)源的學(xué)生、搞超聲或相控陣驅(qū)動(dòng)的工程師、還有想把DDS當(dāng)可編程時(shí)鐘源用的硬件愛(ài)好者。整套資料以原理圖和源碼為主配合寄存器配置說(shuō)明屬于能直接抄作業(yè)的工程包不是純理論文檔。2 硬件架構(gòu)拆解原理圖里決定成敗的鏈路2.1 電源樹(shù)設(shè)計(jì)三個(gè)電壓域的順序與接地AD9959是數(shù)?;旌闲酒韴D上最容易被低估的就是電源。工程里采用的是典型的“主電源進(jìn)LDO再分兩路”方案5V輸入經(jīng)過(guò)一級(jí)降壓到3.3V供給數(shù)字IO和MCU側(cè)3.3V再經(jīng)第二級(jí)LDO降到1.8V模擬電壓?jiǎn)为?dú)給DDS核心的模擬部分供電。數(shù)字3.3V和模擬1.8V之間用磁珠或0歐電阻做單點(diǎn)連接模擬地和數(shù)字地在DDS芯片下方匯合成一個(gè)點(diǎn)避免地環(huán)路把DAC的雜散帶到輸出端。這里的關(guān)鍵是上電順序。工程源碼頭文件里對(duì)PWR_DOWN引腳做了延時(shí)控制MCU上電后先拉高復(fù)位再等LDO輸出穩(wěn)定最后才釋放DDS的硬件復(fù)位。很多人在調(diào)試時(shí)遇到DDS輸出全是直流分量查了一圈發(fā)現(xiàn)是復(fù)位釋放過(guò)早芯片內(nèi)部的寄存器還沒(méi)完成自校準(zhǔn)。這個(gè)坑在原理圖評(píng)審階段看不出來(lái)只能靠時(shí)序控制來(lái)兜底。2.2 參考時(shí)鐘鏈路沒(méi)有內(nèi)部PLL別指望倍頻原理圖上AD9959的REFCLK引腳接的是100MHz有源晶振經(jīng)過(guò)AC耦合電容進(jìn)入芯片。這個(gè)選擇值得注意AD9959內(nèi)部沒(méi)有集成PLL系統(tǒng)時(shí)鐘SYSCLK直接等于參考時(shí)鐘頻率想要更高輸出頻率就得換更高頻的晶振或外部時(shí)鐘源。工程里沒(méi)有用時(shí)鐘芯片做倍頻而是老老實(shí)實(shí)讓SYSCLK跑100MHz四條通道的最大輸出頻率按奈奎斯特限制在50MHz以內(nèi)實(shí)際原理圖上的低通濾波器截止頻率也按這個(gè)來(lái)設(shè)計(jì)。晶振旁邊通常還會(huì)引出一路SYNC_CLK信號(hào)到MCU。這個(gè)引腳是SYSCLK的四分頻輸出在需要多片DDS同步或者想讓MCU感知DDS時(shí)序時(shí)非常有用。工程里SYNC_CLK只接到了MCU的輸入捕獲引腳用于調(diào)試時(shí)確認(rèn)SYSCLK是否真正起振。如果你拿到板子后懷疑晶振沒(méi)工作直接量這個(gè)引腳是最快的判斷手段。2.3 SPI與控制引腳CS、SCLK、SDIO、IO_UPDATE的優(yōu)先級(jí)原理圖的SPI部分走線很短這符合AD9959的工作特點(diǎn)。芯片支持單線SDIO和四線SDIO兩種串行模式工程源碼默認(rèn)用的是四線模式四個(gè)數(shù)據(jù)腳DIO0到DIO3全部接到MCU的GPIO上這樣每條寄存器寫(xiě)指令可以一次寫(xiě)入32位數(shù)據(jù)比單線模式快四倍。代價(jià)是按四線模式的電平要求來(lái)配置IO狀態(tài)初始化時(shí)CS先拉高、SCLK空閑電平為高這個(gè)時(shí)序細(xì)節(jié)在源碼的SPI初始化函數(shù)里寫(xiě)得很清楚。IO_UPDATE引腳是整套同步機(jī)制的核心原理圖上直接從MCU的GPIO引出沒(méi)有加RC濾波。這個(gè)引腳必須保持干凈任何毛刺都會(huì)導(dǎo)致寄存器緩沖區(qū)的意外加載。工程里的做法是把IO_UPDATE和其他控制引腳分開(kāi)走線避免和SCLK長(zhǎng)距離平行減少串?dāng)_。FPGA或MCU側(cè)控制時(shí)一般情況下先寫(xiě)完整組寄存器再統(tǒng)一拉一次IO_UPDATE讓四個(gè)通道的配置同時(shí)生效。2.4 DAC輸出鏈路差分電流如何變成可用信號(hào)AD9959的DAC輸出是互補(bǔ)電流型每個(gè)通道有兩根輸出腳單獨(dú)一根對(duì)地是電流兩根之間是差分信號(hào)。原理圖上每?jī)陕份敵鱿冉?jīng)過(guò)一對(duì)電阻把電流轉(zhuǎn)成電壓再接一階LC低通濾波器最后通過(guò)SMA座輸出。電阻取值直接影響輸出幅度工程里用的是200歐姆對(duì)地差分阻抗400歐姆滿量程輸出大約對(duì)應(yīng)-4dBm左右適合直接進(jìn)頻譜儀或做下變頻實(shí)驗(yàn)。低通濾波器的截止頻率放在80MHz左右略高于最大輸出頻率的1.5倍這樣既能抑制DAC的鏡像頻率又不會(huì)讓目標(biāo)信號(hào)衰減太多。如果你的應(yīng)用需要更高輸出頻率原理圖里的LC參數(shù)要重新計(jì)算特別是電感值頻率往上走之后寄生電容的影響會(huì)變得非常明顯。3 軟件工程結(jié)構(gòu)拿到源碼包先從哪里讀起3.1 目錄結(jié)構(gòu)與關(guān)鍵文件定位一個(gè)能跑的STM32工程的目錄結(jié)構(gòu)通常是這樣這個(gè)資源包也不例外Project/ ├── Core/ │ ├── Inc/ │ │ ├── ad9959.h │ │ ├── spi_driver.h │ │ └── main.h │ └── Src/ │ ├── main.c │ ├── ad9959.c │ └── spi_driver.c ├── Hardware/ │ ├── AD9959_SCH.pdf │ └── AD9959_EDA_Source/ └── Docs/ ├── AD9959_Datasheet_CN.pdf └── 寄存器配置說(shuō)明.md先看Hardware目錄下的原理圖PDF確認(rèn)你手上的板子和這份源碼是同一套硬件定義重點(diǎn)關(guān)注電源引腳、參考時(shí)鐘頻率和IO_UPDATE接到了MCU的哪個(gè)端口。然后打開(kāi)ad9959.c這個(gè)文件里是DDS相關(guān)的全部驅(qū)動(dòng)代碼包括初始化、頻率設(shè)置、相位設(shè)置和幅度設(shè)置。最后才是main.cmain里一般只做命令解析和狀態(tài)機(jī)調(diào)度。資源包里的寄存器配置說(shuō)明文檔建議從頭到尾讀一遍里面把每一條初始化寄存器的值都注釋了對(duì)應(yīng)功能比直接看數(shù)據(jù)手冊(cè)省力很多。文檔里寫(xiě)的寄存器地址和位定義和源碼頭文件保持一致改代碼時(shí)兩邊對(duì)照著看不容易出錯(cuò)。3.2 寄存器映射與位定義頭文件ad9959.h里定義了芯片的全部寄存器地址和關(guān)鍵位核心部分長(zhǎng)這樣/* AD9959寄存器地址定義 */ #define AD9959_CSR 0x00 /* 通道選擇寄存器 */ #define AD9959_FR1 0x01 /* 功能配置寄存器1 */ #define AD9959_FR2 0x02 /* 功能配置寄存器2 */ #define AD9959_CFR 0x03 /* 通道功能配置寄存器 */ #define AD9959_CH_CFR 0x04 /* 通道CFR起始地址 */ #define AD9959_CH_FTW 0x07 /* 頻率調(diào)諧字起始地址 */ #define AD9959_CH_POW 0x0B /* 相位偏移字起始地址 */ #define AD9959_CH_ACR 0x0E /* 幅度控制字起始地址 */ /* CSR中通道選擇位 */ #define CSR_CH1 0x01 #define CSR_CH2 0x02 #define CSR_CH3 0x04 #define CSR_CH4 0x08 #define CSR_ALL_CHANNELS 0x0F寄存器地址映射是整個(gè)驅(qū)動(dòng)的基礎(chǔ)。CSR用來(lái)選擇當(dāng)前要操作的通道FR1和FR2是整個(gè)芯片的全局配置CFR則是每個(gè)通道獨(dú)立的功能配置。寫(xiě)通道頻率字時(shí)先通過(guò)CSR選中對(duì)應(yīng)通道再往CH_FTW地址寫(xiě)4字節(jié)數(shù)據(jù)DDS會(huì)在IO_UPDATE上升沿把這4字節(jié)加載到工作寄存器。參數(shù)說(shuō)明CSR_ALL_CHANNELS0x0F表示一次操作同時(shí)作用于四個(gè)通道多通道同步時(shí)特別有用省去四次CSR切換。CH_FTW后連續(xù)4個(gè)地址對(duì)應(yīng)四路通道因?yàn)槊柯奉l率字占4字節(jié)實(shí)際寫(xiě)入時(shí)地址是按通道自動(dòng)偏移的。每個(gè)寄存器寫(xiě)入都是先發(fā)地址字節(jié)再發(fā)數(shù)據(jù)字節(jié)這個(gè)順序在spi_driver里固定。3.3 SPI底層驅(qū)動(dòng)的兩種模式工程里兩種SPI驅(qū)動(dòng)方式都實(shí)現(xiàn)了一種用MCU硬件SPI外設(shè)一種用GPIO模擬時(shí)序。硬件SPI寫(xiě)法效率高但AD9959的四線模式需要在每次傳輸前把IO方向切成輸入或輸出硬件SPI處理起來(lái)有點(diǎn)繞所以工程默認(rèn)用的是GPIO模擬void spi_write_frame(uint8_t addr, uint32_t data, uint8_t channel_sel) { uint8_t i; uint8_t addr_with_sel ((channel_sel 0x0F) 4) | (addr 0x0F); CS_LOW(); /* 地址階段一次傳輸7位地址和通道選擇 */ for (i 0; i 8; i) { SCLK_LOW(); if (addr_with_sel 0x80) SDIO_HIGH(); else SDIO_LOW(); SCLK_HIGH(); addr_with_sel 1; } /* 數(shù)據(jù)階段32位數(shù)據(jù)按MSB先發(fā) */ for (i 0; i 32; i) { SCLK_LOW(); if (data 0x80000000) SDIO_HIGH(); else SDIO_LOW(); SCLK_HIGH(); data 1; } CS_HIGH(); }這段代碼把地址字節(jié)的高四位用作通道選擇低四位放寄存器地址正好對(duì)應(yīng)AD9959的指令格式。**參數(shù)說(shuō)明**channel_sel傳入的是CSR中的通道掩碼比如CSR_CH20x02就只操作第2通道data是完整的32位寄存器值頻率字、相位字、幅度字都統(tǒng)一走這個(gè)函數(shù)區(qū)別只是調(diào)用時(shí)傳入的地址和值不同。GPIO模擬的好處是時(shí)序完全可控不依賴SPI外設(shè)的極性配置出問(wèn)題時(shí)用邏輯分析儀抓波形很容易對(duì)照手冊(cè)排查。4 核心代碼拆解一次波形更新的完整鏈路4.1 上電初始化序列初始化代碼的目標(biāo)是讓DDS進(jìn)入已知狀態(tài)四通道關(guān)閉、輸出靜音等MCU配置好再逐個(gè)打開(kāi)void ad9959_init(void) { /* 硬件復(fù)位拉低復(fù)位引腳至少10us */ RESET_LOW(); delay_us(20); RESET_HIGH(); delay_us(10); /* 全局配置關(guān)閉四倍頻使能SYNC_CLK輸出 */ spi_write_frame(AD9959_FR1, 0x00C00000, CSR_ALL_CHANNELS); /* 通道配置DAC電流設(shè)為中檔關(guān)閉通道使能 */ spi_write_frame(AD9959_CH_CFR, 0x00000000, CSR_ALL_CHANNELS); /* 清空所有通道頻率字和相位字 */ spi_write_frame(AD9959_CH_FTW, 0x00000000, CSR_ALL_CHANNELS); spi_write_frame(AD9959_CH_POW, 0x00000000, CSR_ALL_CHANNELS); /* 統(tǒng)一觸發(fā)IO_UPDATE讓上述配置生效 */ io_update_pulse(); }初始化里最后一步的io_update_pulse是必須的。前面所有spi_write_frame操作都只是往緩沖區(qū)寫(xiě)數(shù)據(jù)只有IO_UPDATE上升沿才會(huì)把緩沖數(shù)據(jù)真正加載進(jìn)芯片的工作寄存器。很多人第一次調(diào)這個(gè)芯片寫(xiě)了寄存器后直接讀發(fā)現(xiàn)讀回來(lái)全是0就是因?yàn)闆](méi)觸發(fā)IO_UPDATE。**參數(shù)說(shuō)明**FR1寫(xiě)入0x00C00000高字節(jié)里的位表示使能SYNC_CLK并關(guān)閉片上倍頻這個(gè)值要和原理圖上的100MHz參考時(shí)鐘匹配如果你的板子時(shí)鐘頻率不同這里需要調(diào)整。CH_CFR里清0表示DAC輸出電流默認(rèn)值、不使能任何通道屬于安全啟動(dòng)狀態(tài)。4.2 頻率字、相位字、幅度字的計(jì)算與寫(xiě)入AD9959用32位頻率調(diào)諧字FTW控制輸出頻率計(jì)算公式是FTW (f_out / SYSCLK) x 2^32。工程里封裝了浮點(diǎn)轉(zhuǎn)整數(shù)的計(jì)算函數(shù)uint32_t ad9959_calc_ftw(double freq_hz) { double sysclk 100.0e6; /* 與原理圖晶振一致 */ double ratio freq_hz / sysclk; uint32_t ftw (uint32_t)(ratio * 4294967296.0); return ftw; } void ad9959_set_freq(uint8_t ch, double freq_hz) { uint32_t ftw ad9959_calc_ftw(freq_hz); spi_write_frame(AD9959_CH_FTW (ch - 1) * 1, ftw, ch_sel(ch)); io_update_pulse(); }相位偏移字和幅度字走同樣的流程不同的是它們不是32位全用。相位字是14位有效值寫(xiě)入時(shí)左對(duì)齊到高14位幅度字是10位有效值同樣左對(duì)齊。工程里專(zhuān)門(mén)寫(xiě)了兩個(gè)函數(shù)處理這種對(duì)齊直接傳0到16383的相位值或0到1023的幅度值函數(shù)內(nèi)部幫你移位。**參數(shù)說(shuō)明**AD9959每通道頻率字地址連續(xù)ch傳入1到4地址計(jì)算時(shí)ch-1就是通道偏移。計(jì)算FTW時(shí)一定要用實(shí)際的SYSCLK頻率如果晶振標(biāo)稱100MHz但實(shí)際偏了100ppm輸出頻率也會(huì)有同等比例的偏差窄帶應(yīng)用里這個(gè)誤差不可忽略。4.3 IO_UPDATE時(shí)序什么時(shí)候觸發(fā)最穩(wěn)多通道同步是這個(gè)芯片的加分項(xiàng)但同步效果完全取決于IO_UPDATE的使用方式void ad9959_set_freq_all_channels(double f1, double f2, double f3, double f4) { /* 第一階段只寫(xiě)緩沖區(qū)不觸發(fā)更新 */ spi_write_frame(AD9959_CH_FTW 0, ad9959_calc_ftw(f1), CSR_CH1); spi_write_frame(AD9959_CH_FTW 1, ad9959_calc_ftw(f2), CSR_CH2); spi_write_frame(AD9959_CH_FTW 2, ad9959_calc_ftw(f3), CSR_CH3); spi_write_frame(AD9959_CH_FTW 3, ad9959_calc_ftw(f4), CSR_CH4); /* 第二階段統(tǒng)一觸發(fā)IO_UPDATE */ io_update_pulse(); }這段代碼的順序是四通道同步的玄學(xué)所在。如果每寫(xiě)完一個(gè)通道就觸發(fā)一次IO_UPDATE四個(gè)通道的頻率更新點(diǎn)會(huì)散布在幾十微秒的時(shí)間窗口里相位關(guān)系全亂。正確做法是把所有寄存器的寫(xiě)入當(dāng)作事務(wù)處理全部寫(xiě)完再提交。**參數(shù)說(shuō)明**io_update_pulse是MCU的GPIO拉高再拉低高電平持續(xù)時(shí)間建議保持在10ns以上即可工程里為了穩(wěn)妥延時(shí)至1us哪怕再小的電容負(fù)載也足夠。SYNC_CLK信號(hào)如果引到MCU可以在IO_UPDATE之前等待一個(gè)SYNC_CLK邊沿讓所有DDS芯片共享同一個(gè)參考時(shí)刻對(duì)于多片級(jí)聯(lián)同步尤為重要。4.4 串口指令解析快速驗(yàn)證波形的小例子資源包里的main.c還有一個(gè)串口指令解析示例通過(guò)UART接收類(lèi)似“F1 1000000”的文本解析后調(diào)用頻率設(shè)置函數(shù)void uart_command_handler(char *cmd) { uint8_t ch 0; double freq 0.0; if (sscanf(cmd, F%d %lf, ch, freq) 2) { if (ch 1 ch 4) { ad9959_set_freq(ch, freq); printf(CH%d set to %.2f Hz\r\n, ch, freq); } } }這個(gè)處理函數(shù)放在串口中斷的環(huán)形緩沖區(qū)里每次完整收到一行就調(diào)用一次。頻率值用double類(lèi)型傳參1Hz步進(jìn)在100MHz系統(tǒng)時(shí)鐘下完全可分辨32位頻率字對(duì)1Hz的分辨率是100MHz / 2^32 ≈ 0.023Hz實(shí)際精度遠(yuǎn)超需求。這個(gè)指令接口留下的擴(kuò)展點(diǎn)很清晰后面加掃頻功能時(shí)只需要擴(kuò)展命令格式。5 避坑記錄上電不輸出波形的排查清單5.1 上電與時(shí)鐘相關(guān)的坑現(xiàn)象一DDS輸出始終是直流電平完全沒(méi)有正弦波。原因是初始化代碼寫(xiě)完后沒(méi)有觸發(fā)IO_UPDATE寄存器緩沖區(qū)的內(nèi)容永遠(yuǎn)沒(méi)進(jìn)工作區(qū)。工程代碼里如果是手動(dòng)單步調(diào)試很容易跳過(guò)這個(gè)函數(shù)。解決方法是檢查init函數(shù)結(jié)尾和每次set函數(shù)的結(jié)尾確保都調(diào)用了io_update_pulse。如果用的是別人改過(guò)的代碼全工程搜一下這個(gè)函數(shù)名看是否有地方把它注釋掉了。現(xiàn)象二頻率設(shè)置值和示波器實(shí)測(cè)值差一大截比如設(shè)置10MHz實(shí)際輸出只有9.6MHz。這是典型的SYSCLK實(shí)際頻率和代碼計(jì)算值不一致。工程假定的是100MHz參考時(shí)鐘但如果原理圖實(shí)際用的是80MHz晶振代碼里sysclk變量沒(méi)跟著改FTW計(jì)算全盤(pán)偏差。解決辦法是先量REFCLK引腳上的實(shí)際頻率再回頭改ad9959_calc_ftw里的sysclk常量。還有一種少見(jiàn)情況是晶振旁邊的負(fù)載電容焊錯(cuò)導(dǎo)致起振頻率偏移幾十ppm對(duì)高精度應(yīng)用影響明顯。現(xiàn)象三只有一個(gè)通道輸出正常其他通道靜音。AD9959的每個(gè)通道都有獨(dú)立的通道使能位位于該通道的CFR寄存器中。初始化時(shí)如果只使能了通道1其他通道自然沒(méi)輸出。排查時(shí)逐通道寫(xiě)CFR讀數(shù)確認(rèn)使能位是否正確順便檢查CSR通道選擇掩碼有沒(méi)有寫(xiě)錯(cuò)。5.2 SPI與寄存器寫(xiě)入相關(guān)的坑現(xiàn)象四SPI寫(xiě)完寄存器后再讀數(shù)據(jù)全對(duì)不上。優(yōu)先懷疑CS和SCLK的時(shí)序關(guān)系。GPIO模擬方式下常見(jiàn)的錯(cuò)誤是SCLK空閑電平極性弄反。工程里默認(rèn)配置是SCLK空閑為低、數(shù)據(jù)在上升沿采樣如果你參考的數(shù)據(jù)手冊(cè)是英文原版注意看串行時(shí)序圖里SCLK的默認(rèn)極性。邏輯分析儀掛上抓一次寫(xiě)操作波形對(duì)照手冊(cè)時(shí)序圖逐bit檢查比自己瞎試快得多。現(xiàn)象五四通道輸出有相位差而且每次上電都不一樣。這個(gè)現(xiàn)象通常源自IO_UPDATE觸發(fā)的時(shí)機(jī)不統(tǒng)一或者四線模式下DIO引腳方向切換時(shí)有毛刺。解決辦法是嚴(yán)格遵循“先寫(xiě)全部緩沖區(qū)最后統(tǒng)一IO_UPDATE”的流程。如果已經(jīng)這樣做了還不同步檢查SYNC_CLK是否接好多片DDS級(jí)聯(lián)時(shí)所有片的SYNC_CLK要接到同一個(gè)外部參考保證內(nèi)部時(shí)序?qū)R。提示排查寄存器問(wèn)題時(shí)讀回驗(yàn)證是最后的手段但不要在IO_UPDATE之前讀緩沖區(qū)和工作區(qū)不一致時(shí)讀回來(lái)的值沒(méi)有任何參考意義。6 二次開(kāi)發(fā)方向把固定頻率輸出改成線性掃頻拿到手的第一版工程只能設(shè)置固定頻率如果要做掃頻信號(hào)源或雷達(dá)回波模擬就得自己加一個(gè)掃頻狀態(tài)機(jī)。改造思路不復(fù)雜在定時(shí)器中斷里按步進(jìn)間隔更新FTW每次更新前計(jì)算當(dāng)前頻率值重走“寫(xiě)寄存器、拉IO_UPDATE”的鏈路。void sweep_timer_isr(void) { if (sweep_enabled) { current_freq sweep_step; if (current_freq sweep_stop) current_freq sweep_start; ad9959_set_freq(sweep_channel, current_freq); } }這個(gè)定時(shí)器中斷頻率決定掃頻的連續(xù)程度。定時(shí)器設(shè)在100us觸發(fā)一次每步頻率步進(jìn)設(shè)成100Hz就能得到從10MHz到20MHz、周期1秒的線性掃頻。驗(yàn)證時(shí)用示波器的余輝模式觀察掃頻包絡(luò)理想情況能看到一個(gè)完整的正弦波幅度包絡(luò)從低到高再折返配合頻譜儀能看到頻率譜線隨時(shí)間連續(xù)移動(dòng)。改代碼時(shí)有兩點(diǎn)值得留意一是定時(shí)器中斷里調(diào)用ad9959_set_freq會(huì)連帶觸發(fā)IO_UPDATE如果中斷頻率過(guò)高SPI傳輸占用時(shí)間會(huì)擠占主循環(huán)建議把掃頻計(jì)算和SPI寫(xiě)入拆到兩個(gè)優(yōu)先級(jí)中斷里只做頻率累加和標(biāo)志位賦值主循環(huán)里統(tǒng)一執(zhí)行寄存器寫(xiě)入。二是掃頻過(guò)程中相位連續(xù)性取決于每次FTW更新的步進(jìn)量步進(jìn)越小相位跳變?cè)讲幻黠@這在調(diào)頻連續(xù)波雷達(dá)的鋸齒波模擬里特別關(guān)鍵。調(diào)試這個(gè)功能時(shí)我吃過(guò)一次虧。最初我把頻率步進(jìn)設(shè)成1MHz定時(shí)器100us觸發(fā)一次示波器上看到的不是連續(xù)掃頻而是一串離散的點(diǎn)頻后來(lái)把步進(jìn)降到1kHz波形立刻連續(xù)了。從那以后我每次做掃頻類(lèi)功能都先估算一下頻率變化率和更新率的比值再確定步進(jìn)量不再想當(dāng)然地隨手填參數(shù)。這個(gè)工程給你的是一套可運(yùn)行的基礎(chǔ)框架真正的價(jià)值在于從單頻到掃頻、從單通道到四通道同步的改造路徑足夠短按上述思路改完第一版掃頻就能體會(huì)到DDS這類(lèi)芯片在信號(hào)生成上的靈活之處。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取