串口模块总结

在这里插入图片描述
上图串口传输的时序图。串口传输数据都是一帧数据 11 位。其中第0位为起始位,1-7位为数据位,第9位为校验位,第10位是停止位。
在串口的总线上“高电平”是默认的状态,当一帧数据的开始传输必须先拉低电平,这就是第 0 位的作用。第 0 位过后就是 8 个数据位,这八个数据位才是一帧数据中最有意义的东西。最后的两位是校验位和停止位,作用如同命名般一样,基本上是没有重要意义。
串口传输还有另一个重要参数就是“波特率”。很多朋友都误解“波特率”是串口传输的传输速度,这样的理解在宏观上是无误。但是在微观上“波特率”就是串口传输中“一个位的周期”,换句话说亦是“一个位所逗留的时间”,常用的波特率有 9600 bps 和 115200 bps ( bit per second )。“9600 bps” 表示每秒可以传输 9600 位。但是经过公式计算“一个位的周期”就会暴露出来。

一个位的周期 = 1 / bps
= 1/ 9600= 0.000104166666666667
我们明白一个事实 :9600 bps ,一位数据占用 0.000104166666666667s 时间。如果是一帧 11 位的数据,就需要0.000104166666666667 x 11 = 0.00114583333333334,那么一秒钟内可以传输1 / 0.00114583333333334 = 872.727272727268872.727272727268 个帧数据。当然这只是在数字上计算出来而已,但是实际上还有许多看不见的延迟因数。

1、接收模块
在这里插入图片描述
Rx_module.v 是一个组合模块,主要是包含 detect_module.v , bps_module.v 和rx_control_module.v,3 个功能模块。
detect_module.v 的输入是连结物理引脚 rx,它主要检测一帧数据的第 0 位,也就是起始位,然后产生一个高脉冲经 H2L_Sig 给 rx_control_module.v ,以表示一帧数据接收工作已经开始。
rx_bps_module.v 是产生波特率定时的功能模块。换一句话说,它是配置波特率的模块。当rx_control_module.v拉高Count_Sig, bps_module.v经BPS_CLK对 rx_control_module.v 产生定时。
rx_control_module.v 是核心控制模块。针对串口的配置主要是 1 帧 11 位的数据,重视八位数据位,无视起始位,校验位和结束位。当 RX_En_Sig 拉高,这个模块就开始工作,它将采集来自 RX_Pin_In 的数据,当完成一帧数据接收的时候,就会产生一个高脉冲给RX_Done_Sig。
在这里插入图片描述
如上图所示,数据采集都是在“每位数据的中间”进行着。在上图中 RX_Pin_In 输入一帧数据,当 detect_module.v 检测到低电平(起始位),rx_control_module.v 和 rx_bps_module.v 就产生定时(与 RX_Pin_In的波特率是一致)。然而 rx_bps_module.v 产生的定时是在每个位时间的中间。在第 0 位数据,采取忽略的态度,然后接下来的 8 位数据位都被采集,最后校验位和停止位,却是采取了忽略的操作。有一点你必须好好注意,串口传输数据“从最低位开始,到最高位结束”。

module detect_module 
(
CLK, RSTn,
RX_Pin_In,
H2L_Sig
);

input CLK;
input RSTn;
input RX_Pin_In;
output H2L_Sig;

/******************************/

reg H2L_F1;
reg H2L_F2;

always @ ( posedge CLK or negedge RSTn )
	if( !RSTn )
		begin
			H2L_F1 <= 1'b1;
			H2L_F2 <= 1'b1;
		end
	else
		begin
			H2L_F1 <= RX_Pin_In;
			H2L_F2 <= H2L_F1;
		end
	
	assign H2L_Sig = H2L_F2 & !H2L_F1;
endmodule

detect_module.v 这个功能模块是为了检查电平由高变低。当检测到电平又高变低,在assign处就会输出高脉冲。

module rx_bps_module
(
CLK, RSTn,
Count_Sig, 
BPS_CLK
);

input CLK;
input RSTn;
input Count_Sig;
output BPS_CLK;

/***************************/

reg [12:0]Count_BPS;

