原创 FPGA与RFID通讯

2011-9-27 10:00 2225 3 3 分类: FPGA/CPLD

大家应该熟悉FPGAPC机通讯的原理,PC机通过串口发送指令给FPGA,FPGA接收指令,再把我们设定的指令回发给PC机。FPGARFID<先发送指令给RFID,比如读标签指令,RFID读到标签后回发给FPGA指令说明自己读到标签了。

我之前疑惑的地方是怎么用按键来控制FPGA通过串口发送指令,之后在网上请教了一些高手,虽然功能能实现,但是还是有点缺陷,希望高手阅读完后有更好的代码,请不吝赐教,谢谢!

The hardware includes the following:

          1.TTL UART UHF RFID reader module

          2.PPGA Board

          3.UHF RFID antenna

The following is a system picture:

          20110927100024001.gif

The jump wire connection is as follows:

1. FPGA GPIO pin 13 -> UHF RFID GND.

2. FPGA GPIO pin 3 -> UHF RFID TX.

3. FPGA GPIO pin 4-> UHF RFID RX.

 

淘宝FPGA XC3S1000开发板购买地址:http://item.taobao.com/item.htm?id=10915682920&

淘宝UHF RFID reader购买地址http://item.taobao.com/item.htm?id=13149808789&

 

FPGA的代码如下:

1.顶层模块

module my_uart_top(clk,rst_n,rx,tx,key_input,txpc);

 

input clk; // 50MHz主时钟

input rst_n;  //低电平复位信号

input rx;   // FPGA接收数据信号

output tx;  // FPGA发送数据信号

input key_input;  //FPGA按键输入

output txpc;  //FPGARS232输出

 

wire bps_start;   //接收到数据后,波特率时钟启动信号置位

wire clk_bps;     // clk_bps的高电平为接收或者发送数据位的中间采样点

wire[7:0] rx_data;   //接收数据寄存器,保存直至下一个数据来到

wire rx_int;  //接收数据中断信号,接收到数据期间始终为高电平

 

//----------------------------------------------------

speed_select      speed_select(        .clk(clk), //波特率选择模块,接收和发送模块复用,不支持全双工通信

                                       .rst_n(rst_n),

                                       .bps_start(bps_start),

                                       .clk_bps(clk_bps)

                                       );

 

 

my_uart_rx        my_uart_rx(          .clk(clk), //接收数据模块

                                       .rst_n(rst_n),

                                       .rx(rx),

                                       .clk_bps(clk_bps),

                                       .bps_start(bps_start),

                                       .rx_data(rx_data),

                                       .rx_int(rx_int),

                                                                  .txpc(txpc)

                                       );

 

 

 

my_uart_tx        my_uart_tx(          .clk(clk), //发送数据模块

                                       .rst_n(rst_n),

                                       .tx(tx),

                                                                  .key_input(key_input)

                                       );

 

endmodule

 

