ZYNQ之verilog实现超声波测距加串口实时显示结果

【项目简介】

本项目使用了HC - HR04超声波模块,实现的障碍目标距离检测,且通过zynq实现uart串口实时显示测试结果,后续还可以添加距离报警模块与串口设置报警距离等其他功能。

系统框图

图1项目整体框架

如图1,mea_dis模块测距,结果显示在led灯上,serial_test模块将测距信息连接data,并依uart通信协议传递给zynq_uart_wrapper 的UART1_rxd接收端,最后将结果实时显示在上位机。

过程结果

图2 zynq_core ip核配置

如图2,Zynq核配置:FCLK1输出50mhz频率的脉冲信号,作为串口发送模块serial_test_tb的输入时钟,FCLK_RESETON作为串口模块serial_test_tb的复位信号。

图3 PL端 端口引脚配置

如图3,PL端的引脚配置:dis接八个灯,展示距离,系统时钟sysclk是H16引脚提供125mzh频率的脉冲信号,复位按键为ST0,超声波驱动信号trig,与超声波返回计算值echo接Y12,Y11两个I/O口。

图4 超声波测距模块测试

     如图4,通过设置echo值的变化,模拟超声波发送与受到障碍物的情况,测得在一定情况下的距离值,并与理论计算值比较,发现一致。

图5 UART发送模块测试

如图5,该部分测试向量,依靠顶层文件serial_test每个信号触发沿改变data值,对比 uart发送数据,观察发现一致。

图6整体效果展示

如图6,可以看到测量结果是正确的,并且串口软件也有结果显示,且一致。

TOP

module TOP(dis,sysclk,rst_n,echo,trig);

output wire [7:0 ] dis;
input  sysclk;
input  rst_n;
input  echo;
output  trig;
wire  clk50, rstn;   //zynq核输出50M时钟,低电平有效复位
                        
 mea_dis( .sysclk(sysclk),.rst_n(rst_n),.echo(echo),.trig (trig),.dis (dis));  


serial_test(.clk(clk50),.reset_n(rstn),.uart_tx(rxd),.data(dis));
               
zynq_uart_wrapper zynqCore(.FCLK0(clk100),.FCLK1(clk50),.FCLK_RESETON(rstn),.UART1_rxd(rxd), .UART1_txd(txd) );                   
                      
endmodule

mea_dis超声波测距模块top

module mea_dis(
    input               	sysclk      	,
    input               	rst_n       	,
    input               	echo        	,
    output              	trig        		,
    output  	[7:0]      dis      
    );
Trig trg(
    .sysclk             	(sysclk	)    ,
    .rst_n              	(rst_n 	)    ,
    .trig               	(trig  	)
    );
ECHO echo_u(
    .sysclk             	(sysclk	)    ,
    .rst_n              	(rst_n 	)    ,
    .echo               	(echo  	)    ,
    .dis                	(dis   	)
    );
Endmodule

HC—HR04驱动模块

module Trig(
    input           sysclk      ,
    input           rst_n       ,
    output          trig        
    );
parameter   		DELAY = ( 70 * 125000 ) + 15 * 125;//发送时钟周期(70ms+15us)
reg 	[20:0] 		cnt;
//---------------count----------------//
always@(posedge sysclk)
    if(!rst_n)
        cnt <= 0;
    else if(cnt == DELAY - 1)
        cnt <= 0;
    else
        cnt <= cnt + 1;
//---------------initial trig--------------//
assign trig = (( cnt > 0) && (cnt < 15 * 125 )) ? 1 : 0;
endmodule

计算距离模块

module ECHO(
    input           sysclk      ,
    input           rst_n       ,
    input           echo        ,
    output  [7:0]  dis				//distance
    );
//————————state——————//
parameter IDLE = 3'b001,
           s1   = 3'b010,
           s2   = 3'b100;
reg     [2:0]       cur_state;
reg     [2:0]       next_state;
reg     [31:0]      cnt;
reg     [31:0]      cnt_reg;
//————————first————————//
always@(posedge sysclk)
    if(!rst_n)
        cur_state <= IDLE;
     else
        cur_state <= next_state;