always @ ( posedge CLK or negedge RSTn )
	if( !RSTn )
		Count_BPS <= 13'd0;
	else if( Count_BPS == 12'd5207 )
		Count_BPS <= 13'd0;
	else if( Count_Sig )
		Count_BPS <= Count_BPS + 1'b1;
	else
		Count_BPS <= 13'd0;

assign BPS_CLK = ( Count_BPS == 13'd2604 ) ? 1'b1 : 1'b0;

endmodule

9600 bps 传输速度使一位数据的周期是 0.000104166666666667s 。以 50Mhz 时钟频率要得到上述的定时需要:N = 0.000104166666666667 / ( 1 / 50Mhz ) = 5208,如果从零开始算起 5208 - 1 亦即 5207 个计数(20 行)。然而,采集数据要求“在周期的中间”,那么结果是 5208 / 2 ,结果等于 1041(29 行)。基本上 rx_bps_module.v 只有在 Count_Sig 拉高的时候(22 行),模块才会开始计数。

module rx_control_module
(
CLK, RSTn,
H2L_Sig, RX_Pin_In, BPS_CLK, RX_En_Sig,
Count_Sig, RX_Data, RX_Done_Sig

);

input CLK;
input RSTn;
input H2L_Sig;
input RX_En_Sig;
input RX_Pin_In;
input BPS_CLK;

output Count_Sig;
output [7:0]RX_Data;
output RX_Done_Sig;

reg [3:0]i;
reg [7:0]rData;
reg isCount;
reg isDone;

always @ ( posedge CLK or negedge RSTn )
	if( !RSTn )
		begin
			i <= 4'd0;
			rData <= 8'd0;
			isCount <= 1'b0;
			isDone <= 1'b0;
		end
	else if ( RX_En_Sig )
		case (i)	
		4'd0:if( H2L_Sig ) 
				begin 
					i <= i + 1'b1; 
					isCount <= 1'b1; 
				end
		4'd1:if( BPS_CLK )
				begin
					i <= i + 1'b1;
				end
		4'd2,4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :
			 if( BPS_CLK )
				begin
					i <= i + 1'b1;
					rData[ i - 2 ] <= RX_Pin_In;
				end
		4'd10:if( BPS_CLK )
				begin
					i <= i + 1'b1;
				end
		4'd11:if( BPS_CLK )
				begin
					i <= i + 1'b1;
				end
		4'd12:	begin 
					i <= i + 1'b1; 
					isDone <= 1'b1; 
					isCount <= 1'b0; 
				end
		4'd13:	begin 
					i <= 1'b0; 
					isDone <= 1'b0; 
				end
		endcase
	
	assign Count_Sig = isCount;
	assign RX_Data = rData;
	assign RX_Done_Sig = isDone;
endmodule

状态机那部分,是 rx_control_module.v 的核心控制功能。在else if ( RX_En_Sig )中,表示了如果 RX_En_Sig 如果没有拉高,这个模块是不会工作。(前面定义了 isCount 标志寄存器,为了使能rx_bps_module.v 输出采集定时信号)当 rx_control_module.v 模块被使能,该模块就会处于就绪状态,一旦 detect_module.v 检查到由高变低的电平变化(状态机第0步),会使步骤 i 进入第 0 位采集,然而 isCount 标志寄存器同时也会被设置为逻辑 1,rx_bps_module.v 便会开始产生波特率的定时。我们知道rx_bps_module.v 产生的定时是在“每位数据的中间”。当i=1,第一次的定时采集时第 0 位数据(起始位),保持忽略态度。i=2至9时,定时采集的是八位数据位,每一位数据位会依低位到最高位储存入 rData 寄存器。i=10-11时,是最后两位的定时采集(校验位,停留位),同时采取忽略的态度。当进入i=12-13,这表示一帧数据的采集工作已经结束。最后会产生一个完成信号的高脉冲,同时间 isCount 会被设置为逻辑 0,亦即停止 rx_bps_module.v 的操作。至于 assign的三个连接,isCount 标志寄存器是 Count_Sig 输出的驱动器,rData 寄存器是RX_Data 输出的驱动器,最后 isDone 标志寄存器是 RX_Done_Sig 输出的驱动寄存器。

module rx_module
(
CLK, RSTn,
RX_Pin_In, RX_En_Sig,
RX_Done_Sig, RX_Data
);

input CLK;
input RSTn;
input RX_Pin_In;
input RX_En_Sig;

output [7:0]RX_Data;
output RX_Done_Sig;

wire H2L_Sig;
detect_module U1
(
.CLK		( CLK 		),
.RSTn		( RSTn 		),
.RX_Pin_In	( RX_Pin_In ), // input - from top
.H2L_Sig	( H2L_Sig 	) // output - to U3
);

wire BPS_CLK;
rx_bps_module U2
(
.CLK		( CLK 		),
.RSTn		( RSTn		 ),
.Count_Sig	( Count_Sig ), // input - from U3
.BPS_CLK	( BPS_CLK 	) // output - to U3
);

wire Count_Sig;
rx_control_module U3
(
.CLK			( CLK 			),
.RSTn			( RSTn 			),
.H2L_Sig		( H2L_Sig 		), // input - from U1
.RX_En_Sig		( RX_En_Sig 	), // input - from top
.RX_Pin_In		( RX_Pin_In 	), // input - from top
.BPS_CLK		( BPS_CLK	    ), // input - from U2
.Count_Sig		( Count_Sig 	), // output - to U2
.RX_Data		( RX_Data 		), // output - to top
.RX_Done_Sig	( RX_Done_Sig 	) // output - to top
);

endmodule

当 rx_module.v 组合模块组织一切以后只保留的输入输出有:输入信号 RX_Pin_In 和RX_En_Sig:输出信号 RX_Data 和 RX_Done_Sig。在试验中, rx_bps_module.v 扮演着“配置波特率”,然而 rx_control_module.v 的工作则对“数据作出过滤”。在典型的应用上“1 位起始位,8 位数据位,1 位校验位,和 1 位停止位”已经成为主流。当然波特率的选择是 9600 bps 还是 115200 bps 这视需要而定。

RTL图
我们要建立如下图 rx_module_demo.v 组合模块 ,它里边包含了一个控制模块对rx_module.v 的调用。一开始 control_module.v 会拉高 RX_En_Sig 使能 rx_module.v 。当有一阵数据经 RX_Pin_In 传入, rx_module.v 就会接收,然后过滤后的数据出输出致 RX_Data , 然后再产生一个高脉冲给 RX_Done_Sig。当 control_module.v 接收到RX_Done_Sig 的高脉冲,拉低 RX_En_Sig,并且将 RX_Data 的“前四位”输出致 4 位LED 资源。 然后过程再一次重复不断。
在这里插入图片描述

module control_module
(
CLK, RSTn,
RX_Done_Sig,
RX_Data,
RX_En_Sig,
Number_Data
);

input CLK;
input RSTn;
input RX_Done_Sig;
input [7:0]RX_Data;
output RX_En_Sig;
output [7:0]Number_Data;

reg [7:0]rData;
reg isEn;

always @ ( posedge CLK or negedge RSTn )
	if( !RSTn )
		rData <= 8'd0;
	else if( RX_Done_Sig ) 
		begin 
			rData <= RX_Data; 
			isEn <= 1'b0; 
		end
	else isEn <= 1'b1;

assign Number_Data = rData;
assign RX_En_Sig = isEn;

endmodule

always模块中一开始的时候就将 isEn 设置为逻辑 1, 这个标志寄存器驱动着 RX_En_Sig。换句话说,此时的 rx_module.v 已经进入就绪状态,然后 control_module.v 等待着 RX_Done_Sig 反馈(23行)。一旦一帧数据接收完毕,RX_Done_Sig 就会产生高脉冲, 然后 rData 就会寄存 RX_Data 的值。同时间 isEn 被设置为逻辑 0(25-26行)。在下一个来临, control_module.v 会再一次设置 isEn 为逻辑 1,已做好接收下一组数据的准备。

module rx_module_demo
(
CLK, RSTn,
RX_Pin_In,
Number_Data
);

input CLK;
input RSTn;
input RX_Pin_In;
output [3:0]Number_Data;
wire RX_Done_Sig;
wire [7:0]RX_Data;

rx_module U1
(
.CLK		 ( CLK 			),
.RSTn		 ( RSTn 		),
.RX_Pin_In	 ( RX_Pin_In 	), // input - from top
.RX_En_Sig	 ( RX_En_Sig 	), // input - from U2
.RX_Done_Sig ( RX_Done_Sig 	), // output - to U2
.RX_Data	 ( RX_Data 		) // output - to U2
);

wire RX_En_Sig;
wire [7:0]Output_Data;

control_module U2
(
.CLK( CLK ),
.RSTn( RSTn ),
.RX_Done_Sig( RX_Done_Sig ), // input - from U1
.RX_Data( RX_Data ), // input - from U1
.RX_En_Sig( RX_En_Sig ), // output - to U1
.Number_Data( Output_Data ) // output - to top
);

assign Number_Data = Output_Data[3:0];

endmodule
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32是一种常用的嵌入式微控制器,具有广泛的应用领域。在STM32的开发中,串口通信是一种常见的通信方式之一。 而涂鸦模块是一种小型的WiFi模块,常用于物联网领域。涂鸦模块集成了WiFi功能和一些常用的传感器接口,通过串口与主控单元进行通信,实现数据的传输与控制。 在STM32中使用涂鸦模块时,需要首先配置串口通信的相关参数。通过STM32的串口模块将数据发送给涂鸦模块,或者接收涂鸦模块发送过来的数据。通常情况下,需要使用串口的中断功能来实现数据的异步收发,提高系统的响应速度。 在使用涂鸦模块时,我们可以通过串口发送AT指令来控制模块的工作状态,如连接WiFi网络、获取传感器数据等。涂鸦模块会将执行结果通过串口返回给STM32,我们可以根据返回的结果判断操作是否成功。 当涂鸦模块连接到WiFi网络后,我们可以通过串口发送HTTP请求,与云端服务器进行数据交互。比如可以发送传感器数据到云端,或者接收从云端发送过来的指令,实现远程控制。 总结来说,STM32与涂鸦模块之间的串口通信可以实现数据的传输与控制,能够方便地集成WiFi功能和与云端的通信。通过串口的配置和使用,我们可以轻松地将STM32和涂鸦模块应用于物联网领域的项目中。 ### 回答2: STM32是一款常用的微控制器,具有强大的功能和广泛的应用范围。而涂鸦模块是一种常用的无线通信模块,可以实现串口通信功能。 STM32串口涂鸦模块的应用场景非常广泛。首先,它可以和其他设备进行无线通信,实现数据的传输和控制。比如,可以将STM32与传感器模块结合,通过串口将传感器采集的数据发送到涂鸦模块,然后通过无线信号将数据传输到接收端进行处理;或者可以将STM32与执行器模块结合,通过串口将控制信号发送到涂鸦模块,然后通过无线信号控制执行器的运动;还可以将STM32与其他智能设备结合,实现智能家居控制、智能车辆控制等应用。 其次,STM32串口涂鸦模块具有简单易用的特点。它使用串口通信协议,只需简单的配置,就可以实现通信功能。同时,它还具有稳定可靠的特性,可以在复杂环境中正常工作,保证数据的稳定传输。 此外,STM32串口涂鸦模块还支持多种通信协议,如UART、SPI和I2C等,可以满足不同应用场景的需求。同时,STM32具有丰富的GPIO接口和中断功能,可以方便地与涂鸦模块进行连接和控制。 研究和应用STM32串口涂鸦模块,可以帮助我们更好地理解和掌握串口通信技术,并且可以应用于物联网、智能控制等领域。通过合理的设计和使用,可以实现各种功能丰富、性能稳定的应用,为现代化生活和生产提供便利。 ### 回答3: STM32是意法半导体(STMicroelectronics)公司推出的32单片机系列产品,具有高性能和低功耗等特点,广泛应用于嵌入式系统开发领域。而串口是一种常见的外设接口,用于与外部设备进行通信。涂鸦模块则是一种基于STM32芯片的串口通信模块,可以用于实现串口数据的收发和处理。 涂鸦模块通常由单片机芯片、串口电路、外设接口等组成。它可以通过串口与其他设备(如电脑、传感器、显示器等)进行通信,实现数据的传输和控制。通过涂鸦模块可以方便地进行数据采集、传输和处理,提高系统的智能化和互联性。 STM32串口涂鸦模块具有以下特点和优势: 1. 高性能:STM32芯片具有强大的计算和处理能力,可以实现复杂的数据处理算法和响应速度要求高的应用。 2. 低功耗:STM32芯片采用低功耗设计,可以节省系统能耗,并具有良好的电源管理功能。 3. 丰富的外设接口:涂鸦模块内置了多个串口接口,可与多个外部设备同时进行通信,提高了系统的灵活性和扩展性。 4. 易于开发和调试:STM32系列产品具有丰富的开发工具和软件支持,开发者可以快速进行开发和调试。 5. 广泛应用:涂鸦模块广泛应用于物联网、智能家居、工业控制等领域,可以实现设备之间的数据交换和远程控制。 总之,STM32串口涂鸦模块是一种方便易用的串口通信模块,可以实现数据的收发和处理,并具有高性能、低功耗和丰富的外设接口等优势。在嵌入式系统开发中发挥着重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值