1.按键软件去抖动 input[KEY_WIDTH-1:0] key_in; //外部按键输入 output[KEY_WIDTH-1:0]key_out; //按键消抖输出 reg[KEY_WIDTH-1:0]dout1,dout2,dout3; //寄存器 parameter KEY_WIDTH = 8; //参数
assign key_out = (dout1 | dout2 | dout3); //按键消抖输出
always @(posedge clk) // always @(posedge count[17]) 当系统时钟是48MHZ时,count一直计算,计到18位为1时也就满足了按键时钟的要求 begin dout1 <= key_in; dout2 <= dout1; dout3 <= dout2; end
//下面是利用按键 消抖后的输出 设置一个标志位,将琴键开关转换为乒乓开关 就需要点击2下才可以回复到原来的状态
always @(negedge key_out) 或者利用边沿检测的知识
always @(posedge clock)//按键6
按键消抖关键在于提取稳定的低电平状态,滤除前沿、后沿抖动毛刺。对于一个按键信号,可以用一个脉冲对它进行采样。如果连续三次采样为低电平,可以认为信号已经处于键稳定状态,这时输出一个低电平按键信号。继续采样的过程中如果不能满足连续三次采样为低,则认为键稳定状态结束,这时输出变为高电平。 按键消抖:按键消抖处理一般有硬件和软件两种方法。软件消抖是检测到有触发后,延时一段时间(一般为10ms)后再检测触发状态,如果与之前检测到的状态相同,则认为有按键按下;如果没有。则判断为误触发。硬件就是加去抖动电路,这样可以从根本上解决按键抖动的问题。 消抖电路的采样时钟要实际应用可以灵活改变,因为按键触发的时间一般为几百毫秒,干扰毛刺脉宽一般为几百毫秒到几毫秒,所以采样时钟的周期一般为几毫秒。 这里我们可以选择5ms 即上式的clk的频率为200HZ
2.按键的边沿(下降沿)检测 reg [7:0] dout1,dout2,dout3,buff; always @(posedge clk) begin dout1 <= key_in; dout2 <= dout1; dout3 <= dout2; end always @(posedge clk) begin buff<=dout1|dout2|dout3; end assign key_out = ~(dout1 | dout2 | dout3)&buff;//按键的边缘检测 if(key_out[0])..然后就可以用key_out来作为控制信号了
//时钟分频部分 系统时钟 48MHZ
3.程序中用到的小分频程序
always @(posedge clk) begin if(dividi_clk) counter<=26'd0;//使counter为0 else counter<=counter+1'b1; end assign dividi=(counter>=26'd48000);//26‘d48000就是分频数(-1)。
如图是8分频的时序图
reg[16:0]count;//时钟分频计数器 120000分频
always @(posedge clock) always @(posedge clock) 都用系统时钟 if(div_clk) always @(posedge clk) begin if(cnt==设定值) //设定值-起始值=分频数的一半,即计数到分频数的一半时反转输出 begin cnt<=起始值; out<=~out; end else cnt<=cnt+1'b1;
end
如图8分频
always@(posedge clk) 4.循环左移,循环右移 现假设 led[4:0] =11101; 循环左移: led<={led[3:0],led[4]}; 循环右移: led<={led[0],led[4:1]};
5.16位的乘法器(吞吐量不大)
if(i == 5'd0) begin//锁存乘数、被乘数
assign yout = yout_r;
5.波特率的设置和利用 系统时钟为50HZ parameter bps9600= 5207,//波特率为9600bpsbps19200= 2603,//波特率为19200bps bps38400 = 1301,//波特率为38400bps bps57600 = 867,//波特率为57600bps bps115200 = 433; //波特率为115200bps parameter bps9600_2 = 2603, bps19200_2 = 1301, bps38400_2 = 650, bps57600_2 = 433, bps115200_2 = 216; `define BPS_PARA5207//波特率为9600时的分频计数值 `define BPS_PARA_22603//波特率为9600时的分频计数值的一半,用于数据采样 reg[12:0] cnt; //分频计数 reg clk_bps_r; //波特率时钟寄存器 always @ (posedge clk or negedge rst_n) if(!rst_n) cnt <= 13'd0; else if(cnt == `BPS_PARA ) cnt <= 13'd0;//波特率计数清零 else cnt <= cnt+1'b1;//波特率时钟计数启动 always @ (posedge clk or negedge rst_n) if(!rst_n) clk_bps_r <= 1'b0; else if(cnt == `BPS_PARA_2) clk_bps_r <= 1'b1;// clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 else clk_bps_r <= 1'b0; assign clk_bps = clk_bps_r;
6.对于inout信号的处理 当遇到inout双向数据的时候,要把它分成2部分, assign data = oe ? data_in : 2'bzz; assign data_out= data;
7.数码管的显示 always @(posedge clock) //定义上升沿触发进程 begin if(div_clk) // 数码管的刷新时间 大概可以是1MS cnt3 <= cnt3 + 1'b1; end always @(posedge clock) begin if(div_clk) begin case(cnt3) //选择扫描显示数据 3'd0:disp_dat = hex_r[15:12]; //第一个数码管 第一个数码管要显示的值 3'd1:disp_dat = hex_r[11:8]; //第二个数码管 3'd2:disp_dat = hex_r[7:4]; //第三个数码管 3'd3:disp_dat = hex_r[3:0]; //第四个数码管 3'd4:disp_dat = data[15:12]; //第五个数码管 3'd5:disp_dat = data[11:8]; //第六个数码管 3'd6:disp_dat = data[7:4]; //第七个数码管 3'd7:disp_dat = data[3:0]; //第八个数码管 endcase case(cnt3) //选择数码管显示位 3'd0:dig_r = 8'b01111111; //选择第一个数码管显示 3'd1:dig_r = 8'b10111111; //选择第二个数码管显示 3'd2:dig_r = 8'b11011111; //选择第三个数码管显示 3'd3:dig_r = 8'b11101111; //选择第四个数码管显示 3'd4:dig_r = 8'b11110111; //选择第五个数码管显示 3'd5:dig_r = 8'b11111011; //选择第六个数码管显示 3'd6:dig_r = 8'b11111101; //选择第七个数码管显示 3'd7:dig_r = 8'b11111110; //选择第八个数码管显示 endcase end end always @(disp_dat) begin case(disp_dat) //七段译码 4'h0:seg_r = 8'hc0; //显示0 4'h1:seg_r = 8'hf9; //显示1 4'h2:seg_r = 8'ha4; //显示2 4'h3:seg_r = 8'hb0; //显示3 4'h4:seg_r = 8'h99; //显示4 4'h5:seg_r = 8'h92; //显示5 4'h6:seg_r = 8'h82; //显示6 4'h7:seg_r = 8'hf8; //显示7 4'h8:seg_r = 8'h80; //显示8 4'h9:seg_r = 8'h90; //显示9 4'ha:seg_r = 8'h88; //显示a 4'hb:seg_r = 8'h83; //显示b 4'hc:seg_r = 8'hc6; //显示c 4'hd:seg_r = 8'ha1; //显示d 4'he:seg_r = 8'h86; //显示e 4'hf:seg_r = 8'h8e; //显示f endcase end //数码管动态扫描显示部分 always @(posedge clk) //count[17:15]大约1ms改变一次 begin case(count[17:15]) //选择扫描显示数据 3'd0:disp_dat = hour[3:0]; //秒个位 第一个数码管要显示的值 3'd1:disp_dat = hour[7:4]; //秒十位 3'd2:disp_dat = 4'ha; //显示"-" 3'd3:disp_dat = hour[11:8]; //分个位 3'd4:disp_dat = hour[15:12]; //分十位 3'd5:disp_dat = 4'ha; //显示"-" 3'd6:disp_dat = hour[19:16]; //时个位 3'd7:disp_dat = hour[23:20]; //时十位 endcase case(count[17:15]) //选择数码管显示位 3'd0:dig_r = 8'b11111110; //选择第一个数码管显示 3'd1:dig_r = 8'b11111101; //选择第二个数码管显示 3'd2:dig_r = 8'b11111011; //选择第三个数码管显示 3'd3:dig_r = 8'b11110111; //选择第四个数码管显示 3'd4:dig_r = 8'b11101111; //选择第五个数码管显示 3'd5:dig_r = 8'b11011111; //选择第六个数码管显示 3'd6:dig_r = 8'b10111111; //选择第七个数码管显示 3'd7:dig_r = 8'b01111111; //选择第八个数码管显示 endcase end always @(posedge clk) begin case(disp_dat) 4'h0:seg_r = 8'hc0; //显示0 4'h1:seg_r = 8'hf9; //显示1 4'h2:seg_r = 8'ha4; //显示2 4'h3:seg_r = 8'hb0; //显示3 4'h4:seg_r = 8'h99; //显示4 4'h5:seg_r = 8'h92; //显示5 4'h6:seg_r = 8'h82; //显示6 4'h7:seg_r = 8'hf8; //显示7 4'h8:seg_r = 8'h80; //显示8 4'h9:seg_r = 8'h90; //显示9 4'ha:seg_r = 8'hbf; //显示- default:seg_r = 8'hff; //不显示 endcase if((count[17:15]== 3'd2)&sec) seg_r = 8'hff; end 数码管的动态扫描显示时刷新率最好大于50HZ,即每显示一轮的时间不超过20ms。每个数码管显示的时间不能太长也不能太短,时间太长会影响刷新率,导致总体显示呈现闪烁的现象;时间太短发光二极管的电流导通时间也就短,会影响总体的显示亮度。一般控制在1ms左右最佳。即数码管的时钟设置为1000Hz 8.复位----异步复位 同步释放
9.移位发送的问题
10.检测信号的上升沿
11.信号的边沿检测
|
共5条
1/1 1 跳转至页
常用Verilog HDL程序
共5条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |