工业控制现场
很多智能仪表都具备RS-232和RS-485两种通信接口类型。
RS-232是美国1969年公布的通信协议,也是工业控制中应用最广泛的一种串行接口,采取不平衡传输方式。
缺点:传输距离短,最大约30米,传输速率低,最高20kb/s,共模能力差,抗干扰能力弱,所以RS232只适合本地设备之间的通信。
RS-485是弥补RS232通信距离短,传输速率低等不足之处,于1983年提出一种串行数据接口标准,RS485采用差分传输方式,也叫平衡传输,有较高的噪音抑制能力,最大传输距离约1200米,最大传输速率10Mb/s增加了双向通信能力,所以RS485是首选的串行接口。
网络通信协议
主机和从机之间搭建的是RS-485网络,硬件是采用RS-485接线,主机呼叫从机地址,从机应答方式通讯。
数据帧10位,1位起始位,8个数据位,1个停止位,无效验。波特率:9600;19200;38400。
RS485可以联网构成分布式,最多并联32台驱动器和32台接收器。
RS485设备网想要互相通信,只有通过主设备(PC)中转才能实现,设备网只容许有一个主设备,其余都是从设备。
RS485电压范围-7~+12V
逻辑“1”,—2v-6v
逻辑“0”,—(-2v)-(-6v)
(1)通过RS232/RS485转换电路将PC机串口RS232信号转换成RS485信号,对于情况比较复杂的工业环境最好是选用防浪涌带隔离珊的产品。(2)通过PCI多串口卡,可以直接选用输出信号为RS485类型的扩展卡。
头文件:uart_tx_top.v
/***************************************************
* Module Name : uart_tx_top
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 串口发送顶层设计
**************************************************/
module uart_tx_top(
Clk, //50M时钟输入
Rst_n, //系统复位
Rs232_Tx, //Rs232输出信号
Rs232_Rx, //RS232数据输入
Rs232_Ren,
key_in0, //按键控制输入
led //数据发送状态
);
input Clk;
input Rst_n;
input key_in0;
output Rs232_Tx;
input Rs232_Rx;
output Rs232_Ren;
output led;
wire send_en;
wire [7:0]data_byte;
wire [7:0]data_rx;
wire key_flag0;
wire key_state0;
wire [2:0]baud_set;
wire uart_state;
assign led = uart_state;
assign send_en = key_flag0 & !key_state0;
assign Rs232_Ren = uart_state;
assign data_byte = 8'b1010_1111;//af
assign baud_set = 3'd4; //设置波特率为115200bps
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Rst_n(Rst_n),
.data_byte(data_byte),
.send_en(send_en),
.baud_set(baud_set),
.Rs232_Tx(Rs232_Tx),
.Tx_Done(),
.uart_state(uart_state)
);
key_filter key_filter0(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(key_in0),
.key_flag(key_flag0),
.key_state(key_state0)
);
/*ISSP ISSP(
.probe(data_rx),
.source(data_byte)
);*/
uart_byte_rx uart_byte_rx(
.Clk(Clk),
.Rst_n(Rst_n),
.baud_set(baud_set),
.Rs232_Rx(Rs232_Rx),
.data_byte(data_rx),
.Rx_Done(Rx_Done)
);
endmodule
按键模块
key_filter.v
/***************************************************
* Module Name : key_filter
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 单按键消抖设计
**************************************************/
module key_filter(
Clk, //50M时钟输入
Rst_n, //模块复位
key_in, //按键输入
key_flag, //按键标志信号
key_state //按键状态信号
);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
state <= IDEL;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
单字节接收模块
uart_byte_rx.v
/***************************************************
* Module Name : uart_byte_rx
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 串口接收模块设计
**************************************************/
module uart_byte_rx(
Clk, //模块时钟50M
Rst_n, //模块复位
baud_set, //波特率设置
Rs232_Rx, //RS232数据输入
data_byte, //并行数据输出
Rx_Done //一次数据接收完成标志
);
input Clk;
input Rst_n;
input [2:0]baud_set;
input Rs232_Rx;
output reg [7:0]data_byte;
output reg Rx_Done;
reg s0_Rs232_Rx,s1_Rs232_Rx;//同步寄存器
reg tmp0_Rs232_Rx,tmp1_Rs232_Rx;//数据寄存器
reg [15:0]bps_DR;//分频计数器计数最大值
reg [15:0]div_cnt;//分频计数器
reg bps_clk;//
reg [7:0]bps_cnt;
reg uart_state;
reg [2:0] r_data_byte [7:0];
//reg [7:0] tmp_data_byte;
reg [2:0] START_BIT,STOP_BIT;
wire nedege;
//同步寄存器,消除亚稳态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
s0_Rs232_Rx <= 1'b0;
s1_Rs232_Rx <= 1'b0;
end
else begin
s0_Rs232_Rx <= Rs232_Rx;
s1_Rs232_Rx <= s0_Rs232_Rx;
end
//数据寄存器
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
tmp0_Rs232_Rx <= 1'b0;
tmp1_Rs232_Rx <= 1'b0;
end
else begin
tmp0_Rs232_Rx <= s1_Rs232_Rx;
tmp1_Rs232_Rx <= tmp0_Rs232_Rx;
end
assign nedege = !tmp0_Rs232_Rx & tmp1_Rs232_Rx;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd324;
else begin
case(baud_set)
0:bps_DR <= 16'd324;
1:bps_DR <= 16'd162;
2:bps_DR <= 16'd80;
3:bps_DR <= 16'd53;
4:bps_DR <= 16'd26;
default:bps_DR <= 16'd324;
endcase
end
//counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
// bps_clk gen
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
//bps counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_cnt <= 8'd0;
else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && (START_BIT > 2)))
bps_cnt <= 8'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rx_Done <= 1'b0;
else if(bps_cnt == 8'd159)
Rx_Done <= 1'b1;
else
Rx_Done <= 1'b0;
// always@(posedge Clk or negedge Rst_n)
// if(!Rst_n)
// data_byte <= 8'd0;
// else if(bps_cnt == 8'd159)
// data_byte <= tmp_data_byte;
// else
// data_byte <= data_byte;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
data_byte <= 8'd0;
else if(bps_cnt == 8'd159)begin
data_byte[0] <= r_data_byte[0][2];
data_byte[1] <= r_data_byte[1][2];
data_byte[2] <= r_data_byte[2][2];
data_byte[3] <= r_data_byte[3][2];
data_byte[4] <= r_data_byte[4][2];
data_byte[5] <= r_data_byte[5][2];
data_byte[6] <= r_data_byte[6][2];
data_byte[7] <= r_data_byte[7][2];
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
START_BIT = 3'd0;
r_data_byte[0] <= 3'd0;
r_data_byte[1] <= 3'd0;
r_data_byte[2] <= 3'd0;
r_data_byte[3] <= 3'd0;
r_data_byte[4] <= 3'd0;
r_data_byte[5] <= 3'd0;
r_data_byte[6] <= 3'd0;
r_data_byte[7] <= 3'd0;
STOP_BIT = 3'd0;
end
else if(bps_clk)begin
case(bps_cnt)
0:begin
START_BIT = 3'd0;
r_data_byte[0] <= 3'd0;
r_data_byte[1] <= 3'd0;
r_data_byte[2] <= 3'd0;
r_data_byte[3] <= 3'd0;
r_data_byte[4] <= 3'd0;
r_data_byte[5] <= 3'd0;
r_data_byte[6] <= 3'd0;
r_data_byte[7] <= 3'd0;
STOP_BIT = 3'd0;
end
6,7,8,9,10,11:START_BIT <= START_BIT + s1_Rs232_Rx;
22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rs232_Rx;
38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rs232_Rx;
54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rs232_Rx;
70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rs232_Rx;
86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rs232_Rx;
102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rs232_Rx;
118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rs232_Rx;
134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rs232_Rx;
150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rs232_Rx;
default:
begin
START_BIT = START_BIT;
r_data_byte[0] <= r_data_byte[0];
r_data_byte[1] <= r_data_byte[1];
r_data_byte[2] <= r_data_byte[2];
r_data_byte[3] <= r_data_byte[3];
r_data_byte[4] <= r_data_byte[4];
r_data_byte[5] <= r_data_byte[5];
r_data_byte[6] <= r_data_byte[6];
r_data_byte[7] <= r_data_byte[7];
STOP_BIT = STOP_BIT;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
uart_state <= 1'b0;
else if(nedege)
uart_state <= 1'b1;
else if(Rx_Done || (bps_cnt == 8'd12 && (START_BIT > 2)))
uart_state <= 1'b0;
else
uart_state <= uart_state;
endmodule
单字节发送模块
uart_byte_tx.v
/***************************************************
* Module Name : uart_byte_tx
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 串口发送模块设计
**************************************************/
module uart_byte_tx(
Clk, //50M时钟输入
Rst_n, //模块复位
data_byte, //待传输8bit数据
send_en, //发送使能
baud_set, //波特率设置
Rs232_Tx, //Rs232输出信号
Tx_Done, //一次发送数据完成标志
uart_state //发送数据状态
);
input Clk;
input Rst_n;
input [7:0]data_byte;
input send_en;
input [2:0]baud_set;
output reg Rs232_Tx;
output reg Tx_Done;
output reg uart_state;
reg bps_clk; //波特率时钟
reg [15:0]div_cnt;//分频计数器
reg [15:0]bps_DR;//分频计数最大值
reg [3:0]bps_cnt;//波特率时钟计数器
reg [7:0]r_data_byte;
localparam START_BIT = 1'b0;
localparam STOP_BIT = 1'b1;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
uart_state <= 1'b0;
else if(send_en)
uart_state <= 1'b1;
else if(bps_cnt == 4'd11)
uart_state <= 1'b0;
else
uart_state <= uart_state;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
r_data_byte <= 8'd0;
else if(send_en)
r_data_byte <= data_byte;
else
r_data_byte <= r_data_byte;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd5207;
else begin
case(baud_set)
0:bps_DR <= 16'd5207;
1:bps_DR <= 16'd2603;
2:bps_DR <= 16'd1301;
3:bps_DR <= 16'd867;
4:bps_DR <= 16'd433;
default:bps_DR <= 16'd5207;
endcase
end
//counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
// bps_clk gen
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
//bps counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_cnt <= 4'd0;
else if(bps_cnt == 4'd11)
bps_cnt <= 4'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Tx_Done <= 1'b0;
else if(bps_cnt == 4'd11)
Tx_Done <= 1'b1;
else
Tx_Done <= 1'b0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rs232_Tx <= 1'b1;
else begin
case(bps_cnt)
0:Rs232_Tx <= 1'b1;
1:Rs232_Tx <= START_BIT;
2:Rs232_Tx <= r_data_byte[0];
3:Rs232_Tx <= r_data_byte[1];
4:Rs232_Tx <= r_data_byte[2];
5:Rs232_Tx <= r_data_byte[3];
6:Rs232_Tx <= r_data_byte[4];
7:Rs232_Tx <= r_data_byte[5];
8:Rs232_Tx <= r_data_byte[6];
9:Rs232_Tx <= r_data_byte[7];
10:Rs232_Tx <= STOP_BIT;
default:Rs232_Tx <= 1'b1;
endcase
end
endmodule