EDITORIAL言葉
私たちが書かれた水のランプドライバを達成するために持っていることのこのセクションには、もちろん、照明が終わりではない、最も重要なのは、我々は、この軽水のコードを達成するために、いくつかの重要な仕様を持つことができるということです。
プロジェクトの要件
次のように我々は、軽水モードを主張:リセットボタンが押されると、すべてのライトは、リセットボタンが解除されると、まず、第1のランプが点灯され、第2のランプが点灯している間に、次に第1のランプは、次いで、オフ、オフ第二の光は、第三の照明ランプ、及び第三のライトがオフになっている間、第四のランプが同時に点灯し、オフであり、第1のランプが点灯しながら、最終的に第四の光が、消灯しているので、サイクル、水を達成。
関連技術の説明
プロジェクトの要件は、私たちが見ていると信じて、そして、我々はそれがどのように行うのですか?コードを書きますか?NO 我々はプロジェクトのニーズを詳しく見てとる内部キーを伴う、LEDが点灯し、我々はまた、光の流れを開始または停止するには、ボタンを制御する必要があります。あなたがコードを書く前に、そう、私たちは、最初にクリアキーを押しべきと違い何解放し、LED照明が低いか高い光です。唯一の明確なパフォーマンスの周辺機器、我々は適切にこれらの周辺機器を駆動するためにコードを書くことがあります。コードは、私たちの思考に反映されているので、私たちが書く前にコードが最初に無益でなければならないコードを書くためにそうブラインド、自分のアイデアをまっすぐ必要があります。
ハードウェア設計
次の図は、ボタンのタッチ示す接続関係FPGAの概略図を
キーが解放され、上記回路図から、FPGAポートはプルアップ抵抗、ハイレベルの検出に等しいです。押下するとき、接地面にキーを介してFPGA端子がローレベルに検出されます。
次の図に示す LEDとFPGAとの接続関係を模式的に
上から見た回路図で、正極のすべてに3.3V電源のLED。次いで、ポートはFPGAの低レベルが与えられた場合にのみ、LEDが点灯します。場合ハイエンドのFPGAは、LED消灯しました。
トップレベルのアーキテクチャ設計
関連する周辺機器のすべてのプロジェクトの要件とプロジェクトの要件は次がそれをコーディングを開始することができません、明確に分析されていますか?答えは -NO!ハハ、本当にケーキの一部であるコードを書くエンジニアのために、実際には、心配しないで、目がああ数行をノックすることができます閉じました。最終的な実装の成功を決める最も重要なプロジェクトは、一般的に特定のコードではなく、予備設計のアーキテクチャは、優れたアーキテクチャは同じように簡単に簡略化することができ、非常に複雑なプロジェクトは徐々に多くの単純なサブに分割されますモジュールは、設計効率と成功率が向上するだけでなく、労働力のチーム、部門として戦うために、より適していないだけ。前設計コードの先頭に最後まで明確な枠組みを持っていないとさえそれは単に原理でできないかもしれない場合は、全体的なアーキテクチャは、良い友達よりも多くの害ように再設計する必要があります。私たちの水のために以下に示すようにただ一つのモジュールにさらに簡単に、非常に単純なものの、基本的なビルディングブロックを、点灯が、その後、私たちは、このような習慣を開発する必要があります。
ポート説明
ポート名 |
機能 |
CLK |
システムクロック入力(50MHzの) |
RST_N |
リセットボタン(アクティブロー) |
pio_led |
4ビットLED駆動ポート |
コードの説明
コードを書くことが最後にでき、特定のコードの実装手順は、(後で書くために何を、何を書くために)、あなたがビデオをサポートしている夢の翼兄弟を見ることができます。ここでは、特定のコードは、直接以下で与えます
/ ************************************************* *** *エンジニア: ドリーム・ブラザーウイング * QQ:761664056 *モジュール機能:水ライト ************************************************** *** / 01 モジュール led_learn ( CLK 02 、 // システム・クロック入力 RST_N 03 、 // システムリセット 04 pio_led // LED 駆動出力 05 )。 06 // システム入力 07 入力 CLKを、 // システム・クロック入力 08 INPUT RST_N ; // リセット 09 // システム出力 10 出力 REG [ 3 : 0 ] pio_led ; // LED 駆動出力 11 // 定義されたバッファレジスタ 12は、 REG [ 1 : 0 ]の状態; // ステータス・レジスタ定義 13 // LED 駆動ロジック 14 常に(@ posedgeの CLK または negedgeの RST_N ) 15 始めます 16 もし(! RST_N ) 17 始めます Pio_led 18は、<= 4'b1111 ; // LEDが消灯しています 。状態19 <= 0 ; // 初期値を登録します 20 終了 21 他に 始めます 22 case(state) 23 0:begin 24 pio_led<=4'b0111;//第一个灯点亮 25 state<=1;//状态跳转 26 end 27 1:begin 28 pio_led<=4'b1011;//第二个灯点亮 29 state<=2;//状态跳转 30 end 31 2:begin 32 pio_led<=4'b1101;//第三个灯点亮 33 state<=3;//状态跳转 34 end 35 3:begin 36 pio_led<=4'b1110;//第四个灯点亮 37 state<=0;//状态跳转 38 end 39 default:state<=0; 40 endcase 41 end 42 end 43 endmodule |
这里我们应用的就是状态机的概念,第一步进行某些操作,然后跳到下一步进行其他操作,直到所有操作完成以后再返回初始状态
那么我们现在想当然写出来的逻辑是不是可以正确实现我们的目标呢?这其实还是一个大大的问号,那么接下来,我们需要做的就是进行逻辑仿真,梦翼师兄在教学过程中常说的一句话就是“对不对,只有仿真说了算”。
接下来我们编写仿真代码如下
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯测试模块 *****************************************************/ 01 `timescale 1ns/1ps //时间单位和精度定义 02 module tb; 03 04 //系统输入 05 reg clk; //系统时钟输入 06 reg rst_n; //系统复位 07 //系统输出 08 wire [3:0]pio_led;//LED驱动输出 09 10 initial 11 begin 12 clk=0; 13 rst_n=0; 14 #1000.1 rst_n=1; 15 end 16 17 always #10 clk=~clk;//50MHz时钟 18 19 led_learn led_learn( 20 .clk(clk), //系统时钟输入 21 .rst_n(rst_n), //系统复位 22 .pio_led(pio_led)//LED驱动输出 23 ); 24 endmodule |
运行仿真软件Modelsim 查看仿真波形(软件具体操作请观看梦翼师兄配套教学视频)
由仿真图,我们可以看到在每个时钟的上升沿pio_led的值发生一次切换,从第一个到第四个灯依次循环点亮,说明逻辑设计正确。
好了,波形仿真正确了,如果下载到开发板,流水灯可以实现了吗?答案还是NO!什么?梦翼师兄疯了吧,一会儿说逻辑对了,一会儿又说流水灯还不能实现,到底能不能愉快的玩耍啦?哈哈,这就是仿真和真实环境条件切换的一个误区。大家试想一下,我们现在每来一个时钟,LED就会切换一次状态,那么由于我们的时钟是50MHz,因此我们的时钟周期仅仅为20Ns,这么快的速度,人的眼睛是无法分辨的,那么在这种条件下,我们当然是看不到流水现象的。
那么如何才能看到流水呢?对,我们必须降低LED的切换速度。那么LED的切换速度和谁有关系呢?第一当然是时钟,假设时钟速度很慢,那么流水的速度自然也会很慢,第二个原因就是状态机,因为不管时钟速度如何,状态机只要控制自己的状态不要那么快切换,那么也可以实现我们的目的。
那么,首先让我们从状态机的角度去控制LED的切换速度,我们给出修改的代码如下
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯 *****************************************************/ 01 module led_learn( 02 clk, //系统时钟输入 03 rst_n, //系统复位 04 pio_led//LED驱动输出 05 ); 06 //系统输入 07 input clk; //系统时钟输入 08 input rst_n; //系统复位 09 //系统输出 10 output reg [3:0]pio_led;//LED驱动输出 11 //中间寄存器定义 12 reg [1:0]state;//状态寄存器定义 13 reg [40:0]counter;//计数寄存器 14 //LED驱动逻辑 15 always@(posedge clk or negedge rst_n) 16 begin 17 if(!rst_n) 18 begin 19 pio_led<=4'b1111;//LED全部熄灭 20 state<=0;//寄存器赋初值 21 counter<=0;//计数器赋初值 22 end 23 else begin 24 case(state) 25 0:begin 26 pio_led<=4'b0111;//第一个灯点亮 27 if(counter<12)//延时时间不够则继续计数 28 counter<=counter+1; 29 else 30 begin 31 state<=1;//状态跳转 32 counter<=0;//计数器清零 33 end 34 end 35 1:begin 36 pio_led<=4'b1011;//第二个灯点亮 37 if(counter<12)//延时时间不够则继续计数 38 counter<=counter+1; 39 else 40 begin 41 state<=2;//状态跳转 42 counter<=0;//计数器清零 43 end 44 end 45 2:begin 46 pio_led<=4'b1101;//第三个灯点亮 47 if(counter<12)//延时时间不够则继续计数 48 counter<=counter+1; 49 else 50 begin 51 state<=3;//状态跳转 52 counter<=0;//计数器清零 53 end 54 end 55 3:begin 56 pio_led<=4'b1110;//第四个灯点亮 57 if(counter<12)//延时时间不够则继续计数 58 counter<=counter+1; 59 else 60 begin 61 state<=0;//状态跳转 62 counter<=0;//计数器清零 63 end 64 end 65 default:state<=0; 66 endcase 67 end 68 end 69 endmodule |
该段代码和上一段代码唯一的区别之处在于我们在状态机状态跳转的部分加入了延时计数器,只有累计时钟上升沿达到一定数量以后,状态才会发生跳转。这样就可以有效延长每个LED灯点亮的时间。当然啦,这里面计数值到12完全是梦翼师兄为了仿真方便而乱写的一个数,如果真的要实现流水灯,计数值应该很大才可以哦。接下来让我们看一下这段代码的仿真波形
对比两个波形图,我们可以看到加延时计数器之后,流水灯的切换速度明显变慢,可以实现我们的设计要求。通过该实验,我们同时也学到了计数器的用法。那么还剩下一种方式,那就是控制我们的频率了,我们设计代码如下
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯 *****************************************************/ 01 module led_learn( 02 clk, //系统时钟输入 03 rst_n, //系统复位 04 pio_led//LED驱动输出 05 ); 06 //系统输入 07 input clk; //系统时钟输入 08 input rst_n; //系统复位 09 //系统输出 10 output reg [3:0]pio_led;//LED驱动输出 11 //中间寄存器定义 12 reg [1:0]state;//状态寄存器定义 13 reg [40:0]counter;//计数器定义 14 reg clk_slow;//慢时钟定义 15 //时钟分频电路 16 always@(posedge clk or negedge rst_n) 17 begin 18 if(!rst_n) 19 begin 20 counter<=0; 21 clk_slow<=0; 22 end 23 else 24 begin 25 if(counter<12) 26 counter<=counter+1; 27 else 28 begin 29 counter<=0; 30 clk_slow<=~clk_slow; 31 end 32 end 33 end 34 35 //LED驱动逻辑 36 always@(posedge clk_slow or negedge rst_n) 37 begin 38 if(!rst_n) 39 begin 40 pio_led<=4'b1111;//LED全部熄灭 41 state<=0;//寄存器赋初值 42 end 43 else begin 44 case(state) 45 0:begin 46 pio_led<=4'b0111;//第一个灯点亮 47 state<=1;//状态跳转 48 end 49 1:begin 50 pio_led<=4'b1011;//第二个灯点亮 51 state<=2;//状态跳转 52 end 53 2:begin 54 pio_led<=4'b1101;//第三个灯点亮 55 state<=3;//状态跳转 56 end 57 3:begin 58 pio_led<=4'b1110;//第四个灯点亮 59 state<=0;//状态跳转 60 end 61 default:state<=0; 62 endcase 63 end 64 end 65 endmodule |
以上代码16-33行为我们添加的计数器分频模块,通过计数器计数,利用快时钟分频得到一路慢时钟。代码36行
36 always@(posedge clk_slow or negedge rst_n) |
我们用分频得到的慢时钟作为状态机的切换时钟,这样也可以有效控制状态机切换的速度。查看仿真波形如下
由仿真图可知,第一:快时钟正确生产了慢时钟 第二:LED在慢时钟的控制下进行切换,说明我们的逻辑设计正确。通过该实验,我们也可以学会分频电路的设计方法。这也是梦翼师兄的初衷,尽可能通过一个实验项目多学东西,后面我们就可以利用这些知识点来解决其他问题啦。