找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 3100|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

FPGA入門(mén)學(xué)習(xí)筆記分享

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:80221 發(fā)表于 2019-4-9 18:50 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
最近開(kāi)始入門(mén)FPGA,斷斷續(xù)續(xù)做了些筆記。

今天裝了lattice開(kāi)發(fā)環(huán)境,嘗試模仿歷程,把LED_shining 歷程敲一遍,進(jìn)行編譯。報(bào)錯(cuò):

提示為23行有語(yǔ)法錯(cuò)誤,原因是module最后一個(gè)參數(shù)不需要逗號(hào)

改掉這里再編譯 提示25行錯(cuò)誤

定位實(shí)際是24行語(yǔ)句少寫(xiě)了分隔符導(dǎo)致,加上之后再編譯就成功了。

管腳分配,結(jié)合硬件手測(cè)分配管腳

兩個(gè)輸入 clk_in ,rst_n_in

兩個(gè)輸出 led1,led2


2019/2/28
  三個(gè)開(kāi)關(guān)控制RGB led實(shí)驗(yàn)。

module LED (sw,led);
input [2:0] sw;//開(kāi)關(guān)輸入信號(hào),利用了其中3個(gè)開(kāi)關(guān)
output [2:0] led;//輸出信號(hào)到RGB LED
assign led = sw;/assign連續(xù)賦值。
endmodule

我想用3個(gè)開(kāi)關(guān)控制兩個(gè)RGB led燈:

代碼改為:

module RGB_LED1(sw,led1,led2);

              input  [2:0] sw;

              output [2:0] led1;

              output [2:0] led2;

            

              assign led1 = sw;

              assign led2 = sw;



endmodule

改為非阻塞賦值的方式:

需要注意的有兩點(diǎn),

1.輸入port只能是wire型不能定義成reg型。

2.非阻塞賦值必須用在always塊中執(zhí)行

3.if 語(yǔ)句或者case 語(yǔ)句 后面只能跟一句賦值語(yǔ)句,若要跟多句,需要用到begin end語(yǔ)句

4.always塊要定義觸發(fā)信號(hào)


module RGB_LED(clk,rst,sw,led1,led2);
input clk,rst;
input [2:0] sw;
output led1,led2;
reg [2:0] led1;
reg [2:0] led2;
always@(posedge clk or negedge rst)

              if(!rst)
                            begin
                                          led1<=0;
                                          led2<=0;
                            end
              else
                            begin
                                          led1<=sw;
                                          led2<=sw;
                            end
endmodule


2019/3/1

開(kāi)關(guān)控制數(shù)碼管顯示0~F;原例程為:

module LED (seg_data_1,seg_data_2,seg_led_1,seg_led_2);
input[3:0] seg_data_1;
input[3:0] seg_data_2;//小腳丫上第二個(gè)數(shù)碼管
output[8:0] seg_led_1;//控制一個(gè)數(shù)碼管需要9個(gè)信號(hào) MSB~LSB=DIG、DP、G、F、E、D、C、B、A
output [8:0] seg_led_2;//在小腳丫上第二個(gè)數(shù)碼管的控制信號(hào)  MSB~LSB=DIG、DP、G、F、E、D、C、B、A
reg[8:0] seg [9:0];//定義了一個(gè)reg型的數(shù)組變量,相當(dāng)于一個(gè)10*9的存儲(chǔ)器,存儲(chǔ)器一共有10個(gè)數(shù),每個(gè)數(shù)有9位寬
initial//在過(guò)程塊中只能給reg型變量賦值,Verilog中有兩種過(guò)程塊always和initial
//initial和always不同,其中語(yǔ)句只執(zhí)行一次
begin
seg[0]=9'h3f;//對(duì)存儲(chǔ)器中第一個(gè)數(shù)賦值9'b00_0011_1111,相當(dāng)于共陰極接地,DP點(diǎn)變低不亮,7段顯示數(shù)字  0
seg[1]=9'h06;//7段顯示數(shù)字  1
seg[2]=9'h5b;//7段顯示數(shù)字  2
seg[3]=9'h4f;//7段顯示數(shù)字  3
seg[4]=9'h66;//7段顯示數(shù)字  4
seg[5]=9'h6d;//7段顯示數(shù)字  5
seg[6]=9'h7d;//7段顯示數(shù)字  6
seg[7]=9'h07;//7段顯示數(shù)字  7
seg[8]=9'h7f;//7段顯示數(shù)字  8
seg[9]=9'h6f;//7段顯示數(shù)字  9
end
assign seg_led_1 = seg[seg_data_1];//連續(xù)賦值,這樣輸入不同四位數(shù),就能輸出對(duì)于譯碼的9位輸出
assign seg_led_2 = seg[seg_data_2];
endmodule


