verilog串口接收多个数据进行处理的实现方法

关于使用串口接收多个数据进行处理的问题,目前网上存在的关于verilog串口通信的资料都是属于讲解对于使用串口实现单个字符的接收与发送。而往往在使用串口进行通信时,接数据端都需要通过串口来接收很多数据,然后当所有数据都接收完或者达到某种条件后开始自己的后续工作。所以在这里我把自己的一些具体实现过程以及verilog源代码分享一下,希望对大家有帮助。
(这里只讲利用串口接收数据并处理的部分,发送那部分后面再分享)
先贴上网上很多的串口接收的代码,如下;

module my_uart_rx( clk,rst_n, rs232_rx,rx_data,rx_int, clk_bps,bps_start ); input clk; // 50MHz主时钟 input rst_n; //低电平复位信号 input rs232_rx; // RS232接收数据信号 input clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点 output bps_start; //接收到数据后,波特率时钟启动信号置位 output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 output rx_int; //接收数据中断信号,接收到数据期间始终为高电平 //---------------------------------------------------------------- reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; //接收数据寄存器,滤波用 wire neg_rs232_rx; //表示数据线接收到下降沿 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; rs232_rx3 <= 1'b0; end else begin rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2; end end //下面的下降沿检测可以滤掉<20ns-40ns的毛刺(包括高脉冲和低脉冲毛刺), //这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍) //(当然我们的有效低脉冲信号肯定是远远大于40ns的) assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; //接收到下降沿后neg_rs232_rx置高一个时钟周期 //---------------------------------------------------------------- reg bps_start_r; reg[3:0] num; //移位次数 reg rx_int; //接收数据中断信号,接收到数据期间始终为高电平 always @ (posedge clk or negedge rst_n) if(!rst_n) begin bps_start_r <= 1'bz; rx_int <= 1'b0; end else if(neg_rs232_rx) begin //接收到串口接收线rs232_rx的下降沿标志信号 bps_start_r <= 1'b1; //启动串口准备数据接收 rx_int <= 1'b1; //接收数据中断信号使能 end else if(num==4'd11) begin //接收完有用数据信息 ///将这个地方的num后面的数字改为了11.原来是12!! bps_start_r <= 1'b0; //数据接收完毕,释放波特率启动信号 rx_int <= 1'b0; //接收数据中断信号关闭 end assign bps_start = bps_start_r; //---------------------------------------------------------------- reg[7:0] rx_data_r; //串口接收数据寄存器,保存直至下一个数据来到 //---------------------------------------------------------------- reg[7:0] rx_temp_data; //当前接收数据寄存器 always @ (posedge clk or negedge rst_n) if(!rst_n) begin rx_temp_data <= 8'd0; num <= 4'd0; rx_data_r <= 8'd0; end else if(rx_int) begin //接收数据处理 if(clk_bps) begin //读取并保存数据,接收数据为一个起始位,8bit数据,1或2个结束位 num <= num+1'b1; case (num) 4'd1: rx_temp_data[0] <= rs232_rx; //锁存第0bit 4'd2: rx_temp_data[1] <= rs232_rx; //锁存第1bit 4'd3: rx_temp_data[2] <= rs232_rx; //锁存第2bit 4'd4: rx_temp_data[3] <= rs232_rx; //锁存第3bit 4'd5: rx_temp_data[4] <= rs232_rx; //锁存第4bit 4'd6: rx_temp_data[5] <= rs232_rx; //锁存第5bit 4'd7: rx_temp_data[6] <= rs232_rx; //锁存第6bit 4'd8: rx_temp_data[7] <= rs232_rx; //锁存第7bit default: ; endcase end else if(num == 4'd11) begin //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据///将这个地方的num后面的数字改为了11.原来是12!! num <= 4'd0; //接收到STOP位后结束,num清零 rx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中 end end assign rx_data = rx_data_r; endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

这里大致就是说串口接收单次数据的处理过程,接收完数据后产生发送标志位,开始发送数据,而对于这里要说的数据缓存处理有两种解决方法,
第一种:十六进制传送,所以每次传送有效数据为八位,因此定义一个寄存器 reg [23:0] rx_cnt;长度为8的整数倍,然后使用移位的方式对数据进行存储,上述代码中NUM计数到11即完成一次数据传输,所以在num=11的地方加入

                rx_cnt[7:0] <= rx_data_r;
                rx_cnt[23:8] <= rx_cnt[15:0] ;
                cnt <= cnt+1;//传送数据计数作用
                if(cnt==NUMBER)//当传送数据达到NUMBER个时候,执行后续程序
                begin
                cnt<=cnt;
                end
