串口接收原理与思路

在这里插入图片描述
在这里插入图片描述
每一次采样应该在每一小段的最中间

##初次设计
源代码:

module uart_byte_rx(
  Clk,
  Reset_n,
  Baud_Set,
  uart_rx,
  Data,
  Rx_Done
    );  
   input  Clk;
 input Reset_n;
  input Baud_Set;
   input uart_rx;
 output reg [7:0] Data;
 output reg Rx_Done;
 
 reg [1:0] uart_rx_r;  //两个D触发器作为边沿检测 
 always @ (posedge Clk)begin
  uart_rx_r[0] <= uart_rx;
  uart_rx_r[1] <=  uart_rx_r[0];
 end
 
 wire pedge_uart_rx;
//  assign pedge_uart_rx =((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1)); [1]是前一个时刻,[0]是新来的一个时刻 D触发器
 assign  pedge_uart_rx =(uart_rx_r == 2'b01);
 wire  nedge_uart_rx;
 // assign   nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));
 assign  nedge_uart_rx =(uart_rx_r == 2'b10);
 
 reg [8:0]  Bps_DR;  //波特率选择器
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 1;
            1:Bps_DR = 1000000000/19200/16/20 - 1;
            2:Bps_DR = 1000000000/38400/16/20 - 1;
            3:Bps_DR = 1000000000/57600/16/20 - 1;
            4:Bps_DR = 1000000000/115200/16/20 - 1;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase
        
 wire bps_clk_16x;
 assign bps_clk_16x = (div_cnt == Bps_DR / 2) ;  //采样时钟
 
 reg RX_EN;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
  RX_EN <= 0;
  else if (nedge_uart_rx)
   RX_EN <= 1;
   else if ((Rx_Done)|| (sta_bit >= 4))   //接收完或者sta不是正确的起始位
    RX_EN <= 0;
 
 reg [8:0] div_cnt;                  //分频器,分出每一次采样的时间。
  always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
  div_cnt <= 0;                 //检测到下降沿的时候开始计数
 else if (RX_EN)begin          /*else if (nedge_uart_rx)此语句不成立,因为nedge是一个瞬时的过程,只维持一个时钟周期,
                                  div只能加一次。需要以nedge为起点来使能div,知道数据接收完成或者发现不是起始位的时候再来停止。
                                   所以需要再产生一个使能的电平计数控制信号RX_EN*/
   if(div_cnt == Bps_DR)
   div_cnt <= 0;
  else 
   div_cnt <=  div_cnt + 1'b1;
   end                               //返回上方bps_clk_16x
  else
    div_cnt <= 0; 
    
 reg [7:0] bps_cnt;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
   bps_cnt <= 0;
else if (RX_EN) begin
   if(bps_clk_16x)begin
     if(bps_cnt == 160)
       bps_cnt <= 0; 
  else 
      bps_cnt <= bps_cnt + 1'b1;     //采样信号来了加一
 end
 else 
      bps_cnt <= bps_cnt;             //采样信号没来保持不变
 end
 else 
    bps_cnt <= 0;
 
 
 //采样数据接收模块
 reg [2:0] r_data [7:0];   // reg with name number    有8个位宽为[2:0]的r_data寄存器。
               // r_data[0][1]  意味着取第零个寄存器的第一位。 
 reg [2:0] sta_bit;
 reg [2:0] sto_bit;
 always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)begin
    sta_bit <= 0;
    sto_bit <= 0;
    r_data[0] <= 0;   //多位宽寄存器数据定义只能一个一个来。
    r_data[1] <= 0;
    r_data[2] <= 0;
    r_data[3] <= 0;
    r_data[4] <= 0;
    r_data[5] <= 0;
    r_data[6] <= 0;
    r_data[7] <= 0;
 end
else if(bps_clk_16x) begin
   case(bps_cnt)
        0 :  begin
        sta_bit <= 0;
    sto_bit <= 0;
    r_data[0] <= 0;   //多位宽寄存器数据定义只能一个一个来。
    r_data[1] <= 0;
    r_data[2] <= 0;
    r_data[3] <= 0;
    r_data[4] <= 0;
    r_data[5] <= 0;
    r_data[6] <= 0;
    r_data[7] <= 0;
 end  /*   5 : sta_bit <=sta_bit + 1'b1;
       6 : sta_bit <=sta_bit + 1'b1;
       7 : sta_bit <=sta_bit + 1'b1;*/
            5,6,7,8,9,10,11 : sta_bit <= sta_bit <=sta_bit + uart_rx;// 从第五位开始计数,累加情况取决于uart_rx给出的状态,若最后 sta_bit数据大于四,则判断为高电平
       // 每一数据采样15次 下一数据的采样开始为16, 有效范围则在21开始。
            21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
            37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
            53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
            69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
            85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
            101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
            117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
            133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;  //什么多不做.
        endcase
    end
       
 always @(posedge Clk or negedge Reset_n)                 //数据状态判定模块
 if(!Reset_n)
       Data <= 0;
    else if ((bps_clk_16x) && (bps_cnt == 159)) begin    // 数据的最后一位,在此之后可输出结果
        Data[0] <=( r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
end   

always @(posedge Clk or negedge Reset_n)
 if(!Reset_n)
     Rx_Done  <= 0;
else if ((div_cnt == Bps_DR/2) && (bps_cnt == 160))
 Rx_Done <= 1;
else 
 Rx_Done <= 0;
 
endmodule

TB文件:

`timescale 1ns / 1ps

module uart_byte_rx_tb();

   reg Clk;
   reg Reset_n;
   wire [2:0]Baud_Set;
   reg uart_rx;
   wire [7:0]Data; 
   wire Rx_Done;
   
   assign Baud_Set = 4;
   
    uart_byte_rx uart_byte_rx(
        Clk,
        Reset_n,
        Baud_Set,
        uart_rx,
        Data,
        Rx_Done,  
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
       Reset_n = 0;
       uart_rx = 1;
       #201;
       Reset_n = 1;
       #200; 
       uart_tx_byte(8'h5a);
       #90000;
       uart_tx_byte(8'ha5);
       #90000;
       uart_tx_byte(8'h86);
       #90000;
       $stop;
    end
    
    task uart_tx_byte;
        input [7:0]tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;         
        end
    endtask
    
endmodule

在这里插入图片描述
此处可改写为:
Data[0] <= r_data[0][2];
// Data[1] <= r_data[1][2];
// Data[2] <= r_data[2][2];
// Data[3] <= r_data[3][2];
// Data[4] <= r_data[4][2];
// Data[5] <= r_data[5][2];
// Data[6] <= r_data[6][2];
// Data[7] <= r_data[7][2];

<think>好的,用户想了解串口数据发送接收的实验方法或代码示例。首先,我需要回顾一下之前提供的引用内容,里面涵盖了不同单片机(如51、STM32、ARM)的串口实现,以及Arduino的例子。用户可能希望有一个通用的指导,或者针对特定平台的示例。 首先,确定用户使用的硬件平台。但用户没有明确说明,所以可能需要提供多个平台的示例,或者给出一个通用的思路。例如,51单片机、STM32、Arduino的代码结构可能不同,但基本步骤相似:初始化串口参数(波特率、数据位、停止位等)、配置发送和接收函数、处理数据。接下来,引用中的资料提到了初始化串口、发送接收数据的方法。比如引用4中的Arduino代码使用Serial.available()检查数据,用Serial.read()读取。引用3提到51单片机使用SCON寄存器和P3引脚。引用2讨论STM32的串口配置。需要将这些信息整合,分步骤说明实验方法,并给出代码示例。用户可能需要具体的代码,所以需要选择常见的平台,比如Arduino和51单片机,因为它们的代码相对简单易懂。同时,要确保代码符合LaTeX格式要求,行内公式用$...$,独立公式用$$...$$,但代码部分可能不需要数学公式,所以主要注意代码块的使用。 另外,用户问题中的引用可能涉及不同实验步骤,比如接线、初始化、调试工具的使用。需要将这些步骤简要说明,比如硬件连接(TX、RX交叉连接,共地),软件配置(波特率设置),然后代码实现发送和接收。最后,生成相关问题,可能涉及串口通信的原理、不同单片机实现的差异、常见问题排查等。需要确保问题主题相关,帮助用户深入理解。现在,整理回答结构:先概述实验步骤,分硬件准备和软件实现,然后给出不同平台的代码示例,最后总结注意事项。确保引用正确,比如引用1提到接线和初始化,引用4展示Arduino代码,引用3和2讨论不同单片机的寄存器配置。</think>### 串口通信数据发送接收实验方法 #### 一、实验步骤 1. **硬件准备** - 将单片机的发送端(TX)接收端(RX)交叉连接,并确保共地[^1][^2]。 - 使用USB转TTL模块连接PC单片机(如需要上位机调试)[^1][^4]。 2. **软件配置** - 初始化串口参数:波特率(如9600)、数据位(8位)、停止位(1位)、校验位(无)[^2][^3]。 - 配置串口中断(若需异步接收)[^3][^5]。 3. **代码实现** - **发送数据**:将数据写入发送寄存器,通过TX引脚逐位输出[^2][^3]。 - **接收数据**:轮询或中断方式读取接收寄存器,通过RX引脚逐位获取[^3][^4]。 --- #### 二、代码示例(多平台) ##### 1. Arduino平台 ```cpp void setup() { Serial.begin(9600); // 初始化串口,波特率9600[^4] } void loop() { if (Serial.available() > 0) { char data = Serial.read(); // 读取一个字节 Serial.write(data); // 回传数据[^4] } } ``` ##### 2. 51单片机(查询方式) ```c #include <reg52.h> void UART_Init() { SCON = 0x50; // 模式1,允许接收 TMOD = 0x20; // 定时器1模式2 TH1 = 0xFD; // 波特率9600 TL1 = 0xFD; TR1 = 1; // 启动定时器[^3] } void main() { UART_Init(); while (1) { if (RI) { // 检测接收完成标志 RI = 0; SBUF = SBUF; // 回传数据[^3] } } } ``` ##### 3. STM32(HAL库) ```c void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart2) { HAL_UART_Transmit(&huart2, &rx_data, 1, 100); // 中断接收后回传[^2] HAL_UART_Receive_IT(&huart2, &rx_data, 1); // 重新启用接收 } } ``` --- #### 三、注意事项 1. **波特率一致性**:单片机上位机(如串口调试助手)需设置相同波特率[^1][^4]。 2. **数据格式**:8位数据位、1位停止位是常见配置[^2][^3]。 3. **抗干扰**:长距离通信时需添加电平转换芯片(如MAX232)[^1][^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值