5883|14

15

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

FPGA--串口通信 [复制链接]

 
本帖最后由 seu_zc 于 2016-9-13 14:30 编辑
串口通信
一、串口通信理论知识.
1、  硬件电路
板子上已经用PL2303芯片实现了串口转USB,所以我们可以直接使用TXD、和RXD来进行操作。下图为USB与PL2303连接图,TXD、RXD接到FPGA的tx和rx端,其中TXD是向主机(一般视为PC端,串口调试助手)写出数据;RXD是FPGA中实现的读取数据模块来读取主机的数据,用以后续使用。
         附件中有PL2303驱动以及资料。

2、  串口通信协议
首先对于串口通信原理,现在基本板子上都实现了串口与USB的转换,所以只需要知道
如何使用对应的接口就行了。
         串口通信主要在于串口协议上面:
         上图是串口传输的时序图,一帧数据为11位。


作用
数据采集时
0
起始位
忽略
1~8
数据位
采集
9
校验位
忽略
10
停止位
忽略
在串口的总线上“高电平”是默认的状态,当一帧数据的开始传输必须先拉低电平,这
就是第0 位的作用。第0 位过后就是8 个数据位,这八个数据位才是一帧数据中最有意
义的东西。最后的两位是校验位和停止位,作用如同命名般一样,基本上是没有重要意
义。

3、  波特率
“波特率”BPS(bit persecond),从字面上理解就是每秒钟传输数据的位数。宏观上一般认为是来标定串口的传输速度。而在微观上,“波特率”就是串口传输中“一个位的周期”,换句话说就是“一个位所逗留的时间”。
以波特率为9600bps为例,每秒传输9600位数据,则有:
一个位的周期 = 1/bps                                                            
                             = 1/9600                                                        
                        =  1.0416666666666666666666666666667e-4                                             
         即一位数据占用时间为0.001041667s。这个数据就是下面在进行数据采样时,根据板子晶振来设定采样个数的依据,也即设定波特率。


二、FPGA模块化电路设计
1、串口接收模块:首先给出框图,有一个整体理解。
框图解读:
a.       电平检测模块:由于串口总线上默认是高电平,串口数据开始位是高电平向低电平转化,所以电平检测模块就是来检测数据高电平转化为低电平时,发送出H2L_Sig(高电平)信号,通知就收控制模块可以进行数据的采集了。下面为检测模块(请看注释解释):
   
module  detect_module(
   
CLK,RSTn,RX_Pin_In,H2L_Sig
   
);
  
   
input CLK;
   
input RSTn;
   
input  RX_Pin_In;
   
output  H2L_Sig;
  
   
/*********************************************/
   
reg H2L_F1;//存放此刻接收到的数据的电平高低
   
reg H2L_F2;//存放上一时刻数据的电平高低
  
   
always  @(posedge CLK or negedge RSTn)
   
begin
   
if(!RSTn)
   
          begin
   
                    H2L_F1 <= 1'b1;
   
                    H2L_F2 <= 1'b1;
   
          end
   
else
   
          begin
   
                    H2L_F1 <= RX_Pin_In;//接收此刻输入数据信号
   
                    H2L_F2 <= H2L_F1;//将原信号赋值H2L_F2
   
          end
   
end
  
   
/*********************************************/
   
assign H2L_Sig = !H2L_F1 &  H2L_F2;//大家可以尝试画一下,当PX_Pin_In 由高到
   
//时H2L_Sig的电平情况
  
   
/*********************************************/
   
endmodule
  

b.      波特率定时模块:上文已经介绍过波特率了,这里就举例说明如何设定波特率。
波特率定时体现在电路中就是采样率,而采样率又与板子上FPGA的时钟有关,所以第一步你要知道板子上FPGA的晶振多大。比如:48M的晶振,波特率为9600,由于一位数据占用的时间为1/9600=0.001041667s,所以定时需要:N=0.001041667*48M=5000,即5000个时钟的时间就是以为数据占用的时间。
这里还要考虑的一个问题是数据的采集,一般而言,数据采集在“每位数据的中间”进行时比较稳定,如上图所示。所以波特率定时模块产生的定时实在每个位的中间,下面会结合代码进行解释。
   
