lcd12864的例子,已经做出来了
FPGA 源程序如下:
- //==========================================================================
- //Filename :lcd12864_picture.v
- //modulename:lcd12864_picture
- //Author :a fei
- //Date :2012-7-8
- //Function :驱动12864,显示图像
- //Uesedfor :
- //==========================================================================
- `timescale 1ns/1ps
- module lcd12864_picture
- (
- //sys_signal
- input i_50m_clk ,
- input i_rst_n ,
-
-
- output reg o_lcd_rs ,//12864端口
- output reg o_lcd_rw ,
- output reg o_lcd_en ,
- output reg [7:0] o_lcd_data ,
- output o_lcd_psb ,
- output [1:0] o_led
- // output o_lcd_rst
- );
- //assign o_lcd_rst = 1'b1 ;
- assign o_lcd_psb = 1'b1 ;
-
-
- //=============================================================================
- //控制状态机状态
- //=============================================================================
- parameter Idle = 11'b00000000001 ;//上电初始状态
- parameter Set_mode = 11'b00000000010 ;//模式设置
- parameter clear1 = 11'b00000000100 ;//数据地址清零
- parameter Disp_on_off = 11'b00000001000 ;//显示开和关
- parameter Cursor = 11'b00000010000 ;//光标设置
- parameter Stand_by = 11'b00000100000 ;//延时
- parameter Clear2 = 11'b00001000000 ;//数据地址清零
- parameter disp_function = 11'b00010000000 ;//开绘图显示
- parameter Wr_address_Y = 11'b00100000000 ;//写行地址
- parameter Wr_address_X = 11'b01000000000 ;//写列地址,列地址自动加1
- parameter Wr_data = 11'b10000000000 ;//写数据
-
-
- reg [10:0] crt_state , next_state ;
- //=================================================================
- reg [15:0] cnt_1000 ;//E、RS信号脉冲宽度计数器 1000*20ns=20us
- reg [15:0] time_cnt2;//写数据地址数据间隔计数器
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if( !i_rst_n )
- cnt_1000 <= 16'b0 ;
- else if(crt_state!=next_state)
- cnt_1000 <= 16'b0 ;
- else if(time_cnt2==16'hffff)
- cnt_1000 <= 16'b0 ;
- else if( cnt_1000 == 16'd4000)
- cnt_1000 <= cnt_1000 ;
- else
- cnt_1000 <= cnt_1000 +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 ;
-
- always@( posedge i_50m_clk or negedge i_rst_n )//写数据或地址时间间隔,写一个字节数据命令的耗时时间
- if( !i_rst_n )
- time_cnt2 <= 16'b0 ;
- else if(crt_state!=next_state)
- time_cnt2 <= 16'b0 ;
- else if( time_cnt2 == 16'hffff)
- time_cnt2 <= 16'h0 ;
- else
- time_cnt2 <= time_cnt2 +1'b1 ;
-
- //==================================================================
- reg[7:0] address_Y ;//行地址
- reg[7:0] address_X ;//列地址
- reg[3:0] cnt_16 ;//列地址计数器
- reg[4:0] cnt_32 ;//行地址计数器
- reg[9:0] rom_addr ;//图片rom地址
- wire[7:0] disp_data ;//图片数据
-
-
- //==================================================================
- //上电等待时间
- //==================================================================
- 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'hff)//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'hff) //时间42ms到
- next_state = Set_mode ;
- else
- next_state = crt_state ;
-
- Set_mode: if(time_cnt1 == 18'h3ffff) //模式设置
- next_state = clear1 ;
- else
- next_state = crt_state ;
-
- clear1 : 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(time_cnt1 == 18'h3ffff)//延时5ms
- next_state = Clear2 ;
- else
- next_state = crt_state ;
-
- Clear2 : if(time_cnt2 == 16'hffff) //清零
- next_state = disp_function ;
- else
- next_state = crt_state ;
-
- disp_function : if(time_cnt2 == 16'hffff) //开绘图功能
- next_state = Wr_address_Y ;
- else
- next_state = crt_state ;
-
- Wr_address_Y : if(time_cnt2 == 16'hffff)//写行地址
- next_state = Wr_address_X ;
- else
- next_state = crt_state ;
-
- Wr_address_X : if(time_cnt2 == 16'hffff)//写列地址
- next_state = Wr_data ;
- else
- next_state = crt_state ;
-
- Wr_data : if(rom_addr==10'd1023&&time_cnt2 == 16'hffff) //1024个字节数据读完时,重新开始读数据
- next_state =Clear2 ;
- else if(cnt_16==4'd15&&time_cnt2 == 16'hffff)//没有读完1024个字节数据,写下一行数据
- next_state = Wr_address_Y ;
- else
- next_state = crt_state ;
-
-
- default :next_state = Idle ;
- endcase
- //===================================================================产生地址和数据
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if(!i_rst_n )
- cnt_16 <= 4'd0 ;
- else if(crt_state==Clear2)
- cnt_16 <= 4'd0 ;
- else if(crt_state==Wr_data)//没一行16个字节,写完一个字节,计数器加1
- if(time_cnt2==16'hffff)
- cnt_16 <= cnt_16+1'b1 ;
- else
- cnt_16 <=cnt_16 ;
- else
- cnt_16 <=4'b0 ;
- always@( posedge i_50m_clk or negedge i_rst_n )//
- if(!i_rst_n )
- cnt_32 <= 5'd0 ;
- else if(crt_state==Clear2)
- cnt_32 <= 5'd0 ;
- else if(cnt_16==4'd15&&time_cnt2==16'hffff)//每写完一行,行数加1
- cnt_32 <= cnt_32+1'b1 ;
- else
- cnt_32 <= cnt_32 ;
-
-
-
-
-
- always@( posedge i_50m_clk or negedge i_rst_n )//分上下屏,半屏的行地址范围8‘h80+(0~31)
- if(!i_rst_n )
- address_Y <=8'b0 ;
- else if(crt_state==Wr_address_Y) //行地址,垂直地址
- address_Y <=8'h80+cnt_32 ;
- else
- address_Y <=address_Y ;
- always@( posedge i_50m_clk or negedge i_rst_n )//分上下屏,只需给出首地址,列地址自动加1
- if(!i_rst_n )
- address_X <=8'b0 ;
- else if(crt_state==Wr_address_X)
- if(rom_addr<10'd512) //上半屏行起始地址
- address_X <=8'h80 ;
- else //下半屏行起始地址
- address_X <=8'h88;
- else
- address_X <=address_X ;
-
- ///=============================================================图像数据
- always@( posedge i_50m_clk or negedge i_rst_n )//rom地址
- if(!i_rst_n )
- rom_addr <= 10'd0 ;
- else if(crt_state==Clear2)
- rom_addr <= 10'd0 ;
- else if(crt_state==Wr_data)
- if(time_cnt2==16'hffff)
- rom_addr <= rom_addr +1'b1 ;
- else
- rom_addr <= rom_addr ;
- else
- rom_addr <= rom_addr ;
-
- ///rom 一共1024个字节数据
-
- picture_rom u0_picture_rom(
- .address( rom_addr ),
- .clock ( i_50m_clk),
- .q ( disp_data)
- );
-
-
-
-
-
- //==================================================================端口输出
-
- ///////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_data)&&(cnt_1000<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_1000>6'd5&&cnt_1000<16'd3900)//高电平
- o_lcd_en <= 1'b1 ;
- else
- o_lcd_en <= 1'b0 ;
-
-
- //lcd_data ,address
- always@( *)
- case(crt_state)
- Idle : o_lcd_data = 8'h30 ;//模式设置
- Set_mode : o_lcd_data = 8'h30 ;//模式设置
- Disp_on_off : o_lcd_data = 8'h0c ;//显示开、关
- Cursor : o_lcd_data = 8'h06 ;//光标设置
- clear1,Clear2 : o_lcd_data = 8'h01 ;//清零
- disp_function : o_lcd_data = 8'h36 ;//绘图功能
- Wr_address_Y : o_lcd_data = address_Y ; //行地址
- Wr_address_X : o_lcd_data = address_X ; //行地址
- Wr_data : o_lcd_data = disp_data ;//数据
- default : o_lcd_data = 8'hff ;
-
- endcase
-
-
- ///=========================================================================
- //LED闪烁,指示fpga工作状态
- //==========================================================================
-
- led_block u0_led_block(
- .i_clk_50M ( i_50m_clk ) ,
- .i_fpga_clk ( i_50m_clk ) ,
- .i_rst_n ( i_rst_n ) ,
-
-
- .o_led ( o_led )
- );
-
-
- endmodule
复制代码
所有资料51hei提供下载:
M15_LCD12864 display picture.zip
(19.46 MB, 下载次数: 96)
|