assign rx_data_out = (cnt==NUMBER)?rx_cnt:rx_data_out;
                  //传送数据达到NUMBER个时候,输出寄存器的数,
                  //此时寄存器含有传送的所有数据。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后把原本的输出口assign rx_data = rx_data_r;去掉,写新的输出
接收的完整代码如下:

//`timescale 1ns / 1ps module my_uart_rx( clk, rst_n, rs232_rx, rx_data, rx_int, start, clk_bps, bps_start, rom_en, rx_data_out ); input clk; // 50MHz主时钟 input rst_n; //低电平复位信号 input rs232_rx; // RS232接收数据信号 input clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点 output bps_start; //接收到数据后,波特率时钟启动信号置位 output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 output rx_int; //接收数据中断信号,接收到数据期间始终为高电平 output reg start; output wire [23:0] rx_data_out; //---------------------------------------------------------------- reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; //接收数据寄存器,滤波用 wire neg_rs232_rx; //表示数据线接收到下降沿 reg [23:0] rx_cnt; always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin rs232_rx0 <= 1'b0; rs232_rx1 <= 1'b0; rs232_rx2 <= 1'b0; rs232_rx3 <= 1'b0; end else begin rs232_rx0 <= rs232_rx; rs232_rx1 <= rs232_rx0; rs232_rx2 <= rs232_rx1; rs232_rx3 <= rs232_rx2; end end //下面的下降沿检测可以滤掉<20ns-40ns的毛刺(包括高脉冲和低脉冲毛刺), //这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍) //(当然我们的有效低脉冲信号肯定是远远大于40ns的) assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; //接收到下降沿后neg_rs232_rx置高一个时钟周期 //---------------------------------------------------------------- reg bps_start_r; reg[3:0] num; //移位次数 reg rx_int; //接收数据中断信号,接收到数据期间始终为高电平 always @ (posedge clk or negedge rst_n) if(!rst_n) begin bps_start_r <= 1'bz; rx_int <= 1'b0; end else if(neg_rs232_rx) begin //接收到串口接收线rs232_rx的下降沿标志信号 bps_start_r <= 1'b1; //启动串口准备数据接收 rx_int <= 1'b1; //接收数据中断信号使能 end else if(num==4'd9) begin //接收完有用数据信息 ///将这个地方的num后面的数字改为了11.原来是12!! bps_start_r <= 1'b0; //数据接收完毕,释放波特率启动信号 rx_int <= 1'b0; //接收数据中断信号关闭 end assign bps_start = bps_start_r; //---------------------------------------------------------------- reg[7:0] rx_data_r; //串口接收数据寄存器,保存直至下一个数据来到 //---------------------------------------------------------------- reg[7:0] rx_temp_data; //当前接收数据寄存器 reg [5:0]cnt; //assign led = (cnt==10)?1:0; always @ (posedge clk or negedge rst_n) if(!rst_n) begin rx_temp_data <= 8'd0; num <= 4'd0; cnt<= 0; start<=0; rx_cnt<=24'b0; //rx_data_out <= 384'd0; rx_data_r <= 8'd0; end else if(rx_int) begin //接收数据处理 if(clk_bps) begin //读取并保存数据,接收数据为一个起始位,8bit数据,1或2个结束位 num <= num+1'b1; case (num) 4'd1: rx_temp_data[0] <= rs232_rx; //锁存第0bit 4'd2: rx_temp_data[1] <= rs232_rx; //锁存第1bit 4'd3: rx_temp_data[2] <= rs232_rx; //锁存第2bit 4'd4: rx_temp_data[3] <= rs232_rx; //锁存第3bit 4'd5: rx_temp_data[4] <= rs232_rx; //锁存第4bit 4'd6: rx_temp_data[5] <= rs232_rx; //锁存第5bit 4'd7: rx_temp_data[6] <= rs232_rx; //锁存第6bit 4'd8: rx_temp_data[7] <= rs232_rx; //锁存第7bit default: ; endcase end else if(num == 4'd9) begin //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据///将这个地方的num后面的数字改为了11.原来是12!! num <= 4'd0; //接收到STOP位后结束,num清零 rx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中 cnt <= cnt+1; rx_cnt[7:0] <= rx_data_r; rx_cnt[23:8] <= rx_cnt[15:0] ; if(cnt==NUMBER)//当传送数据达到NUMBER个时候,执行后续程序 begin cnt<=cnt; start<=1;//数据接收完成信号 end end end assign rx_data_out = (cnt==6'd48)?rx_cnt:rx_data_out; endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118