原例程用的是數(shù)據(jù)流描述方式(assign)實(shí)現(xiàn)的,我改為行為描述方式(initial+always)
并從顯示0~9擴(kuò)展為顯示0~F
注意的是 initial后面是不需要“:”
Initial 和always后都可以用非阻塞賦值,多個(gè)要用包含在begin...end 里。
module SHUMAGUAN(sw,key,led1,led2);
              input [3:0] sw;
              input [3:0] key;
              output led1,led2;
              reg [8:0] led1;
              reg [8:0] led2;
              reg [8:0] seg[16:0];
              initial
                            begin
                                          seg[0] <= 9'h0x3F;
                                          seg[1] <= 9'h0x06;
                                          seg[2] <= 9'h0x5B;
                                          seg[3] <= 9'h0x4F;
                                          seg[4] <= 9'h0x66;
                                          seg[5] <= 9'h0x6D;
                                          seg[6] <= 9'h0x7D;
                                          seg[7] <= 9'h0x07;
                                          seg[8] <= 9'h0x7F;
                                          seg[9] <= 9'h0x6F;
                                          seg[10]<= 9'h0x77;
                                          seg[11]<= 9'h0x7C;
                                          seg[12]<= 9'h0x39;
                                          seg[13]<= 9'h0x5E;
                                          seg[14]<= 9'h0x79;
                                          seg[15]<= 9'h0x71;
                            end
              always@(sw or key)
                            begin
                                          case(sw)
                                                                      4'b0000:led1 <= seg[0];
                                                                      4'b0001:led1 <= seg[1];
                                                                      4'b0010:led1 <= seg[2];
                                                                      4'b0011:led1 <= seg[3];
                                                                      4'b0100:led1 <= seg[4];
                                                                      4'b0101:led1 <= seg[5];
                                                                      4'b0110:led1 <= seg[6];
                                                                      4'b0111:led1 <= seg[7];
                                                                      4'b1000:led1 <= seg[8];
                                                                      4'b1001:led1 <= seg[9];
                                                                      4'b1010:led1 <= seg[10];
                                                                      4'b1011:led1 <= seg[11];
                                                                      4'b1100:led1 <= seg[12];
                                                                      4'b1101:led1 <= seg[13];
                                                                      4'b1110:led1 <= seg[14];
                                                                      4'b1111:led1 <= seg[15];
                                                                      default:led1 <= seg[0];                                                                                   
                                          endcase
                                          case(key)
                                                                      4'b0000:led2 <= seg[0];
                                                                      4'b0001:led2 <= seg[1];
                                                                      4'b0010:led2 <= seg[2];
                                                                      4'b0011:led2 <= seg[3];
                                                                      4'b0100:led2 <= seg[4];
                                                                      4'b0101:led2 <= seg[5];
                                                                      4'b0110:led2 <= seg[6];
                                                                      4'b0111:led2 <= seg[7];
                                                                      4'b1000:led2 <= seg[8];
                                                                      4'b1001:led2 <= seg[9];
                                                                      4'b1010:led2 <= seg[10];
                                                                      4'b1011:led2 <= seg[11];
                                                                      4'b1100:led2 <= seg[12];
                                                                      4'b1101:led2 <= seg[13];
                                                                      4'b1110:led2 <= seg[14];
                                                                      4'b1111:led2 <= seg[15];
                                                                      default:led2 <= seg[0];                                                      
                                          endcase
                            end
Endmodule

2019/3/5
按鍵消抖:
需要掌握兩個(gè)概念:
脈沖邊沿檢測(cè):用一個(gè)頻率更高的時(shí)鐘去觸發(fā)待檢測(cè)的信號(hào),用兩個(gè)寄存器去存儲(chǔ)相鄰兩個(gè)時(shí)鐘采集的值,然后進(jìn)行異或運(yùn)算,如果不為0,則代表了上升沿或者下降沿。
消抖方法,第一次檢測(cè)脈沖,delay20ms,再檢測(cè)key是否為低,如果為低則正面按鍵按下。否則認(rèn)為是抖動(dòng)。

