回到梦开始的地方,如今回过头来看串口协议,确实清晰了很多,但是奈何好记性不如烂笔头,我还是要重新记录一下学习的知识点,方便查找和学习。
波特率(Band Rate):
串口协议中很重要的一点就是波特率,波特率的概念是每秒钟传送码元的个数,就是一秒钟传输了几个二进制的个数,他的单位是Bit/s和bps两种。常见的串口速度有115200bps 9600bps等等,串口(RS232)的最大传输速率是 115200bps,表示一秒钟传输了115200个二进制 。
波特率和字节的关系
1GB=1024MB
1MB=1024KB
1KB=1024B(字节)
我们需要串口接收的数据数每秒512字节,串口的波特率是115200位/秒
波特率115200=115200(位/秒)
如果没有校验位,就应该除以10,得到的是每秒字节数:波特率115200=115200(位/秒)=11520(字节/秒)
再除以1024,就是每秒KB数:波特率115200=115200(位/秒)=11.25(KB/秒)也就是满足每秒可以接收512字节。
**在Verilog代码中,我们只需要理解计算这两个值就可以完成串口代码的梳理,**假设我们FPGA使用的是50MHZ的系统时钟 波特率使用的是9600bps 传输一个bit需要的时钟周期个数是50_000_000/9600个个数,得到个数之后再用这个个数乘以周期的时间便是传输1bit需要的时间50_000_000/9600*20便是1bit需要的时间。
1.串口通信的信号线只需要两条线就可以完成,TX和RX TX发送端 RX为接收端。
2.起始位,数据线从高变低,低有效为0,数据传输开始。
3.数据位,起始位传输之后便是数据位开始,一般为8位,传输时低位(LSB)在前,高位(MSB)在后。
4.校验位,校验位可以认为是一个特殊的数据位,通常使用的是奇偶校验,使用串口协议时通常取消奇偶校验位。
5.停止位,停止位高有效为1,他表示这一个个字节传输结束。
6.位时间,起始位、数据位、校验位的位宽度是一致的,停止位有0.5位、1位、1.5位格式,一般为1位。
7.空闲位,持续的高电平。
7.帧:从起始位开始到停止位结束的时间间隔称之为一帧。

