电子森林STEP-MXO2_1 入门部分全部实验

news/2025/3/22 20:53:19/

前言

本部分实验基于电子森林小脚丫开发板的数电入门教程实验。实验链接:step-mxo2入门教程 电子森林] (eetree.cn)

其中代码是博主学习后根据自己思路自己敲的,并非直接复制,且仅供学习交流使用,侵删。

lattice 环境配置在此不再赘述~

按键LED

module LED (key,sw,led);input [3:0] key;input [3:0] sw;output [7:0] led;assign led={key, sw};endmodule

1688844371133

三色LED

开发板上的一个三色LED灯,通过赋3位值来决定亮哪个颜色。用三个按键控制 easy

module LED (key,led);input [2:0] key;output [2:0] led;assign led={key};endmodule

image-20230709033048500

3-8译码器

三个按键输出8个状态。主要是练习 always case 的使用。

module LED (key,led);input [2:0] key;output [7:0] led;reg [7:0] led;always @(key)begincase(key)3'b000:led=8'b11111110;3'b001:led=8'b11111101;3'b010:led=8'b11111011;3'b011:led=8'b11110111;3'b100:led=8'b11101111;3'b101:led=8'b11011111;3'b110:led=8'b10111111;3'b111:led=8'b01111111;default:;		endcaseendendmodule

数码管显示

两个数码管,每个需要9位输入,其中4位是数据输入,可以输入10种状态对应0-9.

我们通过按键和拨码开关传入数据。led 设置我想就记住就行先。

module SEG_LED (key,sw,seg_led_1,seg_led_2);input [3:0] key;input  [3:0] sw;output [8:0] seg_led_1;output [8:0] seg_led_2;reg [8:0] seg [9:0];initialbeginseg[0]=9'h3f;seg[1]=9'h06;seg[2]=9'h5b;seg[3]=9'h4f;seg[4]=9'h66;seg[5]=9'h6d;seg[6]=9'h7d;seg[7]=9'h07;seg[8]=9'h7f;seg[9]=9'h6f;endassign seg_led_1=seg[key];assign seg_led_2=seg[sw];endmodule

image-20230709111832655

时钟分频

算法

偶数倍频:光看上升或者下降沿个数就行,0N/2-1时翻转,N/2N-1时再翻转。

奇数倍频:形如下图。

image-20230709151349660

如图为5分频,输入5个周期输出1个周期。所以每2.5个周期一翻转,比如从上升沿开始,再经过两个上升沿,后一个下降沿后翻转。

这样就没法只通过上升或者下降沿去判断了,因为结尾是半个上升/下降沿。不过通过纯上升,下降沿的波形(上升沿比下降沿多一个周期)我们可以发现,两者and操作得到的就是我们想要的结果。

实现

module div(clk_in, rst_n ,clk_out);input clk_in,rst_n;output clk_out;parameter WIDTH=3;parameter N=5;reg [WIDTH-1:0] cnt_p, cnt_n;reg clk_p, clk_n;always @ (posedge clk_in or negedge rst_n)beginif(!rst_n)cnt_p<=0;else if(cnt_p==(N-1))cnt_p<=0;else cnt_p<=cnt_p+1;endalways @ (negedge clk_in or negedge rst_n)beginif(!rst_n)cnt_n<=0;else if(cnt_n==(N-1))cnt_n<=0;else cnt_n<=cnt_n+1;endalways @ (posedge clk_in or negedge rst_n)beginif(!rst_n)clk_p<=0;else if(cnt_p<(N>>1))clk_p<=0;else clk_p<=1;endalways @ (negedge clk_in or negedge rst_n)beginif(!rst_n)clk_n<=0;else if(cnt_n<(N>>1))clk_n<=0;else clk_n<=1;endassign clk_out=(N==1)?clk_in:(N[0])?clk_p&clk_n:clk_p;
endmodule

