这篇博文主要解决在双通道幅频相可调的DDS信号发生器中串口连续接收一帧信息时时间间隔和接收实现问题。

1. 多个字节接收如何实现?

2. 目前常见的是uart传输8bit信息,但是如果要传输一帧,多个字节时,他们之间的间隔将多长?

一、UART接收协议代码编写:

主要包含波特率时钟生成、数据采样接收、标志信号生成;

1. 模块分析

时钟问题:1)为了避免使用组合逻辑产生的时钟触发导致的毛刺问题,所有的模块的时钟均采用系统时钟或者PLL产生的时钟,然后用组合逻辑产生的时钟作为使能;

2) 需要对波特率时钟产生,计数,用于接收每bit信号时判断;

3)为了对输入的每bit信号进行采样,需要在波特率时钟的基础上再计数并生成一个系统时钟高电平的采样时钟,方便再采样时钟到来时,将输入的数据寄存,并将所有采样点数据累加,判断

输入的 究竟是1还是0;

数据采样接收:专门用一个模块data_samp来对每一bit的信号进行6次采样,在每次波特率时钟clk_bps上升沿到来时开始计数,计满5028/6时采样计数+1,并使采样时钟为高电平(其余时间为低电平),以便每次采样时钟到来时对数据进行累加,并在最后一个采样时钟时对数据判断时1还是0;

标志信号生成:在串口信后接收或者每bit数据采样过程中,均需要产生_state的状态信号,以便在接收或者采样过程中对状态的判断或者计数,让不在过程中时,状态保持低电平。同时还能有效降低功耗,及波形分析复杂度。

2. 代码

如下是单bit采样模块及UART接收8比特数据模块。

