FPGA与STM32之间的UART通信实验

这篇具有很好参考价值的文章主要介绍了FPGA与STM32之间的UART通信实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.UART串口介绍

2.实验任务

3.FPGA代码

4.STM32代码

5.总结

1.UART串口介绍

        UART是一种采用异步串行方式的通用异步收发传输器,在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。

        UART串口通信需要两根信号线来实现,一根用于串口发送,另一根负责串口接收。

        UART的一帧数据由4部分组成:起始位、数据位、奇偶校验位和停止位。起始位标志着一帧数据的开始,低电平有效;数据位代表一帧数据中的有效数据;校验位分为奇校验和偶校验检测数据是否出错;在空闲状态下总线处于高电平。

fpga与stm32通信,fpga开发,stm32,arm,单片机,c语言

        UART通信过程中更多数据格式及传输速率时刻设置的,并且要求双方遵循同样的设置。其中起始位;数据位可选5-8位,一般选择8位;校验位一般选择无校验位;停止位一般选择1位。传输速率用波特率表示,波特率表示每秒传输二进制数据的位数,单位时bps(位/秒),常用的波特率有9600、115200等

2.实验任务

  • 上位机通过串口调试工具将数据发送给MCU的UART2,MCU的UART2接收到的数据通MCU的UART1发送给FPGA的UART1,FPGA的UART1接收到的数据通过FPGA的UART2发送给上位机。

  • 上位机通过串口调试工具将数据发送给FPGA的UART2,FPGA的UART2接收到的数据通FPGA的UART1发送给MCU的UART1,MCU的UART1接收到的数据通过MCU的UART2发送给上位机。

fpga与stm32通信,fpga开发,stm32,arm,单片机,c语言

3.FPGA代码

        FPGA主控芯片是EP4CE10F17C8。

        在顶层模块上,对uart1和uart2接收到的数据和发送数据进行控制和操作。

        顶层模块代码:

module test(
	input           	sys_clk,          //外部50M时钟
    input           	sys_rst_n,        //外部复位信号,低有效
	
    //uart1接口
    input   wire        uart1_rxd,         //UART接收端口
    output  wire        uart1_txd,		   //UART发送端口
	
	//uart2接口
    input   wire        uart2_rxd,         //UART接收端口
    output  wire        uart2_txd		   //UART发送端口
);

wire clk_1m_w;

//parameter define
parameter  CLK_FREQ = 50000000;       //定义系统时钟频率
parameter  UART_BPS = 256000;         //定义串口波特率
parameter  CMD_PKGEND = 8'h65;	//数据包尾
//uart1接口  
wire       uart1_recv_en;             //UART1接收完成使能
wire [7:0] uart1_recv_data;           //UART1接收到的数据

reg        uart1_send_en;			  //UART1发送使能
wire 	   uart1_txd_busy;            //UART1发送忙标志

//uart2接口
wire       uart2_recv_en;            //UART2接收完成使能
wire [7:0] uart2_recv_data;          //UART2接收到的数据

reg        uart2_send_en;			 //UART2发送使能
wire 	   uart2_txd_busy;			 //UART2发送忙标志

//边沿检测接口
reg        uart2_en_d0; 
reg        uart2_en_d1; 
wire       uart2_en_flag;

//边沿检测接口
reg        uart1_en_d0; 
reg        uart1_en_d1; 
wire       uart1_en_flag;

//uart2_uart1 fifo写接口
reg  uart2_wrreq;
wire [7:0] uart2_data_in;
wire uart2_wrfull;
 
//uart2_uart1 fifo读接口
reg  uart2_fifo_flag; //uart2_uart1开始读fifo标志
reg  uart2_rdreq;
wire [7:0] uart2_data_out;
wire uart2_rdempty;

//uart1_uart2 fifo写接口
reg  uart1_wrreq;
wire [7:0] uart1_data_in;
wire uart1_wrfull;
 
//uart1_uart2 fifo读接口
reg  uart1_fifo_flag; //uart1_uart2开始读fifo标
reg  uart1_rdreq;
wire [7:0] uart1_data_out;
wire uart1_rdempty;

//*****************************************************
//**                    main code
//*****************************************************
//捕获uart2_recv_en上升沿,得到一个时钟周期的脉冲信号
assign uart2_en_flag = (~uart2_en_d1) & uart2_en_d0;
//捕获uart1_recv_en上升沿,得到一个时钟周期的脉冲信号
assign uart1_en_flag = (~uart1_en_d1) & uart1_en_d0;

