加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

源碼系列:基于FPGA的數(shù)模轉(zhuǎn)換(DA)設(shè)計

04/08 11:58
4070
閱讀需 21 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。

今天給大俠帶來基于FPGA的數(shù)模轉(zhuǎn)換(DA)設(shè)計,附源碼,獲取源碼,請在“FPGA技術(shù)江湖”公眾號內(nèi)回復(fù)“?數(shù)模轉(zhuǎn)換設(shè)計源碼”,可獲取源碼文件。話不多說,上貨。

設(shè)計背景:

數(shù)模轉(zhuǎn)換器(Digital to Analog Converter)即DAC,是數(shù)字世界和模擬世界之間的橋梁。人類生活在模擬世界中,雖然數(shù)字器件及設(shè)備的比重日益增強,但是DAC的發(fā)展仍是必不可少的。從航空航天、國防軍事到民用通信、多媒體、數(shù)字信號處理等都涉及到DAC應(yīng)用。DAC基本上由4個部分組成,即權(quán)電阻網(wǎng)絡(luò)、運算放大器、基準電源模擬開關(guān)。它是一種將二進制數(shù)字量形式的離散信號轉(zhuǎn)換成以參考電壓為基準的模擬量的轉(zhuǎn)換器。

設(shè)計原理:

本設(shè)計采用串行數(shù)/模轉(zhuǎn)換芯片TLC5620,TLC5620是一個擁有四路輸出的數(shù)/模轉(zhuǎn)換器,時鐘頻率最大可達到1MHz。TLC5620芯片接口如下:

該芯片主要有以下特點:四通道8位電壓輸出DA轉(zhuǎn)換器、5V單電源供電、串行接口、高阻抗基準輸入、可編程1或2輸出范圍、同時更新設(shè)備、內(nèi)部上電復(fù)位、低功耗、半緩沖輸出。該芯片主要應(yīng)用于:可編程電源、數(shù)字控制放大器/誤差器、移動通信、自動測試設(shè)備、研發(fā)過程檢測和控制和信號合成等。

芯片接口功能表如下:

轉(zhuǎn)換公式:V = REF*(CODE/256)* (1+RNG)

V:實際電壓;REF:基準電壓;CODE:輸入8位數(shù)據(jù);RNG:范圍。

TLC5620的接口時序如下列圖所示:

圖1 LOAD控制更新(LDAC為低電平

圖2 LDAC控制更新(LDAC為低電平)

 

圖3 LOAD控制更新(使用8位串行數(shù)據(jù),LOAD為低電平)

圖4 LDAC控制更新(使用8位串行數(shù)據(jù))

如圖1所示:當(dāng)LOAD為高電平時,數(shù)據(jù)在CLK的下降沿被鎖存至DATA,只要所有數(shù)據(jù)被鎖存,則將LOAD拉低,將數(shù)據(jù)從串行輸入寄存器傳送到所選擇的DAC。如圖2所示:串行編程期間LDAC為高電平,數(shù)據(jù)在LOAD為低電平時進行鎖存,當(dāng)LDAC變?yōu)榈碗娖綍r傳送至DAC輸出。如圖3、4所示:輸入數(shù)據(jù)最高位(MSB)在前,數(shù)據(jù)傳輸使用兩個8個時鐘周期。

在本設(shè)計中運用的是圖1的工作時序:

數(shù)據(jù)通道選擇:

RNG:控制DAC輸出范圍。當(dāng)RNG為低時,輸出范圍在基準電壓和GND之間;當(dāng)RNG為高時,輸出范圍為兩倍的基準電壓和GND。

設(shè)計架構(gòu)

本設(shè)計驅(qū)動TLC5620將輸入的數(shù)字量轉(zhuǎn)換為實際的模擬量(電壓),通過四個按鍵控制四路輸出的電壓變化,每按一次,電壓值也隨之上升,同時在數(shù)碼管上也依次顯示相應(yīng)的值(依次為A1,A0,RNG,輸入DATA)。本設(shè)計采用的開發(fā)板的基準電壓為2.5V。設(shè)計架構(gòu)圖如下所示:

