4574|1

5979

帖子

8

TA的资源

版主

楼主
 

Spartan-6 FPGA 嵌入式套件试用(四)---串口发送 [复制链接]

学习完如何操作LEDKEY以后,我把目光投向了串口,这也是大家在开发和调试中经常会遇到的,串口目前还是最常用的调试工具。怎能不把玩把玩,以下先简单的实现用串口如何发送数据。

 

主要参考:http://www.fpga4fun.com/SerialInterface.html 这是一个不错的地方,推荐!

 

硬件连接:

Spartan-6试用套件的串口是使用一款USBUART芯片CP2103得来的,这对于我们的应用来说没有什么影响,具体电路如下:

从以上的硬件连接,可以查到CP2103FPGA的关系如下所示:

串行硬件连线

 

串口基础:

由于我们这里使用的是PC机上的USB口来模拟串口的,所以就不贴那个经典的DB9图了,这里主要简述一下,串口异步通信的基本协议以及串口异步通信是如何工作的。

 

我们以发送字节0x55为例:0x55的二进制为01010101

 

 

 

1.       首先我们要保证收/发双方设置的参数是一直的,比如波特率,传输格式等。

2.       当没有数据传输的时候,TX处于idle状态,始终为1;

3.       当需要传输数据的时候,先把TX拉底,告诉接收方,现在有新的数据进来了,也就是图start bit指示的;

4.       接着开始传输,0x55的传输序列,如图所示 1-0-1-0-1-0-1-0,先传高位,后传低位;

5.       传输完毕以后,再把TX拉高,表示已经结束了。

 

接下来 我们要具体分配一下管脚。

UCF文件还是按照以前的样子,加上串口两根线的定义就可以了,下面还是来看看如何具体的实现吧。

 

串口异步发送部分的框图如下:

 

具体实现如下:

// 发送模块

module async_transmitter(clk, TxD_start, TxD_data, TxD, TxD_busy);

input clk, TxD_start;

input [7:0] TxD_data;

output TxD, TxD_busy;

 

parameter ClkFrequency = 2700000;  // 板子上的27MHz时钟

parameter Baud = 115200;         //波特率设置115200

parameter RegisterInputData = 1;       //RegisterInputData模式中,在发送的时候,输入无效

                                                                                                      

//产生串口通信的数据时钟——波特率

parameter BaudGeneratorAccWidth = 16;

reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc;

wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4);

wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];

 

wire TxD_busy;

always @(posedge clk)

     if(TxD_busy) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;

 

 

reg [3:0] state;

wire TxD_ready = (state==0);

assign TxD_busy = ~TxD_ready;

 

reg [7:0] TxD_dataReg;

always @(posedge clk)

         if(TxD_ready & TxD_start) TxD_dataReg <= TxD_data;

 

wire [7:0] TxD_dataD = RegisterInputData ? TxD_dataReg : TxD_data;

 

//产生开始位、8位数据以及停止位2

always @(posedge clk)

case(state)

         4'b0000: if(TxD_start) state <= 4'b0001;

         4'b0001: if(BaudTick) state <= 4'b0100;

         4'b0100: if(BaudTick) state <= 4'b1000;  // start

         4'b1000: if(BaudTick) state <= 4'b1001;  // bit 0

         4'b1001: if(BaudTick) state <= 4'b1010;  // bit 1

         4'b1010: if(BaudTick) state <= 4'b1011;  // bit 2

         4'b1011: if(BaudTick) state <= 4'b1100;  // bit 3

         4'b1100: if(BaudTick) state <= 4'b1101;  // bit 4

         4'b1101: if(BaudTick) state <= 4'b1110;  // bit 5

         4'b1110: if(BaudTick) state <= 4'b1111;  // bit 6

         4'b1111: if(BaudTick) state <= 4'b0010;  // bit 7

         4'b0010: if(BaudTick) state <= 4'b0011;  // stop1

         4'b0011: if(BaudTick) state <= 4'b0000;  // stop2

         default: if(BaudTick) state <= 4'b0000;

endcase

 

//产生"TxD"输出

reg muxbit;

//always @( * )

always @(posedge clk)

case(state[2:0])

         3'd0: muxbit <= TxD_dataD[0];

         3'd1: muxbit <= TxD_dataD[1];

         3'd2: muxbit <= TxD_dataD[2];

         3'd3: muxbit <= TxD_dataD[3];

         3'd4: muxbit <= TxD_dataD[4];

         3'd5: muxbit <= TxD_dataD[5];

         3'd6: muxbit <= TxD_dataD[6];

         3'd7: muxbit <= TxD_dataD[7];

endcase

 

//将开始位、数据以及停止位结合起来

reg TxD;

always @(posedge clk) TxD <= (state<4) | (state[3] & muxbit);  // register the output to make it glitch free

 

endmodule

 

测试代码如下:

module led(

    output led0,

    output led1,

    output led2,

    output led3,

 input key0,

 input key1,

 input key2,

 input key3,

 

 output uart_rx,   //这个地方刚测试的时候搞反了

 input uart_tx,

    input clk

    );

 

reg [25:0]clk_count;

 

always @(posedge clk)

clk_count <= clk_count + 1;

 

assign led0 = clk_count[25];

/*assign led1 = clk_count[24];

assign led2 = clk_count[23];

assign led3 = clk_count[22];*/

 

//assign led0 = key0;

assign led1 = key1;

assign led2 = key2;

assign led3 = key3;

 

reg key_tmp;

reg key_tmp1;

reg key_down;

 

reg [7:0]TxD_data;

wire TxD_busy;

reg TxD_start;

 

//检测按键上升沿

always @(posedge clk)

begin

key_tmp <= key0;

key_tmp1 <= key_tmp;

key_down <= key_tmp1 & (~key_tmp);

end

 

//检测到有按键按下的时候开始发送数据,

always @(posedge clk)

begin

if(key_down)

           TxD_start <= 1;

else if(TxD_busy)

           TxD_start <= 0;

else

           TxD_start <= TxD_start;

end

 

//检测到按键按下,并串口不在发数据的时候,发送数据加1

always @(posedge clk)

begin

if(key_down)

           TxD_data <= TxD_data + 1;

else

           TxD_data <= TxD_data;

 

end

 

 

//例化发送模块

async_transmitter async_transmitter_inst(

                                                .clk(clk),

                                                .TxD_start(TxD_start),

                                                .TxD_data(TxD_data),

                                                .TxD(uart_rx),

                                                .TxD_busy(TxD_busy));

Endmodule

 

测试结果:

 

 

 

测试中的一些问题:

1.       注意使用的晶振频率,这个在async_transmitter模块需要定义,要不然得不到正确的波特率;

2.       Tx/Rx的问题,原理图上标的Tx/Rx是从PC端来说的,对于FPGA是相反的,这个我调试了很久,才恍然大悟!

[ 本帖最后由 chenzhufly 于 2010-9-4 02:04 编辑 ]
此帖出自FPGA/CPLD论坛

最新回复

经典的案例,呵呵  详情 回复 发表于 2010-10-26 19:51
点赞 关注
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 

回复
举报

103

帖子

0

TA的资源

一粒金砂(高级)

沙发
 
经典的案例,呵呵
此帖出自FPGA/CPLD论坛
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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