//————————second————————//
always@(*)
    case(cur_state)
       IDLE  :begin//空闲状态
            if(echo == 1)
                next_state = s1;
            else
                next_state = IDLE;
       end
        s1   :begin//
            if(echo == 0)
                next_state = s2;
            else
                next_state = s1;
        end
        s2   :begin
            next_state = IDLE;
        end
        default:next_state = IDLE;
    endcase    
//——————————third——————————//
always@(posedge sysclk)
    if(!rst_n)
        begin
            cnt     <= 0;
            cnt_reg <= 0;
        end
     else
        case(cur_state)
            IDLE :begin
                cnt     <= 0;
                cnt_reg <= cnt_reg;
            end
             s1  :begin
                cnt     <= cnt + 1;
                cnt_reg <= cnt_reg;
             end
             s2  :begin
                cnt_reg <= cnt;
                cnt     <= 0;
             end
             default:begin
                cnt     <= 0;
                cnt_reg <= 0;
             end
        endcase   
//————————distance——————————//
assign dis = (cnt_reg * 8)/58/1000;
endmodule

串口接收uart模块

module serial_test(clk,reset_n,uart_tx,data);
    input clk;
    input [7:0] data;
    input reset_n;
    output uart_tx;
    reg send_go;
    wire [7:0]data;
    wire tx_done;
  
    serial   s1(
    .clk(clk),
    .reset_n(reset_n),
    .data(data),
    .send_go(send_go),
    .uart_tx(uart_tx),
    .tx_done(tx_done),
    .baud_set(4)
    );
    
    //设置计数器每满10ms send_en拉高
    reg[18:0]cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            cnt<=0;
        else if(cnt==499999)
            cnt<=0;
        else
            cnt=cnt+1;                
    end    
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            send_go<=0;
        else if(cnt==1)
            send_go<=1;
        else
            send_go<=0;       
    end

endmodule

协议模块

module serial(
    clk,
    reset_n,
    data,  send_go,
    //串行信号带
    uart_tx,
    //发送结束标志
    tx_done,
    //可设置多种波特率
    baud_set
    );
    input clk,reset_n;
    input[7:0] data;
    reg send_en;
    //典型波特率有300,1200,2400,9600,19200,115200
    //设置5种模式 0:9600,1:19200,2:38400,3:57600,4:115200
    input[2:0] baud_set;
    input send_go;
    output reg uart_tx;
    output reg tx_done;
    wire bps_clk;
    assign bps_clk=(div_cnt==bps_dr-1);
   //计数器 之五种模式设置的值
    reg[17:0] bps_dr;
    always@(*)begin
        case(baud_set)
            0:bps_dr=1000000000/9600/20;
            1:bps_dr=1000000000/19200/20;
            2:bps_dr=1000000000/38400/20;
            3:bps_dr=1000000000/57600/20;
            4:bps_dr=1000000000/115200/20;
            default:bps_dr=1000000000/9600/20;
        endcase
    end
    
   always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            send_en<=0;
        else if(send_go)
            send_en<=1;
        else if(tx_done)
            send_en<=0;    
    end  
    reg [7:0] datacache;
    always@(posedge clk)begin
        if(send_go)
            datacache<=data;
        else
            datacache<=datacache;    
    end     
    
    //计数器
    reg[17:0] div_cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            div_cnt<=0;
        else if(send_en)begin
            if(bps_clk)
                div_cnt<=0;
            else
                div_cnt<=div_cnt+1; 
            end   
        else
            div_cnt<=0;            
    end 
       
    reg[3:0] bps_cnt;
    always@(posedge clk,negedge reset_n)begin
        if(!reset_n)
            bps_cnt<=0;
        else if(send_en)begin
            if(div_cnt==1)begin
            if(bps_cnt==12)
                bps_cnt<=0;
            else    
                bps_cnt<=bps_cnt+1'b1;
            end  
            end 
        else
            bps_cnt<=0;           
    end
    
  //发送数据
  always@(posedge clk,negedge reset_n)begin
    if(!reset_n)
        begin
        uart_tx<=1;
        tx_done<=0;
        end
    else begin
        case(bps_cnt)
            1:uart_tx<=0;
            2:uart_tx<=datacache[0];
            3:uart_tx<=datacache[1];
            4:uart_tx<=datacache[2];
            5:uart_tx<=datacache[3];
            6:uart_tx<=datacache[4];
            7:uart_tx<=datacache[5];
            8:uart_tx<=datacache[6];
            9:uart_tx<=datacache[7]; 
            10:uart_tx<=1;
            11:begin
                uart_tx<=1;
            end
           default:uart_tx<=1;
        endcase
    end
  end  
  always@(posedge clk,negedge reset_n)begin
    if(!reset_n)
        tx_done<=0;   
    else if((bps_clk)&&(bps_cnt==10))
        tx_done<=1;
    else
        tx_done<=0;                  
  end