key_test模塊通過四個按鍵輸入的值,組合輸出兩個數(shù)據(jù),11位的wr_data是TLC_DA模塊解碼所需的數(shù)據(jù)。20位的out_data是seg_num模塊數(shù)碼管顯示所需的數(shù)據(jù)。

設(shè)計代碼

頂層top模塊代碼如下:

module top(    //頂層模塊:將各個模塊組合//外部接口  input         clk,   //系統(tǒng)時鐘50MHz   input         rst_n, //低電平復(fù)位  input   [3:0] key,   //四個按鍵組成的按鍵信號,低電平有效
  output        da_data,//DA串行接口數(shù)據(jù)  output       da_clk, //DA串行接口時鐘       output        da_ldac,//DA更新信號  output     da_load, //DA串行接口加載控制信號  output  [7:0] seg,   //數(shù)碼管段選  output  [2:0] sel   //數(shù)碼管位選);  //內(nèi)部信號:模塊內(nèi)部的接口信號,比如模塊TLC_DA的輸出信號data_in,通過內(nèi)部信號r_data與模塊key_test的輸入信號wr_data相連  wire [10:0] wr_data;  wire [19:0] out_data;  //輸入給數(shù)碼管的數(shù)據(jù)
  //模塊例化  TLC_DA TLC_DA_inst(         //輸入數(shù)字量轉(zhuǎn)換為模擬量模塊    .clk(clk),    .rst_n(rst_n),    .da_clk(da_clk),                  .da_data(da_data),    .da_ldac(da_ldac),    .da_load(da_load),    .data_in(wr_data)  );
  key_test key_test_inst(    //按鍵控制模塊    .clk(clk),    .rst_n(rst_n),    .key(key),    .wr_data(wr_data),    .out_data(out_data)  );
  seg_num seg_num_inst(      //數(shù)碼管顯示模塊    .clk(clk),    .rst_n(rst_n),    .data_in(out_data),    .seg(seg),    .sel(sel)  );
endmodule

key_test模塊代碼如下:

module key_test(     //按鍵控制模塊//端口信號:模塊的輸入輸出接口  input           clk,       //50MHZ  input           rst_n,     //低電平復(fù)位  input  [3:0]    key,       //四個按鍵組合信號
  output [10:0]    wr_data,    //輸出一幀數(shù)據(jù),為DA模塊的輸入數(shù)字量  output [19:0]    out_data    //輸出數(shù)碼管顯示數(shù)據(jù) );
  //計數(shù)器時鐘分頻   reg [30:0] cnt;  reg        clk_r;  //分頻時鐘:在消除抖動的時鐘頻率下進行按鍵的檢測  always@(posedge clk or negedge rst_n) //按鍵消抖,時間為0.2s進行一次檢測    if(!rst_n)      begin        cnt <= 0;        clk_r <= 0;      end   else if(cnt < 30'd1000_0000)        cnt <= cnt + 1'b1;    else       begin         cnt <= 0;        clk_r <= ~clk_r;       end
  //按鍵為低電平有效,當(dāng)檢測到對應(yīng)按鍵之后,相應(yīng)數(shù)值加1,并顯示相應(yīng)的通道  reg [7:0]  data;     //按鍵輸入數(shù)據(jù)  reg [1:0]  channel;  //通道選擇  reg [7:0]  key1,key2,key3,key4; //相應(yīng)四個按鍵  always@(posedge clk_r or negedge rst_n )   if(!rst_n)           begin      key1 <= 8'h00;      key2 <= 8'h00;      key3 <= 8'h00;      key4 <= 8'h00;      data <= 8'h00;      channel <= 2'b00;      end   else    case(key)      4'b1110 : begin      //按鍵1:選擇通道A,且輸入數(shù)字量加1          channel <= 2'b00;            key1 <= key1 + 1'b1;            data <= key1;            end     4'b1101 : begin     //按鍵2:選擇通道B,且輸入數(shù)字量加1            channel <= 2'b01;            key2 <= key2 + 1'b1;            data <= key2;            end     4'b1011 : begin    //按鍵3:選擇通道C,且輸入數(shù)字量加1            channel <= 2'b10;            key3 <= key3 + 1'b1;            data <= key3;            end     4'b0111 : begin   //按鍵4:選擇通道D,且輸入數(shù)字量加1            channel <= 2'b11;            key4 <= key4 + 1'b1;            data <= key4;            end     default :;    endcase
  //用賦值語句將需要的數(shù)據(jù)組合起來,在此例中將RNG默認為1  assign wr_data = {channel,1'b1,data};  assign out_data = {{3'b000,channel[1]},3'b000,channel[0],4'h1,data};
endmodule

TLC_DA模塊代碼如下:

module TLC_DA(    //輸入數(shù)字量轉(zhuǎn)換為模擬量模塊,本實驗用TLC5620 //端口信號:模塊的輸入輸出接口  input         clk,   //系統(tǒng)時鐘50MHz   input         rst_n, //低電平復(fù)位  input [10:0]  data_in, //輸入一幀數(shù)據(jù)    output         da_data, //串行數(shù)據(jù)接口  output        da_clk,  //串行時鐘接口       output reg    da_ldac, //更新控制信號  output reg     da_load  //串行加載控制接口  );
  //計數(shù)器時鐘分頻:根據(jù)芯片內(nèi)部的時序要求進行分頻  reg [30:0] cnt;  wire       da_clk_r;  //TLC 5620內(nèi)部時鐘信號  always@(posedge clk or negedge rst_n)  //滿足協(xié)議中的時鐘要求,在TLC 5620中時鐘要求不大于1MHZ    if(!rst_n)      cnt  <= 6'd0;    else        cnt <= cnt + 1'b1;
  assign da_clk_r = cnt[5];
  //接收時序狀態(tài)機      reg [2:0]  state;  reg [3:0]  cnt_da;  reg        da_data_r;  reg        da_data_en;  //限定da_data,da_clk的有效區(qū)域  always@(posedge da_clk_r or negedge rst_n)    if(!rst_n)      begin        state <= 0;        cnt_da <= 0;        da_load <= 1;        da_ldac <= 0;              da_data_r <= 1'b1;        da_data_en <= 0;      end    else      case(state)        0: state <= 1;        1: begin          da_load <= 1;          da_data_en <= 1;            if(cnt_da <= 10)              begin                cnt_da <= cnt_da + 1'b1;                case(cnt_da)                  0:  da_data_r <= data_in[10];                  1:  da_data_r <= data_in[9];                  2:  da_data_r <= data_in[8];                  3:  da_data_r <= data_in[7];                  4:  da_data_r <= data_in[6];                  5:  da_data_r <= data_in[5];                  6:  da_data_r <= data_in[4];                  7:  da_data_r <= data_in[3];                  8:  da_data_r <= data_in[2];                  9:  da_data_r <= data_in[1];                  10: da_data_r <= data_in[0];                  default:;                endcase                state <= 1;              end            else              begin                cnt_da <= 0;                state <= 2;                da_data_en <= 0;              end          end        2: begin            da_load <= 0;            state <= 3;          end        3: begin            da_load <= 1;            state <= 0;          end        default: state <= 0;      endcase
  assign da_data = (da_data_en) ? da_data_r : 1'b1;  assign da_clk  = (da_data_en)?da_clk_r : 1'b0;
endmodule

seg_num模塊代碼如下:

module seg_num(      //數(shù)碼管顯示模塊:選擇數(shù)碼管0-4共5個數(shù)碼管顯示{A1,A0,RNG,DATA}//端口信號:模塊的輸入輸出接口  input         clk,   //系統(tǒng)時鐘50MHz   input         rst_n, //低電平復(fù)位  input  [19:0]  data_in, //20位輸入數(shù)據(jù)
  output reg [7:0] seg,   //數(shù)碼管段選  output reg [2:0] sel    //數(shù)碼管位選  );
  //通過查找表的方式,將相應(yīng)位的數(shù)碼管與數(shù)據(jù)的相應(yīng)位一一對應(yīng)  reg [3:0]  num;     always@(*)    case(sel)           4: num = data_in[3:0];    //第五個數(shù)碼管顯示數(shù)據(jù)的低四位[3:0]      3: num = data_in[7:4];    //第四個數(shù)碼管顯示數(shù)據(jù)的低四位[7:4]      2: num = data_in[11:8];   //第三個數(shù)碼管顯示數(shù)據(jù)的低四位[11:8]      1: num = data_in[15:12];  //第二個數(shù)碼管顯示數(shù)據(jù)的低四位[15:12]      0: num = data_in[19:16];  //第一個數(shù)碼管顯示數(shù)據(jù)的低四位[19:16]      default:;    endcase
  //通過查找表的方式,將數(shù)據(jù)與數(shù)碼管的顯示方式一一對應(yīng)    always@(*)      case(num)      0:  seg <= 8'hC0;    //8'b1100_0000      1:  seg <= 8'hF9;  //8'b1111_1001      2:   seg <= 8'hA4;  //8'b1010_0100        3:  seg <= 8'hB0;  //8'b1011_0000      4:  seg <= 8'h99;  //8'b1001_1001      5:  seg <= 8'h92;  //8'b1001_0010      6:  seg <= 8'h82;  //8'b1000_0010      7:  seg <= 8'hF8;  //8'b1111_1000      8:  seg <= 8'h80;  //8'b1000_0000      9:  seg <= 8'h90;  //8'b1001_0000      default:seg <= 8'hFF; //8'b1111_1111    endcase
  //計數(shù)器時鐘分頻:用cnt第10位的變化作為分頻時鐘    reg [23:0]  cnt;        always@(posedge clk or negedge rst_n)     if(!rst_n)      cnt <= 4'd0;    else      cnt <= cnt + 1'b1;  //在分頻時鐘下,數(shù)碼管的0-5位依次循環(huán)  always@(posedge cnt[10] or negedge rst_n)   //分頻時鐘為2^10/50M    if(!rst_n)      sel <= 0;    else if(sel < 4)      sel <= sel + 1'b1;    else      sel <= 0;      

仿真測試

test頂層模塊測試代碼:

`timescale 1 ns/ 1 ns    //設(shè)置仿真時間單位與精度分別為1ns/1ns           //若設(shè)為`timescale 1ns/1ps  (#200 就是延時200 ns; 1ps就是仿真的精度)module test;    //測試模塊:主要是將激勵信號賦相應(yīng)的值,仿真之后觀察波形,驗證與實際功能是否一樣
  //端口信號定義,激勵信號為reg型  reg       clk;  reg     rst_n;  reg  [3:0]   key;                                                wire [7:0]  seg;  wire [2:0]   sel;
  //模塊例化                           top top(     .clk(clk),    .rst_n(rst_n),    .key(key),    .seg(seg),    .sel(sel)  );
   //初始化激勵,以及給相應(yīng)激勵賦值    initial                                                    begin                                                        clk = 0;rst_n = 0; key = 4'b1111;   //在復(fù)位階段,將激勵賦初值
    #200     rst_n = 1;      //在延時200ns后將復(fù)位信號置為1
    //實現(xiàn)按鍵1開,關(guān)    #500000  key = 4'b1110;    #500000  key = 4'b1111;
    end
  always  #10  clk = ~clk;  //時鐘的表示,即每隔10ns翻轉(zhuǎn)一次,一個周期的時間即為20ns,時鐘為1/20ns = 50MHZ
endmodule

仿真圖如下:

由于仿真時間原因,這里只測試按鍵1按下時的數(shù)碼管顯示,顯示為00100,表示通道A,RNG為1,輸入數(shù)字量為00。之后實際下板驗證,用萬用表也可測出輸入數(shù)字量對應(yīng)的電壓值。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
10M08SCM153I7G 1 Intel Corporation Field Programmable Gate Array, 8000-Cell, CMOS, PBGA153, 8 X 8 MM, 0.50 MM PITCH, ROHS COMPLIANT, MBGA-153

ECAD模型

下載ECAD模型
$25.33 查看
A3P250-FG144I 1 Microchip Technology Inc Field Programmable Gate Array, 6144 CLBs, 250000 Gates, 350MHz, CMOS, PBGA144
$21.02 查看
A3P1000-FG484I 1 Microchip Technology Inc Field Programmable Gate Array, 24576 CLBs, 1000000 Gates, 350MHz, CMOS, PBGA484
$375.77 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

任何技術(shù)的學(xué)習(xí)就好比一個江湖,對于每一位俠客都需要不斷的歷練,從初入江湖的小白到歸隱山林的隱世高人,需要不斷的自我感悟自己修煉,讓我們一起仗劍闖FPGA乃至更大的江湖。