题目一
1、并行数据流转换为一种特殊串行数据流模块,即把输入的4位并行数据转换为协议要求的串行数据流。
分析:设计成两个可综合的电路模块,第一个模块能把四位的并行数据转换为符合以下协议的串行数据流,数据流用scl和sda两条线传输,sclk为时钟信号,data[3:0]为输入数据,ack为模块1请求模块0发新数据信号。
第二个模块则是接收数据模块,并将数据转换为相应16信号线的高电平,即若数据为1,第一条信号线为高电平,数据为n,则第n条线为高电平.
模块0为测试模块,用于接收模块一的ack和产生新的输入数据data[3:0]
通信协议:scl为不断输出的时钟信号,如果scl为高电平,sda由高变低时刻,串行数据流开始,sda由低变高,串行数据流结束。 sda信号的串行数据位必须在scl为低电平时变化,若变高则为1,否则为0
模块1代码
module ptosda(rst,sclk,ack,scl,sda,data);
input sclk,rst;
input [3:0] data;
output ack,scl,sda;
reg scl,ack,link_sda,sdabuf;
reg [3:0] databuf;
reg [7:0] state;
assign sda = link_sda?sdabuf:1`b0;//控制sdabuf输出到串行总线上
parameter ready = 8`b0000_0000,
start = 8`b0000_0001,
bit1 = 8`b0000_0010,
bit2 = 8`b0000_0100,
bit3 = 8`b0000_1000,
bit4 = 8`b0001_0000,
bit5 = 8`b0010_0000,
stop = 8`b0100_0000,
IDEA = 8`b1000_0000;
always@(posedge sclk or negedge rst)
begin
if(!rst)
sck<=1;//因为sda只在scl低电平时变化有效,所以复位将它拉高
else
scl = ~scl;
end
always@(posedge ack)//发出ack请求新数据时把老数据存起来
databuf <=data;
//主状态机:产生控制信号
always @(negedge sclk or negedge rst)
if(!rst)
begin
link_sda <=0;
state <=ready;
sdabuf<=1;
ack<=0;
end
else begin
case(state)
ready: if(ack)
begin
link_sda<=1;//把sdabuf与sda串行总线连接
state<=start;
end
else
begin
link_sda<=0;
state<=ready;
ack<=1;
end
start: if(scl&&ack)//sda开始传输
begin
sdabuf<=0;//在sda连接的前提下输出开始信号
state = bit1;
end
else state<=start;
bit1: if(!scl)//时钟为低电平时送出最高位
begin
sdabuf<=databuf[3];
state<=bit2;
ack<=0;
end
else state<=bit1;
bit2: if(!scl)
begin
sdabuf<=databuf[2];
state<=bit3;
end
else state <= bit2;
bit3: if(!scl)
begin
sdabuf<=databuf[1];
state<=bit4;
end
else state <= bit3;
bit4: if(!scl)
begin
sdabuf<=databuf[0];
state<=bit5;
end
else state <= bit4;
//四位并行数据传送完
bit5: if(!scl)
begin
sdabuf <=0;//把sda拉低
state<=stop;
end
else state<=bit5;
stop: if(scl)//在scl为高时,sda由低变高表示结束
begin
sdabuf <=1;//把sda拉高
state<=IDLe;
end
else state<=stop;
IDLe: begin
link_sda<=0;//把sdabuf与sda串行总线脱开
state<=ready;
end
default :begin
link_sda<=0;
sdabuf<=1;
state<=ready;
end
endcase
end
endmodule
模块2代码
module out16hi(scl,sda);
input scl,sda;
output [15:0]outhigh;
reg [5:0] mstate;
reg[3:0]pdata,pdatabuf;
reg [15:0]outhigh;
reg startflag,endflag;
//clk为高时,sda由高变低表示串行数据流开始
always@(negedge sda)
begin
if(scl)
begin
startflag<=1;
end
else if(endflag)
startflag<=0;
end
//clk为高时,sda由低变高表示串行数据流结束
always@(posedge sda)
if(scl)
begin
endflag<=1;//串行数据结束
pdatabuf<=pdata;//把收到的四位数据存入寄存器
end
else
endflag<=0;//数据接收还没有结束
parameter ready=6`b00_0000;
sbit0=6`b00_0001;
sbit1=6`b00_0010;
sbit2=6`b00_0100;
sbit3=6`b00_1000;
sbit4=6`b01_0000;
always@(pdatabuf)//把收到的数据转换成相应的高电平
begin
case (pdatabuf)
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
4`b0001:outhigh = 16`b0000_0000_0000_0001
endcase
end
always@(posedge scl)
if(startflag)
case(mstate)
sbit0:begin
mstate<=sbit1;
pdata[3]<=sda;
$display("i am in sdabit0");
end
sbit1:begin
mstate<=sbit2;
pdata[2]<=sda;
$display("i am in sdabit1");
end
sbit2:begin
mstate<=sbit3;
pdata[1]<=sda;
$display("i am in sdabit2");
end
sbit3:begin
mstate<=sbit4;
pdata[0]<=sda;
$display("i am in sdabit3");
end
sbit4:begin
mstate<=sbit0;
$display("i am in sdastop");
end
default: mstate<=sbit0;
endmodule