首先约定波特率为9600(可变),无校验位
将数据线打两拍,防止亚稳态并捕获其的下降沿信号(起始位0)
检测到下降沿后拉高数据传输标志,意味着数据开始接收;并在传输第九个数据(终止位1)的正中(数据比较稳定)将数据传输标志拉低,意味着数据接收完成
对时钟进行计数,每一个周期(在设定波特率条件下传输一位所需要的时间)对数据线进行采样并将数据寄存,同时记录传输个数(记录当前共接收了多少个数据)
接收到第九个数据(终止位1)后,拉高接收完成标志位
————————————————
module uart_rx(
input sys_clk, //50M系统时钟
input sys_rst_n, //系统复位
input uart_rxd, //接收数据线
output reg uart_rx_done, //数据接收完成标志
output reg [7:0]uart_rx_data //接收到的数据
);
//常量化波特率,可更改
parameter BPS=9600; //波特率9600bps,可更改
parameter SYS_CLK_FRE=50_000_000; //50M系统时钟
localparam BPS_CNT=SYS_CLK_FRE/BPS; //传输一位数据所需要的时钟个数
reg uart_rx_d0; //寄存1拍
reg uart_rx_d1; //寄存2拍
reg [15:0] clk_cnt; //时钟计数器
reg [3:0] rx_cnt; //接收计数器
reg rx_flag; //接收标志位
reg [7:0] uart_rx_data_reg; //数据寄存
wire neg_uart_rx_data; //数据的下降沿
assign neg_uart_rx_data=uart_rx_d1 & (~uart_rx_d0); //捕获数据线的下降沿,用来标志数据传输开始
//将数据线打两拍,作用1:同步不同时钟域信号,防止亚稳态;作用2:用以捕获下降沿
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
uart_rx_d0<=1'b0;
uart_rx_d1<=1'b0;
end
else begin
uart_rx_d0<=uart_rxd;
uart_rx_d1<=uart_rx_d0;
end
end
//捕获到数据下降沿(起始位0)后,拉高传输开始标志位,并在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rx_flag<=1'b0;
else begin
if(neg_uart_rx_data)
rx_flag<=1'b1;
else if((rx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2))//在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
rx_flag<=1'b0;
else
rx_flag<=rx_flag;
end
end
//时钟每计数一个BPS_CNT(传输一位数据所需要的时钟个数),即将数据计数器加1,并清零时钟计数器
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
rx_cnt<=4'd0;
clk_cnt<=16'd0;
end
else if(rx_flag)begin
if(clk_cnt<BPS_CNT-1'b1)begin
clk_cnt<=clk_cnt+1'b1;
rx_cnt<=rx_cnt;
end
else begin
clk_cnt<=16'd0;
rx_cnt<=rx_cnt+1'b1;
end
end
else begin
rx_cnt<=4'd0;
clk_cnt<=16'd0;
end
end
//在每个数据的传输过程正中(数据比较稳定)将数据线上的数据赋值给数据寄存器
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
uart_rx_data_reg<=8'd0;
else if(rx_flag)
if(clk_cnt==BPS_CNT/2) begin
case(rx_cnt)
4'd1:uart_rx_data_reg[0]<=uart_rxd;
4'd2:uart_rx_data_reg[1]<=uart_rxd;
4'd3:uart_rx_data_reg[2]<=uart_rxd;
4'd4:uart_rx_data_reg[3]<=uart_rxd;
4'd5:uart_rx_data_reg[4]<=uart_rxd;
4'd6:uart_rx_data_reg[5]<=uart_rxd;
4'd7:uart_rx_data_reg[6]<=uart_rxd;
4'd8:uart_rx_data_reg[7]<=uart_rxd;
default:;
endcase
end
else
uart_rx_data_reg<=uart_rx_data_reg;
else
uart_rx_data_reg<=8'd0;
end
//当数据传输到终止位时,拉高传输完成标志位,并将数据输出
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
uart_rx_done<=1'b0;
uart_rx_data<=8'd0;
end
else if(rx_cnt==4'd9)begin
uart_rx_done<=1'b1;
uart_rx_data<=uart_rx_data_reg;
end
else begin
uart_rx_done<=1'b0;
uart_rx_data<=8'd0;
end
end
endmodule
————————————————
接收端仿真代码
`timescale 1ns/1ns //定义时间刻度
//模块、接口定义
module uart_rx_tb();
reg sys_clk;
reg sys_rst_n;
reg uart_rxd;
wire uart_rx_done;
wire uart_rx_data;
//例化被测试的接收模块
uart_rx #(
.BPS (9600), //波特率9600
.SYS_CLK_FRE (50_000_000)//时钟频率50M
)
u_uart_rx(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_rxd (uart_rxd),
.uart_rx_done (uart_rx_done),
.uart_rx_data (uart_rx_data)
);
localparam CNT=50_000_000/9600*20; //计算出传输每个时钟所需要的时间
initial begin //传输8位数据 8'b01010101
//初始时刻定义
sys_clk <=1'b0;
sys_rst_n<=1'b0;
uart_rxd<=1'b1;
#20 //系统开始工作
sys_rst_n<=1'b1;
#(CNT/2)
uart_rxd<=1'b0;//开始传输起始位
#CNT
uart_rxd<=1'b1;//传输最低位,第1位
#CNT
uart_rxd<=1'b0;//传输第2位
#CNT
uart_rxd<=1'b1;//传输第3位
#CNT
uart_rxd<=1'b0; //传输第4位
#CNT
uart_rxd<=1'b1;//传输第5位
#CNT
uart_rxd<=1'b0;//传输第6位
#CNT
uart_rxd<=1'b1;//传输第7位
#CNT
uart_rxd<=1'b0; //传输最高位,第8位
#CNT
uart_rxd<=1'b1; //传输终止位
end
always begin
#10 sys_clk=~sys_clk; //时钟20ns,50M
end
endmodule
————————————————
module uart_tx(
input sys_clk, //50M系统时钟
input sys_rst_n, //系统复位
input [7:0] uart_data, //发送的8位置数据
input uart_tx_en, //发送使能信号
output reg uart_txd //串口发送数据线
);
parameter SYS_CLK_FRE=50_000_000; //50M系统时钟
parameter BPS=9_600; //波特率9600bps,可更改
localparam BPS_CNT=SYS_CLK_FRE/BPS; //传输一位数据所需要的时钟个数
reg uart_tx_en_d0; //寄存1拍
reg uart_tx_en_d1; //寄存2拍
reg tx_flag; //发送标志位
reg [7:0] uart_data_reg; //发送数据寄存器
reg [15:0] clk_cnt; //时钟计数器
reg [3:0] tx_cnt; //发送个数计数器
wire pos_uart_en_txd; //使能信号的上升沿
//捕捉使能端的上升沿信号,用来标志输出开始传输
assign pos_uart_en_txd= uart_tx_en_d0 && (~uart_tx_en_d1);
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
uart_tx_en_d0<=1'b0;
uart_tx_en_d1<=1'b0;
end
else begin
uart_tx_en_d0<=uart_tx_en;
uart_tx_en_d1<=uart_tx_en_d0;
end
end
//捕获到使能端的上升沿信号,拉高传输开始标志位,并在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
tx_flag<=1'b0;
uart_data_reg<=8'd0;
end
else if(pos_uart_en_txd)begin
uart_data_reg<=uart_data;
tx_flag<=1'b1;
end
else if((tx_cnt==4'd9) && (clk_cnt==BPS_CNT/2))begin//在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
tx_flag<=1'b0;
uart_data_reg<=8'd0;
end
else begin
uart_data_reg<=uart_data_reg;
tx_flag<=tx_flag;
end
end
//时钟每计数一个BPS_CNT(传输一位数据所需要的时钟个数),即将数据计数器加1,并清零时钟计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
clk_cnt<=16'd0;
tx_cnt <=4'd0;
end
else if(tx_flag) begin
if(clk_cnt<BPS_CNT-1)begin
clk_cnt<=clk_cnt+1'b1;
tx_cnt <=tx_cnt;
end
else begin
clk_cnt<=16'd0;
tx_cnt <=tx_cnt+1'b1;
end
end
else begin
clk_cnt<=16'd0;
tx_cnt<=4'd0;
end
end
//在每个数据的传输过程正中(数据比较稳定)将数据寄存器的数据赋值给数据线
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
uart_txd<=1'b1;
else if(tx_flag)
case(tx_cnt)
4'd0: uart_txd<=1'b0;
4'd1: uart_txd<=uart_data_reg[0];
4'd2: uart_txd<=uart_data_reg[1];
4'd3: uart_txd<=uart_data_reg[2];
4'd4: uart_txd<=uart_data_reg[3];
4'd5: uart_txd<=uart_data_reg[4];
4'd6: uart_txd<=uart_data_reg[5];
4'd7: uart_txd<=uart_data_reg[6];
4'd8: uart_txd<=uart_data_reg[7];
4'd9: uart_txd<=1'b1;
default:;
endcase
else
uart_txd<=1'b1;
end
endmodule
————————————————
发送端仿真代码
`timescale 1ns/1ns //定义时间刻度
//模块、接口定义
module uart_tx_tb();
reg sys_clk;
reg sys_rst_n;
reg [7:0] uart_data;
reg uart_tx_en;
wire uart_txd;
//例化被测试的接收模块
uart_tx #(
.BPS (9600), //波特率9600
.SYS_CLK_FRE (50_000_000)//时钟频率50M
)
u_uart_tx(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_data (uart_data),
.uart_tx_en (uart_tx_en),
.uart_txd (uart_txd)
);
localparam CNT=50_000_000/9600*20; //计算出传输每个时钟所需要的时间
initial begin //传输8位数据 8'b01010101
//初始时刻定义
sys_clk <=1'b0;
sys_rst_n <=1'b0;
uart_tx_en <=1'b0;
uart_data <=8'b01010101;//发送数据 01010101
#20 //系统开始工作
sys_rst_n <=1'b1;
#(CNT/2)
uart_tx_en <=1'b1;
#20
uart_tx_en <=1'b0;
end
always begin
#10 sys_clk=~sys_clk; //时钟20ns,50M
end
endmodule
————————————————
module uart_top(
input sys_clk, //系统时钟
input sys_rst_n, //系统复位
input uart_rxd, //接收端口
output uart_txd //发送端口
);
parameter UART_BPS=9600; //波特率
parameter CLK_FREQ=50_000_000; //系统频率50M
wire uart_en_w;
wire [7:0] uart_data_w;
//例化发送模块
uart_tx#(
.BPS (UART_BPS),
.SYS_CLK_FRE (CLK_FREQ))
u_uart_tx(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_tx_en (uart_en_w),
.uart_data (uart_data_w),
.uart_txd (uart_txd)
);
//例化接收模块
uart_rx #(
.BPS (UART_BPS),
.SYS_CLK_FRE (CLK_FREQ))
u_uart_rx(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_rxd (uart_rxd),
.uart_rx_done (uart_en_w),
.uart_rx_data (uart_data_w)
);
endmodule
————————————————
顶层模块仿真代码
`timescale 1ns/1ns //定义时间刻度
//模块、接口定义
module uart_top_tb();
reg sys_clk;
reg sys_rst_n;
reg uart_rxd;
wire uart_txd;
//例化被测试的接收模块
uart_top #(
.UART_BPS (9600), //波特率9600
.CLK_FREQ (50_000_000)//时钟频率50M
)
u_uart_top(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_rxd (uart_rxd),
.uart_txd (uart_txd)
);
localparam CNT=50_000_000/9600*20; //计算出传输每个时钟所需要的时间
initial begin //传输8位数据 8'b01010101
//初始时刻定义
sys_clk <=1'b0;
sys_rst_n<=1'b0;
uart_rxd<=1'b1;
#20 //系统开始工作
sys_rst_n<=1'b1;
#(CNT/2)
uart_rxd<=1'b0;//开始传输起始位
#CNT
uart_rxd<=1'b1;//传输最低位,第1位
#CNT
uart_rxd<=1'b0;//传输第2位
#CNT
uart_rxd<=1'b1;//传输第3位
#CNT
uart_rxd<=1'b0; //传输第4位
#CNT
uart_rxd<=1'b1;//传输第5位
#CNT
uart_rxd<=1'b0;//传输第6位
#CNT
uart_rxd<=1'b1;//传输第7位
#CNT
uart_rxd<=1'b0; //传输最高位,第8位
#CNT
uart_rxd<=1'b1; //传输终止位
end
always begin
#10 sys_clk=~sys_clk; //时钟20ns,50M
end
endmodule
————————————————
将8位或者多位数据拆分为一位一位的发送出去的过程称为并转串。将一位一位接收的数据合并为8位或者多位数据的过程称为串转并。
对于串行通信设备来说,发送方都是在执行并转串,接收方都是在执行串转并。
UART设备为串行通信设备。
全双工通信、半双工通信和单工通信
全双工通信是指在同一时刻信息可以进行双向传输。例如:打电话,说的同时也能听。
半双工通信是指在同一时刻信息只能单向传输,双方都可以进行发送和接收,但是不能够同时发送和接收。例如:对讲机通信。
单工通信是指在通信过程中,只能够设备A发送,设备B接收。例如:听收音机。
SANXIN – B01的开发板上的UART接口设备可以做到半双工通信。
UART的通信电平标准
两个设备之间能够互相通信的基础条件为电平标准相同。UART的接口标准有很多,有RS232、RS485等等。
台式PC上一般会有一个DB9,接口标准为RS232。
此接口在各个工业板上也有很多。随着技术的发展,PC上的DB9的接口逐渐被淘汰,换成了USB接口。
我们的开发板上选择使用USB接口,方便大家学习,便于和PC进行通信。
FPGA芯片是无法(较为复杂)发出对应的电平标准,如:RS485、RS232、USB接口电平等。在大多数板卡设计时,都会在FPGA外围添加电平转换器,将FPGA的电平标准转换为通信的电平标准。
我们的开发板上采用USB <->UART(LVCOMS/LVTTL)的电平转换芯片CP2102。所以开发板上的供电端口不仅仅可以供电,还可以进行通信。
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
功能需求:主机使用一个串口,与两个从机进行双向通信,主机向从机发送数据,从机能够返回数据,由于结构限制,主机与从机之间只有3根线(电源、地、数据线),并且从机上没有设物理的电源开关,需要通过与主机连接的数据线来控制开机,总结如下:1、数据线只有1根2、能够双向通信3、主机能够控制从机开机4、主机可以单独向1个从机发数据,也可以同时向两个从机发送数据根据需求,设计出如下电路:工作原理分析:VCC_24V_IN、GND、LINE_L(LINE_R)三根线接线连接到从机,电源开启电路是从机内部的电源控制。开机的逻辑:*主机先上电,LINE_L因为主机的R1上拉而有高电平,使Q6导通,Q5的G极电压被
FPGA时钟和时钟域时钟树所谓时钟树为FPGA内部资源,分:全局时钟树,区域时钟树,IO时钟树原则上优先使用全局时钟树,在GT接口上使用IO时钟树,一般工具也会对GT时钟加以限制;时钟树使用方式正确的物理连接FPGA会由物理管脚专门用于全局时钟设置,通过查询数据手册可以在PCB设计阶段进行确认,当外部时钟接入此管脚时,工具会自动占有全局时钟树资源,当接入普通信号时不会分配时钟树资源;恰当的代码描述原语的使用,即BUFG的使用,可以将PLL的输出等内部时钟进行全局时钟资源的分配;IO时钟资源需要参考相应接口手册,以ultrascale的GTH为例,其JESD204的时钟方案针对不同的子类会由不同
外部SPIFLASH:MicronN25Q128A13ESE40G(128Mbit(16MByte))FPGA:XC7A100T CPU:Microblaze第一种情况:Microblaze在简单的应用,比如运行LED,IIC,SPI,UART之类的低俗接口驱动,或做一些简单的辅助型工作时,一般生成的applicationelf文件都不大,在10几KB或者几十,百几KB,此时使用FPGA内部的BRAM资源已经足够。XC7A100T本身就有600几KB的BRAM资源。这种情况下直接将硬件流文件和elf文件合并为download.bit文件,在直接烧录到外部SPIFLAH即可。1.Xilinx--
我有一个RaspberryPiTFT7"触摸屏显示器,我想创建一个简单的应用程序来显示和输出系统数据(即CPU使用率、温度等)。我注意到目前常见的实现方法是使用pygame库输出到显示器连接到的帧缓冲区/dev/fb1。我想执行相同的操作,但使用Ruby,因为我更熟悉这门语言。有人可以为我指明正确的方向,让我知道如何开始吗?我查看了rubygame和gosu库,它们似乎能够做我想做的事情,即绘制屏幕,但我找不到任何关于如何将输出定向到的信息帧缓冲区本身。 最佳答案 rubycorelib有一个IO您应该能够使用该类将输出定向
目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式 2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置 3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一
1FPGA启动流程图1 7SerialsFPGA配置流程1.1DevicePower-Up1.2ClearConfigurationMemory在上电后的任何时间内,可以对Slave-FPGA配置存储器(BlockRAM)进行复位处理。复位方式是将PROGRAM_B信号拉低(下降沿有效)。1.3SampleModePins当复位完成后,INIT_B恢复高电平,Slave-FPGA对M[2:0]模式引脚进行采样,然后开始在CCLK上升沿接收配置数据。1.4Synchronization在接收配置数据前,Slave-FPGA首先进行总线位宽检测。主机发送的配置文件中,“BusWidthAutoDe
假设我有一个包含帖子的博客应用程序。创建帖子后,将创建一个工作人员来处理一些后台操作。我的情况是,在提交表单后我想显示某种加载消息(gif加载器等),当工作人员完成时我想隐藏加载消息并显示工作人员提供的一些数据。我的问题是,传达工作人员已完成工作并将其显示在用户前端的最佳方式是什么。worker回调看起来像这样defworker_finish#messagetheuserend 最佳答案 我认为您可能忽略了拥有后台工作人员的意义,基本上,您试图做的是弄巧成拙。--如果用户提交表单并且你在你的Controller中排队作业,只是为了让