module rx_bps_module(
   
         CLK,RSTn,
   
         Count_Sig,
   
         BPS_CLK
   
);
  
   
input CLK;
   
input RSTn;
   
input Count_Sig;//计时控制标志,高电平启动计时
   
output BPS_CLK;//波特率时钟,即数据采集控制
  
   
/*********************************************/
   
reg [12:0] Count_BPS;
  
   
always @(posedge CLK or negedge RSTn)
   
begin
   
         if(!RSTn)
   
                   Count_BPS  <= 13'd1;
   
         else  if(Count_BPS == 13'd5000)
   
                   Count_BPS  <= 13'd1;
   
         else  if(Count_Sig)
   
                   Count_BPS  <= Count_BPS + 1'b1;
   
         else
   
                   Count_BPS  <= 13'd1;
   
end
  
   
/*********************************************/
   
assign BPS_CLK = (Count_BPS ==  13'd2500)?1'b1:1'b0;//定时器的一半进行数据采集
  
   
endmodule
  

c.       接收控制模块:主要完成控制信号的产生和数据的采集。这里不多说了,直接上代码。
   
module rx_control_module(
   
         CLK,RSTn,
   
         H2L_Sig,RX_Pin_In,BPS_CLK,RX_En_Sig,
   
         Count_Sig,RX_Data,RX_Done_Sig
   
);
  
   
input CLK;
   
input RSTn;
   
input H2L_Sig;//开始采集标志
   
input RX_Pin_In;//输入的数据
   
input BPS_CLK;//数据采集标志
   
input RX_En_Sig;//数据采集就绪,等待数据,高电平有效
   
output Count_Sig;
   
output [7:0] RX_Data;
   
output RX_Done_Sig;
  
   
/*********************************************/
   
reg [3:0] i;
   
reg [7:0] rData;
   
reg isCount;
   
reg isDone;
  
   
always @(posedge CLK or negedge RSTn)
   
begin
   
         if(!RSTn)
   
                   begin
   
                            i  <= 4'd0;
   
                            rData  <= 8'd0;
   
                            isCount  <= 1'b0;
   
                            isDone  <= 1'b0;
   
                   end
   
         else  if(RX_En_Sig)
   
                   case(i)
   
                            4'd0:
   
                                     if(H2L_Sig)//起始位开始标志
   
                                               begin
   
                                                        i  <= i + 1'b1;
   
                                                        isCount  <= 1'b1;
   
                                               end
  
   
                            4'd1:
   
                                     if(  BPS_CLK ) //起始位,无数据,采取忽略策略
   
                                               begin  
   
                                                        i  <= i + 1'b1;
   
                                               end  
  
   
                            4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8,4'd9://八位数据位的读取
   
                                     if(BPS_CLK)
   
                                               begin
   
                                                        i  <= i + 1'b1;
   
                                                        rData[i-2]  <= RX_Pin_In;
   
                                               end
  
   
                            4'd10:
   
                                     if(  BPS_CLK )//校验位,忽略
   
                                               begin  
   
                                                        i  <= i + 1'b1;
   
                                               end
  
   
                            4'd11  :
   
                                     if(  BPS_CLK ) //结束位,忽略
   
                                               begin        
   
                                                        i  <= i + 1'b1;
   
                                               end
  
   
                            4'd12://结束位之后,一帧数据完成标志isDone置为高电平,关闭计数器
   
                                               begin
   
                                                        i  <= i + 1'b1;
   
                                                        isDone  <= 1'b1;
   
                                                        isCount  <= 1'b0;
   
                                               end
  
   
                            4'd13://isDone置为低电平,等待下一帧数据
   
                                     begin
   
                                               i  <= 1'b0;
   
                                               isDone  <= 1'b0;
   
                                     end
  
   
                   endcase   
   
end
  
   
/*********************************************/
   
assign Count_Sig = isCount;
   
assign RX_Data = rData;
   
assign RX_Done_Sig = isDone;
  
   
/*********************************************/
   
endmodule
  

小结:以上就是串口读取数据的模块,关于如何在中间采集数据,大家可以画一个图,一看就清楚了。可以将三个模块进行一下组合,如下:
关于波特率:我的理解就是发送和接收端的数据统一,能够使得发送的数据在接收端能够准确的在以为数据的中间就行采集到。


三、串口接收实验
1、下图是通过串口来控制LED的实验框图,其中串口接收模块是上面三个模块的组合模块,而控制模块主要是来产生RX_En_Sig信号和接收数据并进行相应处理。这里的数据来源于PC端,由串口调试助手来完成。
2、控制模块
   
module control_module(
   
          CLK, RSTn,
   
          RX_Done_Sig,
   
          RX_Data,
   
          RX_En_Sig,
   
          Number_Data
   
);
  
   
input CLK;
   
input RSTn;
   
input RX_Done_Sig;
   
input [7:0] RX_Data;
   
output RX_En_Sig;
   
output [7:0]Number_Data;
  
   
/*********************************************/
   
reg [7:0]rData;
   
reg isEn;
  
   
always @ ( posedge CLK or negedge RSTn )
   
          if( !RSTn )
   
                   rData  <= 8'd0;
   
          else if( RX_Done_Sig )
   
                   begin  
   
                            rData  <= RX_Data; // 数据接收完成后,
   
                            isEn  <= 1'b0;
   
                   end
   
          else
   
                            isEn  <= 1'b1;
  
   
/*********************************/
   
assign Number_Data = rData;
   
assign RX_En_Sig = isEn;
  
   
/*********************************/
   
endmodule
  

将该控制模块与上面三个模块的组合模块再进行组合就得到实验电路图:

分配好引脚,PX_Pin_In接到FPGA的rx引脚,下载到板子上,打开串口调试助手,以十六进制发送OF,则控制的LED后四位熄灭。

说明:该程序我通过自己写的发送模块向该接受模块进行传输数据,LED能够实现预定的功能,但是通过串口调试助手进行发送数据,则不能实现预定功能。大家可以在自己的板子上试试,有什么问题可以指正。谢谢!

serial.rar

2.85 KB, 下载次数: 19

串口

WIN7系统PL2303驱动与PL2303资料.zip

3.01 MB, 下载次数: 18

PL2303

此帖出自FPGA/CPLD论坛

最新回复

是的  详情 回复 发表于 2016-9-21 23:47
点赞 关注(1)
 

回复
举报

59

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
此帖出自FPGA/CPLD论坛
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

图片刚编辑完又没出现,又得重新编辑一次了。你试一下下面附件的程序能不能用串口调试助手发送数据进行接收。
此帖出自FPGA/CPLD论坛

点评

额!!!木有板子!!!我就看看!!!支持一下!  详情 回复 发表于 2016-9-13 13:29
 
 
 

回复

59

帖子

0

TA的资源

一粒金砂(中级)

4
 
seu_zc 发表于 2016-9-13 11:41
图片刚编辑完又没出现,又得重新编辑一次了。你试一下下面附件的程序能不能用串口调试助手发送数据进行接 ...

额!!!木有板子!!!我就看看!!!支持一下!
此帖出自FPGA/CPLD论坛
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

5
 
reallmy 发表于 2016-9-13 13:29
额!!!木有板子!!!我就看看!!!支持一下!

恩恩 谢谢
此帖出自FPGA/CPLD论坛
 
 
 

回复

1950

帖子

4

TA的资源

版主

6
 
谢谢分享!

串口,是入门到开发的必过技术。
太过重要,楼主有必要再写上一两回。

比如 rx_Pin_in 不要到处用
输入信号去噪,等等。
此帖出自FPGA/CPLD论坛
个人签名MicroPython中文社区https://micropython.org.cn/forum/  
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

7
 
5525 发表于 2016-9-13 21:44
谢谢分享!

串口,是入门到开发的必过技术。
太过重要,楼主有必要再写上一两回。

比如 rx_Pin_in  ...

谢谢知道,我这还在学习基础,也是照葫芦画瓢,把东西弄懂之后写成帖子,可以理会的更透彻点。
此帖出自FPGA/CPLD论坛
 
 
 

回复

1950

帖子

4

TA的资源

版主

8
 
还在学习基础 就能把uart写出来,这个感觉很不错啊。要是有天赋,要么爱动手。
此帖出自FPGA/CPLD论坛

点评

我是看一个文档写的,内容跟上面差不多,只不过自己做过几遍之后,再自己一个字一个字敲出来,写成文档,理解的更加透彻些了。刚学习也只能照葫芦画瓢了  详情 回复 发表于 2016-9-21 16:06
个人签名MicroPython中文社区https://micropython.org.cn/forum/  
 
 
 

回复

2721

帖子

0

TA的资源

纯净的硅(中级)

9
 
再看了下,校验位在停止位后
此帖出自FPGA/CPLD论坛

点评

不懂什么意思,校验位应该在停止位之前,你说的是上面的代码放在了后面吗?  详情 回复 发表于 2016-9-21 16:12
 
 
 

回复

3138

帖子

0

TA的资源

裸片初长成(初级)

10
 
 没深钻,粗粗浏览了下,觉得楼主虽已知道接收数据的位置应该在每个 BPS_CLK 的中点上,但却似乎未考虑到 BPS_CLK 定时器的启动要依存于 RX_Pin_in 的下降沿,而不是可由自己随意定的。
此帖出自FPGA/CPLD论坛

点评

你好,我看了下你指出的这个问题。由于Rx_Pin_In下降沿出发了H2L_Sig这个信号为高点平,进而使得Count_Sig信号为高点平,最后启动了BPS_CLK这个定时器。但是我的疑问是自己能够随意定义BPS_CLK定时器的开和关能够提  详情 回复 发表于 2016-9-21 16:04
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

11
 
仙猫 发表于 2016-9-18 02:21
 没深钻,粗粗浏览了下,觉得楼主虽已知道接收数据的位置应该在每个 BPS_CLK 的中点上,但却似乎未考虑到  ...

你好,我看了下你指出的这个问题。由于Rx_Pin_In下降沿出发了H2L_Sig这个信号为高点平,进而使得Count_Sig信号为高点平,最后启动了BPS_CLK这个定时器。但是我的疑问是自己能够随意定义BPS_CLK定时器的开和关能够提高什么性能吗?我这里的这种处理方式有什么不妥吗?新手求指导,谢谢!
此帖出自FPGA/CPLD论坛

点评

扫瑞,代码是对的,是我看漏了,定时器被Rx的第1个下降沿启动没问题。 而且停止位之后不再看BPS_CLK,这个处理非常到位。  详情 回复 发表于 2016-9-21 19:52
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

12
 
5525 发表于 2016-9-14 21:29
还在学习基础 就能把uart写出来,这个感觉很不错啊。要是有天赋,要么爱动手。

我是看一个文档写的,内容跟上面差不多,只不过自己做过几遍之后,再自己一个字一个字敲出来,写成文档,理解的更加透彻些了。刚学习也只能照葫芦画瓢了
此帖出自FPGA/CPLD论坛
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

13
 
suoma 发表于 2016-9-17 23:24
再看了下,校验位在停止位后

不懂什么意思,校验位应该在停止位之前,你说的是上面的代码放在了后面吗?
此帖出自FPGA/CPLD论坛

点评

是的  详情 回复 发表于 2016-9-21 23:47
 
 
 

回复

3138

帖子

0

TA的资源

裸片初长成(初级)

14
 
seu_zc 发表于 2016-9-21 16:04
你好,我看了下你指出的这个问题。由于Rx_Pin_In下降沿出发了H2L_Sig这个信号为高点平,进而使得Count_Si ...

扫瑞,代码是对的,是我看漏了,定时器被Rx的第1个下降沿启动没问题。
而且停止位之后不再看BPS_CLK,这个处理非常到位。
此帖出自FPGA/CPLD论坛
 
 
 

回复

2721

帖子

0

TA的资源

纯净的硅(中级)

15
 
seu_zc 发表于 2016-9-21 16:12
不懂什么意思,校验位应该在停止位之前,你说的是上面的代码放在了后面吗?

是的
此帖出自FPGA/CPLD论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表