最近開(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)
2019-4-9 18:50 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|