verlog简单的SPI收发接受器

verlog简单的SPI收发接受器

主程序代码如下

/***********************************
作者:robetwu
时间:2020.7.15
环境:Quartus 13.0
发送和接受缓存器可以使用memory
*******************/
module sample_spi(clk,rst_n,wr,rd,si,sclk,so,cs,data_out,data_receive_buff);

input clk;
input rst_n;
input wr;
input rd;
input si;//master线MISO
output reg sclk;//可以使用PLL或者定时器时钟以满足外设时钟要求
output reg cs;//片选
output reg so;//master线MOSI
reg [7:0]data_in;
reg [7:0]data_out_reg;//发送缓存寄电器
output  [7:0]data_out;

assign data_out=data_out_reg;//将发射的数据放入发射受寄电器中


//CPOL核CPHA的相关配置如下
//空闲状态sclk为低,CPOL=0;相位CPHA=0在sclk时钟的下降延发射接受数据
//空闲状态sclk为低,CPOL=0;相位CPHA=1在sclk时钟的上升延发射接受数据
//空闲状态sclk为高,CPOL=1;相位CPHA=0在sclk时钟的上升延发射接受数据
//空闲状态sclk为高,CPOL=1;相位CPHA=1在sclk时钟的下降延发射接受数据
always@(posedge clk or negedge rst_n)
	if(!rst_n)
		begin
		sclk<=1;//配置为CPOL=1,CPHA=0;
		cs<=1;
		end
	else if(wr|rd)
		begin
			sclk=~sclk;
			cs<=0;
		end
	else
		begin
		sclk<=1;
		cs<=1;
		end
		
reg [4:0]send_stata;
reg [4:0]receive_stata;

//发生状态,发生从高向低发生
parameter bit7=4'd0,bit6=4'd1,bit5=4'd2,bit4=4'd3,
bit3=4'd4,bit2=4'd5,bit1=4'd6,bit0=4'd7,bit_end=4'd8;

//发送指令

always@(posedge sclk)
if(wr)
begin
send_stata<=bit7;
send_task;
end

task	send_task;
begin
case(send_stata)
bit7:
	begin
	so<=data_out_reg[7];//发送接受
	send_stata<=bit6;
	end
bit6:
	begin
	so<=data_out_reg[6];//发送
	send_stata<=bit5;
	end
bit5:
	begin
	so<=data_out_reg[5];//发送
	send_stata<=bit4;
	end
bit4:
	begin
	so<=data_out_reg[4];//发送
	send_stata<=bit3;
	end
bit3:
	begin
	so<=data_out_reg[3];//发送
	send_stata<=bit2;
	end
bit2:
	begin
	so<=data_out_reg[2];//发送
	send_stata<=bit1;
	end
bit1:
	begin
	so<=data_out_reg[1];//发送
	send_stata<=bit0;
	end
bit0:
	begin
	so<=data_out_reg[0];//发送
	send_stata<=bit_end;
	end
bit_end:
	begin
	so<='bz;//发送
	send_stata<=bit7;
	end	

endcase
end
endtask

//接受指令
//接受状态 ,接收从高向低接受
parameter bit70=4'd0,bit60=4'd1,bit50=4'd2,bit40=4'd3,
bit30=4'd4,bit20=4'd5,bit10=4'd6,bit00=4'd7,bit_end0=4'd8;
output reg[7:0]data_receive_buff;//接受缓存寄电器
reg js_byte;

always@(*)
if(js_byte==1)
	data_out_reg<=data_receive_buff;
else
	data_out_reg<=8'hzz;
//assign data_out_reg=(js_byte==1)?data_receive_buff:8'hzz;

always@(posedge sclk)
	if(rd)
	begin
	js_byte<=0;
	receive_stata<=bit70;
	receive_task;
	end


task receive_task;
case(receive_stata)
bit70:
	begin
	data_receive_buff[7]<=si;//接受
	receive_stata<=bit60;
	end
