('*' 또는 '-'는 don't care로써 0또는1 아무거나 써도 상관없음)
module i2c_txtlcd_top(
input clk, reset_p,
input [3:0] btn,
output scl, sda,
output [15:0]led);
parameter IDLE = 6'b00_0001;
parameter INIT = 6'b00_0010;
parameter SEND_DATA = 6'b00_0100;
parameter SEND_COMMAND = 6'b01_0000;
wire clk_usec;
clock_div_100 usec_clk (.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_usec));
reg [21:0] count_usec; //3초 대기를 위함
reg count_usec_e;
always @(negedge clk or posedge reset_p)begin
if(reset_p)count_usec = 0;
else if(clk_usec && count_usec_e)count_usec = count_usec + 1; //S_IDLE에서 count_usec_e를 1주면 카운트 시작
else if(!count_usec_e)count_usec = 0; //count_usec_e가 0이되면 리셋
end
wire [3:0] btn_pedge;
button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_pedge[0]));
button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_pedge[1]));
button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_pedge[2]));
button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_pedge[3]));
reg [7:0] send_buffer;
reg rs, send;
wire busy;
i2c_lcd_send_byte txtlcd(.clk(clk), .reset_p(reset_p),
.addr(7'h27),
.send_buffer(send_buffer), //보낼 데이터
.rs(rs), .send(send), // send가 1됬을때 1바이트 보냄
.scl(scl), .sda(sda),
.busy(busy), //보내는 동안 시간이 걸리기 때문에 busy가 0일때만 send 가능
.led(led));
reg [5:0] state, next_state; //6비트짜리 상태들
always @(negedge clk or posedge reset_p)begin
if(reset_p)state = IDLE;
else state = next_state;
end
reg init_flag;
reg [3:0] cnt_data;
always @(posedge clk or posedge reset_p)begin
if(reset_p)begin
next_state = IDLE;
init_flag = 0;
cnt_data = 0;
rs = 0;
end
else begin
case(state)
IDLE:begin
if(init_flag)begin
if(btn_pedge[0])next_state = SEND_DATA;
if(btn_pedge[1])next_state = SEND_COMMAND;
end
else begin
if(count_usec <= 22'd80_000)begin
count_usec_e = 1;
end
else begin
next_state = INIT;
count_usec_e = 0;
end
end
end
INIT:begin
if(busy)begin
send = 0;
if(cnt_data >= 6)begin
next_state = IDLE;
init_flag = 1;
cnt_data = 0;
end
end
else if(!send)begin //send가 1이되면 i2c_lcd_send_byte모듈에서 엣지디텍터에 의해 한 클락 뒤에 send_pedge가 발생하고 이 send_pedge신호를 보고 i2c_lcd_send_byte모듈의 상태머신에서 busy가 1이된다,
case(cnt_data) //그러면 busy가 1이되기 전에 이미 이쪽 상태머신에 들어와 다시 case문에 들어와서 1번케이스의 send_buffer를 바꾸기 때문에 send가 0일때만 들어올 수 있도록 조건을 건다
0:send_buffer = 8'h33;
1:send_buffer = 8'h32;
2:send_buffer = 8'h28;
3:send_buffer = 8'h0f;
4:send_buffer = 8'h01;
5:send_buffer = 8'h06;
endcase
rs = 0;
send = 1;
cnt_data = cnt_data + 1;
end
end
SEND_DATA:begin
if(busy)begin
next_state = IDLE;
send = 0;
if(cnt_data >= 9)cnt_data = 0;
else cnt_data = cnt_data + 1;
end
else begin
send_buffer = "0"+cnt_data; //"A":A의 대문자 아스키값 ""사용//"A"+cnt_data:아스키코드 값 점점 증가//"0"+cnt_data:점점 증가하는 숫자 출력(0에 해당하는 아스키값에 cnt_data 덤함
rs = 1; //데이터 레지스터에게 보냄
send = 1;
end
end
SEND_COMMAND:begin
if(busy)begin
next_state = IDLE;
send = 0;
if(cnt_data >= 9)cnt_data = 0;
else cnt_data = cnt_data + 1;
end
else begin
// send_buffer = 8'h18; //버튼1을 누르면 화면 왼쪽으로 밀림
send_buffer = 8'hc0; //칸 주소지를 정하여 화면 아랫줄 첫칸으로 커서 보냄
rs = 0; //커맨드 레지스터에게 보냄
send = 1;
end
end
endcase
end
end
endmodule
module i2c_txtlcd_top(
input clk, reset_p,
input [3:0] btn,
output scl, sda,
output [15:0]led);
parameter IDLE = 6'b00_0001;
parameter INIT = 6'b00_0010;
parameter SEND_DATA = 6'b00_0100;
parameter SEND_COMMAND = 6'b00_1000;
parameter SEND_STRING = 6'b01_0000;
wire clk_usec;
clock_div_100 usec_clk (.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_usec));
reg [21:0] count_usec; //3초 대기를 위함
reg count_usec_e;
always @(negedge clk or posedge reset_p)begin
if(reset_p)count_usec = 0;
else if(clk_usec && count_usec_e)count_usec = count_usec + 1; //S_IDLE에서 count_usec_e를 1주면 카운트 시작
else if(!count_usec_e)count_usec = 0; //count_usec_e가 0이되면 리셋
end
wire [3:0] btn_pedge;
button_cntr btn0(.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_pedge(btn_pedge[0]));
button_cntr btn1(.clk(clk), .reset_p(reset_p), .btn(btn[1]), .btn_pedge(btn_pedge[1]));
button_cntr btn2(.clk(clk), .reset_p(reset_p), .btn(btn[2]), .btn_pedge(btn_pedge[2]));
button_cntr btn3(.clk(clk), .reset_p(reset_p), .btn(btn[3]), .btn_pedge(btn_pedge[3]));
reg [7:0] send_buffer;
reg rs, send;
wire busy;
i2c_lcd_send_byte txtlcd(.clk(clk), .reset_p(reset_p),
.addr(7'h27),
.send_buffer(send_buffer), //보낼 데이터
.rs(rs), .send(send), // send가 1됬을때 1바이트 보냄
.scl(scl), .sda(sda),
.busy(busy), //보내는 동안 시간이 걸리기 때문에 busy가 0일때만 send 가능
.led(led));
reg [5:0] state, next_state; //6비트짜리 상태들
always @(negedge clk or posedge reset_p)begin
if(reset_p)state = IDLE;
else state = next_state;
end
reg init_flag;
reg [3:0] cnt_data;
reg [8*5-1:0] hello; //40비트짜리 레지스터//5글자 짜리 문자열 변수, 한 글자당 8비트//[]안에 변수안됨 상수만 가능
reg [3:0] cnt_string;
always @(posedge clk or posedge reset_p)begin
if(reset_p)begin
next_state = IDLE;
init_flag = 0;
cnt_data = 0;
rs = 0;
hello = "HELLO"; //8비트씩 5글자가 순서대로 들어감
cnt_string = 0;
end
else begin
case(state)
IDLE:begin
if(init_flag)begin
if(btn_pedge[0])next_state = SEND_DATA;
if(btn_pedge[1])next_state = SEND_COMMAND;
if(btn_pedge[2])next_state = SEND_STRING;
end
else begin
if(count_usec <= 22'd80_000)begin
count_usec_e = 1;
end
else begin
next_state = INIT;
count_usec_e = 0;
end
end
end
INIT:begin
if(busy)begin
send = 0;
if(cnt_data >= 6)begin
next_state = IDLE;
init_flag = 1;
cnt_data = 0;
end
end
else if(!send)begin //send가 1이되면 i2c_lcd_send_byte모듈에서 엣지디텍터에 의해 한 클락 뒤에 send_pedge가 발생하고 이 send_pedge신호를 보고 i2c_lcd_send_byte모듈의 상태머신에서 busy가 1이된다,
case(cnt_data) //그러면 busy가 1이되기 전에 이미 이쪽 상태머신에 들어와 다시 case문에 들어와서 1번케이스의 send_buffer를 바꾸기 때문에 send가 0일때만 들어올 수 있도록 조건을 건다
0:send_buffer = 8'h33;
1:send_buffer = 8'h32;
2:send_buffer = 8'h28;
3:send_buffer = 8'h0f;
4:send_buffer = 8'h01;
5:send_buffer = 8'h06;
endcase
rs = 0; //커맨드 레지스터에게 보냄
send = 1;
cnt_data = cnt_data + 1;
end
end
SEND_DATA:begin
if(busy)begin
next_state = IDLE;
send = 0;
if(cnt_data >= 9)cnt_data = 0;
else cnt_data = cnt_data + 1;
end
else begin
send_buffer = "0"+cnt_data; //"A":A의 대문자 아스키값 ""사용//"A"+cnt_data:아스키코드 값 점점 증가//"0"+cnt_data:점점 증가하는 숫자 출력(0에 해당하는 아스키값에 cnt_data 덤함
rs = 1; //데이터 레지스터에게 보냄
send = 1;
end
end
SEND_COMMAND:begin
if(busy)begin
next_state = IDLE;
send = 0;
if(cnt_data >= 9)cnt_data = 0;
else cnt_data = cnt_data + 1;
end
else begin
send_buffer = 8'h18; //버튼1을 누르면 화면 왼쪽으로 밀림
// send_buffer = 8'hc0; //칸 주소지를 정하여 화면 아랫줄 첫칸으로 커서 보냄
rs = 0; //커맨드 레지스터에게 보냄
send = 1;
end
end
SEND_STRING:begin
if(busy)begin
send = 0;
if(cnt_string >= 5)begin
next_state = IDLE;
cnt_string = 0;
end
end
else if(!send)begin //send가 1이되면 i2c_lcd_send_byte모듈에서 엣지디텍터에 의해 한 클락 뒤에 send_pedge가 발생하고 이 send_pedge신호를 보고 i2c_lcd_send_byte모듈의 상태머신에서 busy가 1이된다,
case(cnt_string) //그러면 busy가 1이되기 전에 이미 이쪽 상태머신에 들어와 다시 case문에 들어와서 1번케이스의 send_buffer를 바꾸기 때문에 send가 0일때만 들어올 수 있도록 조건을 건다
0:send_buffer = hello[39:32];
1:send_buffer = hello[31:24];
2:send_buffer = hello[23:16];
3:send_buffer = hello[15:8];
4:send_buffer = hello[7:0];
endcase
rs = 1; //커맨드 레지스터에게 보냄
send = 1;
cnt_string = cnt_string + 1;
end
end
endcase
end
end
endmodule