【 FPGA 】超聲波測距小實驗(三)回響脈寬計數(shù)之均值濾波
這是小實驗還是接著上個小實驗的:超聲波測距小實驗(一)
數(shù)碼管顯示回響信號脈沖寬度
先說說實驗的要求:
超聲波測距回響脈寬計數(shù)之均值濾波處理,每100ms產(chǎn)生1個超聲波測距模塊所需的10us高脈沖激勵(超聲波測距模塊的觸發(fā)信號),并用數(shù)碼管以16進(jìn)制數(shù)據(jù)顯示經(jīng)過濾波處理的回響信號的高脈沖計數(shù)值(以10us為單位)。
如下為功能框圖:
濾波算法與實現(xiàn):
先給出主模塊程序,再給出其他子模塊的程序,然后選取其中的某些部分來講解:
主模塊:
/
//工程硬件平臺: Xilinx Spartan 6 FPGA
/
//每100ms產(chǎn)生1個超聲波測距模塊所需的10us高脈沖激勵,并用數(shù)碼管以16進(jìn)制數(shù)據(jù)顯示經(jīng)過濾波處理的回響信號的高脈沖計數(shù)值(以10us為單位)
module sp6(
input ext_clk_25m, //外部輸入25MHz時鐘信號
input ext_rst_n, //外部輸入復(fù)位信號,低電平有效
output ultrasound_trig, //超聲波測距模塊脈沖激勵信號,10us的高脈沖
input ultrasound_echo, //超聲波測距模塊回響信號
output[3:0] dtube_cs_n, //7段數(shù)碼管位選信號
output[7:0] dtube_data //7段數(shù)碼管段選信號(包括小數(shù)點為8段)
);
//-------------------------------------
//PLL例化
wire clk_12m5; //PLL輸出12.5MHz時鐘
wire clk_25m; //PLL輸出25MHz時鐘
wire clk_50m; //PLL輸出50MHz時鐘
wire clk_100m; //PLL輸出100MHz時鐘
wire sys_rst_n; //PLL輸出的locked信號,作為FPGA內(nèi)部的復(fù)位信號,低電平復(fù)位,高電平正常工作
pll_controller uut_pll_controller
(// Clock in ports
.CLK_IN1(ext_clk_25m), // IN
// Clock out ports
.CLK_OUT1(clk_12m5), // OUT
.CLK_OUT2(clk_25m), // OUT
.CLK_OUT3(clk_50m), // OUT
.CLK_OUT4(clk_100m), // OUT
// Status and control signals
.RESET(~ext_rst_n),// IN
.LOCKED(sys_rst_n)); // OUT
//-------------------------------------
//25MHz時鐘進(jìn)行分頻,產(chǎn)生一個100KHz頻率的時鐘使能信號
wire clk_100khz_en; //100KHz頻率的一個時鐘使能信號,即每10us產(chǎn)生一個時鐘脈沖
clkdiv_generation uut_clkdiv_generation(
.clk(clk_25m), //時鐘信號
.rst_n(sys_rst_n), //復(fù)位信號,低電平有效
.clk_100khz_en(clk_100khz_en) //100KHz頻率的一個時鐘使能信號,即每10us產(chǎn)生一個時鐘脈沖
);
//-------------------------------------
//每100ms產(chǎn)生一個10us的高脈沖作為超聲波測距模塊的激勵
wire[15:0] echo_pulse_num; //以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)的最終值
wire echo_pulse_en; //超聲波測距模塊回響信號計數(shù)值有效信號
ultrasound_controller uut_ultrasound_controller(
.clk(clk_25m), //時鐘信號
.rst_n(sys_rst_n), //復(fù)位信號,低電平有效
.clk_100khz_en(clk_100khz_en), //100KHz頻率的一個時鐘使能信號,即每10us產(chǎn)生一個時鐘脈沖
.ultrasound_trig(ultrasound_trig), //超聲波測距模塊脈沖激勵信號,10us的高脈沖
.ultrasound_echo(ultrasound_echo), //超聲波測距模塊回響信號
.echo_pulse_en(echo_pulse_en), //超聲波測距模塊回響信號計數(shù)值有效信號
.echo_pulse_num(echo_pulse_num) //以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)的最終值
);
//-------------------------------------
//緩存最近采集到的8組超聲波測距回響脈沖計數(shù)值,對它們進(jìn)行累加并求平均
wire[15:0] echo_pulse_filter_num; //濾波處理后的超聲波測距模塊回響信號高脈沖計數(shù)值
filter uut_filter(
.clk(clk_25m), //時鐘信號
.rst_n(sys_rst_n), //復(fù)位信號,低電平有效
.echo_pulse_en(echo_pulse_en), //超聲波測距模塊回響信號計數(shù)值有效信號
.echo_pulse_num(echo_pulse_num), //以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)的最終值
.echo_pulse_filter_num(echo_pulse_filter_num) //濾波處理后的超聲波測距模塊回響信號高脈沖計數(shù)值
);
//-------------------------------------
//4位數(shù)碼管顯示驅(qū)動
seg7 uut_seg7(
.clk(clk_25m), //時鐘信號
.rst_n(sys_rst_n), //復(fù)位信號,低電平有效
.display_num(echo_pulse_filter_num), //顯示數(shù)據(jù)
.dtube_cs_n(dtube_cs_n), //7段數(shù)碼管位選信號
.dtube_data(dtube_data) //7段數(shù)碼管段選信號(包括小數(shù)點為8段)
);
endmodule
/
//工程硬件平臺: Xilinx Spartan 6 FPGA
/
module clkdiv_generation(
input clk, //外部輸入25MHz時鐘信號
input rst_n, //外部輸入復(fù)位信號,低電平有效
output clk_100khz_en //100KHz頻率的一個時鐘使能信號,即每10us產(chǎn)生一個時鐘脈沖
);
//-------------------------------------------------
//時鐘分頻產(chǎn)生
reg[7:0] cnt; //時鐘分頻計數(shù)器,0-249
//1s定時計數(shù)
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 8'd0;
else if(cnt < 8'd249) cnt <= cnt+1'b1;
else cnt <= 8'd0;
assign clk_100khz_en = (cnt == 8'd249) ? 1'b1:1'b0; //每40us產(chǎn)生一個40ns的高脈沖
endmodule
/
//工程硬件平臺: Xilinx Spartan 6 FPGA
//開發(fā)套件型號: SF-SP6 特權(quán)打造
// 僅供SF-SP6開發(fā)套件學(xué)習(xí)使用,謝謝支持
//官方淘寶店鋪: http://myfpga.taobao.com/
//最新資料下載: 百度網(wǎng)盤 http://pan.baidu.com/s/1jGjAhEm
//公 司: 上海或與電子科技有限公司
/
module ultrasound_controller(
input clk, //外部輸入25MHz時鐘信號
input rst_n, //外部輸入復(fù)位信號,低電平有效
input clk_100khz_en, //100KHz頻率的一個時鐘使能信號,即每10us產(chǎn)生一個時鐘脈沖
output ultrasound_trig, //超聲波測距模塊脈沖激勵信號,10us的高脈沖
input ultrasound_echo, //超聲波測距模塊回響信號
output reg echo_pulse_en, //超聲波測距模塊回響信號計數(shù)值有效信號
output reg[15:0] echo_pulse_num //以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)的最終值
);
//-------------------------------------------------
//1s定時產(chǎn)生邏輯
reg[13:0] timer_cnt; //1s計數(shù)器,以100KHz(10us)為單位進(jìn)行計數(shù),計數(shù)100ms需要的計數(shù)范圍是0~9999
//1s定時計數(shù)
always @(posedge clk or negedge rst_n)
if(!rst_n) timer_cnt <= 14'd0;
else if(clk_100khz_en) begin
if(timer_cnt < 14'd9_999) timer_cnt <= timer_cnt+1'b1;
else timer_cnt <= 14'd0;
end
else ;
assign ultrasound_trig = (timer_cnt == 14'd1) ? 1'b1:1'b0; //10us高脈沖生成
//-------------------------------------------------
//超聲波測距模塊的回響信號echo打兩拍,產(chǎn)生上升沿和下降沿標(biāo)志位
reg[1:0] ultrasound_echo_r;
always @(posedge clk or negedge rst_n)
if(!rst_n) ultrasound_echo_r <= 2'b00;
else ultrasound_echo_r <= {ultrasound_echo_r[0],ultrasound_echo};
wire pos_echo = ~ultrasound_echo_r[1] & ultrasound_echo_r[0]; //echo信號上升沿標(biāo)志位,高電平有效一個時鐘周期
wire neg_echo = ultrasound_echo_r[1] & ~ultrasound_echo_r[0]; //echo信號下降沿標(biāo)志位,高電平有效一個時鐘周期
//-------------------------------------------------
//以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)
reg[15:0] echo_cnt; //回響高脈沖計數(shù)器
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_cnt <= 16'd0;
else if(pos_echo) echo_cnt <= 16'd0; //計數(shù)清零
else if(clk_100khz_en && ultrasound_echo_r[0]) echo_cnt <= echo_cnt+1'b1;
else ;
//計數(shù)脈沖數(shù)鎖存
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_pulse_num <= 16'd0;
else if(neg_echo) echo_pulse_num <= echo_cnt;
//計數(shù)脈沖有效使能信號鎖存
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_pulse_en <= 1'b0;
else echo_pulse_en <= neg_echo;
endmodule
/
//工程硬件平臺: Xilinx Spartan 6 FPGA
/
module seg7(
input clk, //時鐘信號,25MHz
input rst_n, //復(fù)位信號,低電平有效
input[15:0] display_num, //數(shù)碼管顯示數(shù)據(jù),[15:12]--數(shù)碼管千位,[11:8]--數(shù)碼管百位,[7:4]--數(shù)碼管十位,[3:0]--數(shù)碼管個位
output reg[3:0] dtube_cs_n, //7段數(shù)碼管位選信號
output reg[7:0] dtube_data //7段數(shù)碼管段選信號(包括小數(shù)點為8段)
);
//-------------------------------------------------
//參數(shù)定義
//數(shù)碼管顯示 0~F 對應(yīng)段選輸出
parameter NUM0 = 8'h3f,//c0,
NUM1 = 8'h06,//f9,
NUM2 = 8'h5b,//a4,
NUM3 = 8'h4f,//b0,
NUM4 = 8'h66,//99,
NUM5 = 8'h6d,//92,
NUM6 = 8'h7d,//82,
NUM7 = 8'h07,//F8,
NUM8 = 8'h7f,//80,
NUM9 = 8'h6f,//90,
NUMA = 8'h77,//88,
NUMB = 8'h7c,//83,
NUMC = 8'h39,//c6,
NUMD = 8'h5e,//a1,
NUME = 8'h79,//86,
NUMF = 8'h71,//8e;
NDOT = 8'h80; //小數(shù)點顯示
//數(shù)碼管位選 0~3 對應(yīng)輸出
parameter CSN = 4'b1111,
CS0 = 4'b1110,
CS1 = 4'b1101,
CS2 = 4'b1011,
CS3 = 4'b0111;
//-------------------------------------------------
//分時顯示數(shù)據(jù)控制單元
reg[3:0] current_display_num; //當(dāng)前顯示數(shù)據(jù)
reg[7:0] div_cnt; //分時計數(shù)器
//分時計數(shù)器
always @(posedge clk or negedge rst_n)
if(!rst_n) div_cnt <= 8'd0;
else div_cnt <= div_cnt+1'b1;
//顯示數(shù)據(jù)
always @(posedge clk or negedge rst_n)
if(!rst_n) current_display_num <= 4'h0;
else begin
case(div_cnt)
8'hff: current_display_num <= display_num[3:0];
8'h3f: current_display_num <= display_num[7:4];
8'h7f: current_display_num <= display_num[11:8];
8'hbf: current_display_num <= display_num[15:12];
default: ;
endcase
end
//段選數(shù)據(jù)譯碼
always @(posedge clk or negedge rst_n)
if(!rst_n) dtube_data <= NUM0;
else begin
case(current_display_num)
4'h0: dtube_data <= NUM0;
4'h1: dtube_data <= NUM1;
4'h2: dtube_data <= NUM2;
4'h3: dtube_data <= NUM3;
4'h4: dtube_data <= NUM4;
4'h5: dtube_data <= NUM5;
4'h6: dtube_data <= NUM6;
4'h7: dtube_data <= NUM7;
4'h8: dtube_data <= NUM8;
4'h9: dtube_data <= NUM9;
4'ha: dtube_data <= NUMA;
4'hb: dtube_data <= NUMB;
4'hc: dtube_data <= NUMC;
4'hd: dtube_data <= NUMD;
4'he: dtube_data <= NUME;
4'hf: dtube_data <= NUMF;
default: ;
endcase
end
//位選譯碼
always @(posedge clk or negedge rst_n)
if(!rst_n) dtube_cs_n <= CSN;
else begin
case(div_cnt[7:6])
2'b00: dtube_cs_n <= CS0;
2'b01: dtube_cs_n <= CS1;
2'b10: dtube_cs_n <= CS2;
2'b11: dtube_cs_n <= CS3;
default: dtube_cs_n <= CSN;
endcase
end
endmodule
/
//工程硬件平臺: Xilinx Spartan 6 FPGA
//緩存最近采集到的8組超聲波測距回響脈沖計數(shù)值,對它們進(jìn)行累加并求平均
module filter(
input clk, //外部輸入25MHz時鐘信號
input rst_n, //外部輸入復(fù)位信號,低電平有效
input echo_pulse_en, //超聲波測距模塊回響信號計數(shù)值有效信號
input[15:0] echo_pulse_num, //以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)的最終值
output[15:0] echo_pulse_filter_num //濾波處理后的超聲波測距模塊回響信號高脈沖計數(shù)值
);
//-------------------------------------------------
//echo_pulse_num信號緩存10拍
reg[15:0] pulse_reg[7:0]; //echo_pulse_num信號緩存寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
pulse_reg[0] <= 16'd0;
pulse_reg[1] <= 16'd0;
pulse_reg[2] <= 16'd0;
pulse_reg[3] <= 16'd0;
pulse_reg[4] <= 16'd0;
pulse_reg[5] <= 16'd0;
pulse_reg[6] <= 16'd0;
pulse_reg[7] <= 16'd0;
end
else if(echo_pulse_en) begin //緩存最新的數(shù)據(jù),使用移位寄存器的方式推進(jìn)最新數(shù)據(jù),推出最老的數(shù)據(jù)
pulse_reg[0] <= echo_pulse_num;
pulse_reg[1] <= pulse_reg[0];
pulse_reg[2] <= pulse_reg[1];
pulse_reg[3] <= pulse_reg[2];
pulse_reg[4] <= pulse_reg[3];
pulse_reg[5] <= pulse_reg[4];
pulse_reg[6] <= pulse_reg[5];
pulse_reg[7] <= pulse_reg[6];
end
//-------------------------------------------------
//對8個數(shù)據(jù)累加并輸出平均值
reg[15:0] sum_pulse_reg;
always @(posedge clk or negedge rst_n)
if(!rst_n) sum_pulse_reg <= 16'd0;
else sum_pulse_reg <= pulse_reg[0]+pulse_reg[1]+pulse_reg[2]+pulse_reg[3]+pulse_reg[4]+pulse_reg[5]+pulse_reg[6]+pulse_reg[7];
assign echo_pulse_filter_num = {3'b000,sum_pulse_reg[15:3]}; //右移3位,相當(dāng)于除以8
endmodule
上篇博文,也就是實驗二已經(jīng)講解了超聲波控制模塊中的某些程序,這里再次貼出:
//超聲波測距模塊的回響信號echo打兩拍,產(chǎn)生上升沿和下降沿標(biāo)志位
reg[1:0] ultrasound_echo_r;
always @(posedge clk or negedge rst_n)
if(!rst_n) ultrasound_echo_r <= 2'b00;
else ultrasound_echo_r <= {ultrasound_echo_r[0],ultrasound_echo};
wire pos_echo = ~ultrasound_echo_r[1] & ultrasound_echo_r[0];????//echo信號上升沿標(biāo)志位,高電平有效一個時鐘周期
wire neg_echo = ultrasound_echo_r[1] & ~ultrasound_echo_r[0];????//echo信號下降沿標(biāo)志位,高電平有效一個時鐘周期
系統(tǒng)運(yùn)行之前,總要先復(fù)位下,這時ultrasound_echo_r的值為00,之后若初遇回響信號ultrasound_echo(高電平),這個always塊的操作是使得ultrasound_echo_r為01,此時,pos_en為1,這就找到了echo信號的上升沿,除了ultrasound_echo_r為01之外,其他任何時候都不會出現(xiàn)pos_en為1,秒否?
同理,如果回響信號從高電平變?yōu)榈碗娖搅耍敲创藭r,ultrasound_echo_r為10,此時neg_echo為1,除此之外,任何時候neg_echo都不會為1,這就找到了回響信號的下降沿。
下面一段程序為:
//以10us為單位對超聲波測距模塊回響信號高脈沖進(jìn)行計數(shù)
reg[15:0] echo_cnt;????????//回響高脈沖計數(shù)器
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_cnt <= 16'd0;
else if(pos_echo) echo_cnt <= 16'd0;????//計數(shù)清零
else if(clk_100khz_en && ultrasound_echo_r[0]) echo_cnt <= echo_cnt+1'b1;
else ;
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_pulse_num <= 16'd0;
else if(neg_echo) echo_pulse_num <= echo_cnt;
不難理解,上升沿到來時,以10us為單位的計數(shù)變量清零,開始計數(shù):????else if(pos_echo) echo_cnt <= 16'd0;????//計數(shù)清零
當(dāng)周期為10us的clk_100khz_en有效且回響信號ultrasound_echo_r[0]為高脈沖時,計數(shù)。
當(dāng)下降沿時候,計數(shù)結(jié)束,將計數(shù)值給echo_pulse_num:?else if(neg_echo) echo_pulse_num <= echo_cnt
---------------------
這篇博文在此基礎(chǔ)上添加了如下程序段:
//計數(shù)脈沖有效使能信號鎖存
always @(posedge clk or negedge rst_n)
if(!rst_n) echo_pulse_en <= 1'b0;
else echo_pulse_en <= neg_echo;
很簡單,這小段程序的意思是:每個回波信號在neg_echo有效時結(jié)束,這時也已經(jīng)對此脈沖計數(shù)完成了,以10us為單位的計數(shù),也就是知道了回波脈寬了。
之后進(jìn)入均值處理的模塊,均值處理模塊,將檢測echo_pulse_en信號什么時候有效,每一個有效期都會得到一個回波脈寬,最后將得到的所有的回波脈寬做均值處理,可以得到更穩(wěn)定的回波脈寬測量。
/echo_pulse_num信號緩存10拍
reg[15:0] pulse_reg[7:0];?? ?//echo_pulse_num信號緩存寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
pulse_reg[0] <= 16'd0;
pulse_reg[1] <= 16'd0;
pulse_reg[2] <= 16'd0;
pulse_reg[3] <= 16'd0;
pulse_reg[4] <= 16'd0;
pulse_reg[5] <= 16'd0;
pulse_reg[6] <= 16'd0;
pulse_reg[7] <= 16'd0;
end
else if(echo_pulse_en) begin?? ?//緩存最新的數(shù)據(jù),使用移位寄存器的方式推進(jìn)最新數(shù)據(jù),推出最老的數(shù)據(jù)
pulse_reg[0] <= echo_pulse_num;
pulse_reg[1] <= pulse_reg[0];
pulse_reg[2] <= pulse_reg[1];
pulse_reg[3] <= pulse_reg[2];
pulse_reg[4] <= pulse_reg[3];
pulse_reg[5] <= pulse_reg[4];
pulse_reg[6] <= pulse_reg[5];
pulse_reg[7] <= pulse_reg[6];
end
這便是均值處理里面的程序,程序開頭說緩存10拍,也就是10個echo_pulse_en有效次數(shù),但我有一個疑問,程序是如何控制緩存了10拍的呢?
下面就直接進(jìn)行均值處理了?先放在這里:
//-------------------------------------------------
//對8個數(shù)據(jù)累加并輸出平均值
reg[15:0] sum_pulse_reg;
always @(posedge clk or negedge rst_n)
if(!rst_n) sum_pulse_reg <= 16'd0;
else sum_pulse_reg <= pulse_reg[0]+pulse_reg[1]+pulse_reg[2]+pulse_reg[3]+pulse_reg[4]+pulse_reg[5]+pulse_reg[6]+pulse_reg[7];
assign echo_pulse_filter_num = {3'b000,sum_pulse_reg[15:3]};?? ?//右移3位,相當(dāng)于除以8
FPGA 單片機(jī)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。