我寫(xiě)的代碼如下(有問(wèn)題):
module key(clk,key,rst,led);
              input key,rst,clk;
              output reg led;
              reg [17:0] count;
              wire key_edge,key_pulse;
              reg key_pre,key_now;
              reg key2_pre,key2_now;
              always@(posedge clk or negedge rst)  //檢測(cè)第一次脈沖發(fā)生 key_edge
                            begin
                                          if(!rst)
                                                        begin
                                                                      key_now=1'b1;
                                                                      key_pre=1'b1;
                                                        end
                                          else
                                                        begin
                                                                      key_now <= key;
                                                                      key_pre <= key_now;
                                                        end
                            end
                           
              assign key_edge = key_pre&(~key_now); //按鍵按下產(chǎn)生一個(gè)周期正脈沖
            
              always@(posedge clk or negedge rst)  //定時(shí)器初始化
                            begin
                                          if(!rst)
                                                        count<=18'h0;
                                          else if(key_edge)
                                                        count<=18'h0;
                                          else
                                                        count<=count+1'h1;
                            end
                           
              always@(posedge clk or negedge rst) //如果有按鍵按下,延時(shí)21ms 再檢測(cè)一次key
                            begin
                                          if(!rst)
                                                        begin
                                                                      key2_now<=1'b1;
                                                        end
                                          else if(count==18'h3ffff)
                                                        begin
                                                                      key2_now<=key;
                    key2_pre<=key2_now;                                          //這里寫(xiě)錯(cuò)了                           
                                                        end
                            end
                           
              //always@(posedge clk or negedge rst)
                            //begin
                                          //if(!rst)
                                                        //key2_pre <=1'b1;
                                          //else
                                                        //key2_pre <=key2_now;
                            //end
                                                      
              assign  key_pulse = key2_pre&(~key2_now);            
            
              always@(posedge clk or negedge rst)
                            begin
                                          if(!rst)
                                                        led<=1'b1;
                                          else if(key_pulse)
                                                        led<=~led;
                                          else
                                                        led<=led;
                            end
endmodule

以上代碼運(yùn)行后并沒(méi)有得到我想要的結(jié)果,按鍵按下亮,松掉熄滅。原因是延時(shí)結(jié)束后key2_pre 不應(yīng)該在這里賦值。因?yàn)橄乱粋(gè)時(shí)鐘clk進(jìn)來(lái)時(shí)count已經(jīng)不等于18‘h3ffff了,則不會(huì)進(jìn)入賦值



需要改為:
              always@(posedge clk or negedge rst) //如果有按鍵按下,延時(shí)21ms 再檢測(cè)一次key
                            begin
                                          if(!rst)
                                                        begin
                                                                      key2_now<=1'b1;
                                                        end
                                          else if(count==18'h3ffff)
                                                        begin
                                                                      key2_now<=key;
                                                        end
                            end

              always@(posedge clk or negedge rst)
                            begin
                                          if(!rst)
                                                        key2_pre <=1'b1;
                                          else
                                                        key2_pre <=key2_now;
                            end
  這里比較難理解,key2_now 是等待21ms后真正的按鍵狀態(tài),而key2_pre是key2_now前一個(gè)周期的狀態(tài),即為高,所以這是如果真正按鍵按下了,會(huì)輸出一個(gè)周期的高電平脈沖。如果檢測(cè)到這個(gè)脈沖,則認(rèn)為按鍵是真的按下了。

2019/4/9
通過(guò)移位寄存器 練習(xí)編寫(xiě)測(cè)試文件,并對(duì)仿真結(jié)果進(jìn)行分析:
移位寄存器源碼:clk 來(lái)一次,高位向低位移位,rst 時(shí)賦初值
module SHIFT(clk,rst,datain,dataout);
              input clk,rst;
              input [6:0] datain;
              output dataout;
              wire dataout;
              reg [6:0] data;
              always@(posedge clk)
                            if(!rst)
                                          data <= datain;
                            else
                                          begin
                                                        data[6] <= 1'b0;
                                                        data[5] <= data[6];
                                                        data[4] <= data[5];
                                                        data[3] <= data[4];
                                                        data[2] <= data[3];
                                                        data[1] <= data[2];
                                                        data[0] <= data[1];
                                          end
              assign dataout = data[0];
endmodule
測(cè)試用例:
測(cè)試需要給條件為 clk 翻轉(zhuǎn)周期,rst 持續(xù)時(shí)間,以及rst 時(shí)給datain 賦的初值

`timescale 1ns/100ps    //
module SHIFT_TEST;
reg clk,rst;
reg [6:0] datain;
wire dataout;
              initial
                            begin
                                          clk = 0;
                                          rst = 1;
                                          datain = 7'b1110101;
                                          #50
                                          rst = 0;
                                          #100
                                          rst = 1;
                            end
always #10 clk = ~clk;
SHIFT u1(
                                                        .clk(clk),
                                                        .rst(rst),
                                                        .datain(datain),
                                                        .dataout(dataout)
         );
Endmodule

仿真結(jié)果如下:

把clk 周期改為20ns 看起來(lái)兩個(gè)圖有差別,實(shí)際上是一樣的,rst 變高后 clk第一個(gè)上一個(gè)升沿為移出的數(shù)據(jù),從clk上升沿往前看一個(gè)周期,其實(shí)都是1,移出的數(shù)據(jù)為1010111,

實(shí)現(xiàn)了移位的功能。RST 為高的時(shí)候數(shù)據(jù)才是有效的,有意思的是在rst為低時(shí),輸出是保持賦值的最低位不變的。

比如改賦值為1110100,clk 周期為20ns 波形如下:


完整的Word格式文檔51黑下載地址:

小腳丫FPGA學(xué)習(xí)筆記.docx (572.01 KB, 下載次數(shù): 22)


評(píng)分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表