打不开仿真显示 license 错误可能是仿真和 license 版本不对。

1688887214194

1688887262813

流水灯

采用模块的思想。我们把前面的3-8译码器(led)部分和时钟分频部分代码结合起来,然后用一个模块去用他俩,传递输入输出。

module flashled (clk,rst,led);input clk,rst;output [7:0]led;reg [2:0] cnt;wire clk1h;LED u1 (.key(cnt),.led(led));div #(.WIDTH(32),.N(12000000)) u2 (         .clk_in(clk),.rst_n(rst),.clk_out(clk1h));               always @(posedge clk1h or negedge rst)if(!rst)cnt<=0;elsecnt<=cnt+1;
endmodule

还有一种简单的 led 赋值法,我们知道 led 形如 1111 1101 也就是8位不断循环来形成流水灯的效果。所以我们只需要让 led 不断循环左移或者右移就行。

led={led[0],led[7:1]};

1688891724885

按键消抖

如果只是一个简单的按下按键翻转LED灯状态,那确实很好写:

module debounce (key,rst,key_pulse);input key,rst;output key_pulse;reg key_pulse;always @(negedge rst or negedge key)beginif(!rst)key_pulse=1;elsekey_pulse=~key_pulse;endendmodule

选用一个按键作为 rst,一个按键为 led 的输入。

但是经典问题,按下按键和松开的一瞬间按键的电平是不断抖动的并不稳定:

image-20230709165306536

这里以(下降沿触发)为例。解决方案为:检测到第一次下降沿后,先延时>10ms,再检测按键是否仍然处于低电平,如果是说明确实是被按下了,如果不是可能只是一个小抖动。

