
5、数码管动态显示、蜂鸣器
蜂鸣器代码太少,于是加到数码管动态显示实验了,一起演示,有个数位貌似坏了,本来想显示数字0-7的。大约每隔1.3ms对8位数码管轮流使能,10.5ms一个周期。蜂鸣器大约763Hz,占空比5/16。
http://v.youku.com/v_show/id_XNDY1OTExMjY0.html
module Seg7_dynamic(clk,rst_n,dig,seg,beep);
input clk;
input rst_n;
output[7:0] dig;
output[7:0] seg;
output beep;
reg[15:0] cnt;
reg[2:0] count;
reg[3:0] data;
reg[7:0] dig_t;
reg[7:0] seg_t;
reg beep;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt = 16'b0;
else
cnt = cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
count = 3'b000;
else if(cnt == 16'hffff)
begin
count = count + 1;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
data = 4'h0;
dig_t = 8'b11111111;
end
else
case(count)
3'b000:
begin
data = 0;
dig_t = 8'b11111110;
end
3'b001:
begin
data = 1;
dig_t = 8'b11111101;
end
3'b010:
begin
data = 2;
dig_t = 8'b11111011;
end
3'b011:
begin
data = 3;
dig_t = 8'b11110111;
end
3'b100:
begin
data = 4;
dig_t = 8'b11101111;
end
3'b101:
begin
data = 5;
dig_t = 8'b11011111;
end
3'b110:
begin
data = 6;
dig_t = 8'b10111111;
end
3'b111:
begin
data = 7;
dig_t = 8'b01111111;
end
endcase
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
seg_t = 8'h00;
else
case(data)
4'h0:seg_t = 8'hc0;
4'h1:seg_t = 8'hf9;
4'h2:seg_t = 8'ha4;
4'h3:seg_t = 8'hb0;
4'h4:seg_t = 8'h99;
4'h5:seg_t = 8'h92;
4'h6:seg_t = 8'h82;
4'h7:seg_t = 8'hf8;
4'h8:seg_t = 8'h80;
4'h9:seg_t = 8'h90;
4'ha:seg_t = 8'h88;
4'hb:seg_t = 8'h83;
4'hc:seg_t = 8'hc6;
4'hd:seg_t = 8'ha1;
4'he:seg_t = 8'h86;
4'hf:seg_t = 8'h8e;
endcase
end
assign dig = dig_t;
assign seg = seg_t;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
beep = 1'b1;
else if(cnt <= 16'hfff && cnt >= 16'h5fff)
beep = 1'b0;
else
beep = 1'b1;
end
endmodule

6、电子琴
第8个按键为功能键,切换中高音,按下键时,LED和数码管同时显示相应音符
http://v.youku.com/v_show/id_XNDY2MzgzMDY4.html
module Elec_organ(clk,rst_n,beep,key,led,seg,dig);
input clk;
input rst_n;
input[7:0] key;
output beep;
output[7:0] led;
output[7:0] seg;
output[7:0] dig;
reg[19:0] cnt,cnt_point;
reg beep;
reg[7:0] dig_t;
reg[7:0] seg_t;
reg[3:0] data;
reg[7:0] key_t;
reg key_flag;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
beep = 1'b1;
dig_t = 8'hff;
end
else if(cnt == cnt_point)
begin
cnt = 20'b0;
if(key_flag)
beep = ~beep;
else
beep = 1'b1;
end
else
begin
cnt = cnt + 1'b1;
dig_t = 8'b0;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
key_t = 8'hff;
key_flag = 1'b0;
end
else if(key[6:0] != 7'h7f)
begin
key_t = key;
key_flag = 1'b1;
end
else
key_flag =1'b0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_point = 20'hfffff;
data = 4'h0;
end
else
case(key_t)
8'b11111110:
begin
cnt_point = 20'd47774;
data = 4'h1;
end
8'b11111101:
begin
cnt_point = 20'd42568;
data = 4'h2;
end
8'b11111011:
begin
cnt_point = 20'd37919;
data = 4'h3;
end
8'b11110111:
begin
cnt_point = 20'd35791;
data = 4'h4;
end
8'b11101111:
begin
cnt_point = 20'd31888;
data = 4'h5;
end
8'b11011111:
begin
cnt_point = 20'd28409;
data = 4'h6;
end
8'b10111111:
begin
cnt_point = 20'd25309;
data = 4'h7;
end
8'b01111110:
begin
cnt_point = 20'd23912;
data = 4'h1;
end
8'b01111101:
begin
cnt_point = 20'd21282;
data = 4'h2;
end
8'b01111011:
begin
cnt_point = 20'd18961;
data = 4'h3;
end
8'b01110111:
begin
cnt_point = 20'd17897;
data = 4'h4;
end
8'b01101111:
begin
cnt_point = 20'd15944;
data = 4'h5;
end
8'b01011111:
begin
cnt_point = 20'd14205;
data = 4'h6;
end
8'b00111111:
begin
cnt_point = 20'd12655;
data = 4'h7;
end
default:
begin
cnt_point = 20'hfffff;
data = 4'h0;
end
endcase
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
seg_t = 8'h00;
else
case(data)
4'h0:seg_t = 8'hc0;
4'h1:seg_t = 8'hf9;
4'h2:seg_t = 8'ha4;
4'h3:seg_t = 8'hb0;
4'h4:seg_t = 8'h99;
4'h5:seg_t = 8'h92;
4'h6:seg_t = 8'h82;
4'h7:seg_t = 8'hf8;
default:seg_t = 8'h86;
endcase
end
assign seg = seg_t;
assign dig = dig_t;
assign led = key_t;
endmodule

7、自动演奏乐曲
本来选的是一首泰坦尼克号的简谱,但是实际效果听不出来,就是一段普通的曲子,后来认真听了原曲,还是人声段有Feeing,曲子感觉比较普通了,简谱可能就打了折扣了!也很有可能是代码的乐曲频率没调好,就不细调了,权当演示功能。
http://v.youku.com/v_show/id_XNDY2NTM2MjY0.html
// 泰坦尼克号主题曲
// 50MHz,每隔大约168ms一个音
//音高与频率的对应关系
//----------------------------------------------------------------------
//| | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
//|低音 |261.6Hz |293.7Hz |329.6Hz |349.2Hz | 392Hz | 440Hz |493.9Hz |
//|中音 |523.3Hz |587.3Hz |659.3Hz |698.5Hz | 784Hz | 880Hz |987.8Hz |
//|高音 |1045.5Hz|1174.7Hz|1318.5Hz|1396.9Hz| 1568Hz | 1760Hz |1975.5Hz|
//----------------------------------------------------------------------
module Beepsong(clk,rst_n,beep);
input clk;
input rst_n;
output beep;
reg[15:0] cnt;
reg[22:0] count;
reg beep;
reg[7:0] state;
reg[15:0] cnt_point;
parameter L_3 = 16'd75850, //低音3
L_5 = 16'd63776, //低音5
L_6 = 16'd56818, //低音6
L_7 = 16'd50618, //低音7
M_1 = 16'd47774, //中音1
M_2 = 16'd42568, //中音2
M_3 = 16'd37919, //中音3
M_4 = 16'd35791, //中音4
M_5 = 16'd31888, //中音5
M_6 = 16'd28409, //中音6
H_1 = 16'd23912; //高音1
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt = 16'b0;
beep = 1'b1;
end
else if(cnt == cnt_point)
begin
cnt = 16'b0;
beep = ~beep;
end
else
cnt = cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
count = 23'b0;
else
count = count + 1'b1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
state = 8'd0;
else if(count == 23'h7fffff)
begin
state = state + 1'b1;
if(state == 8'd79)
state = 8'd0;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_point = 16'hffff;
else
case(state)
8'd0,8'd1,8'd2,8'd3:cnt_point = M_1;
8'd4,8'd7,8'd16:cnt_point = L_7;
8'd5,8'd6,8'd8:cnt_point = M_1;
8'd9,8'd11:cnt_point = M_2;
8'd10:cnt_point = M_3;
8'd12,8'd13,8'd14,8'd15:cnt_point = M_1;
8'd17,8'd18:cnt_point = M_1;
8'd19:cnt_point = L_5;
8'd20,8'd21,8'd22:cnt_point = M_1;
8'd23,8'd26:cnt_point = L_7;
8'd24,8'd25,8'd27:cnt_point = M_1;
8'd28,8'd30:cnt_point = M_2;
8'd29:cnt_point = M_3;
8'd31,8'd32,8'd33,8'd34:cnt_point = M_1;
8'd36,8'd37:cnt_point = M_1;
8'd38:cnt_point = L_5;
8'd39:cnt_point = M_1;
8'd40:cnt_point = M_2;
8'd41:cnt_point = L_5;
8'd42:cnt_point = M_5;
8'd43:cnt_point = M_4;
8'd44:cnt_point = M_3;
8'd45:cnt_point = M_2;//
8'd46,8'd48:cnt_point = M_3;
8'd47:cnt_point = M_4;
8'd49:cnt_point = M_2;
8'd50:cnt_point = M_1;
8'd51,8'd52:cnt_point = L_7;
8'd53:cnt_point = L_6;
8'd54:cnt_point = L_5;//
8'd55:cnt_point = M_1;
8'd56:cnt_point = M_2;
8'd57:cnt_point = L_5;
8'd58:cnt_point = M_5;
8'd59:cnt_point = M_4;
8'd60:cnt_point = M_3;
8'd61:cnt_point = M_2;//
8'd62,8'd64:cnt_point = M_3;
8'd63:cnt_point = M_4;
8'd65:cnt_point = M_2;
8'd66,8'd68:cnt_point = M_1;
8'd67:cnt_point = L_7;//
8'd69,8'd70:cnt_point = L_7;
8'd71:cnt_point = M_1;
8'd72,8'd76:cnt_point = M_2;
8'd73,8'd75:cnt_point = M_3;
8'd74:cnt_point = M_4;
8'd77,8'd78:cnt_point = M_1;
default:cnt_point = 16'hffff;
endcase
end
endmodule

8、LCD1602显示
静态显示,逐步显示,滚动显示三种效果
以下代码说明:
1.初始化一定要特别注意,不成功就无法正常显示了,模块输出最奥都设为高阻
2.计数器大小可以调,决定了执行状态机的频率,也就影响了显示字符的频率
3.1602寄存器配置,不能马虎,建议改动多试试效果,修改一个寄存器即可滚动显示
4.贴出代码为滚动效果的,稍作修改就可以显示其他效果
PS:1.发给EEPW的视频还没搜索到,暂时展示优酷链接的视频,稍后补上
2.最近忙于其他事,几天没有更新,同时抽空做1602实验时受阻,遇到问题,耽搁了进程,今天终于找到原因,独立搞定,因此请没有做过1602实验的朋友们先认真阅读1602pdf文档
静态显示效果(严格的说应该是视觉上静态)
逐步显示效果(一个字符一个字符的显示)
http://v.youku.com/v_show/id_XNDY5NjY2MTIw.html
滚动显示效果(整体滚动)
http://v.youku.com/v_show/id_XNDY5NjY2NzYw.html
module LCD1602(clk,rst_n,RS,RW,EN,data);
input clk;
input rst_n;
output RS;
output RW;
output EN;
output[7:0] data;
reg[24:0] cnt;
reg[7:0] data;
reg lcd_rs;
reg lcd_rw;
reg lcd_en;
reg[3:0] state;
reg[5:0] address;
reg trig;
parameter IDLE = 4'b0000; //空闲
parameter CLEAR = 4'b0001; //清屏
parameter RETURNCURSOR = 4'b0010; //归home位
parameter SETMODE = 4'b0011;
//输入方式设置,读写数据后ram地址增/减1;画面动/不动
parameter SWITCHMODE = 4'b0100;
//显示状态设置,显示开/关;光标开/关;闪烁开/关
parameter SHIFT = 4'b0101;
//光标画面滚动 画面/光标平移一位;左/右平移一位
parameter SETFUNCTION = 4'b0110;
//工作方式设置 1:8/1:4位数据接口;两行/一行显示;5x10/5x7点阵
parameter SETDDRAM1 = 4'b0111; //设置DDRAM
parameter SETDDRAM2 = 4'b1000; //设置DDRAM
parameter READFLAG = 4'b1001; //读状态
parameter WRITERAM1 = 4'b1010; //写RAM
parameter WRITERAM2 = 4'b1011; //写RAM
function [7:0] strram; //函数调用
input [5:0] n;
begin
case(n)
6'b000000:strram="I"; //显示的字符
6'b000001:strram="'";
6'b000010:strram="m";
6'b000011:strram=" ";
6'b000100:strram="p";
6'b000101:strram="l";
6'b000110:strram="a";
6'b000111:strram="y";
6'b001000:strram="b";
6'b001001:strram="l";
6'b001010:strram="o";
6'b001011:strram="n";
6'b001100:strram="g";
6'b001101:strram="^";
6'b001110:strram="_";
6'b001111:strram="^";
6'b010000:strram="I";
6'b010001:strram="t";
6'b010010:strram="'";
6'b010011:strram="s";
6'b010100:strram=" ";
6'b010101:strram="E";
6'b010110:strram="E";
6'b010111:strram="P";
6'b011000:strram="W";
6'b011001:strram=" ";
6'b011010:strram="D";
6'b011011:strram="I";
6'b011100:strram="Y";
6'b011101:strram="^";
6'b011110:strram="o";
6'b011111:strram="^";
default: strram="X";
endcase
end
endfunction
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt = 25'b0; //cnt可以改变一下,自己试试效果
else
cnt = cnt + 1'b1;
end
/*assign EN = cnt[15]; //lcd enable,keep same time; >1000ns
wire trig = (cnt == 16'h7FFF) ? 1'b1 : 1'b0; //when lcd_en is steady,write a cmd*/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
trig = 0;
lcd_en = 0;
end
else if(cnt < 25'h0ffffff)
begin
lcd_en = 0;
end
else if(cnt == 25'h0ffffff)
begin
trig = 1'b1; //生成一个触发脉冲,控制1602的操作指令
lcd_en = 1'b1;
end
else
trig = 0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
data = 8'hzz;
lcd_rs = 1'bz; //这里最好都设置为高阻,以免初始化失败
lcd_rw = 1'bz;
state = IDLE;
address = 6'b0;
end
else if(trig == 1'b1)
begin
case(state)
IDLE: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'hzz;
state = CLEAR;
end
CLEAR: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b00000001; //清屏01
state = SETFUNCTION;
end
SETFUNCTION: begin
lcd_rs = 0;
lcd_rw = 0; //3C
data = 8'b00111100;
state = SWITCHMODE;
end
SWITCHMODE: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b00001100; //显示状态开关设置0C
state = SETMODE;
end
SETMODE: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b00000111; //输入方式设置06固定,07滚动
state = SHIFT;
end
SHIFT: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b00001100; //光标画面滚动
state = SETDDRAM1;
end
SETDDRAM1: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b10000000; //显示数据存储器地址80,第一行
state = WRITERAM1;
end
SETDDRAM2: begin
lcd_rs = 0;
lcd_rw = 0;
data = 8'b11000000; //显示数据存储器地址80+40,第二行
state = WRITERAM2;
end
WRITERAM1: begin
if(address <= 6'b001111)
begin
lcd_rs = 1;
lcd_rw = 0;
data = strram(address); //写数据
address = address+1;
state = WRITERAM1;
end
else
begin
lcd_rs = 0;
lcd_rw = 0;
state = SETDDRAM2;
end
end
WRITERAM2: begin
if(address <= 6'b011111)
begin
lcd_rs = 1;
lcd_rw = 0;
data = strram(address); //写数据
address = address+1;
state = WRITERAM2;
end
else
begin
lcd_rs = 0;
lcd_rw = 0;
state = SETDDRAM1;
address = 6'b000000;
end
end
default: state = IDLE;
endcase
end
end
assign RS = lcd_rs;
assign RW = lcd_rw;
assign EN = lcd_en;
endmodule

实现功能:借助串口调试助手,上位机发送一个字符,下位机接收,并把该字符发送给上位机
PS:开始用模块写,写起来自己都糊涂了,就搁置几天不写了,后来仔细把串口的原理和逻辑搞清楚,然后就开始重新写了,不用模块,不用状态机,完全按照自己的逻辑来,上电测试,一次性通过!噢耶!
结论:原理最重要!
(开始使用EEPW的视频了)
http://v.eepw.com.cn/video/play/id/2093
module fpga_uart(clk,rst_n,uart_rx,uart_tx);
input clk;
input rst_n;
input uart_rx;
output uart_tx;
reg[12:0] cnt;
reg neg_rx_start; %检测接收起始位信号
reg cnt_start; %计数器启动信号
reg tx_data;
reg[10:0] data;
reg[3:0] num,n;
reg rx_end; %接收结束信号
reg tx_end; %发送结束信号
reg tx_start; %发送开始信号
reg clk_bps;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt = 0;
else if(cnt == 13'd5208)
cnt = 0;
else if(cnt_start)
cnt = cnt + 1'b1;
else
cnt = 0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
neg_rx_start = 0;
cnt_start = 0;
end
else if(cnt < 13'd8)
begin
if(!uart_rx)
begin
cnt_start = 1;
if(cnt == 13'd7)
neg_rx_start = 1;
end
else if(rx_end)
begin
if(tx_end)
cnt_start = 0;
else
cnt_start = 1;
end
else if(neg_rx_start)
cnt_start = 1;
else
begin
neg_rx_start = 0;
cnt_start = 0;
end
end
else if(num == 4'd11)
begin
neg_rx_start = 0;
cnt_start = 0;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_bps = 0;
else if(cnt == 13'd2604)
clk_bps = 1;
else
clk_bps = 0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
num = 0;
rx_end = 0;
data = 11'd0;
end
else if(num == 11)
begin
num = 0;
rx_end = 1;
end
else if(neg_rx_start)
begin
if(clk_bps)
begin
num = num + 1'b1;
case(num)
4'd1: data[0] = uart_rx;
4'd2: data[1] = uart_rx;
4'd3: data[2] = uart_rx;
4'd4: data[3] = uart_rx;
4'd5: data[4] = uart_rx;
4'd6: data[5] = uart_rx;
4'd7: data[6] = uart_rx;
4'd8: data[7] = uart_rx;
4'd9: data[8] = uart_rx;
4'd10: data[9] = uart_rx;
4'd11: data[10] = uart_rx;
endcase
end
end
else if(tx_end)
rx_end = 0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
tx_start = 0;
else if(tx_end)
tx_start = 0;
else if(rx_end)
tx_start = 1;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
tx_end = 0;
n = 0;
end
else if(neg_rx_start)
tx_end = 0;
else if(n == 4'd10)
begin
tx_end = 1;
n = 0;
end
else if(tx_start)
begin
if(clk_bps)
begin
case(n)
4'd0: tx_data = 1'b0;
4'd1: tx_data = data[1];
4'd2: tx_data = data[2];
4'd3: tx_data = data[3];
4'd4: tx_data = data[4];
4'd5: tx_data = data[5];
4'd6: tx_data = data[6];
4'd7: tx_data = data[7];
4'd8: tx_data = data[8];
4'd9: tx_data = 1'b1;
default: tx_data = 1'b1;
endcase
n = n + 1;
end
end
end
assign uart_tx = tx_data;
endmodule
回复
打赏帖 | |
---|---|
我踩过的那些坑之混合OTL功放与落地音箱被打赏50分 | |
汽车电子中巡航控制系统的使用被打赏10分 | |
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏100分 | |
分享汽车电子中巡航控制系统知识被打赏10分 | |
分享安全气囊系统的检修注意事项被打赏10分 | |
分享电子控制安全气囊计算机知识点被打赏10分 | |
【分享开发笔记,赚取电动螺丝刀】【OZONE】使用方法总结被打赏20分 | |
【分享开发笔记,赚取电动螺丝刀】【S32K314】芯片启动流程分析被打赏40分 | |
【分享开发笔记,赚取电动螺丝刀】【S32K146】S32DS RTD 驱动环境搭建被打赏12分 | |
【分享开发笔记,赚取电动螺丝刀】【IAR】libc标注库time相关库函数使用被打赏23分 |