Basys3+HC-SR04調試

Basys3+HC-SR04調試

來自專欄 FPGA學習之旅1 人贊了文章

  • HC-SR04是一個最基礎的超聲波測距模塊,具體的樣子是這樣的:

一共四個管腳,分別是VCC、GND、Trig、Echo信號

  • 工作原理:
  1. 給超聲波模塊接入電源和地。
  2. 給脈衝觸發引腳(trig)輸入一個長大於10us的高電平方波。
  3. 輸入方波後,模塊會自動發射8個40KHz的聲波,與此同時回波引腳(echo)端的電平會由0變為1;
  4. 當超聲波返回被模塊接收到時,回波引 腳端的電平會由1變為0;定時器記下的這個時間即為超聲波由發射到返回的總時長。
  5. 根據聲音在空氣中的速度為344米/秒,即可計算出所測的距離。

HC-SR04的觸發時序圖


  • 當使用Arduino去控制這個模塊的時候,有現成的函數來輸出脈衝和計算輸入的信號長度,但是這種信號的輸出輸入對FPGA來說是長項,所以我打算也用Basys3控制一次,分析後需要如下模塊:

分頻模塊(用於產生周期為1MHz的信號來輸出大於10us的高電平方波)

計數模塊(用於測量返回的波形的長度)

七段數碼管的控制模塊(用於輸出測量後的長度)


  • 分頻模塊的Verilog代碼

module Clk1m(clkin,clkout);input clkin;output clkout;reg clkout;reg [6:0]flag1=0;always @(posedge clkin) begin if(flag1<50) begin flag1<=flag1+1; clkout<=1b1; end else if(flag1<100) begin flag1<=flag1+1; clkout<=1b0; end else if(flag1==100) begin flag1<=0; clkout<=1b1; endendendmodule

因為Basys3的自帶晶振頻率是100MHz,所以將信號分為100塊,50塊為高電平,50塊為低電平,這樣就可以產生周期頻率為1MHz的信號。


  • 計數模塊的Verilog代碼

module PosCounter(clk_1m,echo,dis_count);input clk_1m,echo;output dis_count;reg [19:0] dis_count;reg [19:0] count;reg [19:0] countfinal;always@(posedge clk_1m)begin if(echo == 1b1) begin count <= count+1; countfinal <= count; end else begin dis_count <= countfinal *120 >> 6; count <= 0; endend endmodule

計數模塊是一塊很重要的部分,剛開始借鑒別人的代碼的時候,發現代碼比較長。

參考博客?

blog.csdn.net

博主用了三個狀態機,並且定義了上升沿和下降沿的信號表示,但是其實沒那麼複雜,經過王大哥的幫助,這個模塊的思路是這樣的:

---檢測Echo信號的高電平(如果是高電平的話,就開啟計數)

---當Echo信號為低電平的時候,停止計數

這裡有個邏輯分析,就是這個信號應該在什麼時候輸出,剛開始的時候我是選擇在檢測到低電平的時候輸出,也就是:

always@(posedge clk_1m)begin if(echo == 1b1) count <= count+1; else begin countfinal <= count; count <= 0; endend assign dis_count <= countfinal *120 >> 6;

但這種寫法實際上是錯誤的,因為輸出的信號大部分時間是處於低電平狀態,所以這種寫法會一直把countfinal置為0,無法將countfinal正確輸出(在一個時鐘內,countfinal是正常的但是之後就是錯誤的)所以需要鎖存數據。


  • 七段數碼管的控制模塊

module Showdigit(in,LED_activating_counter,out1,out2);input [19:0] in;input [1:0] LED_activating_counter;output reg [6:0] out1;output reg [3:0] out2;reg [3:0] outnumber;always @(*)begin case(LED_activating_counter) 2b00: begin out2 = 4b0111; outnumber = in/10000;//百位 end 2b01: begin out2 = 4b1011; outnumber = (in / 1000)%100;//十位 end 2b10: begin out2 = 4b1101; outnumber = ((in / 100)%10);//個位 end 2b11: begin out2 = 4b1110; outnumber = ((in / 10)%10);//0.1 end default: out2 = 4b1111; // "0" endcaseendalways@(*)begin case(outnumber) 4b0000: out1 = 7b0000001; // "0" 4b0001: out1 = 7b1001111; // "1" 4b0010: out1 = 7b0010010; // "2" 4b0011: out1 = 7b0000110; // "3" 4b0100: out1 = 7b1001100; // "4" 4b0101: out1 = 7b0100100; // "5" 4b0110: out1 = 7b0100000; // "6" 4b0111: out1 = 7b0001111; // "7" 4b1000: out1 = 7b0000000; // "8" 4b1001: out1 = 7b0000100; // "9" default: out1 = 7b0000001; // "E" endcaseendendmodule

Basys3的七段數碼管是位選的,所以需要產生一個掃描信號。


  • 經過這次的調試以後,感覺利用FPGA去學習一些東西其實是很好的途徑,因為在Verilog里,沒有像C語言的庫一樣的東西(當然,有IP核)但是對於感測器這方面的東西,重新去造輪子會學到很多知識,比如:看網上的博客說這個模塊可以利用5V驅動,但是我用3.3V的電壓去驅動的時候就無法輸出正常的數據,所以Bug&Debug是最好的成長方式哈哈!

推薦閱讀:

【原創】Sublime+Verilator建立強大的verilog編寫環境
FPGA學習(二)——實現AM信號調製與解調

TAG:現場可編輯邏輯門陣列FPGA | Verilog | 感測器 |