endmodule

PS端代码-vitis端

功能

主要功能是实现两个UART串口之间的双向中继传输

原理:它使用Xilinx提供的驱动库函数对UART进行初始化和配置,并根据需要设置波特率和FIFO阈值。通过不断检查串口的接收缓冲区是否有数据,并将数据发送到另一个串口,从而实现了数据在两个串口之间的传递。


#include "xparameters.h"
#include "xplatform_info.h"
#include "xuartps.h"
#include "xil_exception.h"
#include "xil_printf.h"
#include "xscugic.h"
char hh[] = "UART TEST\n";

#define		UART_ID		XPAR_PS7_UART_1_DEVICE_ID
#define		UART_INT_ID	XPAR_XUARTPS_1_INTR
#define		SCU_ID		XPAR_SCUGIC_0_DEVICE_ID
XUartPs_Config *uart_config;
XUartPs uart_inst;
XScuGic_Config *xscu_config;
XScuGic scu_inst;
void uart_Handler(void *callback){
	XUartPs *psuart = (XUartPs *)callback;
	u8 dec_rec;
	u32 status;
	//XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,25);
	status = XUartPs_ReadReg(psuart->Config.BaseAddress,XUARTPS_IMR_OFFSET);
	status&= XUartPs_ReadReg(psuart->Config.BaseAddress,XUARTPS_ISR_OFFSET);
	if(status&XUARTPS_IXR_RXOVR){
		dec_rec = XUartPs_RecvByte(XPAR_PS7_UART_1_BASEADDR);
		XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR,dec_rec);
		//清除中断标志位
		XUartPs_WriteReg(psuart->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR);
		xil_printf("%x",XUartPs_ReadReg(psuart->Config.BaseAddress,XUARTPS_ISR_OFFSET));
	}
}

int main()
{
	int status;
	//print("UART TEST\n");
	//串口初始化
	uart_config = XUartPs_LookupConfig(UART_ID);
	status =  XUartPs_CfgInitialize(&uart_inst,
			uart_config, uart_config->BaseAddress);
	if(status!=XST_SUCCESS){
		print("failed\n");
		return XST_FAILURE;
	}
	XUartPs_EnableUart(&uart_inst);
	//设置串口模式
	XUartPs_SetOperMode(&uart_inst, XUARTPS_OPER_MODE_NORMAL);
	//速率设置
	status =  XUartPs_SetBaudRate(&uart_inst, 115200);
	//设置FIFO溢出个数
	XUartPs_SetFifoThreshold(&uart_inst, 1);
	if(status!=XST_SUCCESS){
		print("failed\n");
		return XST_FAILURE;
	}
	//查找中断控制器
	xscu_config = XScuGic_LookupConfig(SCU_ID);
	status = XScuGic_CfgInitialize(&scu_inst,xscu_config,
			xscu_config->CpuBaseAddress);
	if(status!=XST_SUCCESS){
		print("failed\n");
		return XST_FAILURE;
	}
	//老规矩,打开中断控制器后打开异常中断的处理函数
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
						 (Xil_ExceptionHandler)XScuGic_InterruptHandler,
						 (void *)&scu_inst);
	Xil_ExceptionEnable();
	//设置回调函数
	XScuGic_Connect(&scu_inst, UART_INT_ID,
				(Xil_InterruptHandler)uart_Handler, (void *)&uart_inst);
	//设置中断的触发方式
	XUartPs_SetInterruptMask(&uart_inst, XUARTPS_IXR_RXOVR);
	//打开中断控制器的使能
	XScuGic_Enable(&scu_inst, UART_INT_ID);
	//XUartPs_Send(&uart_inst, (u8*)hh, (u32)strlen(hh));
	print("UART TEST\n");
	while(1){
	}

	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

is llong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值