
基于FPGA的数字钟——(一)串口通信模块
仿真波形图
接收后data_out数据
发布日期:2021-05-07 22:56:09
浏览次数:23
分类:精选文章
本文共 10220 字,大约阅读时间需要 34 分钟。
(一)串口通信模块设计
1.串口通信协议
UART通信的一帧一般由11到12位数据组成。1bit的起始位,检测为低电平表示数据开始传输;紧接着8bits的数据;然后是1bit的奇偶校验位,可以是奇校验或者偶校验;最后是1bit或2bits的停止位,必须为高电平,表示一个字符数据的传输结束。
其中校验位是可选的,用来检验数据是否传输正确。如果有校验位,则需要保证收发双方选择同样的一种检验方式。奇校验就是保证数据中的1是奇数,比如如果8bit数据中有3bits的1,校验位置0;如果有4bits的1,校验位置1。偶校验就是保证数据中的1是偶数。
原文链接:https://blog.csdn.net/FPGADesigner/article/details/75201194
波特率:波特率表示数据传输的速率,单位bps,表示位每秒。比如9600bps就表示1s可以传输9600bits的数据。异步收发没有时钟打拍来控制数据的传输,就需要保证收发双方在波特率设置上的一致。确保接收数据的完整性。
2.串口发送模块实现
默认采用115200的波特率。不使用校验位。设计一个波特率计数器对系统时钟进行分频而实现波特率时钟。
使用三段式状态机进行发送的时序控制,采用BCD码对状态进行编码。
`timescale 1ns / 1ps//// Company: NanJing University of Information Science & Technology// Engineer: Yang Cheng Yu// // Create Date: 2019/12/29 15:55:40// Design Name: uart_tx// Module Name: uart_tx// Project Name: Clock// Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //module uart_tx#( parameter BAUD_RATE = 115200)( input clk, input rst, output reg tx, input [7:0] data_in, input send_require, output reg wr, output reg tx_done ); localparam baud_cnt_max = 50_000_000/BAUD_RATE-1; reg[12:0] baud_cnt; reg[3:0] state; localparam IDLE =4'b0000; localparam START =4'b0001; localparam SEND_BIT0=4'b0011; localparam SEND_BIT1=4'b0010; localparam SEND_BIT2=4'b0110; localparam SEND_BIT3=4'b0100; localparam SEND_BIT4=4'b0101; localparam SEND_BIT5=4'b0111; localparam SEND_BIT6=4'b1111; localparam SEND_BIT7=4'b1110; wire sd_rq_pedge;//发送请求上升沿 reg sd_rq_temp0; reg sd_rq_temp1; assign sd_rq_pedge = (sd_rq_temp0)&(!sd_rq_temp1); reg cnt_en; reg cnt_full; always@(posedge clk or negedge rst)begin if(!rst)begin sd_rq_temp0 <= 1'b0; sd_rq_temp1 <= 1'b0; end else begin sd_rq_temp0 <= send_require; sd_rq_temp1 <= sd_rq_temp0; end end always@(posedge clk or negedge rst)begin if(!rst)begin baud_cnt <= 13'd0; cnt_full <= 1'b0; end else begin if(cnt_en) if(baud_cnt==baud_cnt_max)begin baud_cnt <= 13'd0; cnt_full <= 1'b1; end else begin baud_cnt <= baud_cnt + 1'b1; cnt_full <= 1'b0; end else begin baud_cnt <= 13'd0; cnt_full <= 1'b0; end end end always@(posedge clk or negedge rst)begin if(!rst) state <= IDLE; else case(state) IDLE:begin if(sd_rq_pedge) state <= START; else state <= IDLE; end START:begin if(cnt_full) state <= SEND_BIT0; else state <= START; end SEND_BIT0:begin if(cnt_full) state <= SEND_BIT1; else state <= SEND_BIT0; end SEND_BIT1:begin if(cnt_full) state <= SEND_BIT2; else state <= SEND_BIT1; end SEND_BIT2:begin if(cnt_full) state <= SEND_BIT3; else state <= SEND_BIT2; end SEND_BIT3:begin if(cnt_full) state <= SEND_BIT4; else state <= SEND_BIT3; end SEND_BIT4:begin if(cnt_full) state <= SEND_BIT5; else state <= SEND_BIT4; end SEND_BIT5:begin if(cnt_full) state <= SEND_BIT6; else state <= SEND_BIT5; end SEND_BIT6:begin if(cnt_full) state <= SEND_BIT7; else state <= SEND_BIT6; end SEND_BIT7:begin if(cnt_full) state <= IDLE; else state <= SEND_BIT7; end default:begin state <= IDLE; end endcase end always@(posedge clk or negedge rst)begin if(!rst)begin cnt_en <= 1'b0; tx <= 1'b1; wr <= 1'b1;//表明可写 tx_done <= 1'b0; end else case(state) IDLE:begin cnt_en <= 1'b0; tx <= 1'b1; wr <= 1'b1; tx_done <= 1'b0; end START:begin cnt_en <= 1'b1; tx <= 1'b0; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT0:begin cnt_en <= 1'b1; tx <= data_in[0]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT1:begin cnt_en <= 1'b1; tx <= data_in[1]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT2:begin cnt_en <= 1'b1; tx <= data_in[2]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT3:begin cnt_en <= 1'b1; tx <= data_in[3]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT4:begin cnt_en <= 1'b1; tx <= data_in[4]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT5:begin cnt_en <= 1'b1; tx <= data_in[5]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT6:begin cnt_en <= 1'b1; tx <= data_in[6]; wr <= 1'b0; tx_done <= 1'b0; end SEND_BIT7:begin cnt_en <= 1'b1; tx <= data_in[7]; wr <= 1'b0; tx_done <= 1'b1; end default:begin cnt_en <= 1'b0; tx <= 1'b1; wr <= 1'b0; tx_done <= 1'b0; end endcase end endmodule
仿真波形图

串口接收模块设计
`timescale 1ns / 1ps//// Company: NanJing University of Information Science & Technology// Engineer: Yang Cheng Yu// // Create Date: 2019/12/29 15:55:40// Design Name: uart_rx// Module Name: uart_rx// Project Name: Clock// Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //module uart_rx#( parameter BAUD_RATE = 115200)( input clk, input rst, input rx, output reg rd, output reg[7:0] data_out, output rx_done ); reg rx_done; localparam baud_cnt_max = 50_000_000/BAUD_RATE-1; localparam baud_cnt_half = (50_000_000/BAUD_RATE)/2-1; wire rx_pin_nedge;//rx_pin下降沿 reg rx_pin_temp0; reg rx_pin_temp1; reg[3:0] state; reg[12:0] baud_cnt; reg cnt_en; reg cnt_half; reg cnt_full; reg rx_over; reg[7:0] data_out_reg; localparam IDLE =4'b0000; localparam GET_START_BIT=4'b0001; localparam GET_BIT0 =4'b0011; localparam GET_BIT1 =4'b0010; localparam GET_BIT2 =4'b0110; localparam GET_BIT3 =4'b0100; localparam GET_BIT4 =4'b0101; localparam GET_BIT5 =4'b0111; localparam GET_BIT6 =4'b1111; localparam GET_BIT7 =4'b1110; assign rx_pin_nedge = (!rx_pin_temp0)&(rx_pin_temp1);//下降沿 always@(posedge clk or negedge rst)begin if(!rst)begin rx_pin_temp0 <= 1'b1; rx_pin_temp1 <= 1'b1; end else begin rx_pin_temp0 <= rx; rx_pin_temp1 <= rx_pin_temp0; end end always@(posedge clk or negedge rst)begin if(!rst)begin baud_cnt <= 13'd0; cnt_full <= 1'b0; cnt_half <= 1'b0; end else begin if(cnt_en) if(baud_cnt==baud_cnt_max)begin baud_cnt <= 13'd0; cnt_full <= 1'b1; cnt_half <= 1'b0; end else if(baud_cnt==baud_cnt_half)begin baud_cnt <= baud_cnt + 1'b1; cnt_full <= 1'b0; cnt_half <= 1'b1; end else begin baud_cnt <= baud_cnt + 1'b1; cnt_full <= 1'b0; cnt_half <= 1'b0; end else begin baud_cnt <= 13'd0; cnt_full <= 1'b0; cnt_half <= 1'b0; end end end always@(posedge clk or negedge rst)begin if(!rst)begin state <= IDLE; end else begin case(state) IDLE:begin if(rx_pin_nedge) state <= GET_START_BIT; else state <= IDLE; end GET_START_BIT:begin if(cnt_full) state <= GET_BIT0; else state <= GET_START_BIT; end GET_BIT0:begin if(cnt_full) state <= GET_BIT1; else state <= GET_BIT0; end GET_BIT1:begin if(cnt_full) state <= GET_BIT2; else state <= GET_BIT1; end GET_BIT2:begin if(cnt_full) state <= GET_BIT3; else state <= GET_BIT2; end GET_BIT3:begin if(cnt_full) state <= GET_BIT4; else state <= GET_BIT3; end GET_BIT4:begin if(cnt_full) state <= GET_BIT5; else state <= GET_BIT4; end GET_BIT5:begin if(cnt_full) state <= GET_BIT6; else state <= GET_BIT5; end GET_BIT6:begin if(cnt_full) state <= GET_BIT7; else state <= GET_BIT6; end GET_BIT7:begin if(cnt_full) state <= IDLE; else state <= GET_BIT7; end default:state <= IDLE; endcase end end always@(posedge clk or negedge rst)begin if(!rst)begin data_out_reg <= 8'b0000_0000; cnt_en <= 1'b0; rx_over <= 1'b0; rd <= 1'b1; rx_done <= 1'b0; end else begin case(state) IDLE:begin data_out_reg <= 8'b0000_0000; cnt_en <= 1'b0; rx_over <= 1'b0; rd <= 1'b1; rx_done <= 1'b0; end GET_START_BIT:begin data_out_reg <= 8'b0000_0000; cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; end GET_BIT0:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[0] <= rx_pin_temp0; else data_out_reg[0] <= data_out_reg[0]; end GET_BIT1:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[1] <= rx_pin_temp0; else data_out_reg[1] <= data_out_reg[1]; end GET_BIT2:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[2] <= rx_pin_temp0; else data_out_reg[2] <= data_out_reg[2]; end GET_BIT3:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[3] <= rx_pin_temp0; else data_out_reg[3] <= data_out_reg[3]; end GET_BIT4:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[4] <= rx_pin_temp0; else data_out_reg[4] <= data_out_reg[4]; end GET_BIT5:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[5] <= rx_pin_temp0; else data_out_reg[5] <= data_out_reg[5]; end GET_BIT6:begin cnt_en <= 1'b1; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; if(cnt_half) data_out_reg[6] <= rx_pin_temp0; else data_out_reg[6] <= data_out_reg[6]; end GET_BIT7:begin cnt_en <= 1'b1; rx_over <= 1'b1; rd <= 1'b0; rx_done <= 1'b1; if(cnt_half) data_out_reg[7] <= rx_pin_temp0; else data_out_reg[7] <= data_out_reg[7]; end default:begin data_out_reg <= data_out_reg; cnt_en <= 1'b0; rx_over <= 1'b0; rd <= 1'b0; rx_done <= 1'b0; end endcase end end always@(posedge clk or negedge rst)begin if(!rst) data_out <= 8'b0000_0000; else if(rx_over) data_out <= data_out_reg; else data_out <= data_out;//保持 endendmodule
状态机转移图



