色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 簡易電壓表設(shè)計(jì)

          簡易電壓表設(shè)計(jì)

          作者: 時間:2023-12-13 來源:電子森林 收藏

          實(shí)驗(yàn)任務(wù)

          • 任務(wù):基于核心板 和 底板 完成簡易設(shè)計(jì)并觀察調(diào)試結(jié)果
          • 要求:通過底板上的串行模數(shù)轉(zhuǎn)換器ADC芯片測量可調(diào)電位計(jì)輸出電壓,并將電壓信息顯示在核心板的數(shù)碼管上。
          • 解析:通過編程驅(qū)動串行ADC芯片,得到數(shù)字量化的電壓信息,將量化的數(shù)字信息轉(zhuǎn)換成BCD碼形式,同時驅(qū)動獨(dú)立數(shù)碼管將電壓值顯示出來。

          實(shí)驗(yàn)?zāi)康?/h4>

          在基礎(chǔ)數(shù)字電路實(shí)驗(yàn)部分我們已經(jīng)掌握了驅(qū)動獨(dú)立數(shù)碼管的原理及方法,本實(shí)驗(yàn)主要學(xué)習(xí)模數(shù)轉(zhuǎn)換器ADC的相關(guān)知識,串行(SPI接口)ADC芯片ADC081S101的驅(qū)動設(shè)計(jì),同時學(xué)習(xí)二進(jìn)制數(shù)轉(zhuǎn)換BCD碼的設(shè)計(jì)方法。

          本文引用地址:http://cafeforensic.com/article/202312/453845.htm
          • 學(xué)習(xí)模數(shù)轉(zhuǎn)換器ADC的相關(guān)知識
          • 串行(SPI接口)ADC芯片ADC081S101的驅(qū)動設(shè)計(jì)
          • 學(xué)習(xí)二進(jìn)制數(shù)轉(zhuǎn)換BCD碼的設(shè)計(jì)方法
          • 完成簡易設(shè)計(jì)實(shí)現(xiàn)

          設(shè)計(jì)框圖

          根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成三個功能模塊實(shí)現(xiàn),

          • ADC081S101driver: 驅(qū)動SPI接口ADC芯片實(shí)現(xiàn)模擬電壓信號采集。 * bintobcd:將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成BCD碼的方法。 * Segmentled:通過驅(qū)動獨(dú)立式數(shù)碼管將電壓數(shù)據(jù)顯示出來。

          Top-Down層次設(shè)計(jì)

           

          模塊結(jié)構(gòu)設(shè)計(jì)

          實(shí)驗(yàn)原理

          ADC介紹

          數(shù)字系統(tǒng),是用數(shù)字信號完成對數(shù)字量進(jìn)行算術(shù)運(yùn)算和邏輯運(yùn)算的電路稱為數(shù)字電路,或數(shù)字系統(tǒng)。而我們生活的世界是模擬的,想要讓數(shù)字系統(tǒng)幫我們處理我們模擬世界的問題,就需要一個橋梁來溝通數(shù)字系統(tǒng)和模擬系統(tǒng)。

          模擬數(shù)字系統(tǒng)通信

          模數(shù)轉(zhuǎn)換器即A/D轉(zhuǎn)換器,或簡稱ADC,通常是指一個將模擬信號轉(zhuǎn)變?yōu)閿?shù)字信號的電子元件。通常的模數(shù)轉(zhuǎn)換器是將一個輸入電壓信號轉(zhuǎn)換為一個輸出的數(shù)字信號。由于數(shù)字信號本身不具有實(shí)際意義,僅僅表示一個相對大小。故任何一個模數(shù)轉(zhuǎn)換器都需要一個參考模擬量作為轉(zhuǎn)換的標(biāo)準(zhǔn),比較常見的參考標(biāo)準(zhǔn)為最大的可轉(zhuǎn)換信號大小。而輸出的數(shù)字量則表示輸入信號相對于參考信號的大小。

          數(shù)模轉(zhuǎn)換器,又稱D/A轉(zhuǎn)換器,簡稱DAC,它是把數(shù)字量轉(zhuǎn)變成模擬的器件。D/A轉(zhuǎn)換器基本上由4個部分組成,即權(quán)電阻網(wǎng)絡(luò)、運(yùn)算放大器、基準(zhǔn)電源和模擬開關(guān)。模數(shù)轉(zhuǎn)換器中一般都要用到數(shù)模轉(zhuǎn)換器,模數(shù)轉(zhuǎn)換器即A/D轉(zhuǎn)換器,簡稱ADC,它是把連續(xù)的模擬信號轉(zhuǎn)變?yōu)殡x散的數(shù)字信號的器件。

          作為模擬系統(tǒng)與數(shù)字系統(tǒng)轉(zhuǎn)換的橋梁,ADC和DAC有很多參數(shù)指標(biāo)來標(biāo)識其性能:

          • 分辨率(轉(zhuǎn)換精度):指ADC或DAC能夠采集或輸出最小電壓與最大電壓之比,也是最小輸入數(shù)字量1與最大輸入數(shù)字量2n-1之比。分辨率通常用數(shù)字量的位數(shù)表示,一般為8位、12位、16位等,N位的ADC或DAC的分辨率為2的N次方。
          • 量程(滿刻度范圍 FSR):指ADC或DAC能夠輸入或輸出模擬電壓的變化范圍。
          • 建立時間:建立時間是衡量DAC輸出達(dá)到最終值所需的時間,指接收到要求輸出的命令至輸出建立到一定精度范圍內(nèi)(通常是0.5LSB、1LSB、2LSB)的時間。
          • 轉(zhuǎn)換時間:指ADC從發(fā)出轉(zhuǎn)換指令開始到獲得穩(wěn)定的二進(jìn)制代碼所需要的時間,轉(zhuǎn)換時間與ADC的類型、原理和位數(shù)有關(guān)。

          并行ADC和串行ADC模型

          上圖兩個都是8位ADC模型,分辨率為 2的8次方等于256,即將Vref分成256份,能夠分辨的模擬步進(jìn)為Vref / 256,量化數(shù)據(jù)N = 256 * Vin / Vref 。

          • 并行ADC與數(shù)字電路接口包含一根clk和8根data管腳,clk為芯片時鐘管腳,data為芯片數(shù)據(jù)管腳,每個clk周期從data管腳采集8bit的數(shù)據(jù),完成一次模數(shù)轉(zhuǎn)換,所以clk頻率等于采樣率。
          • 串行ADC(以ADC081S101為例)與數(shù)字電路接口為三根線(cs,clk,din),兼容三線SPI總線,cs為芯片使能管腳,clk為芯片時鐘管腳,din為芯片數(shù)據(jù)管腳,當(dāng)ADC芯片使能時每個clk周期從din采集1bit的數(shù)據(jù),但是根據(jù)ADC081S101的時序,需要16個clk完成一次采樣,所以clk頻率至少等于采樣率的16倍。
          ADC模塊電路連接

          這里我們以底板上的ADC模塊電路,其電路圖如下:

          ADC模塊電路

          如ADC模塊電路所示,直接連接ADC081S101芯片的控制端,ADC有6個管腳,3腳Vin為VCC和Vref功能復(fù)用,即Vin = VCC = Vref。ADC前端是運(yùn)放電路LMV721,運(yùn)放模塊為電壓跟隨電路,再往前端是一個跳冒排針,用來選擇ADC采樣信號的來源,當(dāng)短路帽將1、2腳短路時,ADC采集電位計(jì)電壓,當(dāng)短路帽將2、3腳短路時,ADC采射頻端子或P4排針信號。本設(shè)計(jì)我們是采樣旋轉(zhuǎn)編碼器的電壓,所以需要用短路帽將1、2腳短路。

          ADC模塊驅(qū)動設(shè)計(jì)

          前面我們了解ADC081S101芯片和FPGA之間連接有三根線(cs、clk、din),兼容SPI總線,SPI是串行外設(shè)接口(Serial Peripheral Interface)的縮寫。SPI是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線(cs、sck、mosi、miso),事實(shí)上3根也可以(單向傳輸時),占用管腳少節(jié)約了芯片的管腳,同時為PCB的布局上節(jié)省空間,正是出于這種簡單易用的特性,如今越來越多的芯片集成這種通信協(xié)議。

          SPI設(shè)備分為主設(shè)備和從設(shè)備,設(shè)備之間共用sck、mosi和miso,另外每個從設(shè)備有一根cs線(不共用),通信在主設(shè)備和從設(shè)備之間進(jìn)行,從設(shè)備與從設(shè)備之間無法直接通信,主設(shè)備可以同時連接多個從設(shè)備,當(dāng)主設(shè)備和某個從設(shè)備通信時,先控制該從設(shè)備cs信號拉低,然后通過sck、mosi和miso進(jìn)行數(shù)據(jù)傳輸。

          多設(shè)備SPI總線連接

          為了讓SPI總線更加靈活應(yīng)用,SPI總線分為4種模式,由兩個參數(shù)控制:

          • CPOL:時鐘極性選擇,為0時SCK空閑為低電平,為1時SCK空閑為高電平
          • CPHA:時鐘相位選擇,為0時在SCK第一個跳變沿采樣,為1時在SCK第二個跳變沿采樣
          MODE0MODE1
          MODE2MODE3

          SPI總線協(xié)議4種模式

          • 模式1:CPOL=0,CPHA=0:此時空閑態(tài)時,SCLK處于低電平,數(shù)據(jù)采樣是在第1個邊沿,也就是 SCLK由低電平到高電平的跳變,所以數(shù)據(jù)采樣是在上升沿,數(shù)據(jù)發(fā)送是在下降沿。
          • 模式2:CPOL=0,CPHA=1:此時空閑態(tài)時,SCLK處于低電平,數(shù)據(jù)發(fā)送是在第1個邊沿,也就是 SCLK由低電平到高電平的跳變,所以數(shù)據(jù)采樣是在下降沿,數(shù)據(jù)發(fā)送是在上升沿。
          • 模式3:CPOL=1,CPHA=0:此時空閑態(tài)時,SCLK處于高電平,數(shù)據(jù)采集是在第1個邊沿,也就是 SCLK由高電平到低電平的跳變,所以數(shù)據(jù)采集是在下降沿,數(shù)據(jù)發(fā)送是在上升沿。
          • 模式4:CPOL=1,CPHA=1:此時空閑態(tài)時,SCLK處于高電平,數(shù)據(jù)發(fā)送是在第1個邊沿,也就是 SCLK由高電平到低電平的跳變,所以數(shù)據(jù)采集是在上升沿,數(shù)據(jù)發(fā)送是在下降沿。

          ADC081S101管腳說明表:

          ADC081S101管腳說明

          注:SDATA信號在SCLK的節(jié)拍下傳輸數(shù)據(jù),當(dāng)SCLK下降沿時SDATA更新數(shù)據(jù)輸出,當(dāng)驅(qū)動程序編程時我們要在上升沿采樣數(shù)據(jù)可以得到穩(wěn)定的輸出。

          ADC081S101串行通信時序如下圖:

          ADC081S101通信時序

          注:

          1. SCLK空閑時為高電平,CPOL = 1,上升沿(第二個邊沿)采樣,CPHA = 1,如果例化通用SPI核完成設(shè)計(jì),需要采用SPI的第四種工作模式。
          2. CS信號拉低有效,經(jīng)過16個時鐘完成一次ADC轉(zhuǎn)換并采樣,采樣回來的數(shù)據(jù)前3位無效,接下來為DB7~DB0(有效數(shù)據(jù)),再接下來為無效數(shù)據(jù)。

          針對ADC081S101時序,我們用Verilog設(shè)計(jì)一個計(jì)數(shù)器,當(dāng)計(jì)數(shù)器值不同時完成不同操作,實(shí)現(xiàn)一次ADC采樣,程序?qū)崿F(xiàn)如下:

          reg [7:0] cnt; //計(jì)數(shù)器
          always @(posedge clk or negedge rst_n)
          	if(!rst_n) cnt <= 1'b0;
          	else if(cnt >= 8'd34) cnt <= 1'b0;
          	else cnt <= cnt + 1'b1;
          	reg [7:0] data;always @(posedge clk or negedge rst_n)
          	if(!rst_n) begin
          		adc_cs <= HIGH; adc_clk <= HIGH;
          	end else case(cnt)
          		8'd0 :  begin adc_cs <= HIGH; 
          		adc_clk <= HIGH; end
          		8'd1 :  begin adc_cs <= LOW;  
          		adc_clk <= HIGH; end
          		8'd2,8'd4,8'd6,8'd8,8'd10,8'd12,8'd14,8'd16,
          		8'd18,8'd20,8'd22,8'd24,8'd26,8'd28,8'd30,8'd32:	
          				begin adc_cs <= LOW;  
          				adc_clk <= LOW;  
          				end
          		8'd3 :  begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		end //0
          		8'd5 :  begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		end //1
          		8'd7 :  begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		end //2
          		8'd9 :  begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		data[7] <= adc_dat; 
          		end //3
          		8'd11 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; data[6] <= adc_dat; 
          		end //4
          		8'd13 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; data[5] <= adc_dat; 
          		end //5
          		8'd15 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		data[4] <= adc_dat; 
          		end //6
          		8'd17 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; data[3] <= adc_dat; 
          		end //7
          		8'd19 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; data[2] <= adc_dat; 
          		end //8
          		8'd21 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		data[1] <= adc_dat; 
          		end //9
          		8'd23 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; data[0] <= adc_dat; 
          		end //10
          		8'd25 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; adc_data <= data; 
          		end //11
          		8'd27 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; adc_done <= HIGH; 
          		end //12
          		8'd29 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; adc_done <= LOW; 
          		end //13
          		8'd31 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		end //14
          		8'd33 : begin adc_cs <= LOW;  
          		adc_clk <= HIGH; 
          		end //15
          		8'd34 : begin adc_cs <= HIGH;  
          		adc_clk <= HIGH; 
          		end
          		default : begin adc_cs <= HIGH;  
          		adc_clk <= HIGH;  
          		end
          	endcase

          到這我們就完成了串行ADC芯片ADC081S101的驅(qū)動設(shè)計(jì),整個采樣周期用了35個系統(tǒng)時鐘,如果我們采用12MHz時鐘作為該模塊系統(tǒng)時鐘,采樣率Fs = 12M/35 = 343Ksps,ADC主頻Fsclk = 12 MHz /2 = 6MHz。

          ADC081S101主頻及采樣率要求如下,按照要求我們當(dāng)前的主頻和采樣率不足,所以在使用該模塊時,可以使用更高的時鐘(比如24MHz)以達(dá)到芯片的要求

          ADC081S101速度

          注:時鐘頻率Fsclk,最小值為10MHz,最大值為20MHz,采樣率在500Ksps~1Msps

          模塊接口如下:clk和rstn為系統(tǒng)時鐘及復(fù)位,adccs,adcclk和adcdat為ADC控制管腳,adcdata為ADC采樣數(shù)據(jù),adcdone產(chǎn)生一個脈沖對應(yīng)adc_data得到一個有效數(shù)據(jù)

          module ADC081S101_driver
          (
          input				clk,		//系統(tǒng)時鐘
          input				rst_n,  	//系統(tǒng)復(fù)位,低有效
          output	reg			adc_cs,		//SPI總線CS
          output	reg			adc_clk,	//SPI總線SCK
          input				adc_dat,	//SPI總線SDA
          output	reg			adc_done,	//ADC采樣完成標(biāo)志
          output	reg [7:0]		adc_data	//ADC采樣數(shù)據(jù)
          );
          系統(tǒng)總體實(shí)現(xiàn)

          因?yàn)樾枰叩臅r鐘供ADC模塊使用,我們例化pll核得到24MHz時鐘,例化PLL的方法我們在基礎(chǔ)數(shù)字電路實(shí)驗(yàn)部分已經(jīng)練習(xí)過,這里就簡單描述一下過程

          打開Tools菜單下的IP Catalog工具,依次找到Libraty → Basic Functions → Clocks; PLLs and Resets → PLL → ALTPLL,打開ALTPLL彈出配置界面,配置inclk0輸入為12MHz,配置c0的時鐘輸出為24MHz,其他所有選項(xiàng)全部默認(rèn),點(diǎn)擊Finish完成pll的IP核例化。

          在頂層模塊VoltageMeas中,同時例化pll模塊和ADC081S101driver模塊,并將pll的c0輸出與ADC081S101_driver模塊的clk連線。

          PLL

           

          PLL

          Pll模塊和ADC081S101_driver模塊的連接程序?qū)崿F(xiàn)如下:

          wire clk_24mhz,locked;
          pll u1
          (
          .areset				(!rst_n			), //pll模塊的復(fù)位為高有效
          .inclk0				(clk			), //12MHz系統(tǒng)時鐘輸入
          .c0					(clk_24mhz		), //24MHz時鐘輸出
          .locked				(locked			)  //pll lock信號輸出
          ); 
          wire adc_done;
          wire [7:0] adc_data;//使用I2C總線驅(qū)動PCF8591的ADC功能,例化
          ADC081S101_driver u2(.clk				(clk_24mhz		),	//系統(tǒng)時鐘
          .rst_n				(rst_n			),	//系統(tǒng)復(fù)位,低有效
          .adc_cs				(adc_cs			),	//SPI總線CS
          .adc_clk			(adc_clk		),	//SPI總線SCK
          .adc_dat			(adc_dat		),	//SPI總線SDA
          .adc_done			(adc_done		),	//ADC采樣完成標(biāo)志
          .adc_data			(adc_data		)	//ADC采樣數(shù)據(jù)
          );

          現(xiàn)在可以得到ADC采樣數(shù)據(jù)了,假設(shè)ADC模擬輸入電壓為3.3V,理論上我們得到的采樣數(shù)據(jù)adc_data應(yīng)該為8’hff,而最終顯示在數(shù)碼管上的數(shù)據(jù)應(yīng)該為3.3,我們?nèi)绾螌?’hff轉(zhuǎn)換成可以顯示的3.3數(shù)據(jù)呢?這就設(shè)計(jì)到ADC量化數(shù)據(jù)的逆向運(yùn)算了,

          我們知道量化運(yùn)算 N = 256 * Vin / Vref,

          那么逆向運(yùn)算為Vin = N * Vref / 256,其中Vref = 3.3V,所以Vin = N * 0.0129

          所以我們需要用FPGA計(jì)算adc_data * 0.0129的結(jié)果,然后為了使用十進(jìn)制的顯示,先將結(jié)果進(jìn)行BCD轉(zhuǎn)碼,然后顯示在數(shù)碼管上。

          將ADC采樣數(shù)據(jù)按規(guī)則轉(zhuǎn)換為電壓數(shù)據(jù)(乘以0.0129),這里我們直接乘以129,得到的數(shù)據(jù)經(jīng)過BCD轉(zhuǎn)碼后小數(shù)點(diǎn)左移4位即可,程序?qū)崿F(xiàn)如下:

          wire [15:0] bin_code = adc_data * 16'd129;

          將二進(jìn)制數(shù)轉(zhuǎn)換成BCD碼的形式,采用左移加三的算法(以8’hff為例): 1、左移要轉(zhuǎn)換的二進(jìn)制碼1位 2、左移之后,BCD碼分別置于百位、十位、個位 3、如果移位后所在的BCD碼列大于或等于5,則對該值加3 4、繼續(xù)左移的過程直至全部移位完成

          Bin to BCD

          二進(jìn)制轉(zhuǎn)BCD碼程序?qū)崿F(xiàn)如下:

          reg		[35:0]		shift_reg; 
          always@(bin_code or rst_n)begin
          	shift_reg = {20'h0,bin_code};
          	if(!rst_n) bcd_code = 0; 
          	else begin 
          		repeat(16) begin //循環(huán)16次  
          			//BCD碼各位數(shù)據(jù)作滿5加3操作,
          			if (shift_reg[19:16] >= 5) shift_reg[19:16] = shift_reg[19:16] + 2'b11;
          			if (shift_reg[23:20] >= 5) shift_reg[23:20] = shift_reg[23:20] + 2'b11;
          			if (shift_reg[27:24] >= 5) shift_reg[27:24] = shift_reg[27:24] + 2'b11;
          			if (shift_reg[31:28] >= 5) shift_reg[31:28] = shift_reg[31:28] + 2'b11;
          			if (shift_reg[35:32] >= 5) shift_reg[35:32] = shift_reg[35:32] + 2'b11;
          			shift_reg = shift_reg << 1; 
          		end
          		bcd_code = shift_reg[35:16];   
          	end 
          	end

          最后得到20位的數(shù)據(jù)輸出,每4位表示一個BCD碼,所以有5位有效數(shù)據(jù),這里我們還需要將小數(shù)點(diǎn)左移4位,計(jì)算出來的數(shù)應(yīng)該是X.XXXX伏特,1個整數(shù)位和4個小數(shù)位,核心板上只有兩個數(shù)碼管,取最高的兩個BCD碼顯示到數(shù)碼管X.X伏特,個位小數(shù)點(diǎn)點(diǎn)亮,分位小數(shù)點(diǎn)熄滅,程序?qū)崿F(xiàn)如下:

          //個位數(shù)碼管模塊例化	Segment_led u4(.seg_dot			(1'b1			),	//seg_dot input
          .seg_data			(bcd_code[19:16]),	//seg_data input
          .segment_led		(seg_1			)	//MSB~LSB = SEG,DP,G,F,E,D,C,B,A
          ); //分位數(shù)碼管模塊例化
          Segment_led u5(.seg_dot			(1'b0			),	//seg_dot input
          .seg_data			(bcd_code[15:12]),	//seg_data input
          .segment_led		(seg_2			)	//MSB~LSB = SEG,DP,G,F,E,D,C,B,A
          );

          綜合后的設(shè)計(jì)框圖如下:

          RTL設(shè)計(jì)框圖

          實(shí)驗(yàn)步驟

          1. 雙擊打開Quartus Prime工具軟件;
          2. 新建工程:File → New Project Wizard(工程命名,工程目錄選擇,設(shè)備型號選擇,EDA工具選擇);
          3. 新建文件:File → New → Verilog HDL File,鍵入設(shè)計(jì)代碼并保存;
          4. 設(shè)計(jì)綜合:雙擊Tasks窗口頁面下的Analysis & Synthesis對代碼進(jìn)行綜合;
          5. 管腳約束:Assignments → Assignment Editor,根據(jù)項(xiàng)目需求分配管腳;
          6. 設(shè)計(jì)編譯:雙擊Tasks窗口頁面下的Compile Design對設(shè)計(jì)進(jìn)行整體編譯并生成配置文件;
          7. 程序燒錄:點(diǎn)擊Tools → Programmer打開配置工具,Program進(jìn)行下載;
          8. 觀察設(shè)計(jì)運(yùn)行結(jié)果。

          實(shí)驗(yàn)現(xiàn)象

          將程序下載到FPGA中,P3接口用短路帽將1、2腳短路,旋轉(zhuǎn)底板右上角的電位計(jì),觀察核心板數(shù)碼管變化,如果有萬用表可以測量P3短路處的電壓,與數(shù)碼管顯示對比。



          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