找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2486|回复: 0
打印 上一主题 下一主题
收起左侧

FPGA入门学习笔记分享

[复制链接]
跳转到指定楼层
楼主
ID:80221 发表于 2019-4-9 18:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近开始入门FPGA,断断续续做了些笔记。

今天装了lattice开发环境,尝试模仿历程,把LED_shining 历程敲一遍,进行编译。报错:

提示为23行有语法错误,原因是module最后一个参数不需要逗号

改掉这里再编译 提示25行错误

定位实际是24行语句少写了分隔符导致,加上之后再编译就成功了。

管脚分配,结合硬件手测分配管脚

两个输入 clk_in ,rst_n_in

两个输出 led1,led2


2019/2/28
  三个开关控制RGB led实验。

module LED (sw,led);
input [2:0] sw;//开关输入信号,利用了其中3个开关
output [2:0] led;//输出信号到RGB LED
assign led = sw;/assign连续赋值。
endmodule

我想用3个开关控制两个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

改为非阻塞赋值的方式:

需要注意的有两点,

1.输入port只能是wire型不能定义成reg型。

2.非阻塞赋值必须用在always块中执行

3.if 语句或者case 语句 后面只能跟一句赋值语句,若要跟多句,需要用到begin end语句

4.always块要定义触发信号


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

开关控制数码管显示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;//小脚丫上第二个数码管
output[8:0] seg_led_1;//控制一个数码管需要9个信号 MSB~LSB=DIG、DP、G、F、E、D、C、B、A
output [8:0] seg_led_2;//在小脚丫上第二个数码管的控制信号  MSB~LSB=DIG、DP、G、F、E、D、C、B、A
reg[8:0] seg [9:0];//定义了一个reg型的数组变量,相当于一个10*9的存储器,存储器一共有10个数,每个数有9位宽
initial//在过程块中只能给reg型变量赋值,Verilog中有两种过程块always和initial
//initial和always不同,其中语句只执行一次
begin
seg[0]=9'h3f;//对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字  0
seg[1]=9'h06;//7段显示数字  1
seg[2]=9'h5b;//7段显示数字  2
seg[3]=9'h4f;//7段显示数字  3
seg[4]=9'h66;//7段显示数字  4
seg[5]=9'h6d;//7段显示数字  5
seg[6]=9'h7d;//7段显示数字  6
seg[7]=9'h07;//7段显示数字  7
seg[8]=9'h7f;//7段显示数字  8
seg[9]=9'h6f;//7段显示数字  9
end
assign seg_led_1 = seg[seg_data_1];//连续赋值,这样输入不同四位数,就能输出对于译码的9位输出
assign seg_led_2 = seg[seg_data_2];
endmodule


原例程用的是数据流描述方式(assign)实现的,我改为行为描述方式(initial+always)
并从显示0~9扩展为显示0~F
注意的是 initial后面是不需要“:”
Initial 和always后都可以用非阻塞赋值,多个要用包含在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
按键消抖:
需要掌握两个概念:
脉冲边沿检测:用一个频率更高的时钟去触发待检测的信号,用两个寄存器去存储相邻两个时钟采集的值,然后进行异或运算,如果不为0,则代表了上升沿或者下降沿。
消抖方法,第一次检测脉冲,delay20ms,再检测key是否为低,如果为低则正面按键按下。否则认为是抖动。

我写的代码如下(有问题):
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)  //检测第一次脉冲发生 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); //按键按下产生一个周期正脉冲
            
              always@(posedge clk or negedge rst)  //定时器初始化
                            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) //如果有按键按下,延时21ms 再检测一次key
                            begin
                                          if(!rst)
                                                        begin
                                                                      key2_now<=1'b1;
                                                        end
                                          else if(count==18'h3ffff)
                                                        begin
                                                                      key2_now<=key;
                    key2_pre<=key2_now;                                          //这里写错了                           
                                                        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

以上代码运行后并没有得到我想要的结果,按键按下亮,松掉熄灭。原因是延时结束后key2_pre 不应该在这里赋值。因为下一个时钟clk进来时count已经不等于18‘h3ffff了,则不会进入赋值



需要改为:
              always@(posedge clk or negedge rst) //如果有按键按下,延时21ms 再检测一次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后真正的按键状态,而key2_pre是key2_now前一个周期的状态,即为高,所以这是如果真正按键按下了,会输出一个周期的高电平脉冲。如果检测到这个脉冲,则认为按键是真的按下了。

2019/4/9
通过移位寄存器 练习编写测试文件,并对仿真结果进行分析:
移位寄存器源码:clk 来一次,高位向低位移位,rst 时赋初值
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
测试用例:
测试需要给条件为 clk 翻转周期,rst 持续时间,以及rst 时给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

仿真结果如下:

把clk 周期改为20ns 看起来两个图有差别,实际上是一样的,rst 变高后 clk第一个上一个升沿为移出的数据,从clk上升沿往前看一个周期,其实都是1,移出的数据为1010111,

实现了移位的功能。RST 为高的时候数据才是有效的,有意思的是在rst为低时,输出是保持赋值的最低位不变的。

比如改赋值为1110100,clk 周期为20ns 波形如下:


完整的Word格式文档51黑下载地址:

小脚丫FPGA学习笔记.docx (572.01 KB, 下载次数: 22)


评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表