Nokia5110液晶,显示中文。
字模需要自己制作,单位字体像素:16×16
/*************************************************
//Module: nokia5110lcd_chinese
//File Name: nokia5110lcd_chinese.v
//Version: 2.0
//Date: 2011.11.30
//Author: wang li
//Code Type: RTL
//Description: 诺基亚5110液晶中文显示,每行显示5个字,显3行。
// clk——时钟输入(1位)
// sel——数码管位选信号输出,不同的数位(8位)
// data——数码管某一位上的数字输出(8位)
**************************************************/
module nokia5110lcd_chinese(sys_clk,reset,lcd_rst,sce,sclk,sdin,cd);
input sys_clk; //系统时钟
input reset; //时钟复位,为0进行复位,为1正常运行
output lcd_rst; //输出信号到51i10的复位引脚,低电平进行复位
output sclk; //输出信号到5110的时钟信号引脚
output sce; //输出信号到5110的片选信号引脚,低电平芯片选通
output sdin;
output cd;
//-----内部寄存器-----
reg [7:0] cnt; //分频计数器 reg [6:0] cnt;
reg clk; //分频时钟
reg sce; //5110片选信号,低电平选通芯片
reg cd; //数据命令切换脚,1为数据,0为命令
reg sdin; //串行数据输入
reg [1:0] p; //状态机1
reg [3:0] p2; //状态机2
reg [3:0] p_back; //状态返回
parameter clk_l=2'd0;
parameter clk_h=2'd1;
parameter clk_rising_edge=2'd2;
parameter clk_falling_edge=2'd3;
parameter idle=4'd0; //状态机2的初始状态
parameter shift_data=4'd1;
parameter shift_data1=4'd2;
parameter clear_screen=43'd3;
parameter set_xy=4'd4;
parameter disp_char=4'd5;
parameter set_xy2=4'd6;
parameter disp_char2=4'd7;
parameter set_xy3=4'd8;
reg [7:0] data_reg; //数据寄存器
reg [3:0] cnt2; //串行传输data_reg时的移位计数器
reg [15:0] cnt3; //状态机2的运行步骤计数器,25步reg [4:0] cnt3;
reg [8:0] cnt4; //显示位置计数器
reg [6:0] char_reg; //字符寄存器
reg [2:0] y_reg; //y坐标寄存器,Y:0~5(3’b101)
reg [6:0] x_reg; //x坐标寄存器,X:0~83(7'b1010011)
reg [0:255] men[5:0]; //字符库,为menory变量,第一个[每个存储单元深度],第二个[存储器的深度]
reg [0:255] temp; //字符暂存寄存器
parameter ONN=1'b0;
parameter OFF=1'b1;
parameter CMD=1'b0;
parameter DATA=1'b1;
//-----字符库,每个字符占8行6列-----
initial
begin
//空白
men[0] = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,
8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,
8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,
8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};
/*-- 文字: 力反 宋体12--现调整为:宽度x高度=16x16 */
men[1] = {8'hFF,8'hEF,8'hEF,8'hEF,8'hEF,8'hEF,8'h00,8'hEF,
8'hEF,8'hEF,8'hEF,8'hEF,8'h0F,8'hFF,8'hFF,8'hFF,
8'hFF,8'h7F,8'hBF,8'hDF,8'hE7,8'hF9,8'hFE,8'hFF,
8'hDF,8'hBF,8'h7F,8'hBF,8'hC0,8'hFF,8'hFF,8'hFF};
/*-- 文字: 虎 宋体12--现调整为:宽度x高度=16x16 */
men[2] = {8'h00,8'h00,8'hF8,8'h08,8'h48,8'h48,8'h48,8'hFF,
8'h4A,8'h2A,8'h2A,8'h0A,8'hCA,8'h18,8'h00,8'h00,
8'h80,8'h60,8'h1F,8'h80,8'h40,8'h20,8'h1C,8'h04,
8'h05,8'h05,8'h7D,8'h81,8'h81,8'hE0,8'h00,8'h00};
men[3] = {8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,
8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,
8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,
8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF,8'hFF};
/*-- 文字: 雄 楷体12--现调整为:宽度x高度=16x16 -*/
men[4] = {8'h00,8'h40,8'h60,8'hE0,8'hFC,8'hBC,8'hA0,8'hE0,
8'hF8,8'hFC,8'h4C,8'hFC,8'hF8,8'hA0,8'h20,8'h00,
8'h10,8'h1C,8'h0F,8'h0F,8'h0F,8'h0F,8'h0F,8'h2C,
8'h7F,8'h7F,8'h15,8'h1F,8'h1F,8'h1A,8'h1A,8'h00};
/*-- 文字: 起 楷体12--现调整为:宽度x高度=16x16 -*/
men[5] = {8'h00,8'h00,8'h00,8'h40,8'hFC,8'hFC,8'hFC,8'hA0,
8'hA0,8'hB0,8'hF0,8'hF0,8'hF0,8'h10,8'h00,8'h00,
8'h21,8'h31,8'h3F,8'h0F,8'h0F,8'h1F,8'h1F,8'h34,
8'h37,8'h2F,8'h6C,8'h6C,8'h66,8'h66,8'h24,8'h20};
// men[0] = {8'h00, 8'h42, 8'h42, 8'h42, 8'h42, 8'hFE}; // 0 sp
// men[1] = {8'h42,8'h42,8'h42,8'h42,8'h00,8'h00}; // 1 !
// men[2] = {8'h08,8'h08,8'h08,8'h08,8'h08,8'h0F}; // 3 #
// men[3] = {8'h08,8'h08,8'h08,8'h08,8'h08,8'h00}; // 4 $
end
//-----
assign sclk=clk; //slck:5110的同步时针输入=分频时钟
assign lcd_rst=1; //lcd_rst:5110的复位信号输出,低电平进行复位
//-----时钟分频-----
always @(posedge sys_clk)
begin
if(!reset) cnt<=0; //rest=0,进行时钟复位
else
begin
cnt<=cnt+1;
if(cnt==49) cnt<=0; //50*20ns=1000ns=1us,产生频率为1Mhz的时钟
if(cnt<25) clk<=0; //占空比调整50%
else clk<=1;
end
end
//-----切换状态机1:模拟clk的状态-----
always @(posedge sys_clk)
begin
if(!reset)
p<=clk_l; //状态机p1=clk_l=2'd0=0
else
case(p)
clk_l:
begin
if(clk) p<=clk_rising_edge; //clk为高电平,p变成上升沿
else p<=clk_l; //clk为低电平,p变成低电平
end
clk_rising_edge:p<=clk_h; //p在上升沿后变成高电平
clk_h:
begin
if(!clk) p<=clk_falling_edge; //clk为低电平,p变成下降沿
else p<=clk_h; //clk为高电平,p变成高电平
end
clk_falling_edge:p<=clk_l; //p在下降沿后变成低电平
default;
endcase;
end
//-----切换状态机2-----
always @(posedge sys_clk)
begin
if(!reset)
begin
p2<=idle; //idle=3'd0;
sce<=OFF; //OFF=1'b1; sce:片选信号,低电平,该芯片工作
cnt3<=0; //cnt3:16位的状态计数器
end
else
case(p2)
//-----------------------------------------------
idle: //p2为idle状态
begin
sce<=OFF;
cnt3<=cnt3+1;
case(cnt3)
//-----data_reg:8位数据寄存器---cd:数据命令切换脚---状态机2的状态------状态返回
0: begin data_reg<=8'h21; //8'b0010_0001 表示命令集的功能设置,
//第2位PD=0,芯片是活动的;PD=1芯片处于掉电模式;
//第1位V=0,水平寻址;V=1垂直寻址模式
//第0位H=1,使用扩展指令集 ;H=0使用基本指令集
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
1: begin data_reg<=8'hc8; //8'b1100_1000设置液晶偏置电压V_op寄存器
//V_op6=1 V_op5=0 V_op4=0 V_op3=1 V_op2=0 V_op1=0 V_op0=0
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
2: begin data_reg<=8'h06; //8'b0000_0110温度控制,温度校正
//第1位TC_1=1
//第0位TC_0=0 整个表示选用温度系数2
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
3: begin data_reg<=8'h13; //8‘b0001_0011设置偏置系统
//第2为BS_2=0 第1位BS_1=1 第0位BD_0=1;
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
4: begin data_reg<=8'h20; //8'b0010_0000表示命令集的功能设置
//第2位PD=0,芯片是活动的;PD=1芯片处于掉电模式;
//第1位V=0,水平寻址;V=1垂直寻址模式
//第0位H=0,使用扩展指令集 ;H=0使用基本指令集
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
5: begin p2<=clear_screen; //p2状态由shift_data换成clear_screen
p_back<=clear_screen; end
6: begin data_reg<=8'h0c; //8'b0000_1100设定显示模式,正常显示
//第2位D=1,
//第0位E=0, DE=01表示普通模式
cd<=CMD;
p2<=shift_data;
p_back<=idle; end
//-----设置显示坐标-----
7: begin p2<=set_xy; //p2状态变成set_xy
p_back<=set_xy; //返回状态也变成set_xy
y_reg<=0; //y坐标为0(范围为0-5)
x_reg<=0; //x坐标为2(范围为0-83)
end
//-----显示字符-----
8: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=4; //雄
end
9: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=0; //空白
end
10: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=3; //黑块
end
11: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=1; //力
end
//-----设置显示坐标-----
12: begin p2<=set_xy; //p2状态变成set_xy
p_back<=set_xy; //返回状态也变成set_xy
y_reg<=2; //y坐标为0(范围为0-5)
x_reg<=0; //x坐标为2(范围为0-83)
end
13: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=1; //力
end
14: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=4; //雄
end
15: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=0; //空格
end
16: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=5; //起
end
17: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=4; //雄
end
//-----设置显示坐标-----
18: begin p2<=set_xy; //p2状态变成set_xy
p_back<=set_xy; //返回状态也变成set_xy
y_reg<=4; //y坐标为0(范围为0-5)
x_reg<=32; //x坐标为2(范围为0-83)
end
19: begin p2<=disp_char; //p2状态变成显示字符
p_back<=disp_char;
char_reg<=4; //雄
end
20: begin cnt3<=20; //执行完后,在这进行停止
end
default;
endcase;
end
//------------------------------------------------
shift_data: //p2为传输数据状态
begin
if(p==clk_falling_edge) //在下降沿进行数据传输
begin
if(cnt2==8)
begin
cnt2<=0;
p2<=p_back;
end
else
begin
p2<=shift_data1;
sce<=ONN;
sdin<=data_reg[7]; //将数据寄存器的最高位发送
end
end
else
p2<=shift_data;
end
//-----------------------------------------------
shift_data1:
begin
if(p==clk_rising_edge) //上升沿数据进行移位
begin
data_reg<={data_reg[6:0],data_reg[7]}; //进行数据高位移位
cnt2<=cnt2+1;
p2<=shift_data;
end
else p2<=shift_data1;
end
//-------------------------------------------------
clear_screen: //清屏
begin
data_reg<=8'h00;
cnt4<=cnt4+1;
sce<=OFF;
cd<=DATA;
if(cnt4==504) //6行*84列=504
begin
cnt4<=0;
p2<=idle;
end
else
p2<=shift_data;
end
//-------------------------------------------------
set_xy: //设置X,y方向坐标
begin
cnt4<=cnt4+1;
sce<=OFF;
cd<=CMD;
case(cnt4)
0:begin data_reg<=(8'b0100_0000 | y_reg);
p2<=shift_data; end
1:begin data_reg<=(8'b1000_0000 | x_reg);
p2<=shift_data; end
2:begin p2<=idle;
cnt4<=0; end
default;
endcase;
end
//-------------------------------------------------
disp_char: //字符从字符库读入
begin
cnt4<=cnt4+1;
sce<=OFF;
cd<=DATA;
if(cnt4==16) //需要修改
begin
p2<=set_xy2;
p_back<=set_xy2; //返回状态也变成set_xy
y_reg<=y_reg+1;
end
else
begin
temp=men[char_reg];
case(cnt4)
0 :data_reg<=temp[0:7];
1 :data_reg<=temp[8:15];
2 :data_reg<=temp[16:23];
3 :data_reg<=temp[24:31];
4 :data_reg<=temp[32:39];
5 :data_reg<=temp[40:47];
6 :data_reg<=temp[48:55];
7 :data_reg<=temp[56:63];
8 :data_reg<=temp[64:71];
9 :data_reg<=temp[72:79];
10:data_reg<=temp[80:87];
11:data_reg<=temp[88:95];
12:data_reg<=temp[96:103];
13:data_reg<=temp[104:111];
14:data_reg<=temp[112:119];
15:data_reg<=temp[120:127];
default;
endcase;
p2<=shift_data;
end
end
//-------------------------------------------------
set_xy2: //设置X,y方向坐标
begin
cnt4<=cnt4+1;
sce<=OFF;
cd<=CMD;
case(cnt4)
17:begin data_reg<=(8'b0100_0000 | y_reg);
p2<=shift_data; end
18:begin data_reg<=(8'b1000_0000 | x_reg);
p2<=shift_data; end
19:begin p2<=disp_char2;
p_back<=disp_char2;
cnt4<=0; end
default;
endcase;
end
//--------------------------------------------------
disp_char2: //字符从字符库读入
begin
cnt4<=cnt4+1;
sce<=OFF;
cd<=DATA;
if(cnt4==16)
begin
p2<=set_xy3;
p_back<=set_xy3; //返回状态也变成set_xy
y_reg<=y_reg-1;
x_reg<=x_reg+16;
cnt4<=0;
end
else
begin
case(cnt4)
0: data_reg<=temp[128:135];
1: data_reg<=temp[136:143];
2: data_reg<=temp[144:151];
3: data_reg<=temp[152:159];
4: data_reg<=temp[160:167];
5: data_reg<=temp[168:175];
6: data_reg<=temp[176:183];
7: data_reg<=temp[184:191];
8: data_reg<=temp[192:199];
9: data_reg<=temp[200:207];
10:data_reg<=temp[208:215];
11:data_reg<=temp[216:223];
12:data_reg<=temp[224:231];
13:data_reg<=temp[232:239];
14:data_reg<=temp[240:247];
15:data_reg<=temp[248:255];
default;
endcase;
p2<=shift_data;
end
end
//-------------------------------------------------
set_xy3: //设置X,y方向坐标
begin
cnt4<=cnt4+1;
sce<=OFF;
cd<=CMD;
case(cnt4)
0:begin data_reg<=(8'b0100_0000 | y_reg);
p2<=shift_data; end
1:begin data_reg<=(8'b1000_0000 | x_reg);
p2<=shift_data; end
2:begin p2<=idle;
p_back<=idle;
cnt4<=0; end
default;
endcase;
end
//-----------------------
default; //状态已完
endcase;
end
endmodule