bit60:
	begin
	data_receive_buff[6]<=si;
	receive_stata<=bit50;
	end
bit50:
	begin
	data_receive_buff[5]<=si;
	receive_stata<=bit40;
	end
bit40:
	begin
	data_receive_buff[4]<=si;
	receive_stata<=bit30;
	end
bit30:
	begin
	data_receive_buff[3]<=si;
	receive_stata<=bit20;
	end
bit20:
	begin
	data_receive_buff[2]<=si;
	receive_stata<=bit10;
	end
bit10:
	begin
	data_receive_buff[1]<=si;
	receive_stata<=bit00;
	end
bit00:
	begin
	data_receive_buff[0]<=si;
	receive_stata<=bit_end0;
	js_byte<=1;
	end
bit_end0:
	begin
	data_receive_buff<=8'hzz;
	receive_stata<=bit70;
	end
endcase
endtask
	

endmodule

测试文件如下


`timescale 1ns/1ns
module sample_spi_tb;
reg clk;
reg rst_n;
reg wr;
reg rd;
reg  si;//master线MISo
wire sclk;
wire cs;
wire so;//master线MOSI
wire [7:0]data_receive_buff;

wire [7:0]data_out;


sample_spi sample_spi_inst(
			.clk(clk),.rst_n(rst_n),.wr(wr),.rd(rd),
			.si(si),.so(so),.sclk(sclk),.cs(cs),
			.data_out(data_out),.data_receive_buff(data_receive_buff));
			

initial
begin
	wr=0;rd=1;rst_n=0;clk=0;
	#10 rst_n=1;
	repeat(20)
	begin
	#20 si=1;
	#20 si=0;
	#20 si=1;
	#20 si=0;
	#20 si=0;
	#20 si=1;
	#20 si=0;
	#20 si=1;
	end
	wr=1;rd=0;
	repeat(20)
	begin
	#20 si=1;
	#20 si=0;
	#20 si=1;
	#20 si=0;
	#20 si=0;
	#20 si=1;
	#20 si=0;
	#20 si=1;
	end
	#10000;
end	

always #10 clk=~clk;

endmodule

测试方式为先读取数据,然后将读取的数据发送出去;

测试结果如下

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以回答你的问题。以下是用Verilog语言编写CAN收发器的代码示例: module can_transceiver( input clk, //时钟信号 input rst_n, //复位信号 input can_rx, //CAN接收信号 output reg can_tx //CAN发送信号 ); reg [11:0] can_id; //CAN标识符 reg [7:0] can_data[7:0]; //CAN数据 //定义状态机 localparam IDLE = 2'b00; //空闲状态 localparam RX = 2'b01; //接收状态 localparam TX = 2'b10; //发送状态 reg [1:0] state = IDLE; //初始状态为IDLE always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; //复位时回到IDLE状态 can_tx <= 1'b0; //CAN发送信号置为0 end else begin case (state) IDLE: begin if (!can_rx) begin //接收到CAN信号 state <= RX; //进入接收状态 can_id <= 0; //初始化CAN标识符 can_data <= 0; //初始化CAN数据 end else if (can_data != 0) begin //有CAN数据需要发送 state <= TX; //进入发送状态 end end RX: begin can_id <= {can_id[0:7], can_rx}; //更新CAN标识符 for (i = 0; i < 8; i = i + 1) begin if (!can_rx) begin can_data[i] <= 1'b0; //接收CAN数据 end else begin can_data[i] <= can_rx; //更新CAN数据 end end if (can_rx) begin state <= IDLE; //接收完毕,回到IDLE状态 end end TX: begin can_tx <= 1'b1; //置CAN发送信号为1 for (i = 0; i < 8; i = i + 1) begin can_tx <= can_data[i]; //发送CAN数据 end state <= IDLE; //发送完毕,回到IDLE状态 end default: state <= IDLE; //默认回到IDLE状态 endcase end end endmodule 请注意,这只是一个简单的示例代码,并不能完全符合您的实际需求。具体实现需要根据您的具体需求进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值