//UART2和UART1边沿检测
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart2_en_d0 <= 1'b0;                                  
        uart2_en_d1 <= 1'b0;
		
		uart1_en_d0 <= 1'b0;                                  
        uart1_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart2_en_d0 <= uart2_recv_en;                               
        uart2_en_d1 <= uart2_en_d0;

		uart1_en_d0 <= uart1_recv_en;                               
        uart1_en_d1 <= uart1_en_d0;  		
    end
end

//UART2写进uart2_uart1 FIFO中
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart2_wrreq <= 0;
		uart2_fifo_flag <= 0;
    end                                                      
    else begin                                               
         if(uart2_en_flag && !uart2_wrfull) begin
			 uart2_wrreq <= 1;
		 end
		 else begin
			 uart2_wrreq <= 0;
		 end
		 
		 if(uart2_en_flag && uart2_recv_data == CMD_PKGEND)begin //检测到数据包尾,uart2_uart1 fifo开始读
			 uart2_fifo_flag <= 1;
		 end
		 if(!uart2_en_flag && uart2_rdempty) begin //uart2_uart1 fifo为空时,将uart2_fifo_flag标志置零
			 uart2_fifo_flag <= 0;
		 end
    end
end

//uart2_uart1 fifo读 uart1发送
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart2_rdreq <= 0;
		uart1_send_en <= 0;
    end                                                      
    else begin                                               
          if(uart2_fifo_flag) begin
          	   //读到数据的下一个周期uart1_txd_busy依旧为0,所以需要增加!uart2_rdreq来延迟一个周期,在第二个周期到来时,uart1_txd_busy为1
			  if(!uart2_rdempty && !uart1_txd_busy && !uart2_rdreq)begin
				  uart2_rdreq <= 1;
				  uart1_send_en <= 1;
			  end
			  else begin
				  uart2_rdreq <= 0;
				  uart1_send_en <= 0;
			  end
		  end
		  else begin
			  uart2_rdreq <= 0;
			  uart1_send_en <= 0;
		  end
    end
end

//UART1写进uart1_uart2 FIFO中
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart1_wrreq <= 0;
		uart1_fifo_flag <= 0;
    end                                                      
    else begin                                               
         if(uart1_en_flag && !uart1_wrfull) begin
			 uart1_wrreq <= 1;
		 end
		 else begin
			 uart1_wrreq <= 0;
		 end
		 
		 if(uart1_en_flag && uart1_recv_data == CMD_PKGEND)begin //检测到数据包尾,uart2_uart1 fifo开始读
			 uart1_fifo_flag <= 1;
		 end
		 if(!uart1_en_flag && uart1_rdempty) begin //uart2_uart1 fifo为空时,将uart2_fifo_flag标志置零
			 uart1_fifo_flag <= 0;
		 end
    end
end

//fifo读 uart1_uart2 uart2发送
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart1_rdreq <= 0;
		uart2_send_en <= 0;
    end                                                      
    else begin                                               
          if(uart1_fifo_flag) begin
          	  //读到数据的下一个周期uart2_txd_busy依旧为0,所以需要增加!uart1_rdreq来延迟一个周期,在第二个周期到来时,uart2_txd_busy为1
			  if(!uart1_rdempty && !uart2_txd_busy && !uart1_rdreq)begin 
				  uart1_rdreq <= 1;
				  uart2_send_en <= 1;
			  end
			  else begin
				  uart1_rdreq <= 0;
				  uart2_send_en <= 0;
			  end
		  end
		  else begin
			  uart1_rdreq <= 0;
		  end
    end
end

//例化锁相环
pll_clk u_pll_clk(                        //时钟分频模块,用于调试
    .inclk0         (sys_clk),
    .c0             (clk_1m_w)
);

//例化uart1接收模块
uart_recv #(                          //串口接收模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口接收波特率
u_uart1_recv(                 
    .sys_clk        (sys_clk), 
    .sys_rst_n      (sys_rst_n),
    
    .uart_rxd       (uart1_rxd),
    .uart_done      (uart1_recv_en),
    .uart_data      (uart1_recv_data)
    );

//例化uart1发送模块
uart_send #(                          //串口发送模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart1_send(                 
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
     
    .uart_en        (uart1_send_en),
    .uart_din       (uart2_data_out),
    .uart_txd       (uart1_txd),
	.uart_txd_busy	(uart1_txd_busy)
    );