module debounce (clk,key,rst,key_pulse);input key;input rst;input clk;output key_pulse;reg key_rst_pre;reg key_rst;reg [17:0] cnt;wire key_edge;always @(posedge clk or negedge rst)beginif(!rst) beginkey_rst_pre<=1'b1;key_rst<=1'b1;endelse beginkey_rst<=key;key_rst_pre<=key_rst;endendassign key_edge=key_rst_pre&~(key_rst);reg key_sec_pre,key_sec;always @(posedge clk or negedge rst)beginif(!rst)cnt<=18'h0;else if(key_edge)cnt<=18'b0;elsecnt<=cnt+1'h1;endalways @(posedge clk or negedge rst)beginif(!rst)key_sec<=1'b1;else if(cnt==18'h3ffff)key_sec<=key;endalways @(posedge clk or negedge rst)beginif(!rst)key_sec_pre<=1'b1;elsekey_sec_pre<=key_sec;endassign key_pulse=key_sec_pre&~(key_sec);endmodule

下降沿的时候 key_edge 置1,只有当起始状态上升沿, key_edge 下降后一定时间内没有新的下降沿(无抖动)且此时仍然为下降沿时脉冲信息才为1.

处理脉冲部分很简单,读到 pulse 如果是1就翻转 led,否则保持。

module top (clk,key,led,rst);input clk;input key;input rst;output reg led;wire key_pulse;debounce u1 (.clk(clk),.key(key),.rst(rst),.key_pulse(key_pulse));always @ (posedge clk or negedge rst)beginif(!rst)led<=1'b1;else if(key_pulse)led<=~led;elseled<=led;endendmodule

这里写的时候有一个很有趣的bug,我把cnt计数++部分漏掉了,然后生成引脚图定义的时候 clk key rst 都是 unconnected 的引脚,查了一下说是“编译器认为你这几个输入对输出无影响 就自动忽略了”。

计时控制

需求:写一个篮球24s计时软件。要求:

  1. 上电后从24开始倒计时到0为止停止。
  2. 按下 rst 归位到24.
  3. 按下按钮后暂停当前计时,再次按下后继续计时。

主要就是写一个模块用到了时钟分频模块(传入参数设定间隔1s),按键模块(用刚刚用的消抖的)。数码管显示 LED显示都可以在本模块内补全。

写的时候发现一个 always 赋值语法规范:一个变量赋值不要在多个 always 里分别有过赋值,会报错,尽量集中到一个 always 里。

module BasketballBoard (key, clk, rst, seg_led_1,seg_led_2,led);input key, clk, rst;output [8:0] seg_led_1;output [8:0] seg_led_2;output reg [7:0] led;reg [8:0] seg [9:0];reg [4:0] SED_LED_H;reg [4:0] SED_LED_L;wire key_pulse;wire clk1h;reg stop_flag=0;reg rst_flag=0;initialbeginseg[0]=9'h3f;seg[1]=9'h06;seg[2]=9'h5b;seg[3]=9'h4f;seg[4]=9'h66;seg[5]=9'h6d;seg[6]=9'h7d;seg[7]=9'h07;seg[8]=9'h7f;seg[9]=9'h6f;endalways @ (posedge key_pulse)if(rst) rst_flag<=~rst_flag;debounce u1 (.clk(clk),.rst(rst),.key(key),.key_pulse(key_pulse));div #(.WIDTH(32),.N(12000000)) u2 ( .clk_in(clk),.rst_n(rst),      .clk_out(clk1h));always @ (posedge clk1h or negedge rst)beginif(!rst)beginSED_LED_H<=4'd2;SED_LED_L<=4'd4;stop_flag<=0;endelse if((!rst_flag)&(!stop_flag))beginled<=8'b11111111;if(SED_LED_L)SED_LED_L<=SED_LED_L-4'd1;else if(SED_LED_H) beginSED_LED_L<=4'd9;SED_LED_H<=SED_LED_H-4'd1;endif((!SED_LED_H)&(!SED_LED_L))stop_flag<=1;endelseled<=8'b00000000;endassign seg_led_1=seg[SED_LED_H];assign seg_led_2=seg[SED_LED_L];endmodule

led seg key rst clk 这些都是和前面采取类似的引脚设置。再加上前面的 div 模块和 key 模块即可。

呈现效果:计时结束和按下暂停键时 LED 灯会全亮来代表暂停时钟。

LED 流水灯

PWM 原理。随着时间推移改变占空比来呈现出不同亮度的 LED。

1688927302381

比如每个周期长度 100,第一个周期设定高电平0 低电平100,第二个周期设定高电平10 低电平90,第三个周期设定高电平20 低电平80……

也就是说我们需要两个计时器,第一个就是老老实实的记录一个又一个周期,0~Period-1.

第二个计时器一方面,在第一个计时器结束一个周期的时候改变一下自己的占空比,比如上例每个周期结束高电平部分+10.

另一方面,第二个计时器和第一个计时器作比较。比如当前第二个计时器是20也就是20高电平 80低电平,那么计时器1<计时器2的时候设置为高电平,计时器1>计时器2的时候设置为低电平。

module WaterLED(clk,rst,led);input clk, rst;output led;reg [13:0] cnt1;reg [13:0] cnt2;parameter CNT_NUM=2400;reg flag=0;always @ (posedge clk or negedge rst)beginif(!rst)cnt1<=13'b0;else if(cnt1==CNT_NUM-1) begincnt1<=13'b0;if(flag==0)if(cnt2>=CNT_NUM) beginflag<=1'b1;endelse cnt2<=cnt2+13'b1;else if(flag==1)if(cnt2<=0) beginflag<=1'b0;endelse cnt2<=cnt2-13'b1;endelse cnt1<=cnt1+13'b1;endassign led=cnt1<cnt2?1:0;
endmodule

代码没啥难的。

交通信号灯

两个三色模块各亮各的,表示主路和支路的红绿灯信号。

主路:15绿,3黄,10红(单位:秒)。

支路:7绿,3黄,18红。

概念:状态机,一种抽象模型。对象有状态(state,比如此例中两个红绿灯的三种状态),事件(event,外界施加的,比如我让计数–,或者切换状态颜色),行为(action,交通灯按 event 自己执行的动作,比如切颜色),切换状态(transition,比如红灯绿灯黄灯之间三种状态)。

一开始觉得很容易写。就是两个数组存储主路支路状态表嘛。

module TrafficLED (clk,rst,LED_1,LED_2);input clk,rst;output reg [2:0] LED_1;output reg [2:0] LED_2;reg [4:0] state_1 [2:0];reg [4:0] state_2 [2:0];reg [2:0] color_state [2:0];reg [2:0] cur_state_1;reg [2:0] cur_state_2;reg [4:0] cur_time_1;reg	[4:0] cur_time_2;wire clk1h;initial beginstate_1[0]=5'd14;state_1[1]=5'd2;state_1[2]=5'd9;state_2[0]=5'd6;state_2[1]=5'd2;state_2[2]=5'd17;color_state[0]=3'b101;color_state[1]=3'b100;color_state[2]=3'b110;cur_time_1=5'd14;cur_time_2=5'd6;enddiv #(.WIDTH(32),.N(12000000)) u2 (         .clk_in(clk),.rst_n(rst),.clk_out(clk1h));always @ (posedge clk1h or negedge rst) beginif(!rst) begincur_state_1<=0;cur_state_2<=0;cur_time_1<=5'd14;cur_time_2<=5'd6;LED_1<=color_state[cur_state_1];LED_2<=color_state[cur_state_2];endelse beginif(cur_time_1)cur_time_1<=cur_time_1-5'b1;else beginif(cur_state_1<2)cur_state_1<=(cur_state_1+1);else cur_state_1<=0;cur_time_1<=state_1[cur_state_1+1];endif(cur_time_2)cur_time_2<=cur_time_2-5'b1;else beginif(cur_state_2<2)cur_state_2<=(cur_state_2+1);else cur_state_2<=0;cur_time_2<=state_2[cur_state_2+1];endLED_1<=color_state[cur_state_1];LED_2<=color_state[cur_state_2];endendendmodule

有两个注意的地方,都是和 fpga 非阻塞赋值相关的。

之前知道 always 里如果用 <= 赋值,所有变量是结束 always 的时候同时赋值的。第一个错误写法是这么写的:

if(cur_time_1)cur_time_1<=cur_time_1-5'b1;
else beginif(cur_state_1<2)cur_state_1<=(cur_state_1+1);else cur_state_1<=0;cur_time_1<=state_1[cur_state_1];//这里有区别end
if(cur_time_2)cur_time_2<=cur_time_2-5'b1;
else beginif(cur_state_2<2)cur_state_2<=(cur_state_2+1);else cur_state_2<=0;cur_time_2<=state_2[cur_state_2];//这里有区别end
LED_1<=color_state[cur_state_1];
LED_2<=color_state[cur_state_2];

因为我想的是,cur_state+1后切换状态为当前cur_state的状态,也就是已经+1过后的状态。

实际不是这么回事,实际上他俩指令是同时执行的,也就是说state[cur_state]还是刚才没+1的状态。

所以我改成 state[cur_state+1] 了。

第二个错误如下:

if(cur_time_1)cur_time_1<=cur_time_1-5'b1;
else begincur_state_1<=(cur_state_1+1);//这里有区别if(cur_state_1==3)cur_state_1<=0;//这里有区别cur_time_1<=state_1[cur_state_1+1];end
if(cur_time_2)cur_time_2<=cur_time_2-5'b1;
else begincur_state_2<=(cur_state_2+1);//这里有区别if(cur_state_2==3)cur_state_2<=0;//这里有区别cur_time_2<=state_2[cur_state_2+1];end
LED_1<=color_state[cur_state_1];
LED_2<=color_state[cur_state_2];

想的也是顺序执行,先+1判断是否超出了(0,1,2)的数组范围,如果超出了就归0.

但是 LED 赋值和 cur_state+1 是同时执行的,也就是有1s我的cur_state是3,LED也尝试获取数组3下标的状态。

所以干脆赋值的时候就:如果为2,直接归0,否则++。这样就不用再一步判断了。


http://www.ppmy.cn/news/854814.html

相关文章

animation.css无法显示动画效果问题解决

在使用【微信开发者工具】开发微信小程序时发现无法在开发者工具中展示出动画效果来 但是真机调试中可以正常的显示动画效果 【关于微信小程序中如何使用animation.css&#xff0c;参考微信小程序使用animation.css_THE WHY的博客-CSDN博客 】 同时发现在官网上点击各个动画并…

阶跃型多模光纤与渐变型多模光纤有何区别?

根据光纤折射率分布方式的不同&#xff0c;多模光纤可分为阶跃型多模光纤和渐变型多模光纤。由于阶跃型多模光纤和渐变型多模光纤的工作原理不同&#xff0c;导致它们在应用方面存在差异性。通过阅读该篇文章&#xff0c;您将充分了解到两者在工作原理和应用方面的区别。 阶跃…

三分钟了解多模光纤和单模光纤的区别-ielab

三分钟了解多模光纤和单模光纤的区别 随着网络的不断发展&#xff0c;高速率网络的要求不断增高&#xff0c;光纤作为主要的网络传输介质被更多的应用在了网络布线当中。但是光纤到底有什么区别呢&#xff1f;相信有很多人都不知道&#xff0c;我们现在就来详细的看一看。 一般…

15. 10BASE-F 型光纤介质和介质连接单元和星形的通用元件

缩写解释&#xff1a; AUI ATTACHMENT UNIT INTERFACE MDI MEDIUM DEPENDENT INTERFACE MII MEDIA INDEPENDENT INTERFACE PLS PHYSICAL LAYER SIGNALING PCS PHYSICAL CODING SUBLAYER PMA PHYSICAL MEDIUM ATTACHMENT MAU MEDIUM ATTACHMENT UNIT PHY PHYSICAL LAYER…

通信用多模光纤主要有哪些类型?OM1~OM5有什么区别

1 前言 根据光纤内光信号传输模式的不同&#xff0c;光纤可分为单模光纤和多模光纤&#xff0c;见《常用通信光纤是如何分类的》一文。 在传送网和有线接入网中&#xff0c;我们接触到的光纤类型主要有&#xff1a;G.652、G.654和G.657&#xff0c;这些都是单模光纤。多模光纤…

网络传输介质 通信中的有线介质:双绞线、同轴电缆、光纤 引导性传输介质

物理层的作用是将比特从一台机器传输到另一台机器。实际传输所用的物理介质可以用多种选择。每一种传输介质都有独特的性质&#xff0c;体现在带宽、延迟、成本以及安装和维护难易程度的不同&#xff0c;因此分别有自己适用的场合。 大致上可以将介质分为引导性介质&#xff0…

ST、SC、FC、LC光纤接头区别?

ST、SC、FC、LC光纤接头区别? 2017-11-07 09:48 ST、SC、FC光纤接头是早期不同企业开发形成的标准&#xff0c;使用效果一样&#xff0c;各有优缺点。 ST、SC连接器接头常用于一般网络。ST头插入后旋转半周有一卡口固定&#xff0c;缺点是容易折断;SC连接头直接插拔&#…

双绞线,同轴电缆和光纤电缆之间的区别—Vecloud微云

我们大多数人都知道ADSL和光纤互联网之间的区别&#xff0c;但是这些连接背后的电缆可能更多是个谜。 三种最常见的通信电缆类型是双绞线&#xff0c;同轴电缆&#xff0c;光纤。 了解这三者之间的差异将使您了解数据如何通过每条电缆传输&#xff0c;这最终会影响您的连接以及…