RS485实验

RS485实验

介绍

RS485采用差分信号进行传输,半双工通信。RS485是一个总线,在同一总线上最多可以挂接32个节点。通信流程简单理解为默认为接收状态,发送数据时切换为发送状态,数据发送完毕后切换为接收状态。发送和接收分别由一个引脚控制,且使能信号相反,可以由一个gpio去控制。下图是一个RS485的芯片,和芯片连接的一端有4个管腿儿,对外只有两条是差分线的。这里注意一下同时发送和接收,发送和接收可以同时使能接收的,发送的数据不仅会对外发,同时也接到了内部的接收器上,因此收发同时使能的话,在没有其他设备发送数据时,发送数据的时候会收到自己发送的数据。
RS485实验_第1张图片RS485实验_第2张图片

从硬件设计上,可以看到还是有可能会有两个设备同时使用总线发送数据的情况,完成半双工通信的话还需要软件上去实现同步。百度了一些资料,发现没有统一的说法,但是看到了一个CSMA/CD(波侦听多路访问/冲突检测),以太网用的是这种方式。大致意思是发送的时候去监听,如果接收到的数据和发送到的数据不一致,说明和其他设备争用了总线,就随机等待一段时间后再发送。

FPGA代码分析

接收和发送数据还是基于之前的串口模块,RS485多了方向的控制。例子设计了一个握手协议,1起始字节(0x55)+1长度字节+有效数据,fpga收到后将数据返回回来,如果可以收到发送的数据表示握手成功。数据需要缓存,所以需要使用一个fifo来实现,接收到的有效数据放入到FIFO里面,之后将FIFO中的数据发送出去。
状态机设计如下:

	case(state)
		IDLE:	/* 空闲状态,进行一些初始化操作 */
		begin
			state 			<= RCV_HEAD;
			rs485_de 		<= 1'b0 ;
			rx_data_ready 	<= 1'b1 ;
		end
		RCV_HEAD:	/* 起始字节接收状态,等待起始字节的到来 */
		begin
			if (rx_data_valid == 1'b1 && rx_data == 8'h55)	//when received data is valid and data is 8'h55,it means the start of data
				state <= RCV_COUNT ;				
		end
		RCV_COUNT:	/* 数据长度接收状态,接收有效的数据长度,保存到一个计数器中 */
		begin
			if (rx_data_valid == 1'b1)	//record data counter
			begin
				if (rx_data > 0)		//if data counter bigger than 0, then goto receive data state or goto IDLE state
					state <= RCV_DATA ;		
				else
					state <= IDLE ;
					
				data_count <= rx_data ;
			end
		end
		RCV_DATA:	/* 数据接收状态,把数据放到fifo里面,这一要看下fifo的时序 */
		begin
			fifo_wren  <= rx_data_valid ;
			fifo_wdata <= rx_data ;
			
			if (rx_data_valid == 1'b1)
			begin
				if (rx_cnt == data_count - 1)	//the last received data
				begin
					rx_cnt 		<= 8'd0 ;
					rs485_de 	<= 1'b1 ;
					state  		<= WAIT ;
				end
				else
					rx_cnt <= rx_cnt + 1'b1 ;
			end
		end
		WAIT:	/* 等待状态,延时1ms */
		begin						
			fifo_wren  <= 1'b0 ;
			if (wait_cnt >= CLK_FRE * 1000) // wait for 1 ms for direction change
			begin
				wait_cnt <= 32'd0 ;
				state <= SEND_WAIT;
			end
			else
			begin
				wait_cnt <= wait_cnt + 32'd1;
			end
		end
		SEND_WAIT:	/* 数据发送等待状态,读取fifo数据 */
		begin		
			if (tx_data_ready == 1'b1)
			begin
				if (tx_cnt == data_count)			//the last data has transferred
				begin
					tx_cnt 			<= 8'd0 ;					
					fifo_rden		<= 1'b0 ;
					state 			<= IDLE ;
				end
				else
				begin
					fifo_rden		<= 1'b1 ;		//read data from fifo
					state 			<= SEND ;
				end
			end
			tx_data_valid 	<= 1'b0 ;
		end
		SEND:	/* 数据发送状态,发送数据 */
		begin
			fifo_rden		<= 1'b0 ;
			tx_data_valid 	<= 1'b1 ;
			
			if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < data_count)
			begin
				tx_cnt <= tx_cnt + 8'd1; //Send data counter
				state  <= SEND_WAIT ;
			end	
		end
		default:
			state <= IDLE;
	endcase

上板测试

没有485串口,不测试。

参考

  1. 原来RS-485这么简单?
  2. 图文详解RS-485,真的很详细了
  3. RS485能否从机向主机发出请求?冲突如何解决?

你可能感兴趣的:(ZYNQ学习,fpga开发,dubbo)