大家应该熟悉FPGA跟PC机通讯的原理,PC机通过串口发送指令给FPGA,FPGA接收指令,再把我们设定的指令回发给PC机。FPGA跟RFID<先发送指令给RFID,比如读标签指令,RFID读到标签后回发给FPGA指令说明自己读到标签了。
我之前疑惑的地方是怎么用按键来控制FPGA通过串口发送指令,之后在网上请教了一些高手,虽然功能能实现,但是还是有点缺陷,希望高手阅读完后有更好的代码,请不吝赐教,谢谢!
The hardware includes the following:
1.TTL UART UHF RFID reader module
2.PPGA Board
The following is a system picture:
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; //FPGA的RS232输出
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; //锁存9bit(1bit起始位,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读标签后有个返回值,通过RFID的uart的tx返回给FPGA,FPGA再通过RS232接口发送给PC机,显示结果如下:
FPGA把RFID返回的数据发给PC机,可以直观的从串口调试软件看出,有一个标签被发现。
无锡速腾固态数据科技有限公司
Soliddigi Technologies Inc.
地址:江苏省无锡市新区菱湖大道 200 号微纳网 A 栋 310 室
邮编: 214135 电话: 0510-85387391 传真: 0510-85387691
E-Mail : sales@soliddigi.com 无锡公司网址: www.soliddigi.com
公司全球电子产品展销平台 http://www.soliddepot.com
文章评论(0条评论)
登录后参与讨论