赞
踩
要使用FPGA与STM32实现串口通信,以下是一般的步骤:
配置STM32的串口模块:使用STM32的库函数或者寄存器配置,选择一个可用的串口模块(例如USART1、USART2等)并设置相应的波特率、数据位、停止位等参数。确保STM32串口的引脚与FPGA连接正确。
配置FPGA与STM32之间的通信接口:确定FPGA与STM32之间的通信接口,通常使用串口通信需要至少两个信号线:一个用于发送数据(TX),一个用于接收数据(RX)。确保FPGA的引脚与STM32的串口引脚相连。
在FPGA中实现串口通信接口:使用HDL(硬件描述语言,如Verilog或VHDL)编写FPGA逻辑,实现串口通信接口。这包括发送和接收数据的逻辑,以及与STM32的串口模块进行数据交换的逻辑。
在STM32中编写串口通信代码:使用STM32的开发环境(如Keil或STM32CubeIDE)编写串口通信的代码。这包括配置STM32串口模块、发送和接收数据的代码。
在FPGA中进行数据的发送和接收:通过FPGA的串口通信接口将数据发送到STM32,或从STM32接收数据。确保数据的格式和协议在FPGA和STM32之间匹配。
在STM32中进行数据的发送和接收:使用STM32的串口通信代码,接收来自FPGA的数据或将数据发送到FPGA。确保STM32的串口配置与FPGA的串口配置匹配。
测试与调试:使用示波器或串口调试工具监视串口数据的发送和接收。检查数据的准确性和完整性,并进行必要的调试和修复。
需要注意的是,FPGA和STM32之间的串口通信需要确保数据格式、波特率等参数的一致性。另外,还需要关注引脚连接和信号电平的匹配,以确保正确的数据传输。具体的实现细节和代码编写可能因具体的FPGA型号和STM32型号而有所不同,你可以参考相关的开发文档和例程来帮助你完成串口通信的实现。
以下为本人做无人船时使用的FPGA与stm32串口通信过程。
首先为FPGA输出PWM波控制两个电机的过程:
- //FPGA 控制舵机程序(verilog)
- module pwm_gen(
-
- input nreset,
- input clk,
- input en,//1
-
- input [31:0] period,
- input [31:0] h_time,
-
- output reg pwm
-
- );
-
- reg [31:0] CNT;
-
- always @ (posedge clk)
- begin
- if(nreset)
- CNT <= 0;
- else if(CNT >= period - 1 )
- CNT <= 0;
- else
- CNT <= CNT + 1;
- end
-
- always @ (posedge clk)
- begin
- if(nreset)
- pwm <= 0;
- else //nreset = 1
- begin
- if(en == 0)
- pwm <= 0;
- else //en = 1
- begin
- if(CNT <= h_time - 1)
- pwm <= 1;
- else
- pwm <= 0;
- end
- end
- end
-
- endmodule
- //125M 20M
- //例化可控制三个舵机
- module PWM1(clk,nreset,uart_rxd,pwm3,pwm4);
- input clk;
- input nreset;
- input uart_rxd;
- output pwm3;//[2:0]
- output pwm4;//[2:0]
- //reg pwm2;
-
- wire [31:0]left0;
- wire [31:0]right0;
- wire clkp0;
- wire uart_rx_done;
- wire uart_rx_data;
- wire locked;
-
- pwm_gen a1(
- .nreset(nreset),
- .clk(clk),
- .en(1),
- .period(2500000),
- .h_time(left0),
- .pwm(pwm3)
- );
- pwm_gen a2(
- .nreset(nreset),
- .clk(clk),
- .en(1),
- .period(2500000),
- .h_time(right0),
- .pwm(pwm4)
- );
- // pwm_gen a2(nreset,clk,1,2500000,right0,pwm4); //125000 250000
- // pwm_gen a2(clk,nreset,1,2500000,1500_000,pwm3[1]);
- // pwm_gen a3(clk,nreset,1,2500000,2000_000,pwm3[2]);
-
-
- //例化被测试的接收模块
- //uart_rx #(
- // .BPS (9600), //波特率9600
- // .SYS_CLK_FRE (50_000_000)//时钟频率50M
- //)
-
- uart_rx u_uart_rx (
- .sys_clk (clkp0),
- .sys_rst_n (sys_rst_n),
- .uart_rxd (uart_rxd),
- .uart_rx_done (uart_rx_done),
- .uart_rx_data (uart_rx_data) ,
- .left(left0),
- .right(right0)
- );
- clk_wiz_0 uu0
- (
- // Clock out ports
- .clk_out1(clkp0),
- .reset(nreset),
- .locked(),
- // Clock in ports
- .clk_in1(clk)
- );
- // 1000 2000
- //1000_000 1500_000 2000_000
- endmodule
其次建立FPGA的uart模块:
- //`timescale 1ns / 1ps
- //
- // Company:
- // Engineer:
- //
- // Create Date: 2023/06/16 18:08:02
- // Design Name:
- // Module Name: uart
- // Project Name:
- // Target Devices:
- // Tool Versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- //
-
-
- module uart_rx(
- input sys_clk, //50M系统时钟
- input sys_rst_n, //系统复位
- input uart_rxd, //接收数据线
- output reg uart_rx_done, //数据接收完成标志
- output reg [7:0]uart_rx_data, //接收到的数据
- output reg [31:0] left, //数据接收完成标志
- output reg [31:0] right //数据接收完成标志
- );
- //常量化波特率,可更改
- parameter BPS=115200; //波特率9600bps,可更改
- parameter SYS_CLK_FRE=50_000_000; //50M系统时钟
- localparam BPS_CNT=SYS_CLK_FRE/BPS; //传输一位数据所需要的时钟个数
-
- reg uart_rx_d0; //寄存1拍
- reg uart_rx_d1; //寄存2拍
- reg [15:0] clk_cnt; //时钟计数器
- reg [3:0] rx_cnt; //接收计数器
- reg rx_flag; //接收标志位
- reg [7:0] uart_rx_data_reg; //数据寄存
- reg [3:0] cnt_dj;//电机PWM值计数
- reg [31:0] count0 = 10'd100;
- wire neg_uart_rx_data; //数据的下降沿
- reg [31:0] lefft;
- reg [31:0] lefft1;
- assign neg_uart_rx_data=uart_rx_d1 & (~uart_rx_d0); //捕获数据线的下降沿,用来标志数据传输开始
- //将数据线打两拍,作用1:同步不同时钟域信号,防止亚稳态;作用2:用以捕获下降沿
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(sys_rst_n)begin
- uart_rx_d0<=1'b0;
- uart_rx_d1<=1'b0;
- end
- else begin
- uart_rx_d0<=uart_rxd;
- uart_rx_d1<=uart_rx_d0;
- end
- end
- //捕获到数据下降沿(起始位0)后,拉高传输开始标志位,并在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(sys_rst_n)
- rx_flag<=1'b0;
- else begin
- if(neg_uart_rx_data)
- rx_flag<=1'b1;
- else if((rx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2))//在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
- rx_flag<=1'b0;
- else
- rx_flag<=rx_flag;
- end
- end
- //时钟每计数一个BPS_CNT(传输一位数据所需要的时钟个数),即将数据计数器加1,并清零时钟计数器
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(sys_rst_n)begin
- rx_cnt<=4'd0;
- clk_cnt<=16'd0;
- end
- else if(rx_flag)begin
- if(clk_cnt<BPS_CNT-1'b1)begin
- clk_cnt<=clk_cnt+1'b1;
- rx_cnt<=rx_cnt;
- end
- else begin
- clk_cnt<=16'd0;
- rx_cnt<=rx_cnt+1'b1;
- end
- end
- else begin
- rx_cnt<=4'd0;
- clk_cnt<=16'd0;
- end
- end
- //在每个数据的传输过程正中(数据比较稳定)将数据线上的数据赋值给数据寄存器
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(sys_rst_n)
- uart_rx_data_reg<=8'd0;
- else if(rx_flag)
- if(clk_cnt==BPS_CNT/2) begin
- case(rx_cnt)
- 4'd1:uart_rx_data_reg[0]<=uart_rxd;
- 4'd2:uart_rx_data_reg[1]<=uart_rxd;
- 4'd3:uart_rx_data_reg[2]<=uart_rxd;
- 4'd4:uart_rx_data_reg[3]<=uart_rxd;
- 4'd5:uart_rx_data_reg[4]<=uart_rxd;
- 4'd6:uart_rx_data_reg[5]<=uart_rxd;
- 4'd7:uart_rx_data_reg[6]<=uart_rxd;
- 4'd8:uart_rx_data_reg[7]<=uart_rxd;
- default:;
- endcase
- end
- else
- uart_rx_data_reg<=uart_rx_data_reg;
- else
- uart_rx_data_reg<=8'd0;
- end
- //当数据传输到终止位时,拉高传输完成标志位,并将数据输出
- always@(posedge sys_clk or negedge sys_rst_n)begin
- if(sys_rst_n)
- begin
- uart_rx_done=1'b0;
- left=32'd125000;
- lefft=32'd0;
- lefft1=32'd0;
- right=32'd0;
- cnt_dj=4'd0;
- uart_rx_data=8'd0;
- end
- else if(rx_cnt==4'd9)
- begin//接收完判断
- uart_rx_done=1'b1;
- uart_rx_data=uart_rx_data_reg;
- // rx_cnt<=4'd0;
- if(uart_rx_data==16'hFF &&cnt_dj==4'd0)
- begin
- cnt_dj=4'd1;
- uart_rx_data=8'd0;
- left=32'd0;
- right=32'd0;
- end
- else if(uart_rx_data!=16'hFF &&cnt_dj==4'd1)
- begin
- left=uart_rx_data*count0;
- cnt_dj=4'd2;
- end
- else if(uart_rx_data==16'hFE &&cnt_dj==4'd2)
- begin
- cnt_dj=4'd3;
- uart_rx_data=8'd0;
- end
- else if(uart_rx_data!=16'hFE &&cnt_dj==4'd3)
- begin
- left=left+uart_rx_data;
- left=left*10'd125;
- cnt_dj=4'd4;
- end
- else if(uart_rx_data==16'hFD &&cnt_dj==4'd4)
- begin
- cnt_dj=4'd5;
- uart_rx_data=8'd0;
- end
- else if(uart_rx_data!=16'hFD &&cnt_dj==4'd5)
- begin
- right=uart_rx_data*count0;
- cnt_dj=4'd6;
- end
- else if(uart_rx_data==16'hFC &&cnt_dj==4'd6)
- begin
- cnt_dj=4'd7;
- uart_rx_data=8'd0;
- end
- else if(uart_rx_data!=16'hFC &&cnt_dj==4'd7)
- begin
- right=right+uart_rx_data;
- right=right*10'd125;
- cnt_dj=4'd0;
- end
- end
- else
- begin
- uart_rx_done<=1'b0;
- uart_rx_data=8'd0;
- end
- end
- endmodule
- // if(uart_rx_data==16'hFF &&cnt_dj==4'd0)
- // begin
- // cnt_dj=4'd1;
- // uart_rx_data=8'd0;
- // left=32'd0;
- // right=32'd0;
- // end
- // else if(uart_rx_data!=16'hFF)
- // begin
- // if(cnt_dj==4'd4)
- // begin
- // right=right+uart_rx_data;
- // cnt_dj=4'd0;
- // end
- // if(cnt_dj==4'd3)
- // begin
- // right=uart_rx_data*100;
- // cnt_dj=4'd4;
- // end
- // if(cnt_dj==4'd2)
- // begin
- // left=left+uart_rx_data;
- // lefft1=left;
- // cnt_dj=4'd3;
- // end
- // if(cnt_dj==4'd1)
- // begin
- // left=uart_rx_data*count0;
- // lefft<=left;
- // cnt_dj=4'd2;
- // end
- // end
-
由于两模块间需要进行分频处理,将125MHZ分成50MHZ,我们采用vivado自带的IP核进行分频处理,具体步骤如下图所示:
仿真模块如下所示:
- `timescale 1ns/1ps
- //module tb;
- // reg sys_clk;
- // reg sys_rst_n;
- // wire PWMA_H, PWMA_L, PWMB_H, PWMB_L, PWMC_H, PWMC_L;
-
- // // Reset generation
- // initial begin
- // sys_rst_n = 0;
- // sys_clk=0;
- // #10;
- // sys_rst_n = 1;
- // #100;
- // $finish; // End simulation after some time
- // end
-
- // // Clock generation
- // always #5 sys_clk = ~sys_clk;
-
- // // Testbench logic
- // reg clk_counter = 0;
-
- // // Instantiate the PWM module
- //PWM1 a4(sys_clk,sys_rst_n,PWMA_H);
-
- // always @(posedge sys_clk) begin
- // if (sys_rst_n) begin
- // clk_counter <= clk_counter + 1;
-
- // // Read PWM output signals
- // $display("Time: %t, PWMA_H: %b, PWMA_L: %b, PWMB_H: %b, PWMB_L: %b, PWMC_H: %b, PWMC_L: %b",
- // $time, PWMA_H, PWMA_L, PWMB_H, PWMB_L, PWMC_H, PWMC_L);
-
- // // Add your testbench assertions or other test logic here
-
- // // Stop simulation after a certain number of clock cycles
- // if (clk_counter == 1000)
- // $finish;
- // end
- // end
-
- //endmodule
-
-
- //模块、接口定义
- module uart_rx_tb();
- reg sys_clk;
- reg sys_rst_n;
- reg uart_rxd;
- wire locked;
- wire clkp0;
- wire PWMA_H;
- wire uart_rx_done;
- wire uart_rx_data;
- wire pwm3;
- wire pwm4;
- wire [31:0] left0;
- wire [31:0] right0;
- pwm_gen a1(sys_rst_n,sys_clk,1,2000000,left0,pwm3);
- pwm_gen a2(sys_rst_n,sys_clk,1,2000000,right0,pwm4);
- //例化被测试的接收模块
- uart_rx #(
- .BPS (9600), //波特率9600
- .SYS_CLK_FRE (50_000_000)//时钟频率50M
- )
- u_uart_rx(
- .sys_clk (clkp0),
- .sys_rst_n (sys_rst_n),
- .uart_rxd (uart_rxd),
- .uart_rx_done (uart_rx_done),
- .uart_rx_data (uart_rx_data),
- .left(left0),
- .right(right0)
- );
- clk_wiz_1 uu1
- (
- // Clock out ports
- .clk_out1(clkp0),
- .reset(sys_rst_n),
- .locked(locked),
- // Clock in ports
- .clk_in1(sys_clk)
- );
-
- // PWM1 a4(sys_clk,sys_rst_n,PWMA_H);
- localparam CNT=50_000_000/9600*20; //计算出传输每个时钟所需要的时间
- initial begin //传输8位数据 8'b01010101
- //初始时刻定义
- sys_clk <=1'b0;
- sys_rst_n<=1'b0;
- uart_rxd<=1'b1;
- #20 //系统开始工作
- sys_rst_n<=1'b1;
- #20 //系统开始工作
- sys_rst_n<=1'b0;
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b1;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b0; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b0;//传输第6位
- #CNT
- uart_rxd<=1'b1;//传输第7位
- #CNT
- uart_rxd<=1'b0; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //FF
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b1;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b1;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b1; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b1;//传输第6位
- #CNT
- uart_rxd<=1'b1;//传输第7位
- #CNT
- uart_rxd<=1'b1; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- // 左右电机的数
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b1;//传输第2位
- #CNT
- uart_rxd<=1'b0;//传输第3位
- #CNT
- uart_rxd<=1'b1; //传输第4位
- #CNT
- uart_rxd<=1'b0;//传输第5位
- #CNT
- uart_rxd<=1'b0;//传输第6位
- #CNT
- uart_rxd<=1'b0;//传输第7位
- #CNT
- uart_rxd<=1'b0; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //FE
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b1;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b1; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b1;//传输第6位
- #CNT
- uart_rxd<=1'b1;//传输第7位
- #CNT
- uart_rxd<=1'b1; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- #(CNT) //00
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b0;//传输第3位
- #CNT
- uart_rxd<=1'b0; //传输第4位
- #CNT
- uart_rxd<=1'b0;//传输第5位
- #CNT
- uart_rxd<=1'b0;//传输第6位
- #CNT
- uart_rxd<=1'b0;//传输第7位
- #CNT
- uart_rxd<=1'b0; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //FD
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b1;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b1; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b1;//传输第6位
- #CNT
- uart_rxd<=1'b1;//传输第7位
- #CNT
- uart_rxd<=1'b1; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //右
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b0; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b0;//传输第6位
- #CNT
- uart_rxd<=1'b0;//传输第7位
- #CNT
- uart_rxd<=1'b0; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //FC
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b1;//传输第3位
- #CNT
- uart_rxd<=1'b1; //传输第4位
- #CNT
- uart_rxd<=1'b1;//传输第5位
- #CNT
- uart_rxd<=1'b1;//传输第6位
- #CNT
- uart_rxd<=1'b1;//传输第7位
- #CNT
- uart_rxd<=1'b1; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- //00
- #(CNT/2)
- uart_rxd<=1'b1;//开始传输起始位
- #(CNT/2)
- uart_rxd<=1'b0;//开始传输起始位
- #CNT
- uart_rxd<=1'b0;//传输最低位,第1位
- #CNT
- uart_rxd<=1'b0;//传输第2位
- #CNT
- uart_rxd<=1'b0;//传输第3位
- #CNT
- uart_rxd<=1'b0; //传输第4位
- #CNT
- uart_rxd<=1'b0;//传输第5位
- #CNT
- uart_rxd<=1'b0;//传输第6位
- #CNT
- uart_rxd<=1'b0;//传输第7位
- #CNT
- uart_rxd<=1'b0; //传输最高位,第8位
- #CNT
- uart_rxd<=1'b1; //传输终止位
- end
-
- always begin
- #5 sys_clk=~sys_clk; //时钟20ns,100M
- end
- // always begin
- // #10 sys_clk=~sys_clk; //时钟20ns,50M
- //end
- endmodule
-
以上便实现了FPGA的接收功能,此时FPGA可以接收FF--FE--FD--FC--的信号,其中--代表16进制数,FF后的16进制数乘100加FE后面的16进制数及为左电机的电机值,同理,FD后面的乘100加FC后面的为右电机的电机值,我们只需要在单片机上实现发送FF--FE--FD--FC--的信号的功能即可完成全部过程。
仿真图如下所示:
从仿真可以看出实验非常成功,对应项目的无人船而言也十分成功。欢迎大家积极讨论留言!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。