//例化uart2接收模块
uart_recv #(                          //串口接收模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口接收波特率
u_uart2_recv(                 
    .sys_clk        (sys_clk), 
    .sys_rst_n      (sys_rst_n),
    
    .uart_rxd       (uart2_rxd),
    .uart_done      (uart2_recv_en),
    .uart_data      (uart2_recv_data)
    );

//例化uart2发送模块
uart_send #(                          //串口发送模块
    .CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率
    .UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart2_send(                 
    .sys_clk        (sys_clk),
    .sys_rst_n      (sys_rst_n),
     
    .uart_en        (uart2_send_en),
    .uart_din       (uart1_data_out),
    .uart_txd       (uart2_txd),
	.uart_txd_busy	(uart2_txd_busy)
    );

//例化uart2_uart1 fifo
uart2_uart1 u_uart2_uart1(
	.wrclk			(sys_clk),
	
	.wrreq			(uart2_wrreq),
	.data			(uart2_recv_data),
	.wrfull			(uart2_wrfull),
	
	.rdclk			(sys_clk),
	
	.rdreq			(uart2_rdreq),
	.q				(uart2_data_out),
	.rdempty		(uart2_rdempty)
);

//例化uart1_uart2 fifo
uart1_uart2 u_uart1_uart2(
	.wrclk			(sys_clk),
	
	.wrreq			(uart1_wrreq),
	.data			(uart1_recv_data),
	.wrfull			(uart1_wrfull),
	
	.rdclk			(sys_clk),
	
	.rdreq			(uart1_rdreq),
	.q				(uart1_data_out),
	.rdempty		(uart1_rdempty)
);


endmodule

         uart接收模块代码:

module uart_recv(
    input			  sys_clk,                  //系统时钟
    input             sys_rst_n,                //系统复位,低电平有效
    
    input             uart_rxd,                 //UART接收端口
    output  reg       uart_done,                //接收一帧数据完成标志信号
    output  reg [7:0] uart_data                 //接收的数据
    );
    
//parameter define
parameter  CLK_FREQ = 50000000;                 //系统时钟频率
parameter  UART_BPS = 115200;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,
                                                //需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器

//wire define
wire       start_flag;

//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end

//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          //检测到起始位
            rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
        else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
            rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程
        else
            rx_flag <= rx_flag;
    end
end

//进入接收过程后,启动系统时钟计数器与接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        rx_cnt  <= 4'd0;
    end                                                      
    else if ( rx_flag ) begin                   //处于接收过程
            if (clk_cnt < BPS_CNT - 1) begin
                clk_cnt <= clk_cnt + 1'b1;
                rx_cnt  <= rx_cnt;
            end
            else begin
                clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
                rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1
            end
        end
        else begin                              //接收过程结束,计数器清零
            clk_cnt <= 16'd0;
            rx_cnt  <= 4'd0;
        end
end

//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)                            //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end

//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
        uart_data <= rxdata;                    //寄存输出接收到的数据
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

endmodule	

        uart发送模块代码:

module uart_send(
    input	      sys_clk,                  //系统时钟
    input         sys_rst_n,                //系统复位,低电平有效
    
    input         uart_en,                  //发送使能信号
    input  [7:0]  uart_din,                 //待发送数据
    output  reg   uart_txd,                  //UART发送端口
	output  reg   uart_txd_busy
    );
    
//parameter define
parameter  CLK_FREQ = 50000000;             //系统时钟频率
parameter  UART_BPS = 115200;                 //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次

//reg define
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                         //系统时钟计数器
reg [ 3:0] tx_cnt;                          //发送数据计数器
reg        tx_flag;                         //发送过程标志信号
reg [ 7:0] tx_data;                         //寄存发送数据

//wire define
wire       en_flag;

//*****************************************************
//**                    main code
//*****************************************************
//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;
                                                 
//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_d0 <= 1'b0;                                  
        uart_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_d0 <= uart_en;                               
        uart_en_d1 <= uart_en_d0;                            
    end
end

//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                                  
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
		uart_txd_busy <= 1'b0;
    end 
    else begin
		if(uart_en) uart_txd_busy <= 1'b1;
		
		if (en_flag) begin                 //检测到发送使能上升沿                      
			tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
			tx_data <= uart_din;            //寄存待发送的数据
		end
		else if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT - 1))begin    //计数到停止位中间时,停止发送过程
			tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
			tx_data <= 8'd0;
			uart_txd_busy <= 1'b0;
		end
		else begin
			tx_flag <= tx_flag;
			tx_data <= tx_data;
		end 
	end