2.波特率选择模块(此处跟RFID同步,为115200bps

module speed_select(clk,rst_n,bps_start,clk_bps);

 

input clk; // 50MHz主时钟

input rst_n;  //低电平复位信号

input bps_start;  //接收到数据后,波特率时钟启动信号置位

output clk_bps;   // clk_bps的高电平为接收或者发送数据位的中间采样点

 

parameter          bps9600    = 5207,    //波特率为9600bps

                            bps19200   = 2603,    //波特率为19200bps

                            bps38400   = 1301,    //波特率为38400bps

                            bps57600   = 867,     //波特率为57600bps

                            bps115200  = 433;     //波特率为115200bps

 

parameter          bps9600_2 = 2603,

                            bps19200_2 = 1301,

                            bps38400_2 = 650,

                            bps57600_2 = 433,

                            bps115200_2 = 216; 

 

reg[12:0] bps_para;      //分频计数最大值

reg[12:0] bps_para_2;    //分频计数的一半

reg[12:0] cnt;           //分频计数

reg clk_bps_r;           //波特率时钟寄存器

 

 

 

//----------------------------------------------------------

              reg[2:0] uart_ctrl;  // uart波特率选择寄存器

//----------------------------------------------------------

 

 always @ (posedge clk or negedge rst_n) begin

    if(!rst_n) begin

                       uart_ctrl <= 3'd4;   //默认波特率为115200bps(与RFID波特率同步,可调)

       end

    else begin

           case (uart_ctrl)  //波特率设置

              3'd0:  begin

                     bps_para <= bps9600;

                     bps_para_2 <= bps9600_2;

                     end

              3'd1:  begin

                     bps_para <= bps19200;

                     bps_para_2 <= bps19200_2;

                     end

 

              3'd2:  begin

                     bps_para <= bps38400;

                     bps_para_2 <= bps38400_2;

                     end

 

              3'd3:  begin

                     bps_para <= bps57600;

                     bps_para_2 <= bps57600_2;

                     end

 

              3'd4:  begin

                     bps_para <= bps115200;

                     bps_para_2 <= bps115200_2;

                     end

 

             default: ;

              endcase

       end

end

 

 

always @ (posedge clk or negedge rst_n)

 

    if(!rst_n) cnt <= 13'd0;

    else if(cnt<bps_para && bps_start) cnt <= cnt+1'b1;  //波特率时钟计数启动

    else cnt <= 13'd0;

 

always @ (posedge clk or negedge rst_n)

 

    if(!rst_n) clk_bps_r <= 1'b0;

    else if(cnt==bps_para_2 && bps_start) clk_bps_r <= 1'b1;    // clk_bps_r高电平为接收或者发送数据位的中间采样点

    else clk_bps_r <= 1'b0;

 

assign clk_bps = clk_bps_r;

endmodule

 

3.发送数据模块

module  my_uart_tx(clk, rst_n, tx, key_input);

    input                    clk,rst_n;

       input                    key_input;                    //按键输入

       output                  tx;                               //串行数据发送端

 

 

       //***************************inner reg*******************************//

       reg[15:0]              div_reg;                       //分频计数器,分频值由波特率决定。分频后得到频率8倍波特率的时钟

       reg[2:0]               div8_tras_reg;               //该寄存器的计数值对应发送时当前位于的时隙数

       reg[3:0]         state_tras;                            //发送状态寄存器

       reg                       clkbaud_tras;                //以波特率为频率的发送使能信号

       reg                       clkbaud8x;                    //8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙

 

 

       reg                       trasstart;                       //开始发送标志

 

       reg                       txd_reg;                       //发送寄存器

       reg[7:0]         txd_buf;                              //发送数据缓存

 

       reg[1:0]         send_state;                           //每次按键给PC发送"430301"字符串,这是发送状态寄存器

       reg[22:0]              cnt_delay;                     //延时去抖计数器

       reg                       start_delaycnt;           //开始延时计数标志

       reg                       key_entry1, key_entry2; //确定有键按下标志

 

       parameter             div_par = 8'h1B;        //分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8 倍,此处值对应115200的波特率,即分频出的时钟频率是115200*8  (CLK  50M)

 

       //**********************************************************//

       assign                   tx = txd_reg;

      

       always@(posedge clk or negedge rst_n)

       begin

              if(!rst_n)begin

                     cnt_delay <= 0;

                     start_delaycnt <= 0;                           

                         end        

              else if(start_delaycnt) begin

                     if(cnt_delay != 23'd8000000) begin

                            cnt_delay <= cnt_delay + 1;

                            end               

                     else begin

                            cnt_delay <= 0;

                            start_delaycnt <= 0;                    

                              end

                     end               

              else        begin

                     if(!key_input && cnt_delay == 0)

                                   start_delaycnt <= 1;             

                            end        

       end

      

       //**********************************************************//

       always@(posedge clk or negedge rst_n)

       begin

              if(!rst_n)

                     key_entry1 <= 0;

              else        begin

                     if(key_entry2)

                            key_entry1 <= 0;

                     else if(cnt_delay == 23'd8000000) begin

                            if(!key_input)

                                   key_entry1 <= 1;

                            end

                     end

       end

      

       //**********************************************************//

       always@(posedge clk or negedge rst_n)

       begin

              if(!rst_n)

                     div_reg <= 0;

              else                                                                begin

                     if(div_reg == div_par - 1)

                            div_reg <= 0;

                     else

                            div_reg <= div_reg + 1; end        

       end

 

       always@(posedge clk or negedge rst_n)                     //分频得到8倍波特率的时钟

       begin

              if(!rst_n)

                     clkbaud8x <= 0;

              else if(div_reg == div_par - 1)

                     clkbaud8x <= ~clkbaud8x;

       end

 

      

       always@(posedge clkbaud8x or negedge rst_n)

       begin

              if(!rst_n)

                     div8_tras_reg <= 0;

              else if(trasstart)

                     div8_tras_reg <= div8_tras_reg + 1;     //发送开始后,时隙数在8倍波特率的时钟下加1循环

       end

 

       //**********************************************************//

       always@(div8_tras_reg)

       begin

              if(div8_tras_reg == 7)

                     clkbaud_tras = 1;                  //在第7个时隙,发送使能信号有效,将数据发出

              else

                     clkbaud_tras = 0;

       end

      

       //**********************************************************//

       always@(posedge clkbaud8x or negedge rst_n)

       begin

              if(!rst_n) begin

                     txd_reg <= 1;

                     trasstart <= 0;

                     txd_buf <= 0;

                     state_tras <= 0;

                     send_state <= 0;

                     key_entry2 <= 0;

                     end        

              else begin

                     if(!key_entry2) begin

                            if(key_entry1) begin

                                   key_entry2 <= 1;

                                   txd_buf <= 8'h43;          

                                   end

                            end        

                     else begin

                            case(state_tras)

                                   4'b0000:                       begin  //发送起始位

                                          if(!trasstart && send_state < 3)

                                                 trasstart <= 1;

                                          else if(send_state < 3)                   begin

                                                 if(clkbaud_tras)                     begin

                                                        txd_reg <= 0;

                                                        state_tras <= state_tras + 1;end end                                        

                                          else                                                                              begin

                                                 key_entry2 <= 0;

                            send_state <= 0;

                                                state_tras <= 0;                                                end end                                            

                                   4'b0001:                                                                begin //发送第1

                                          if(clkbaud_tras)                                        begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;          end end                              

                                   4'b0010:                                                                begin //发送第2

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;          end end                              

                                    4'b0011:                                                        begin //发送第3

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;          end end

                                   4'b0100:                                                                begin //发送第4

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;   end end

                                   4'b0101:                                                                begin //发送第5

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;   end end                              

                                   4'b0110:                                                          begin //发送第6

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;   end end

                                   4'b0111:                                                          begin //发送第7

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg <= txd_buf[0];

                                                 txd_buf[6:0] <= txd_buf[7:1];

                                                 state_tras <= state_tras + 1;   end end                              

                                   4'b1000:                                                                begin //发送第8

                                          if(clkbaud_tras)                                               begin

                                                 txd_reg<=txd_buf[0];

                                                 txd_buf[6:0]<=txd_buf[7:1];

                                                 state_tras<=state_tras+1;

                                           end

                                    end

                                   4'b1001: begin //发送停止位

                                          if(clkbaud_tras) begin

                                                 txd_reg<=1;

                                                 txd_buf<=8'h55;

                                                 state_tras<=state_tras+1;

                                           end

                                    end

                                   4'b1111:begin

                                          if(clkbaud_tras) begin

                                                 state_tras<=state_tras+1;

                                                 send_state<=send_state+1;

                                                 trasstart<=0;

                                                 case(send_state)

                                                        3'b00:

                                                               txd_buf<=8'h03;

                                                        3'b01:

                                                               txd_buf<=8'h01;

                                                        default:

                                                               txd_buf<=0;

                                                  endcase

                                           end

                                    end

                                   default: begin

                                          if(clkbaud_tras) begin

                                                 state_tras<=state_tras+1;

                                                 trasstart<=1;

                                           end

                                    end

                             endcase

                      end

               end

       end

 

endmodule

 

4.接受数据模块

module my_uart_rx(clk,rst_n,rx,clk_bps,bps_start,rx_data,rx_int,txpc);

 

input clk;    // 50MHz主时钟

input rst_n;  //低电平复位信号

input rx;    // FPGA接收数据信号

input clk_bps;    // clk_bps的高电平为接收或者发送数据位的中间采样点

output bps_start;  //接收到数据后,波特率时钟启动信号置位

output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到

output rx_int;    //接收数据中断信号,接收到数据期间始终为高电平

output txpc;    //RFID发送的数据通过RS232发送给pc

//----------------------------------------------------------------

 

reg rx0,rx1,rx2; //接收数据寄存器,滤波用

wire neg_rx;   //表示数据线接收到下降沿

 

always @ (posedge clk or negedge rst_n) begin

    if(!rst_n) begin

           rx0 <= 1'b1;

           rx1 <= 1'b1;

           rx2 <= 1'b1;

       end

    else begin

           rx0 <= rx;

           rx1 <= rx0;

           rx2 <= rx1;

       end

end

 

assign neg_rx = rx2 & ~rx1; //接收到下降沿后neg_rx置高一个时钟周期

 

 //----------------------------------------------------------------

 

reg bps_start_r;

reg[3:0]   num;   //移位次数

reg rx_int;   //接收数据中断信号,接收到数据期间始终为高电平

 

 always @ (posedge clk or negedge rst_n) begin

    if(!rst_n) begin

           bps_start_r <= 1'bz;

           rx_int <= 1'b0;

       end

    else if(neg_rx) begin

           bps_start_r <= 1'b1; //启动接收数据

           rx_int <= 1'b1;   //接收数据中断信号使能

           end

    else if(num==4'd10) begin

           bps_start_r <= 1'bz; //数据接收完毕

           rx_int <= 1'b0;    //接收数据中断信号关闭

       end

end

 

assign bps_start = bps_start_r;

 

//----------------------------------------------------------------

reg[7:0] rx_data_r;  //接收数据寄存器,保存直至下一个数据来到

//----------------------------------------------------------------

 

 

reg[7:0]   rx_temp_data; //但前接收数据寄存器

reg rx_data_shift;   //数据移位标志

 

 always @ (posedge clk or negedge rst_n) begin

    if(!rst_n)

       begin

           rx_data_shift <= 1'b0;

           rx_temp_data <= 8'd0;

           num <= 4'd0;

           rx_data_r <= 8'd0;

       end

 

    else if(rx_int) begin    //接收数据处理

       if(clk_bps) begin //读取并保存数据,接收数据为一个起始位,8bit数据,一个结束位      

              rx_data_shift <= 1'b1;

              num <= num+1'b1;

              if(num<=4'd8) rx_temp_data[7] <= rx;    //锁存9bit1bit起始位,8bit数据)

           end

       else if(rx_data_shift)

           begin    //数据移位处理   

              rx_data_shift <= 1'b0;

              if(num<=4'd8) rx_temp_data <= rx_temp_data >> 1'b1;  //移位8次,第1bit起始位移除,剩下8bit正好时接收数据

              else if(num==4'd10)

                  begin

                     num <= 4'd0;  //接收到STOP位后结束,num清零

                     rx_data_r <= rx_temp_data;  //把数据锁存到数据寄存器rx_data

                  end

           end

       end

end

 

assign rx_data = rx_data_r;

assign txpc = rx; //接受到的数据发给PC机,在PC机串口调试工具上显示

 

endmodule

 

每次按下开关,key_input有个低电平。FPGA发送设定好的数据430301,即为RFID读标签的指令,RFID读标签后有个返回值,通过RFIDuarttx返回给FPGAFPGA再通过RS232接口发送给PC机,显示结果如下:

 

20110927100024002.gif

FPGARFID返回的数据发给PC机,可以直观的从串口调试软件看出,有一个标签被发现。

 

无锡速腾固态数据科技有限公司

Soliddigi Technologies Inc.

地址:江苏省无锡市新区菱湖大道 200 号微纳网 A 310

邮编: 214135 电话: 0510-85387391 传真: 0510-85387691

E-Mail sales@soliddigi.com 无锡公司网址: www.soliddigi.com

公司全球电子产品展销平台 http://www.soliddepot.com

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
3
关闭 站长推荐上一条 /3 下一条