查看: 572|回复: 0

[评测分享] 【PGL22G开发板】+串口回环

[复制链接]
  • TA的每日心情
    无聊
    前天 22:47
  • 签到天数: 65 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2023-5-7 09:51:38 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 feifeiz 于 2023-5-7 09:54 编辑

    一、前言
    继上一篇完成蜂鸣器进行音乐播放后,对开发板的资源以及开发环境有了一定了解,本次继续对开发板功能进行探索。串口是开发过程中基本都会使用的一个外设,可以通过串口进行通信,调试等,如可以使用开发板的串口与其他板子或者模块进行通信,因此,本次在开发板实现串口与上位机通信功能,同时实现串口控制板载的LED。
    二、串口简介

    串行接口(SerialInterface)是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种,按接口可以划分为RS232,RS485等,在工业控制领域中应用非常广泛。

    三、硬件连接
    打开PGL22G开发板原理图,找到USB转串口部分,如下所示,测试中需确保P1是连接的,默认为连接状态。
    1.png

    继续查找CH340与FPGA连接的引脚,如下所示,UART1_TX接到了T10引脚,UART1_RX接到芯片的T10引脚
    2.png

    同时查看LED0的硬件连接,如下所示,接到芯片的F3引脚
    3.png

    接下来就得到总的引脚使用情况
      信号名
      
      方向
      
      管脚
      
      端口说明
      
      Sys_clk
      
      input
      
      B5
      
      系统时钟
      
      Sys_rst_n
      
      input
      
      G5
      
      系统复位
      
      Uart_rxd
      
      input
      
      R10
      
      串口接收
      
      Uart_txd
      
      input
      
      T10
      
      串口发送
      
      led
      
      output
      
      F3
      
      LED输出
      

    四、程序设计
    总体设计,通过上位机给开发板下发数据,开发板对接收数据进行判断,当接收到的数据是约定的数据时,LED常亮,默认为熄灭状态,模块设计,顶层模块,串口接收模块,总体实现框图。
    4.png

    在顶层模块设计中,添加LED控制输出定义。

    moduleuart_loopback_top(

    input sys_clk, //外部50M时钟
    input sys_rst_n, //外部复位信号,低有效

    input uart_rxd, //UART接收端口
    output uart_txd, //UART发送端口
    output led
    );

    //parameter define
    parameter CLK_FREQ = 50000000; //定义系统时钟频率
    parameter UART_BPS = 115200; //定义串口波特率
    //wire define
    wire uart_recv_done; //UART接收完成
    wire [7:0] uart_recv_data; //UART接收数据
    wire uart_send_en; //UART发送使能
    wire [7:0] uart_send_data; //UART发送数据
    wire uart_tx_busy; //UART发送忙状态标志

    //*****************************************************
    //** main code
    //*****************************************************

    //串口接收模块
    uart_recv #(
    .CLK_FREQ (CLK_FREQ), //设置系统时钟频率
    .UART_BPS (UART_BPS)) //设置串口接收波特率
    u_uart_recv(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .uart_rxd (uart_rxd),
    .uart_done (uart_recv_done),
    .uart_data (uart_recv_data),
    .led (led)
    );

    //串口发送模块
    uart_send #(
    .CLK_FREQ (CLK_FREQ), //设置系统时钟频率
    .UART_BPS (UART_BPS)) //设置串口发送波特率
    u_uart_send(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .uart_en (uart_send_en),
    .uart_din (uart_send_data),
    .uart_tx_busy (uart_tx_busy),
    .uart_txd (uart_txd)
    );
    //串口环回模块
    uart_loop u_uart_loop(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .recv_done (uart_recv_done), //接收一帧数据完成标志信号
    .recv_data (uart_recv_data), //接收的数据
    .tx_busy (uart_tx_busy), //发送忙状态标志
    .send_en (uart_send_en), //发送使能信号
    .send_data (uart_send_data) //待发送数据
    );
    Endmodule
    接收模块中,对接收到的数据进行判断,当接收到上位机下发的数据为1后LED常亮。

    moduleuart_recv(

    input sys_clk, //系统时钟
    input sys_rst_n, //系统复位,低电平有效
    input uart_rxd, //UART接收端口
    output reg uart_done, //接收一帧数据完成标志
    output reg rx_flag, //接收过程标志信号
    output reg [3:0] rx_cnt, //接收数据计数器
    output reg [7:0] rxdata,
    output reg [7:0] uart_data, //接收的数据
    output reg led
    );
    //parameter define
    parameter CLK_FREQ = 50000000; //系统时钟频率
    parameter UART_BPS = 9600; //串口波特率

    localparam BPS_CNT =CLK_FREQ/UART_BPS; //为得到指定波特率,

    //需要对系统时钟计数BPS_CNT次
    //reg define
    reg uart_rxd_d0;
    reg uart_rxd_d1;
    reg [15:0] clk_cnt; //系统时钟计数器
    //wire define
    wire start_flag;

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

    assign start_flag = uart_rxd_d1& (~uart_rxd_d0);


    //对UART接收端口的数据延迟两个时钟周期

    always @(posedge sys_clk ornegedge 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 ornegedge 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; //接收过程结束,标志位rx_flag拉低
    else
    rx_flag <= rx_flag;
    end
    end

    //进入接收过程后,启动系统时钟计数器

    always @(posedge sys_clk ornegedge sys_rst_n) begin

    if (!sys_rst_n)
    clk_cnt <= 16'd0;
    else if ( rx_flag ) begin //处于接收过程
    if (clk_cnt < BPS_CNT - 1)
    clk_cnt <= clk_cnt + 1'b1;
    else
    clk_cnt <= 16'd0; //对系统时钟计数达一个波特率周期后清零
    end
    else
    clk_cnt <= 16'd0; //接收过程结束,计数器清零
    end

    //进入接收过程后,启动接收数据计数器

    always @(posedge sys_clk ornegedge sys_rst_n) begin

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

    //根据接收数据计数器来寄存uart接收端口数据

    always @(posedge sys_clk ornegedge 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 ornegedge sys_rst_n) begin

    if ( !sys_rst_n)
    led <= 1'b0;
    else if(rxdata == 1)
    led <= 1'b1;
    end


    //数据接收完毕后给出标志信号并寄存输出接收到的数据

    always @(posedge sys_clk ornegedge 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
    五、实验现象
    编译工程,生成.sbit文件
    5.png

    连接开发板
    6.png

    下载
    7.png

    打开XCOM,在发送区输入1,点击发送
    8.png

    开发板状态,LED0常亮
    9.jpg

    六、总结
    本篇为过渡性文章,通过阅读串口回环章节进行一点拓展,本质上为了实现串口通讯,学会编程,熟悉模块设计以及开发方法及经验。





    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-19 20:41 , Processed in 0.123722 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.