end

//进入发送过程后,启动系统时钟计数器与发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        tx_cnt  <= 4'd0;
    end                                                      
    else if (tx_flag) begin                 //处于发送过程
        if (clk_cnt < BPS_CNT - 1) begin
            clk_cnt <= clk_cnt + 1'b1;
            tx_cnt  <= tx_cnt;
        end
        else begin
            clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
            tx_cnt  <= tx_cnt + 1'b1;       //此时发送数据计数器加1
        end
    end
    else begin                              //发送过程结束
        clk_cnt <= 16'd0;
        tx_cnt  <= 4'd0;
    end
end

//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end

endmodule	          

4.STM32代码

        STM32的主控芯片是STM32F103RCT6。

        main.c代码:

#include "sys.h"
#include "usart.h"

int main(void)
{	
	u8 t;
	u8 len;
	delay_init();	    	 //延时函数初始化	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	uart1_init(256000);	 //串口初始化为25600
	uart2_init(256000);
	printf("初始化成功\r\n");
	while(1)
	{
		if(USART2_RX_STA&0x8000)
		{					   
			len=USART2_RX_STA&0x3fff;//得到此次接收到的数据长度
			
			for(t=0;t<len;t++)
			{
				USART1->DR=USART2_RX_BUF[t];
				while((USART1->SR&0X40)==0);//等待发送结束
			}
			
			USART2_RX_STA=0;
		}
		else if(USART1_RX_STA&0x8000)
		{					   
			len=USART1_RX_STA&0x3fff;//得到此次接收到的数据长度
			for(t=0;t<len;t++)
			{
				USART2->DR=USART1_RX_BUF[t];
				while((USART2->SR&0X40)==0);//等待发送结束
			}
			USART1_RX_STA=0;
		}
		else
		{
			delay_ms(10);   
		}
	}	 
}

        usart.c文件代码:

#include "sys.h"
#include "usart.h"

u8 USART1_RX_BUF[USART1_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
u16 USART1_RX_STA=0;       //接收状态标记

u8 USART2_RX_BUF[USART2_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
u16 USART2_RX_STA=0;       //接收状态标记
  
void uart1_init(u32 bound){
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
	//USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

	USART_Init(USART1, &USART_InitStructure); //初始化串口1
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

void uart2_init(u32 bound){
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	
	//USART2_TX   GPIOA.2
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
   
	//USART2_RX	  GPIOA.3初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3

	//Usart2 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
	//USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

	USART_Init(USART2, &USART_InitStructure); //初始化串口2
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口2接受中断
	USART_Cmd(USART2, ENABLE);                    //使能串口2 

}

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x65结尾)
	{
		
		Res =USART_ReceiveData(USART1);	//读取接收到的数据  
		if((USART1_RX_STA&0x8000)==0)//接收未完成
		{
			USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ;
			USART1_RX_STA++;
			if(Res==0x65) USART1_RX_STA|=0x8000;	//接收完成了
			else if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收
			
		}
    } 
}

void USART2_IRQHandler(void)
{
	u8 Res;
	
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是65结尾)
	{
		Res =USART_ReceiveData(USART2);	//读取接收到的数据
		if((USART2_RX_STA&0x8000)==0)//接收未完成
		{
			USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
			USART2_RX_STA++;
			if(Res==0x65) USART2_RX_STA|=0x8000;	//接收完成了
			else if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//接收数据错误,重新开始接收	  
		}
    }
}

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
	/* 发送一个字节数据到串口 */
	USART_SendData(USART2, (uint8_t) ch);

	/* 等待发送完毕 */
	while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);		    
	return (ch);
}

        usart.h文件代码:

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART1_REC_LEN  			200  	//定义最大接收字节数 200
#define USART2_REC_LEN  			200  	//定义最大接收字节数 200

