这是例程
全部资料51hei下载地址:
M07_LCD1602 display character.zip
(18.18 MB, 下载次数: 22)
Quartus 工程 qsf 文件管脚约束命令,把以下命令拷贝到新建 quartus 工程的 qsf 文件即可完成管脚约束(注
意信号名必须相同) :
3 实验步骤
3.1 综合
(1)运行综合工具。
(2)打开项目工程,项目工程存放于以软件开发工具命名的文件夹中。
(3)编译运行或直接点击下载,下载 FPGA 软件到目标板。
(4)查看软件运行效果
3.2 仿真
请参考视频讲解。
主要命令:
切换仿真路径 cd {仿真库路径} ,如:cd {F:\Verilog_demo\M06_Digital clock\clock\sim};
run 100us:仿真运行时间长度 100us ;
do wave.do:运行波形文件;
vlog ../src/*.v:编译 scr路径下的所有 v文件
vsim:开始仿真命令
quit –sim:退出仿真
4 实验结果
4.1 结果演示
4.1.1 MODELSIM 仿真演示
图表 2 modelsim 仿真波形
仿真时可以通过按比例修改数据通信时间长度,模拟真实通信协议,来缩短仿真时间。
4.1.2 MATLAB 数据分析
略。
4.1.3 开发板演示
通过以上的讲解,相信各位已经可以熟练驱动 LCD1602 了吧,在今后的使用中,可以试着将一些采集的数据
用1602 显示出来显示,比如传感器温度啊,时间啊,AD采集的电压值啊…等等。
4.2 特别说明
源程序如下:
- //==========================================================================
- //Filename :lcd1602_ctl.v
- //modulename:lcd1602_inf
- //Author :a fei
- //Function :驱动1602,包括初始化和数据的写,写入数据由用户定义
- //==========================================================================
- `timescale 1ns/1ps
- module lcd1602_ctl
- (
- //sys_signal
- input i_50m_clk ,
- input i_rst_n ,
- input [7:0] i_disp_data ,//写入的数据
- input i_data_trig ,//数据触发
-
- input i_addr_trig1 ,//第一行地址触发信号
- input i_addr_trig2 ,//第二行地址触发信号
- input [7:0] i_addr , //地址
-
- output reg o_lcd_rs ,//1602端口
- output reg o_lcd_rw ,
- output reg o_lcd_en ,
- output reg [7:0] o_lcd_data
- );
-
-
- //=============================================================================
- //控制状态机状态
- //=============================================================================
- parameter Idle = 10'b0000000001 ;//
- parameter Set_mode = 10'b0000000010 ;//模式设置
- parameter Disp_on_off = 10'b0000000100 ;//显示开和关
- parameter Cursor = 10'b0000001000 ;//光标设置
- parameter Clear = 10'b0000010000 ;//数据地址清零
- parameter Stand_by = 10'b0000100000 ;//准备就绪,初始化完成
- parameter Wr_address1 = 10'b0001000000 ;//写第一行首地址
- parameter Wr_data1 = 10'b0010000000 ;//写第一行数据
- parameter Wr_address2 = 10'b0100000000 ;//写第二行首地址
- parameter Wr_data2 = 10'b1000000000 ;//写第二行数据
-
- reg [9:0] crt_state , next_state ;
- //=================================================================
- reg [15:0] cnt_4000 ;//TC,en脉冲宽度 4000*20ns=80us
- reg data_trig ;
- reg addr_tirg1 ;
- reg addr_tirg2 ;
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- cnt_4000 <= 16'b0 ;
- else if(crt_state!=next_state)
- cnt_4000 <= 16'b0 ;
- else if(!data_trig &&i_data_trig)
- cnt_4000 <= 16'b0 ;
- else if( cnt_4000 == 16'd4000)
- cnt_4000 <= cnt_4000 ;
- else
- cnt_4000 <= cnt_4000 +1'b1 ;
-
- reg [18:0] time_cnt1 ;//5ms计时器,每个指令间隔
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- time_cnt1 <= 18'b0 ;
- else if(crt_state!=next_state)
- time_cnt1 <= 18'b0 ;
- else if( time_cnt1 == 18'h3ffff)
- time_cnt1 <= time_cnt1 ;
- else
- time_cnt1 <= time_cnt1 +1'b1 ;
-
- //==================================================================
- //检测数据、地址触发信号
- reg[7:0] disp_data ;
- reg[7:0] address ;
- reg[3:0] data_cnt ;
- reg[15:0] time_cnt2 ;
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- data_trig <= 1'b0 ;
- else
- data_trig <= i_data_trig ;
-
- always@( posedge i_50m_clk)
- disp_data <= i_disp_data ;
- always@( posedge i_50m_clk)
- addr_tirg1 <= i_addr_trig1 ;
- always@( posedge i_50m_clk)
- addr_tirg2 <= i_addr_trig2 ;
-
-
- always@( posedge i_50m_clk)
- address <= i_addr ;
-
- always@( posedge i_50m_clk) //数据持续最小时间控制
- if(crt_state==Wr_data1||crt_state==Wr_data2)
- if(! data_trig &&i_data_trig)
- time_cnt2 <= 16'b0 ;
- else if(time_cnt2==16'hffff)
- time_cnt2 <= time_cnt2 ;
- else
- time_cnt2 <=time_cnt2+1'b1 ;
- else
- time_cnt2 <= 16'b0 ;
- always@( posedge i_50m_clk) //数据个数计数器
- if(crt_state==Wr_data1||crt_state==Wr_data2)
- if(! data_trig &&i_data_trig)
- data_cnt <= data_cnt +1'b1 ;
- else
- data_cnt <= data_cnt ;
- else
- data_cnt <=4'b0 ;
-
-
- //==================================================================
- //状态转移
- //==================================================================
- reg [19:0] power_up_cnt ;//上电等待时间42ms
-
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- power_up_cnt <= 20'b0 ;
- else if(power_up_cnt==20'hfffff)//power_up_cnt==22'hff
- power_up_cnt<= power_up_cnt ;
- else
- power_up_cnt <= power_up_cnt + 1'b1 ;
- //====================================================================
- //????
- //====================================================================
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- crt_state <= Idle ;
- else
- crt_state <= next_state ;
- always@( *)
- case(crt_state)
- Idle : if(power_up_cnt==20'hfffff) //时间42ms到
- next_state = Set_mode ;
- else
- next_state = crt_state ;
-
- Set_mode: if(time_cnt1 == 18'h3ffff) //模式设置
- next_state = Clear ;
- else
- next_state = crt_state ;
-
- Clear : if(time_cnt1 == 18'h3ffff)//清零
- next_state = Disp_on_off ;
- else
- next_state = crt_state ;
-
-
- Disp_on_off: if(time_cnt1 == 18'h3ffff)//显示开、关
- next_state = Cursor ;
- else
- next_state = crt_state ;
-
- Cursor : if(time_cnt1 == 18'h3ffff)//光标设置
- next_state = Stand_by ;
- else
- next_state = crt_state ;
-
-
- Stand_by :if(!addr_tirg1&&i_addr_trig1)//准备就绪
- next_state = Wr_address1 ;
- else if(!addr_tirg2&&i_addr_trig2)
- next_state = Wr_address2 ;
- else
- next_state = crt_state ;
- Wr_address1 : if( !data_trig &&i_data_trig)//写第一行数据
- next_state = Wr_data1 ;
- else
- next_state = crt_state ;
- Wr_data1 : if(data_cnt==4'd6&&time_cnt2 == 16'hffff) //写第一行数据,返回准备状态
- next_state = Stand_by ;
- else
- next_state = crt_state ;
-
- Wr_address2 : if( !data_trig &&i_data_trig)//第二行数据
- next_state = Wr_data2 ;
- else
- next_state = crt_state ;
-
- Wr_data2 : if(data_cnt==4'd4&&time_cnt2==16'hffff) //第二行数据
- next_state = Stand_by ;
- else
- next_state = crt_state ;
-
- default :next_state = Idle ;
- endcase
-
-
- //==================================================================端口输出
-
- ///////lcd_rs,1写数据 ,0写命令
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- o_lcd_rs <= 1'b0 ;
- else if((crt_state ==Wr_data2||crt_state ==Wr_data1)&&cnt_4000<16'd4000)
- o_lcd_rs <= 1'b1 ;
- else
- o_lcd_rs <= 1'b0 ;
-
- //==lcd_rw ,总是写
- always@( posedge i_50m_clk)
- o_lcd_rw <= 1'b0 ;
-
- //====lcd_en
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- o_lcd_en <= 1'b0 ;
- else if(crt_state==Stand_by)
- o_lcd_en <= 1'b0 ;
- else if(cnt_4000>5'd10&&cnt_4000<16'd3990)
- o_lcd_en <= 1'b1 ;
- else
- o_lcd_en <= 1'b0 ;
-
-
- //lcd_data ,?????
- always@( *)
- case(crt_state)
- Idle : o_lcd_data = 8'h38 ;
- Set_mode : o_lcd_data = 8'h38 ;//模式设置
- Disp_on_off : o_lcd_data = 8'h0e ;//显示开、关
- Cursor : o_lcd_data = 8'h06 ;//光标设置
- Clear : o_lcd_data = 8'h01 ;//清零
- Wr_address1,Wr_address2 : o_lcd_data = address [7:0] ; //地址
- Wr_data1 ,Wr_data2 : o_lcd_data = disp_data[7:0] ;//数据
- default : o_lcd_data = 8'hff ;
-
- endcase
-
- endmodule
复制代码
|