/*****************file function: uart signal continuous receiverfile cretor: MEMEMEdata:2021-06-09******************/
module uart_ctrl(input clk,rst_n,   //clk=50Minput data_in,output [7:0]uart_data_out,output wire rev_end,output reg rev_state);reg [12:0]bps_cnt;
reg clk_bps;
reg [4:0]clk_bps_cnt;
reg error_state;
reg [7:0]uart_data_out_r;
wire uart_data_in;
wire start_flag;
assign uart_data_out=(rev_end)? uart_data_out_r:8'dZ;
assign rev_end=(clk_bps_cnt==11)?1'b1:1'b0;/***********bps generate********************/// different bps' timepiece
parameter t_9600_cnt  =5028,   //9600 bpst_19200_cnt =2604,   //19200 bpst_38400_cnt =1302,   t_57600_cnt =868,t_115200_cnt=434;always @(posedge clk or negedge rst_n)beginif(~rst_n)  bps_cnt<=0;else if (rev_state)if (bps_cnt==t_9600_cnt-1) bps_cnt<=0;else bps_cnt<=bps_cnt+1'b1;else bps_cnt<=0;endalways @(posedge clk or negedge rst_n)beginif(~rst_n) clk_bps<=0;else if (rev_state)if(bps_cnt==1) clk_bps<=1;else  clk_bps<=0;else  clk_bps<=clk_bps;end
always@(posedge clk or negedge rst_n)beginif(~rst_n) clk_bps_cnt<=0;else if (rev_state)if(clk_bps) clk_bps_cnt<=clk_bps_cnt+1'b1;else clk_bps_cnt<=clk_bps_cnt;else clk_bps_cnt<=0;end/************bps generate end *****************/always @(posedge clk or negedge rst_n)beginif(~rst_n) rev_state<=0;else if(start_flag) rev_state<=1;else if(rev_end) rev_state<=0;else rev_state<=rev_state;end/********************protol process***************************/
always @(posedge clk or negedge rst_n)beginif(~rst_n)begin error_state<=0;endelse if (rev_state)begincase(clk_bps_cnt)1:beginif (uart_data_in==0) error_state<=0;else error_state<=1;end2:beginuart_data_out_r[0]<=uart_data_in;error_state<=0;end3:beginuart_data_out_r[1]<=uart_data_in;end4:beginuart_data_out_r[2]<=uart_data_in;end5:beginuart_data_out_r[3]<=uart_data_in;end6:beginuart_data_out_r[4]<=uart_data_in;end7:beginuart_data_out_r[5]<=uart_data_in;end8:beginuart_data_out_r[6]<=uart_data_in;end9:beginuart_data_out_r[7]<=uart_data_in;end10:beginif (uart_data_in==1) error_state<=0;else error_state<=1;enddefault:;endcaseendenddata_samp data_samp(.clk(clk),.rst_n(rst_n),.data_in(data_in),.clk_bps(clk_bps),.uart_data_in(uart_data_in),.start_flag(start_flag));
endmodule
module data_samp(input clk,rst_n,input clk_bps,input data_in,output reg uart_data_in,output start_flag);// input data register
reg [1:0]data_in_r;
reg [3:0]uart_data_in_r;
reg [9:0]samp_rate_cnt;
reg [4:0]samp_cnt;
reg clk_bps_r;
reg clk_samp;
reg samp_state;
wire samp_start_flag;
wire data_samp_end;
parameter t_9600_cnt  =5028,   //9600 bpst_19200_cnt =2604,   //19200 bpst_38400_cnt =1302,   t_57600_cnt =868,t_115200_cnt=434;assign samp_start_flag =(~clk_bps_r && clk_bps)?1'b1:1'b0;
assign start_flag=(data_in_r[1] && ~data_in_r[0])? 1'b1:1'b0;   // negedge data
assign data_samp_end=(samp_cnt==7)?1'b1:1'b0;  //?????????????6/7?always @(posedge clk or negedge rst_n)beginif(~rst_n)begindata_in_r[1]<=0;data_in_r[0]<=0;endelse begindata_in_r[0]<=data_in;data_in_r[1]<=data_in_r[0];endend//one bit' sample rate
always @(posedge clk or negedge rst_n)beginif(~rst_n)clk_bps_r<=0;else clk_bps_r<=clk_bps;endalways @(posedge clk or negedge rst_n)beginif(~rst_n) samp_state<=0;else if(samp_start_flag) samp_state<=1;else if(data_samp_end) samp_state<=0;else samp_state<=samp_state;endalways @(posedge clk or negedge rst_n)beginif(~rst_n) samp_rate_cnt<=0;else if(samp_state)if(samp_rate_cnt==t_9600_cnt/7) samp_rate_cnt<=0;else samp_rate_cnt<=samp_rate_cnt+1'b1;  else samp_rate_cnt<=0;endalways @(posedge clk or negedge rst_n)beginif(~rst_n) samp_cnt<=0;else if (samp_state)if(clk_samp)samp_cnt<=samp_cnt+1'b1;else samp_cnt<=samp_cnt;else samp_cnt<=0;end
always @(posedge clk or negedge rst_n)beginif(~rst_n) clk_samp<=0;else if(samp_rate_cnt==t_9600_cnt/14) clk_samp<=1;else clk_samp<=0;endalways @(posedge clk or negedge rst_n)beginif(~rst_n)   beginuart_data_in_r<=0;endelse if (samp_state)beginif (clk_samp)begincase(samp_cnt)1: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; end2: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; end3: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; end4: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; end5: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; end6: begin uart_data_in_r <= uart_data_in_r+data_in_r[1]; enddefault: ;endcaseendendelse uart_data_in_r<=0;
end
always @(posedge clk or negedge rst_n)beginif(~rst_n)  uart_data_in<=0;else if(samp_cnt==6)if(uart_data_in_r[2]==1) uart_data_in<=1;else uart_data_in<=0;else uart_data_in<=uart_data_in;end
endmodule

仿真可以识别多byte的传输,每byte间间隔2000ns结果如下:

若多byte连续传输时,结果如下:仿真结果出错,因此 ,byte之间需要间隔。

修改:保证两个数据8bit之间有一点时间即可,及上一个数据结束位不会紧挨着下一数据的起始位即可。

协议改进:其实在采样模块,将波特率时钟再分成6个采样时钟,但是每个采样点所执行的命令是一样的。而在串口协议中,需要接收8比特的信号,加上前后的起始位和结束位,一共10bit信号,这10比特需要分开依次判断。所以没必要把采样单独拎出来作为一个模块,并计数和生成采样时钟,可以直接将串口接收的波特率时钟周期再缩小,每次对6个小时钟进行判断。

其次,输出在模块输出串口数据是最好不要用高阻态,因为这样的话只有在一段时间内有值,其余时间内为高阻态,不方便下一个模块对数据寄存和处理。

二、多字节传输:

本次一帧需要连续传输8个字节,而uart每次输出1个字节,因此多字节传输模块只要在一帧开始即第一字节传输进来时产生起始信号,在第8字节传输进来后产生结束一帧信号接收,同时若中间两个字节传输间隔过长,则产生中断错误信号,数据重新开始接收。

代码如下:

module uart_frames_transmit(input [7:0]uart_data,input clk,rst_n,input uart_end,output reg [63:0]fram_data,output reg fram_end,fram_begin);reg [3:0]uart_end_cnt;
reg uart_end_r;
reg [17:0]fram_rduart_tim;reg error_interrupt;
reg fram_rddata_flag;
reg[3:0]fram_rddata_flag_cnt;
wire uart_end_flag;
wire fram_state;
assign fram_state=(fram_rddata_flag_cnt>=4'd1 && fram_rddata_flag_cnt<=4'd8)?1'b1:1'b0;//*****uart transimit 1 bytes end flag******//
assign uart_end_flag=(!uart_end_r & uart_end)? 1'b1:1'b0;
always @(posedge clk or negedge rst_n) beginif(~rst_n) uart_end_r<=0;else uart_end_r<=uart_end;end
always @(posedge clk or negedge rst_n) beginif(~rst_n) uart_end_cnt<=0;else if(uart_end_flag) uart_end_cnt<=uart_end_cnt+1'b1;else uart_end_cnt<=uart_end_cnt;end//*****time counter of register input data ******//
always @(posedge clk or negedge rst_n) beginif(~rst_n) fram_rduart_tim<=0;else if(fram_rduart_tim>=100560) fram_rduart_tim<=0; else if(uart_end_flag) fram_rduart_tim<=18'd1;else if(fram_rduart_tim>0) fram_rduart_tim<=fram_rduart_tim+1'b1;       else fram_rduart_tim<=0;end
always @(posedge clk or negedge rst_n) beginif(~rst_n)  fram_rddata_flag<=0; else if(fram_rduart_tim==20000) fram_rddata_flag<=1; // reader uart data at 20000*20ns after flag=1 else fram_rddata_flag<=0; end
always @(posedge clk or negedge rst_n) beginif(~rst_n) fram_rddata_flag_cnt<=0;else if(error_interrupt) fram_rddata_flag_cnt<=0;else if(fram_rddata_flag_cnt<4'd8)if(fram_rddata_flag) fram_rddata_flag_cnt<=fram_rddata_flag_cnt+1'b1;else fram_rddata_flag_cnt<=fram_rddata_flag_cnt;else fram_rddata_flag_cnt<=0;end  //*****uart transmition interrupt request******//
always @(posedge clk or negedge rst_n) beginif(~rst_n) error_interrupt<=0;else if(fram_rduart_tim==100560 && fram_rddata_flag_cnt!=4'd8) error_interrupt<=1;else error_interrupt<=0;end//*****frames transmit flag******//
reg fram_rddata_flag_r;
always @(posedge clk or negedge rst_n) beginif(~rst_n) fram_rddata_flag_r<=0;else fram_rddata_flag_r<=fram_rddata_flag;end
always @(posedge clk or negedge rst_n) beginif(~rst_n) beginfram_begin<=0;fram_end<=0;endelse if(fram_rddata_flag_cnt==1 && fram_rddata_flag_r) beginfram_begin<=1;fram_end<=0;endelse if(fram_rddata_flag_cnt==8)beginfram_begin<=0;fram_end<=1;endelse beginfram_begin<=0;fram_end<=0;endendalways @(posedge clk or negedge rst_n) beginif(~rst_n)  beginfram_data<=0;endelse if (error_interrupt) fram_data<=0;else if(fram_state && fram_rddata_flag_r)  fram_data<={fram_data[55:0],uart_data};  else fram_data<= fram_data;endendmodule

仿真结果如下:

可以看出在每次信号传输进来后,先产生每字节读数据的flag,然后将输入的数据保存到fram_data中,并对输入的字节计数,如果有中断错误信号,则fram传输结束,fram_data清零,重新计数并接收信号。如果没有中断,则连续接收8字节数据后结束一帧的传输。如下所示:在一帧结束时,输出完整的8字节信号:AA 03 00 8E 21 00 00 88;

test bench代码如下:

`timescale 10ns/10ns
`define clk_period 20      //50Mmodule uart_top_tb();reg clk,rst_n;  //clk=50Mreg  data;wire [63:0]fram_data;wire fram_end,fram_begin;uart_top uart_top(.clk(clk),.rst_n(rst_n),.uart_din(data),.fram_data(fram_data),.fram_end(fram_end),.fram_begin(fram_begin));initial clk=1'b1;
always #(`clk_period/2) clk=~clk;task byte_trm;
input [7:0]data_r;
//input bps_tim;    //uart's bps_clk
begin#(`clk_period*200);data=0;#(`clk_period*5028);data=data_r[0];#(`clk_period*5028);data=data_r[1];#(`clk_period*5028);data=data_r[2];#(`clk_period*5028);data=data_r[3];#(`clk_period*5028);data=data_r[4];#(`clk_period*5028);data=data_r[5];#(`clk_period*5028);data=data_r[6];#(`clk_period*5028);data=data_r[7];#(`clk_period*5028);data=1;#(`clk_period*5028);end
endtaskinitial beginrst_n=0;data=1;#(`clk_period*200);rst_n=1;#(`clk_period*20);byte_trm(8'hAA);#(`clk_period*2000);byte_trm(8'h03);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*60000);#(`clk_period*20);byte_trm(8'hAA);#(`clk_period*2000);byte_trm(8'h03);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h8e);#(`clk_period*2000);byte_trm(8'h21);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h88);#(`clk_period*60000);byte_trm(8'hAA);#(`clk_period*2000);byte_trm(8'h03);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*60000);#(`clk_period*20);byte_trm(8'hAA);#(`clk_period*2000);byte_trm(8'h03);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h8e);#(`clk_period*2000);byte_trm(8'h21);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h00);#(`clk_period*2000);byte_trm(8'h88);#(`clk_period*60000);$stop;end
endmodule

顶层模块代码如下:

module uart_top(input clk,rst_n,input uart_din,output [63:0]fram_data,output fram_end,fram_begin);wire [7:0]uart_data_out;
wire rev_state;
uart_ctrl uart_ctrl(.clk(clk),.rst_n(rst_n),.data_in(uart_din),.uart_data_out(uart_data_out),.rev_end(rev_end),.rev_state());
uart_frames_transmit uart_frames_transmit(.uart_data(uart_data_out),.clk(clk),.rst_n(rst_n),.uart_end(rev_end),.fram_data(fram_data),.fram_end(fram_end),.fram_begin(fram_begin));endmodule

以上代码功能虽然是实现了,但是整体的代码分了抽样、串口信号接收、帧信号接收以及顶层模块,用了4个文件编写整个代码,对于实现连续串口信号接收这一小小功能来说有点框架累赘(文件有点多)。

实战篇:UART串口连续接收实现相关推荐

  1. stm32串口接收不定长数据_基于STM32之UART串口通信协议--接收

    一.前言 1.简介 回顾上一篇UART发送当中,已经讲解了如何实现UART的发送操作了,接下来这一篇将会继续讲解如何实现UART的接收操作. 2.UART简介 嵌入式开发中,UART串口通信协议是我们 ...

  2. 应用:使用uart串口接收模块接收信号,控制led灯闪烁

    功能描述: 使用遵循uart协议的接收模块接收控制信号,用来控制led的闪烁. 设计输入: 1.uart输入信号 2.时钟信号 3.复位信号 4.led信号 设计思路: 总体上:前面已经写了串口接收模 ...

  3. python串口连续数据_Python代码从串口连续接收可变数据

    通常,您与微通信所做的工作是将单个字符用于轻量级或创建通信协议.基本上你有一个开始标志,结束标志和某种校验和,以确保数据正确传输.有很多方法可以做到这一点. 以下代码适用于Python 3.您可能必须 ...

  4. rtthread 串口dma接收_RT-Thread 设备驱动UART浅析

    OS版本:RT-Thread 4.0.0 芯片:STM32F407 RT-Thread的串口驱动框架与Linux相识,分成 I/O设备框架 + 设备底层驱动: 1. serial设备初始化及使用 将配 ...

  5. ZYNQ进阶之路14--PS端uart串口接收不定长数据

    ZYNQ进阶之路14--PS端uart串口接收不定长数据 导语 ZYNQ串口简介 实现步骤 导语 繁忙的博主又来了,本节我们实现一个比较简单的东西:串口.之前的章节中我们也有使用PS端的串口进行收发数 ...

  6. DY-SV17F语音播放模块应用篇二 【UART 串口模式】

    UART 串口模式 是采用波特率为9600的全双工串口通信. 语音模块做为从机处理,上电默认等待状态,所有播放操作全由主机控制. 从机不会主动发起通信,所有通信都是由主机发起. 串口模式接线图: 使用 ...

  7. 树莓派UART串口编程--使用wiringPi库-C开发【1-基础应用】

    一.串口说明 莓派3B+上UART串口位于GPIO的8脚和10脚,分别为GPIO8=Tx,GPIO10=Rx.在连接外部接口时,需要交换接口,即GPIO8连接到外设的Rx,GPIO10连接到外设的Tx ...

  8. stm32的rxne和idle中断_STM32 HAL CubeMX 串口IDLE接收空闲中断+DMA

    历程详解 详解包括: 中断原理讲解 例程流程详解 库函数分析详解 对应寄存器介绍 对应函数介绍 对应注释详解 本篇文章提供两种方法: 一种是 :IDLE 接收空闲中断+DMA 一种是: IDLE 接收 ...

  9. 【蓝桥杯】单片机学习(7)——UART串口通信

    UART串口通信 一.基础知识介绍 1.通信方式的分类 2.RS232通信接口 3.UART模块介绍 (1)串口控制寄存器SCON(可位寻址) (2)电源控制寄存器PCON(不可位寻址) (3)辅助寄 ...

最新文章

  1. Bagging与随机森林算法原理小结
  2. GetLogicalDriveStringS获取驱动器根路径
  3. 怎么将算法改成程序_多肉烂根怎么办?将土培改成水培,长势好,叶子变得更水灵...
  4. java集合类——Stack栈类与Queue队列
  5. 【tensorflow】tf.layers.conv1d函数解析(一维卷积)
  6. ASP.NET Core IHostEnvironment和IApplicationLifetime介绍
  7. python基础课程2(看代码看注释)--条件判断|循环|函数|生成器|类
  8. jdbcTemplate查询方法
  9. python + selenium 练习篇 - 定位元素的方法
  10. 深入解析MVVM架构
  11. POJ NOI0105-32 求分数序列和
  12. arraylist/vector add()方法诡异之---多次add进去的对象最终都变成最后一次add进去的对象值...
  13. android仿饿了么筛选,Android仿饿了么搜索功能
  14. 常见电平信号、RS232与RS485相关知识总结
  15. TYPEC 接口芯片CC逻辑原理与必要性
  16. 【AcWing】AcWing 2. 01背包问题
  17. 莫言教学常启迪学生多动脑 主张把自己当罪人写-莫言-诺贝尔文学奖-兰传斌
  18. 怎么打云开服务器iis_云服务器怎么重启iis
  19. Google搜索的10个小技巧,部分适用于百度
  20. 视频直播APP开发分析

热门文章

  1. 重启 mysql_重启MySQL的正确方法
  2. RTOS随笔之FreeRTOS
  3. MIT操作系统实验lab1(pingpong案例:附代码、详解)
  4. python 长度为8-10位的用户密码 : 包含数字字母下划线 正则表达式(简单易懂,代码可以指运行)
  5. 27岁,月薪税前15000多吗?
  6. SEO工具之外链检查工具
  7. php熊掌号api,thinkphp5.1如何实现熊掌号资源API提交功能?
  8. MySQL正则表达式判断身份证_php正则判断是否为合法身份证号的方法
  9. 仙剑缘_仙剑缘手游最新单机版客户端下载-仙剑缘单机版v1.3.2 安卓版-腾牛安卓网...
  10. 没有带手机的一个星期