发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2025年03月23日 00时36分30秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
【Oozie】(三)Oozie 使用实战教学,带你快速上手!
2021-05-08
师兄面试遇到这条 SQL 数据分析题,差点含泪而归!
2021-05-08
C语言的数值溢出问题(上)
2021-05-08
8051单片机(STC89C52)以定时器中断模式实现两倒计时器异步计时
2021-05-08
vue项目通过vue.config.js配置文件进行proxy反向代理跨域
2021-05-08
android:使用audiotrack 类播放wav文件
2021-05-08
聊聊我的五一小假期
2021-05-08
数据库三个级别封锁协议
2021-05-08
ACM/NCPC2016 C Card Hand Sorting(upc 3028)
2021-05-08
ubuntu学习笔记-常用文件、命令以及作用(hosts、vim、ssh)
2021-05-08
SLAM学习笔记-求解视觉SLAM问题
2021-05-08
程序员应该知道的97件事
2021-05-08
create-react-app路由的实现原理
2021-05-08
openstack安装(九)网络服务的安装--控制节点
2021-05-08
shell编程(六)语言编码规范之(变量)
2021-05-08
vimscript学习笔记(二)预备知识
2021-05-08
Android数据库
2021-05-08
HTML基础,块级元素/行内元素/行内块元素辨析【2分钟掌握】
2021-05-08
STM8 GPIO模式
2021-05-08