波特率配置程序网上代码很多,这里就不贴出来了。

(0)

相关推荐

  • 【精品博文】串口接收模块电路设计

    概述 串口通信指串口按位(bit)发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据.这里主要讲解串口接收模块的电路设计. 图1 串口传输时 ...

  • 【精品博文】详细解析基于FPGA的LCD1602驱动控制

    赢一个双肩背包 有多难? 戳一下试试看! →_→ 长摁识别 [主题]:详细解析基于FPGA的LCD1602驱动控制 [作者]:LinCoding [时间]:2016.11.23 这周末去找女票玩了,回 ...

  • 一天一个设计实例-3万字讲解UART和实例

    用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART.它将要传输的资料在串行通信与并行通信之间加以转换.作为把并行输入信号转成串 ...

  • 一天一个设计实例-任意分频器设计

    (一)分频器相关原理1.DDS原理任意分频原理起源于DDS(Direct Digital Synthesizer,直接频率合成法)的原理,DDS是重要的频率合成方法,在波形发生器中占有举足轻重的地位. ...

  • 二进制转BCD码

    应用: 用fpga实现对数码管显示,以前通常的方法是进行整除和取余进行运算,但是fpga并不擅长乘法除法运算,所以可以用BCD码来转换. BCD码:通俗的可以理解为用四位二进制数表示一位十进制数字.例 ...

  • 【精品博文】详细解析基于FPGA的串口通信

    赢一个双肩背包 有多难? 戳一下试试看! →_→ 长摁识别 [主题]:详细解析基于FPGA的串口通信 [作者]:LinCoding [时间]:2016.11.28 串口通信,用的实在太广泛了,原理也很 ...

  • 串口协议FPGA实现

    嵌入式专栏 152篇原创内容 公众号 来源 | 电子电路开发学习 标准串口协议的Verilog实现 基于Verilog实现标准串口协议发送8位数据:起始位 + 8位数据位 + 校验位 + 停止位 = ...

  • STM32串口空闲中断接收不定长数据(DMA方式)

    在使用STM32的串口接收数据的时候,我们常常会使用接收中断的方式来接收数据,常用的是RXNE.这里分享另一种接收数据的方式--IDLE中断(PS:本文的例子运行在STM32F103ZET6上). 一 ...

  • 成功vue el-date-picker后台接收不到数据解决

    以前是这样,接收不到数据 <el-table-column prop="TreatmentTime" label="治疗时间" align="c ...

  • 附源码-终极串口接收(二)

    来源:公众号[鱼鹰谈单片机] 作者:鱼鹰Osprey ID   :emOsprey 前段时间需要写个串口接收程序,一时没找到源码,就想着自己写过一篇文章<终极串口接收方式,极致效率>,看看 ...

  • 终极串口接收方式,极致效率

    在上一篇笔记<如何写一个健壮且高效的串口接收程序?>中鱼鹰分析了串口接收的一些坑,这些经验对于写一个好的串口接收程序是很有帮助的,而且笔记中最后得出一个串口接收的总结"空闲中断 ...

  • 如何写一个健壮且高效的串口接收程序?

    导读:学单片机的大概最先.最常写的通信程序应该就是串口程序了,但是如何写出一个健壮且高效的串口接收程序呢?接下来鱼鹰将根据多年的开发经验教你如何编写串口接收程序(可在公众号获取个人编写的串口接收源码) ...

  • TCP通信接收数据不完整的解决方法

    一.TCP协议.Socket编程流程 TCP/IP协议及socket封装 套接字的编程流程: 二.Send 和 Recv的基本介绍 2.1 Send函数 int send( SOCKET s, con ...

  • stm32的串口接收字符串以十六进制数

    #include 'pbdata.h' uint8_t TxBuffer1[] = 'USART Interrupt Example: This isUSART1 DEMO';   uint8_t R ...

  • 太好了,这本期刊明确接收生信数据文章而且不要版面费

    这本期刊是有明确规定接收生信数据挖掘类文章: Target identification and validation Assay design, development, miniaturizati ...

  • vs c 串口接收代码

    #include<stdio.h> #include <iostream> #include <windows.h> #include <atltime.h& ...