时间:2024-07-25 来源:网络搜集 关于我们 0
1)实验平台:正点原子开拓者FPGA 开发板
2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html
第十七章 RS485串口通信实验
RS-485是针对UART串口的一种接口标准,它定义了串行通信系统中发送器和接收器的一系
列电气特性。相比于RS-232,RS-485标准的通信系统抗干扰能力较强,可实现长距离数据传输,
同时支持多个收发器连接到同一个通信网络中。因此,RS-485在工业控制领域以及有类似需求
的系统中得到了广泛的应用。
本章包括以下几个部分:
17.1 RS-485简介
17.2 实验任务
17.3 硬件设计
17.4 程序设计
17.5 下载验证
RS-485简介
在“串口通信实验”章节我们详细地介绍了UART串口通信以及RS-232接口标准。实际上,
除了RS-232之外,RS-422和RS-485也都是常用的串行通信接口标准,它们定义了接口不同的电
气特性,如RS-232是单端输入输出,而RS-422/485为差分输入输出等。
在介绍RS-485之前,我们先来了解一下串口通信过程中单端传输与差分传输的差别。单端
传输是指在发送或接收过程中,用信号线对地线的电压值来表示逻辑“0”和“1”。而差分传
输使用两根信号线来传输一路信号,这两根信号线上传输的信号幅值相等,相位相差180度(极
性相反),用它们的差值来表示逻辑“0”和“1”,如图 17.1.1所示。
图 17.1.1 差分传输方式
在传输过程中,当信号线上叠加了频率、幅值和相位都相同的干扰信号时(共模干扰),
对于单端传输而言,由于地线电位为0,则传输的信号就包含了干扰信号;而在差分传输方式
下,干扰可以通过两个信号线上电压的差值抵消,相当于抑制了共模干扰,如图 17.1.2所示。
因此相对于单端传输方式,差分传输大大提高了信号在传输过程中的抗干扰能力,但是需要多
余的信号线来实现信号传输。
图 17.1.2 差分传输抑制共模干扰
RS-232接口标准出现较早,信号采用负逻辑电平、单端传输方式工作。通过一根信号线发
送,一根信号线接收,加上一根地线,RS-232可实现全双工通信。由于单端传输方式抗干扰能
力差,导致RS-232标准通信距离短(小于15米),数据传输速率低等问题。另外RS-232仅支持
一对一通信,存在无法实现多个设备互联的缺点。
RS-422由RS-232发展而来,它是为弥补RS-232之不足而提出的。RS-422采用差分传输(又
称平衡传输)方式,将最大传输速率提高到10Mbps;当传输速率在100kbps以下时,传输距离
可达1200米。由于采用差分传输方式,RS-422需要4根信号线来实现全双工通信,两根用于发
送、两根用于接收,一般会再加上一根地线。RS-422允许在一条传输总线上连接最多10个接收
器,从而实现单个设备发送,多个设备接收的功能。
为扩展应用范围,在RS-422基础上又制定了RS-485标准。RS-485同样采用差分传输方式,
但是RS-485只有2根信号线,由发送和接收共用,因此发送和接收不能同时进行,只能实现半
双工通信。RS-485增加了多点、双向通信能力,即允许多个发送器连接到同一条总线上,各设
备通过使能信号控制发送和接收过程。
实验任务
本节实验任务是使用两块开拓者开发板通过RS-485端口互联,由各自开发板上的四个按键
分别控制对方开发板上四个LED灯的亮灭。当按键按下时,对方开发板上对应的LED灯点亮;按
键释放时,对应的LED灯熄灭。
硬件设计
RS485串口部分的原理图如图 17.3.1所示。由于FPGA串口输入输出引脚为TTL电平,用3.3V
代表逻辑“1”,0V代表逻辑“0”;而RS-485电平标准采用差分信号的差值电压来代表逻辑“0”
和“1”。因此当FPGA与RS485接口标准的设备通信时,需要加电平转换芯片SP3485,实现RS485
电平与TTL电平的转换。
图 17.3.1 RS485串口原理图
由于RS-485为半双工通信方式,需要通过使能信号来控制发送和接收过程。在图 17.3.1
中,电平转换芯片SP3485的2号引脚为低电平接收使能,3号引脚为高电平发送使能。在这里我
们将两个引脚连接在一起,只需要通过一个信号RS485_DE即可控制收发过程:当RS485_DE为高
电平时,SP3485处于发送过程;当RS485_DE为低电平时,SP3485处于接收过程。
图 17.3.2 RS232/RS485选择接口
图 17.3.2为RS232/RS485的选择接口,由上图可知,SP3485芯片端口的RS485_RX和
RS485_TX并没有直接和FPGA的引脚相连接,而是连接到开发板的P2口,RS232串口和RS485串口
共用P2口的UART2_TX和UART2_RX,UART2_TX和UART2_RX是直接和FPGA的引脚相连接的,这样的
设计方式实现了有限IO的多种复用功能。因此,在做RS485串口通信实验时,需要使用杜邦线
或者跳帽将RS485_RX和UART2_TX连接在一起,RS485_TX和UART2_RX连接在一起。
本实验中,各端口信号的管脚分配如下表所示:
表 17.3.1 RS485串口通信实验管脚分配
程序设计
根据实验任务,我们可以大致规划出系统的控制流程:当检测到有按键按下或释放时,将
按键数据通过RS485串口发送出去;而当RS485串口接收到对方发送的按键数据时,根据接收到
的数据改变LED灯的显示状态。由此画出系统的功能框图如下所示:
图 17.4.1 RS485串口实验系统框图
由系统总体框图可知,FPGA部分包括五个模块,顶层模块(rs485_uart_top)、接收模块
(uart_recv)、发送模块(uart_send)、按键消抖模块(key_debounce)和LED灯控制模块
(led_ctrl)。其中在顶层模块中完成对另外四个模块的例化。
由于RS-485只是对接口标准的定义,数据的传输仍然是按照UART串口通信协议进行。因此
我们可以直接调用“串口通信实验”中的串口发送和接收模块。在这里我们仍然设置数据位为
8位,停止位为1位,无校验位,波特率为115200bps。
各模块端口及信号连接如图 17.4.2所示:
图 17.4.2 顶层模块原理图
key_debounce为按键消抖模块,在检测到有按键按下或释放时对按键数据进行消抖处理,
在按键数据稳定后给出通知信号key_flag,并将数据由串口发送模块uart_send发送出去。
uart_recv为串口接收模块,它负责接收对方发送的按键数据,并在一帧数据(8位)接收结束
后给出通知信号uart_done。当LED灯控制模块led_ctrl检测到该通知信号时,根据接收到的按
键数据改变板卡上LED灯的显示状态。
顶层模块的代码如下:
1 module rs485_uart_top(
2 input sys_clk, //外部50M时钟
3 input sys_rst_n, //外部复位信号,低有效
4
5 input [3:0] key, //按键
6 output [3:0] led, //led灯
7 //uart接口
8 input rs485_uart_rxd, //rs485串口接收端口
9 output rs485_uart_txd, //rs485串口发送端口
10 output rs485_tx_en //rs485发送使能,高有效
11 );
12
13 //parameter define
14 parameter CLK_FREQ = 50000000; //定义系统时钟频率
15 parameter UART_BPS = 115200; //定义串口波特率
16
17 //wire define
18 wire tx_en_w; //UART发送使能
19 wire rx_done_w; //UART接收完毕信号
20 wire [7:0] tx_data_w; //UART发送数据
21 wire [7:0] rx_data_w; //UART接收数据
22 wire [3:0] key_value_w; //消抖后的按键数据
23
24 //*****************************************************
25 //** main code
26 //*****************************************************
27 assign tx_data_w = {4d0,key_value_w}; //将按键消抖后的值送到发送模块
28
29 uart_recv #( //串口接收模块
30 .CLK_FREQ (CLK_FREQ), //设置系统时钟频率
31 .UART_BPS (UART_BPS)) //设置串口接收波特率
32 u_uart_recv(
33 .sys_clk (sys_clk),
34 .sys_rst_n (sys_rst_n),
35
36 .uart_rxd (rs485_uart_rxd),
37 .uart_done (rx_done_w),
38 .uart_data (rx_data_w)
39 );
40
41 uart_send #( //串口发送模块
42 .CLK_FREQ (CLK_FREQ), //设置系统时钟频率
43 .UART_BPS (UART_BPS)) //设置串口发送波特率
44 u_uart_send(
45 .sys_clk (sys_clk),
46 .sys_rst_n (sys_rst_n),
47
48 .uart_en (tx_en_w),
49 .uart_din (tx_data_w),
50 .uart_txd (rs485_uart_txd),
51 .tx_flag (rs485_tx_en) //rs485串口发送使能,高有效
52 );
53
54 key_debounce u_key_debounce(
55 .sys_clk (sys_clk),
56 .sys_rst_n (sys_rst_n),
57
58 .key (key),
59 .key_flag (tx_en_w), //按键有效通知信号
60 .key_value (key_value_w) //按键消抖后的数据
61 );
62
63 led_ctrl u_led_ctrl(
64 .sys_clk (sys_clk),
65 .sys_rst_n (sys_rst_n),
66
67 .led_en (rx_done_w), //led控制使能
68 .led_data (rx_data_w[3:0]), //led控制数据
69 .led (led)
70 );
71
72 endmodule
顶层模块中主要完成对其余模块的例化,需要注意的是程序第27行:由于板卡上只有4个
按键,而串口通信过程中数据位为8位,因此需要将消抖后得到的4按键位数据高位补四个零,
然后再给到串口发送模块。同样,在将接收的按键数据用于LED灯控制时,仅将低四位有效位
赋值给LED灯控制模块,如第68行所示。
串口接收程序与“串口通信实验”章节中的接收模块完全相同,而串口发送程序有一点细
微的差异:将串口发送模块内部的“发送过程标志寄存器”tx_flag作为输出端口引出,如代
码中第51行所示。由于在发送过程中tx_flag为高电平,发送结束后tx_flag拉低,因此可以将
其赋值给RS-485串口发送使能信号rs485_tx_en,用于控制串口通信的发送和接收过程。
rs485_tx_en信号通过FPGA管脚与SP3485芯片的DE和RE引脚相连,因此在串口发送过程中使能
SP3485进入发送状态,其他时间SP3485均处于接收状态。
有关串口收发过程更详细的介绍请大家参考“串口通信实验”,下面我们来介绍一下另外
两个模块:按键消抖模块和LED灯控制模块。
在机械按键按下和释放的过程中,由于机械触点的弹性作用,按键开关在闭合的瞬间不会
立即稳定地导通,在释放时也不是立刻就能完全断开。因此,在闭合及断开的瞬间均伴随有一
连串的抖动,如图 17.4.3所示。按键的抖动过程体现在数字电路中就是不断变化的高低电平,
为避免在抖动过程中采集到错误的按键状态,我们需要对按键数据进行消除抖动处理。
图 17.4.3 机械按键抖动过程
按键抖动的时间长短由按键的机械特性决定,一般为5ms~10ms,在抖动时间内按键状态
可能会不断的发生变化。由于按键的抖动过程持续时间较短,很快就趋于稳定状态。因此在按
键按下及释放之后,若按键能稳定在同一状态且持续时间达20ms,我们就认为抖动过程已经结
束,此时的采集的按键数据有效。
按键消抖模块的代码如下所示:
1 module key_debounce(
2 input sys_clk, //外部50M时钟
3 input sys_rst_n, //外部复位信号,低有效
4
5 input [3:0] key, //外部按键输入
6
7 output reg key_flag, //按键数据有效信号
8 output reg [3:0] key_value //按键消抖后的数据
9 );
10
11 //reg define
12 reg [31:0] delay_cnt;
13 reg [ 3:0] key_reg;
14
15 //*****************************************************
16 //** main code
17 //*****************************************************
18 always @(posedge sys_clk or negedge sys_rst_n) begin
19 if (!sys_rst_n) begin
20 key_reg <= 4b1111;
21 delay_cnt <= 32d0;
22 end
23 else begin
24 key_reg <= key;
25 if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
26 delay_cnt <= 32d1000000; //给延时计数器重新装载初始值(计数时间为20ms)
27 else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
28 if(delay_cnt > 32d0)
29 delay_cnt <= delay_cnt - 1b1;
30 else
31 delay_cnt <= delay_cnt;
32 end
33 end
34 end
35
36 always @(posedge sys_clk or negedge sys_rst_n) begin
37 if (!sys_rst_n) begin
38 key_flag <= 1b0;
39 key_value <= 4b1111;
40 end
41 else begin
42 if(delay_cnt == 32d1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
43 key_flag <= 1b1; //此时消抖过程结束,给出一个时钟周期的标志信号
44 key_value <= key; //并寄存此时按键的值
45 end
46 else begin
47 key_flag <= 1b0;
48 key_value <= key_value;
49 end
50 end
51 end
52
53 endmodule
程序中第25行不断检测按键状态,一旦发现按键状态发生改变时,就给计数器delay_cnt
赋初值1000000。在按键状态不发生改变时delay_cnt递减从而实现倒计时的功能,在倒计时过
程中,一旦检测到按键状态发生改变,则说明有抖动产生,此时重新给delay_cnt赋初值,并
开始新一轮倒计时。在50Mhz时钟驱动下,delay_cnt若能由1000000递减至1,则说明按键状态
保持稳定时间达20ms,此时输出一个时钟周期的通知信号key_flag,并将此时的按键数据寄存
输出。
串口接收模块在接收对方发送的按键数据后,将数据低4位(高4位为零)给到LED控制模
块,并输出通知信号uart_done。LED灯控制模块在检测到uart_done的上升沿时,利用接收到
的按键数据改变LED灯的显示状态。
LED灯控制模块的代码如下:
1 module led_ctrl(
2 input sys_clk, //外部50M时钟
3 input sys_rst_n, //外部复位信号,低有效
4
5 input led_en, //led控制使能
6 input [3:0] led_data, //led控制数据
7
8 output reg [3:0] led //led灯
9 );
10
11 //reg define
12 reg led_en_d0;
13 reg led_en_d1;
14
15 //wire define
16 wire led_en_flag;
17
18 //*****************************************************
19 //** main code
20 //*****************************************************
21 //捕获led_en上升沿,得到一个时钟周期的脉冲信号
22 assign led_en_flag = (~led_en_d1) & led_en_d0;
23
24 always @(posedge sys_clk or negedge sys_rst_n) begin
25 if (!sys_rst_n) begin
26 led_en_d0 <= 1b0;
27 led_en_d1 <= 1b0;
28 end
29 else begin
30 led_en_d0 <= led_en;
31 led_en_d1 <= led_en_d0;
32 end
33 end
34
35 always @(posedge sys_clk or negedge sys_rst_n) begin
36 if (!sys_rst_n)
37 led <= 4b0000;
38 else if(led_en_flag) //在led_en上升沿到来时,改变led灯的状态
39 led <= ~led_data; //按键按下时为低电平,而led高电平时点亮
40 else
41 led <= led;
42 end
43
44 endmodule
由于开拓者开发板上的按键在按下时为低电平,而LED为高电平时点亮,因此为了实现按
键按下时点亮对应LED灯的功能,需要将按键数据取反后赋值给LED输出端口寄存器,如代码中
第39行所示。
下载验证
首先我们打开RS485串口通信实验工程,在工程所在的路径下打开rs485_uart_top /par文
件夹,在里面找到“rs485_uart_top.qpf”并双击打开。注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。串口工程打开后如图 17.5.1所
示。
接下来我们将两个开拓者开发板上的RS485接口用两根杜邦线连接起来,如图 17.5.2所
示。连接时注意接口位置一一对应,不要接反了。另外开拓者开发板上的CAN接口与RS485接口
十分相像,使用时请注意区分。还有一点需要注意的是,两块开发板的P2口都需要使用杜邦线
或者跳帽进行连接选择RS485口,否则无法进行RS485串口通信。然后分别将两个开发板上的下
载器一端连电脑,另一端与开发板上的JTAG下载端口连接,最后连接电源线并打开电源开关。
图 17.5.1 RS485串口通信实验工程
图 17.5.2 开拓者RS485接口、跳帽位置
接下来我们下载程序,验证两个开拓者开发板上的按键通过RS-485通信端口控制对方LED
灯亮灭的功能。工程打开后通过点击工具栏中的“Programmer”图标打开下载界面,通过“Add
File” 按 钮 选择串 口工程 中
rs485_uart_top/par/output_files 目 录 下 的“rs485_uart_top.sof”文件,下载界面如图 17.5.3所示。
开发板电源打开后,在程序下载界面点击“Hardware Setup”,在弹出的对话框中选择当
前的硬件连接为“USB-Blaster[USB-0]”。然后点击“Start”将工程编译完成后得到的sof文
件下载到第一块开发板中,如图 17.5.3所示。然后重新设置硬件连接为“USB-Blaster[USB-
1]”,将“rs485_uart_top.sof”文件下载到第二块开发板中。
图 17.5.3 程序下载完成界面
下载完成后我们依次按下任意一个开发板上的四个按键,可以观察到另外一个开发板上对
应的LED灯在按下时点亮,释放时熄灭,说明程序下载验证成功。