当前位置:文档之家› 单总线传输协议b2s (附全部verilog源码)

单总线传输协议b2s (附全部verilog源码)

1. 讲废话小弟最近做了一个项目(用Lattice的CPLD),话说前面还算顺利,就在即将完工的时候,发现(TMD)I/O不够用,有一功能需要CPLD传输8bit数据到另一个控制器做进一步处理,but现在仅剩下一个I/O,好吧,我被卡死在这里了。

终于,在一个月黑风高的夜晚(本人喜欢把气氛营造的悲壮一点,嘎嘎。

),突然想到DS18B20的单总线传输协议,以前也了解过其他的协议,心想,为嘛自己不整一个类似的东东出来yy 一下呢,所以有了此贴。

解释一下,本次原创单总线传输协议命名为b2s(不才,取了个类似I2C的名,由于本人有一个贱贱的英文名Bob,所以用了b,各位轻喷啊;s代表single,意为单线传输),本协议含传送端(transmitter)和接收端(receiver)两部分,基于verilog语言,仅使用单个I/O口进行多位数据的传输,传输方向为单向,用于I/O不够用的情况,亲测绝对可用,如果大家以后有用得到的时候,可以直接拿来使用。

本人拥抱开源,所有源码能贴出来尽量贴出来,为大家节省积分,攒RP。

废话完毕,下面为各位客官准备干货。

2. 晒干货ps. 带★号处可根据需要进行修改.发送端源码:/*********************************************************************** *******************Author: Bob LiuE-mail:*************************File Name: b2s_transmitter.vFunction: b2s发送端, 默认发送32bit数据,数据宽度可更改Version: 2013-5-13 v1.0************************************************************************ ********************/module b2s_transmitter(clk, //时钟基准,不限频率大小,但必须与接收端一致din, //待发送数据b2s_dout //b2s数据输出端口);parameter WIDTH=32; //★设定b2s发送数据的位宽,可根据需要进行更改input clk;input [WIDTH-1:0] din;output b2s_dout;//===================================================== =========//b2s数据发送时序//===================================================== =========reg b2s_dout_r;reg [3:0] state;reg [9:0] cnt;reg [4:0] count; //★与发送数据位宽保持一致(如发送32bit数据时,count宽度为5;发送8bit时,count宽度为4)always @ (posedge clk)begincase(state)//初始化0: begincount<=0;b2s_dout_r<=1;if(cnt==19) //b2s_dout_r高电平持续20个时钟beginstate<=1;cnt<=0;endelsebegincnt<=cnt+1;endend//开始信号时序1: beginb2s_dout_r<=0;if(cnt==19) //b2s_dout_r低电平持续20个时钟beginstate<=2;cnt<=0;endelsebegincnt<=cnt+1;endend2: beginb2s_dout_r<=1;if(cnt==19) //b2s_dout_r高电平持续20个时钟begincnt<=0;state<=3;endelsebegincnt<=cnt+1;endend//待发送数据的逻辑电平判断3: beginif(din[count]==1)state<=4;elsestate<=8;end//逻辑1的发送时序4: beginb2s_dout_r<=0;if(cnt==9) //b2s_dout_r低电平持续10个时钟begincnt<=0;state<=5;endelsebegincnt<=cnt+1;endend5: beginb2s_dout_r<=1;if(cnt==29) //b2s_dout_r高电平持续30个时钟begincnt<=0;state<=6;endelsebegincnt<=cnt+1;endend//逻辑0的发送时序8: beginb2s_dout_r<=0;if(cnt==29) //b2s_dout_r低电平持续30个时钟begincnt<=0;state<=9;endelsebegincnt<=cnt+1;endend9: beginb2s_dout_r<=1;if(cnt==9) //b2s_dout_r高电平持续10个时钟begincnt<=0;state<=6;endelsebegincnt<=cnt+1;endend//统计已发送数据位数6: begincount<=count+1'b1;state<=7;end7: beginif(count==WIDTH) //当一组数据所有位发送完毕,返回并继续下一次发送beginb2s_dout_r<=1;if(cnt==999) //b2s_dout_r高电平持续1000个时钟begincnt<=0;state<=0;endelsebegincnt<=cnt+1;endendelse //当一组数据未发送完毕,则继续此组下一位数据的发送state<=3;end//default值设定default: beginstate<=0;cnt<=0;count<=0;endendcaseendassign b2s_dout=b2s_dout_r;endmodule接收端源码:/*********************************************************************** *******************Author: Bob LiuE-mail:*************************File Name: b2s_receiver.vFunction: b2s接收端, 默认接收32bit数据,接收数据宽度请与发送端发送数据宽度保持一致Version: 2013-5-13 v1.0************************************************************************ ********************/module b2s_receiver(clk, //时钟基准,不限频率大小,但必须与发送端一致b2s_din, //b2s发送端发送过来的信号dout //b2s接收端解码出的数据);parameter WIDTH=32; //★设定b2s接收数据位数, 默认接收32bit数据,接收数据宽度请与发送端发送数据宽度保持一致input clk;input b2s_din;output [WIDTH-1:0] dout;//================================================== //b2s_din信号边沿检测//================================================== reg [1:0] b2s_din_edge=2'b01;always @ (posedge clk)beginb2s_din_edge[0] <= b2s_din;b2s_din_edge[1] <= b2s_din_edge[0];end//================================================== //time_cnt -- 存储b2c_din信号下降沿及其最近的下一个上升沿之间的时间//================================================== reg [1:0] state0;reg [5:0] time_cnt_r;always @ (posedge clk)begincase(state0)0: begintime_cnt_r<=0;state0<=1;end1: beginif(b2s_din_edge==2'b10)state0<=2;elsestate0<=state0;end2: beginif(b2s_din_edge==2'b01)beginstate0<=0;endelsetime_cnt_r<=time_cnt_r+1'b1;enddefault: begintime_cnt_r<=0;state0<=0;endendcaseendwire [5:0] time_cnt;assign time_cnt=(b2s_din_edge==2'b01)?time_cnt_r:'b0; //当b2s_din上升沿瞬间,读取time_cnt_r的值//==================================================//b2s解码时序//==================================================reg [2:0] state;reg [4:0] count; //★与接收数据位数保持一致(如接收32bit数据时,count宽度为5;接收8bit时,count宽度为4)reg [WIDTH-1:0] dout_r;always @ (posedge clk)begincase(state)0: begincount<=WIDTH;if((time_cnt>15)&&(time_cnt<25)) //判断起始信号state<=1;elsestate<=state;end1: beginif((time_cnt>5)&&(time_cnt<15)) //判断接收到的位是否为1begindout_r[WIDTH-1]<=1;state<=2;endelse if((time_cnt>25)&&(time_cnt<35)) //判断接收到的位是否为0begindout_r[WIDTH-1]<=0;state<=2;endelsebeginstate<=state;endend2: begincount<=count-1'b1; //每读取一个bit,count计数减1state<=3;end3: if(count==0) //数据读取完毕,返回并继续下一组数据的读取beginstate<=0;endelsestate<=4; //数据未读取完毕,则进行移位 4: begindout_r<=(dout_r>>1); //数据右移1位state<=1;enddefault: beginstate<=0;count<=WIDTH;endendcaseendassign dout=(count==0)?dout_r:dout; //每当一组数据读取完毕,则更新一次dout的值endmodule也许有些盆友第一次看到上面的代码,不知如何调用,所以下面给出调用示例作为参考。

相关主题