extern u8  USART1_RX_BUF[USART1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART1_RX_STA;         		//接收状态标记	

extern u8  USART2_RX_BUF[USART2_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART2_RX_STA;         		//接收状态标记	

void uart1_init(u32 bound);
void uart2_init(u32 bound);

#endif

5.总结

  • 波特率不宜选太高,会导致通信不了;

  • FPGA方面注意FIFO读请求置1后,在下一个时钟周期读的数据才会更新,所以uar待t发送的数据要延时一周期后再接收fifo读到的数据。

  • FPGA方面的uart发送模块需要注意FIFO每读取一次数据uart发送一次,所以增加了uart_txd_busy,防止fifo连续读数据。文章来源地址https://www.toymoban.com/news/detail-640588.html

到了这里,关于FPGA与STM32之间的UART通信实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • FPGA主SPI与STM32从机通信

    FPGA主SPI与STM32从机通信

    目录 概述 FPGA的SPI主机代码 STM32从机 SPI模式配置 SPI参数设置  SPI的DMA传输配置 STM32从机SPI接收代码         不说一些SPI原理之类的废话,浪费空间。我使用的硬件环境为STM32F407VET6和DE0-nano,长什么样子如下图。  使用cubemx配置工程,FPGA使用Quartus软件,时序仿真图如下    

    2024年02月02日
    浏览(8)
  • 基于SPI实现stm32与fpga通信(一)

    SPI通信协议有以下4种模式: 模式0:时钟极性为0,时钟相位为0,数据在时钟下降沿捕获,数据在时钟上升沿改变。 模式1:时钟极性为0,时钟相位为1,数据在时钟上升沿捕获,数据在时钟下降沿改变。 模式2:时钟极性为1,时钟相位为0,数据在时钟上升沿捕获,数据在时钟

    2024年04月16日
    浏览(18)
  • ARM开发,stm32mp157a-A7核(UART总线实验)

    ARM开发,stm32mp157a-A7核(UART总线实验)

    ---.h头文件--- ---.c功能实现文件--- ---.c主函数测试文件--- 结果: 字符:  字符串: 

    2024年02月11日
    浏览(11)
  • K210 UART串口通信介绍与 STM32通信

    目录 K210-UART串口通信相关函数: 使用K210串口的时候需要映射引脚: K210与STM32串口通信  发送单字节: K210端 STM32端 发送数据包 K210端 STM32端  K210的UART模块支持全双工通信,可以同时进行数据的发送和接收。在K210上使用UART串口通信,你可以连接外部设备,如传感器、显示器

    2024年03月23日
    浏览(12)
  • 【单片机】基于STM32的UART串口通信

    【单片机】基于STM32的UART串口通信

    简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作。实验内容基于 正点原子精英板 开发板,单片机芯片为 STM32F103ZET6 。 在后面我会以我使用的STM32F429开发板来举例讲解(其他STM32系列芯片大多数都可以按照这些步骤来操作

    2024年01月17日
    浏览(40)
  • STM32CubeMX教程9 USART/UART 异步通信

    开发板(正点原子stm32f407探索者开发板V2.4) STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 逻辑分析仪nanoDLA 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 USART1与PC进行异步通信(阻塞传输方式、中断传输方式) ,具体为 使用WK_UP按键

    2024年02月03日
    浏览(10)
  • 学习笔记一:树莓派与STM32的UART通信

    学习笔记一:树莓派与STM32的UART通信

    树莓派4B一共包含两个串口,一个是硬件串口(/dev/ttyAMA0),一个是mini串口(/dev/ttyS0)。硬件串口因为使用其单独的时钟源,性能高,稳定可靠,成为使用较为广泛的串口;另一个mini串口性能低,功能简单,但是没有单独的时钟源,会受到内部时钟的影响,树莓派本身运行

    2023年04月18日
    浏览(23)
  • STM32 UART串口通信IDLE空闲中断的使用步骤

    参考了各路大神的资料,蒙蔽了半天,终于学会了,记录一下,以后忘了可以回来复习参考。 一、首先在stm32cube中配置打开对应uart串口的中断 二、工程main函数调用 __HAL_UART_ENABLE_IT(huart1,UART_IT_IDLE);//hal库宏定义,使能串口空闲中断     HAL_UART_Receive_DMA(huart1,data,sizeof(data));//使

    2024年02月12日
    浏览(5)
  • STM32CubeMx+MATLAB Simulink串口输出实验,UART/USART串口测试实验

    STM32CubeMx+MATLAB Simulink串口输出实验,UART/USART串口测试实验

    STM32CubeMx+MATLAB Simulink串口输出实验

    2024年02月21日
    浏览(11)
  • OpenMV与STM32之间的通信

    OpenMV与STM32之间使用串口进行通信。 详细解释可以看代码里面的注释。 注意:转换成字节型传输时,负数会以补码形式传输,比如:-1在单片机接受时变成255. 先在项目中加入串口通信包,PA2为TXD,PA3为RXD。可以开一个串口通过串口助手打印接收到的数据。 注意:OpenMV的TXD和

    2024年02月16日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包