前言

好久没更新博客了,这篇文章写写停停,用了近一周的时间,终于写完了。本篇文章介绍,串口协议数据帧格式、串行通信的工作方式、电平标准、编码方式及Verilog实现串口发送一个字节数据和接收一个字节数据。

对于MCU串口的发送接收,可能就是1行代码就能实现串口的发送和接收:

STM32的串口接收和发送

//STM32发送1个字节
USART_SendData(USART1, 'A');
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); //STM32接收1个字节:
uint8_t Res;
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
Res = USART_ReceiveData(USART1);

51单片机的发送和接收

//51单片机发送1个字节
SBUF = 'A;
while(!TI);
TI=0; //51单片机接收1个字节:
char Res;
if(RI)
{
Res = SBUF;
RI = 0;
}

更方便一点的,通过重写C库fput函数和fgetc函数,还可以实现printf直接重定向到串口,用来输出一些调试信息再方便不过了。

STM32实现输入输出重定向到串口发送接收

//可重定向printf函数
int fputc(int ch, FILE *f)
{
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
//可重定向scanf函数
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}

而MCU上的串口是半导体厂商预先设计好的,几乎是MCU的标配,高度集成,使用起来十分方便,但是串口的引脚基本上是固定的,不可以更改。对于硬件橡皮泥——FPGA来说,需要使用HDL从底层串口数据帧来实现,可以直接在任意一个引脚实现串口功能。为了用Verilog HDL实现标准的串口通讯协议,我们有必要先来详细了解一下串口通讯协议。

串口数据帧格式

波特率

波特率,即比特率(Baud rate),即通信双方“沟通的语言”,通信双方要设置为一样的波特率才可以正常通信。表示每秒发送的二进制位数,即传输1位的时间是:1/波特率 秒,如,波特率9600bps,即每秒传输9600bit,那么每一位的时间为:1/9600 s = 104.1666us,常用的波特率有:4800/9600/115200/12800等等,也可以根据需要自定义波特率大小,如1M或者3M,但是有的PC或者USB-TTL模块不支持太高速度的波特率,常用的USB-TTL芯片有:CH340,CP2102,PL2103,FT232等,其中FT232HL芯片最大支持12M的波特率,当然价格也比其他芯片高一些。

起始位和停止位

数据帧从起始位开始,到停止位结束。起始信号用逻辑0表示,而停止位是用逻辑1表示,一般有0.5位、1位、1.5位或2位停止位,常用的一般是1位停止位,只要通信双方约定一致即可。

数据位

起始位之后,紧跟着的是数据位,低位(LSB)在前,高位(MSB)在后,一般有5位、6位、7位和8位数据位,常用的是8位数据位,因为一个字节正好是8位。

校验位

校验位一般用来判断接收的数据位有无错误,校验方法有:奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)及无校验(noparity)。奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个8位长的有效数据为:01101001,此时共有4个“1”,为达到奇数个"1"的效果,校验位为“1”,让“1”的个数变成5个(奇数)。偶校验刚好相反,要求有效数据和校验位的“1”数量为偶数,则此时为达到偶校验效果,校验位为“0”。而0校验,即校验位总是为“0”,1校验校验位总是为“1”。奇偶校验逻辑相反,01校验逻辑相反。一般是奇偶校验或者是无校验位。

奇偶校验的Verilog实现

在Verilog中奇偶校验的计算非常简单,根据奇偶校验的原理,偶校验为数据位各位异或,奇校验是偶校验取反,通过使用单目运算符的缩减功能,可以非常简单的计算奇偶校验位:

input [7:0] data_in,       //需要发送的8位数据

wire even_bit;  //偶校验位 = 各位异或
wire odd_bit; //奇校验位 = ~偶校验位 assign even_bit = ^data_in; //一元约简运算符,等效于data_in[0] ^ data_in[1] ^ .....
assign odd_bit = ~even_bit; wire POLARITY_BIT = even_bit; //偶校验

关于波特率允许的误差

经过我的实际测试,波特率是有一定的容错范围的,例如,STM32配置成115200波特率,每10ms发送一个30字节的字符串,串口芯片用的CH340,上位机波特率设置成113000-121000也可以接收,无乱码,差不多正负2000的波特率,这容错范围也太大了,当然如果发送频率太快,数据量太大,误码率肯定会大大增加,所以还是建议通信双方使用同样的波特率以减少误差。

串口数据的实际波形

使用串口上位机连接USB-TTL模块,发送一个字节数据:1位停止位+8位数据位+1位奇校验位+1位停止位,使用示波器的单次触发功能,可以在USB-TTL模块的TX引脚测得串口协议数据的实际波形,你知道这发送的是什么字符吗?

一个字符的实际波形

两个字符的实际波形

单工、半双工、全双工、异步和同步的区别

在介绍串口的电平标准之前,先来了解一下串行通信的工作方式,即单工、半双工、全双工,异步和同步的区别。

单工

单工,即数据传输只在一个方向上传输,只能你给我发送或者我给你发送,方向是固定的,不能实现双向通信,如:室外天线电视、调频广播等。

半双工

半双工比单工先进一点,传输方向可以切换,允许数据在两个方向上传输,但是某个时刻,只允许数据在一个方向上传输,可以基本双向通信,如:对讲机,IIC通信。

全双工

比半双工更先进的是全双工,允许数据同时在两个方向传输。发送和接收完全独立,在发送的同时可以接收信号,或者在接收的同时可以发送。它要求发送和接收设备都要有独立的发送和接收能力,如:电话通信,SPI通信,串口通信。

同步和异步的区别

串行通信可以分为两种类型,一种叫同步通信,另一种叫异步通信。

简单的说,就是同步通信需要时钟信号,而异步通信不需要时钟信号。

  • 同步:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
  • 异步:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

SPI和IIC为同步通信,UART为异步通信,而USART为同步&异步通信。

  • USART:通用同步和异步收发器
  • UART:通用异步收发器

即USART支持同步和异步收发,而UART只支持异步收发。

如STM32的串口工作在同步模式时,即智能卡模式时,就需要连接同步时钟引脚。

常用的串行通信协议/电平标准

TTL电平

即普通MCU芯片输出的串口电平,如各MCU输出的串口信号就是TTL电平。低电平为0-GND,高电平为1-VCC,标准的数字电路逻辑。特点是速度快,延迟低,但是功耗大。基本上用于板内两个芯片之间短距离通信。

RS232

RS232是工业上常用的串口标准,无论是PLC的232接口,还是工控机上的串口,输出的串口电平都是232电平标准,232标准采用负逻辑电平,即-15-3v为逻辑1,+3+15为逻辑0,这里的电平是指RX和TX相对于GND的电压,可见无论在电压范围还是电压极性上都和TTL不同,显然这两种电平不能直接连接,需要使用MAX232类似的电平转换芯片,对两种电平进行互相转换,全双工,传输距离一般控制在20m以内,原因是RS-232属单端信号传送,存在共地噪声和不能抑制共模干扰等问题。

RS485

在要求通信距离为几十米到上千米时,广泛采用RS-485 串行总线标准。RS-485采用平衡发送和差分接收,因此具有抑制共模干扰的能力。加上总线收发器具有高灵敏度,能检测低至200mV的电压,故传输信号能在千米以外得到恢复。 RS-485采用半双工工作方式,任何时候只能有一点处于发送状态,因此,发送电路须由使能信号加以控制。RS-485用于多点互连时非常方便,可以省掉许多信号线。应用RS-485 可以联网构成分布式系统,其允许最多并联32台驱动器和32台接收器。

RS422

RS-422和RS-485电路原理基本相同,都是以差分方式发送和接受,不需要数字地线。RS-422通过两对双绞线可以全双工工作收发互不影响,而RS485只能半双工工作,发收不能同时进行,但它只需要一对双绞线。RS422和RS485在19kpbs下能传输1200米。RS-422的电气性能与RS-485完全一样。主要的区别在于:RS-422有4根信号线:两根发送(Y、Z)、两根接收(A、B)。由于RS-422的收与发是分开的所以可以同时收和发(全双工)。

串行通信的编码方式

RZ编码

RZ编码也成为归零码,归零码的特性就是在一个周期内,用二进制传输数据位,在数据位脉冲结束后,需要维持一段时间的低电平。如图:

上图表示的是单极性归零码,即低电平表示0,正电平表示1。对于双极性归零码来说,则是高电平表示1,负电平表示0。如下图所示:

NRZ编码

NRZ编码也成为不归零编码,也是我们最常见的一种编码,即正电平表示1,低电平表示0。它与RZ码的区别就是它不用归零,也就是说,一个周期可以全部用来传输数据,这样传输的带宽就可以完全利用。

NRZI编码

NRZI编码的全称为反向不归零编码,这种编码方式集成了前两种编码的优点,即既能传输时钟信号,又能尽量不损失系统带宽。对于USB2.0通信的编码方式就是NRZI编码。其实NRZI编码方式非常的简单,即信号电平翻转表示0,信号电平不变表示1。例如想要表示00100010(B),则信号波形如下图所示:

例如有一段数据为:1111 1111 (B)要发送,则整个传输线上的电平状态是这样的:

Manchester编码

曼彻斯特编码,又称数字双向码、分相码或相位编码(PE),是一种常用的的二元码线路编码方式。常用在以太网通信,列车总线控制,工业总线等领域。在曼彻斯特编码中,每一位的中间有一跳变,位中间的跳变既作时钟信号,又作数据信号;从高到低跳变表示“0”,从低到高跳变表示“1”。其中非常值得注意的是,在每一位的"中间"必有一跳变,根据此规则,可以得出曼彻斯特编码波形图的画法。例如:传输二进制信息0,若将0看作一位,我们以0为中心,在两边用虚线界定这一位的范围,然后在这一位的中间画出一个电平由高到低的跳变。后面的每一位以此类推即可画出整个波形图。举个图例吧,若要表示数据1001 1010(B),则信号波形图如下图所示:

曼彻斯特编码方式也如前面所说,虽然传输了时钟信号,但也损失了一部分的带宽,主要表现在相邻相同数据上。但对于高速数据来说,这种编码方式无疑是这几种编码方式中最优的,相比NRZI编码,曼彻斯特编码不存在长时间信号状态不变导致的时钟信号丢失的情况,所以在这种编码方式在以太网通信中是十分常用的。

串行和并行哪个速度快?

串口,即串行通信接口,与之对应的是并行接口。在实际时钟频率比较低的情况下,并口因为可以同时传输若干比特,速率确实比串口快。但是,随着技术的发展,时钟频率越来越高,当时钟频率提高到一定的程度时,并行接口因为有多条并行且紧密的导线,导线之间的相互干扰越来越严重。而串口因为导线少,线间干扰容易控制,况且加上差分信号的加持,抗干扰性能大大提升,因此可以通过不断提高时钟频率来提高传输速率,这就是为什么现在高速传输都采用串行方式的原因。例如常见的USB、SATA、PCIe、以太网等。

如果有人问关于串行传输与并行传输谁更好的问题,你也许会脱口而出:串行通信好!但是,串行传输之所以走红,是由于将单端信号传输转变为差分信号传输,并提升了控制器工作频率的原因,而“在相同频率下并行通信速度更高”这个基本道理是永远不会错的,通过增加位宽来提高数据传输率的并行策略仍将发挥重要作用。当然,前提是有更好的措施来解决并行传输过程中的种种问题。

标准串口协议的Verilog实现

基于Verilog实现标准串口协议发送8位数据:起始位 + 8位数据位 + 校验位 + 停止位 = 11位,每1位的时间是16个时钟周期,所以输入时钟应该为:波特率*16,带Busy忙信号输出。实现方法比较简单,数据帧的拼接、计数器计时钟周期,每16个时钟周期输出一位数据即可。

串口发送1个字节实现

/*
串口协议发送:起始位 + 8位数据位 + 校验位 + 停止位 = 11位 * 16 = 176个时钟周期
clk频率 = 波特率 * 16
*/ module uart_tx_8bit( //input
input clk, //UART时钟=16*波特率
input rst_n,
input [7:0] data_in, //需要发送的数据
input trig, //上升沿发送数据 //output
output busy, //高电平忙:数据正在发送中
output reg tx //发送数据信号 ); reg[7:0] cnt; //计数器
reg trig_buf;
reg trig_posedge_flag;
// reg trig_negedge_flag;
reg send; reg [10:0] data_in_buf; //trig上升沿读取输入的字节,拼接数据帧 wire odd_bit; //奇校验位 = ~偶校验位
wire even_bit; //偶校验位 = 各位异或
wire POLARITY_BIT = even_bit; //偶校验
// wire POLARITY_BIT = odd_bit; //奇校验 assign even_bit = ^data_in; //一元约简,= data_in[0] ^ data_in[1] ^ .....
assign odd_bit = ~even_bit;
assign busy = send; //输出的忙信号 //起始位+8位数据位+校验位+停止位 = 11位 * 16 = 176个时钟周期
parameter CNT_MAX = 176; always @(posedge clk)
begin
if(!rst_n)
begin
trig_buf <= 0;
trig_posedge_flag <= 0;
// trig_negedge_flag <= 0;
end
else
begin
trig_buf <= trig;
trig_posedge_flag <= (~trig_buf) & trig; //在trig信号上升沿时产生1个时钟周期的高电平
// trig_negedge_flag <= trig_buf & (~trig); //在trig信号下降沿时产生1个时钟周期的高电平
end
end always @(posedge clk)
begin
if(!rst_n)
send <= 0;
else if (trig_posedge_flag & (~busy)) //当发送命令有效且线路为空闲时,启动新的数据发送进程
send <= 1;
else if(cnt == CNT_MAX) //一帧资料发送结束
send <= 0;
end always @ (posedge clk)
begin
if(!rst_n)
data_in_buf <= 11'b0;
else if(trig_posedge_flag & (~busy)) //只读取一次数据,一帧数据发送过程中,改变输入无效
data_in_buf <= {1'b1, POLARITY_BIT, data_in[7:0], 1'b0}; //数据帧拼接
end always @ (posedge clk)
begin
if(!rst_n)
cnt <= 0;
else if(!send || cnt >= CNT_MAX)
cnt <= 0;
else if(send)
cnt <= cnt + 1;
end always @(posedge clk)
begin
if(!rst_n)
tx <= 1;
else if(send)
begin
case(cnt) //1位占用16个时钟周期
0: tx <= data_in_buf[0]; //低位在前,高位在后
16: tx <= data_in_buf[1]; //bit0,占用第16~31个时钟
32: tx <= data_in_buf[2]; //bit1,占用第47~32个时钟
48: tx <= data_in_buf[3]; //bit2,占用第63~48个时钟
64: tx <= data_in_buf[4]; //bit3,占用第79~64个时钟
80: tx <= data_in_buf[5]; //bit4,占用第95~80个时钟
96: tx <= data_in_buf[6]; //bit5,占用第111~96个时钟
112: tx <= data_in_buf[7]; //bit6,占用第127~112个时钟
128: tx <= data_in_buf[8]; //bit7,占用第143~128个时钟
144: tx <= data_in_buf[9]; //发送奇偶校验位,占用第159~144个时钟
160: tx <= data_in_buf[10]; //发送停止位,占用第160~167个时钟
CNT_MAX: tx <= 1; //无空闲位
default:;
endcase
end
else if(!send)
tx <= 1;
end endmodule

仿真波形

串口接收1个字节实现

串口接收部分的实现,涉及到串口数据的采样,对于MCU来说,不同单片机集成外设的处理方式有所不同,具体采样原理可以参考内核的Reference Manual。以传统51内核为例,按照所设置的波特率,每个位时间被分为16个时间片。UART接收器会在第7、8、9三个时间片进行采样,按照三取二的逻辑获得该位时间内的采样结果。其它一些类型的单片机则可能会更加严苛,例如有些工业单片机会五取三甚至七取五(设置成抗干扰模式时)。

本程序中采用的中间值采样,即取16个时钟周期中的中间位作为当前的采样值。

//Verilog实现串口协议接收,带错误指示,校验错误和停止位错误

/*
16个时钟周期接收1位,中间采样
*/
module my_uart_rx( input clk, //采样时钟
input rst_n,
input rx, //UART数据输入
output reg [7:0] dataout, //接收数据输出
output reg rx_ok, //接收数据有效,高说明接收到一个字节
output reg err_check, //数据出错指示
output reg err_frame //帧出错指示 ); reg [7:0] cnt;
reg [10:0] dataout_buf; reg rx_buf;
reg rx_negedge_flag;
reg receive; wire busy;
wire odd_bit; //奇校验位 = ~偶校验位
wire even_bit; //偶校验位 = 各位异或
wire POLARITY_BIT; //本地计算的奇偶校验
// wire polarity_ok;
// assign polarity_ok = (POLARITY_BIT == dataout_buf[9]) ? 1 : 0; //校验正确=1,否则=0 assign busy = rx_ok;
assign even_bit = ^dataout; //一元约简,= data_in[0] ^ data_in[1] ^ .....
assign odd_bit = ~even_bit;
assign POLARITY_BIT = even_bit; //偶校验
// assign POLARITY_BIT = odd_bit; //奇校验 parameter CNT_MAX = 176; //rx信号下降沿标志位
always @(posedge clk)
begin
if(!rst_n)
begin
rx_buf <= 0;
rx_negedge_flag <= 0;
end
else
begin
rx_buf <= rx;
rx_negedge_flag <= rx_buf & (~rx);
end
end
//在接收期间,保持高电平
always @(posedge clk)
begin
if(!rst_n)
receive <= 0;
else if (rx_negedge_flag && (~busy)) //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程
receive <= 1; //开始接收数据
else if(cnt == CNT_MAX) //接收数据完成
receive <= 0;
end
//起始位+8位数据位+校验位+停止位 = 11位 * 16 = 176个时钟周期
always @ (posedge clk)
begin
if(!rst_n)
cnt <= 0;
else if(!receive || cnt >= CNT_MAX)
cnt <= 0;
else if(receive)
cnt <= cnt + 1;
end
//校验错误:奇偶校验不一致
always @ (posedge clk)
begin
if(!rst_n)
err_check <= 0;
else if(cnt == 152)
begin
// if(POLARITY_BIT == rx)
if(POLARITY_BIT != dataout_buf[9]) //奇偶校验正确
err_check <= 1; //锁存
// else
// err_check <= 1;
end
end
//帧错误:停止位不为1
always @ (posedge clk)
begin
if(!rst_n)
err_frame <= 0;
else if(cnt == CNT_MAX)
begin
if(dataout_buf[10] != 1) //停止位
err_frame <= 1;
// else
// err_frame <= 1; //如果没有接收到停止位,表示帧出错
end
end always @ (posedge clk)
begin
if(!rst_n)
dataout <= 11'h00;
else if(receive)
begin
// if(rx_ok)
if(cnt >= 137)
dataout <= dataout_buf[8:1]; //数据位:8-1位
// else if(!rx_ok)
// dataout <= 0;
end
end always @ (posedge clk)
begin
if(!rst_n)
rx_ok <= 0;
else if(receive)
begin
if(cnt >= 137) //137-169
rx_ok <= 1;
else
rx_ok <= 0;
end
else
rx_ok <= 0;
end //起始位+8位数据+奇偶校验位+停止位 = 11 * 16 = 176位 always @(posedge clk)
begin
if(!rst_n)
dataout_buf <= 8'h00;
else if(receive)
begin
case (cnt) //中间采样
8'd8: dataout_buf[0] <= rx; //起始位=0
8'd24: dataout_buf[1] <= rx; //LSB低位在前
8'd40: dataout_buf[2] <= rx;
8'd56: dataout_buf[3] <= rx;
8'd72: dataout_buf[4] <= rx;
8'd88: dataout_buf[5] <= rx;
8'd104: dataout_buf[6] <= rx;
8'd120: dataout_buf[7] <= rx;
8'd136: dataout_buf[8] <= rx; //MSB高位在后
8'd152: dataout_buf[9] <= rx; //奇偶校验位
8'd168: dataout_buf[10] <= rx; //停止位=1
default:;
endcase
end
end endmodule

代码工程下载

工程包含:

  • my_uart_rx:串口接收1个字节示例程序
  • uart_tx_8bit:串口发送1个字节示例程序
  • uart_tx_demo:串口每隔500ms循环发送0-9字符

参考资料:

推荐阅读:


我的博客:www.wangchaochao.top

或微信扫码关注我的公众号:mcu149

详解串行通信协议及其FPGA实现的更多相关文章

  1. http协议报头详解HTTP协议结构

    http协议 请求报文和响应报文都是由以下4部分组成 1.请求行 2.请求头 3.空行 4.消息主体 下图为http请求的报文结构 下图为http响应报文结构 请求行 格式为: Method Requ ...

  2. iOS 详解NSObject协议

      协议就是一组接口的集合,遵守一个协议之后就拥有的该协议中所有方法的声明.NSObject这个类遵守了NSObject协议,并且实现了NSObject协议里的所有方法,所以NSObject类及其子类 ...

  3. 一:详解 HTTP 协议

    本篇文章篇幅比较长,先来个思维导图预览一下. 一张图带你看完本篇文章 一.概述 1.计算机网络体系结构分层 计算机网络体系结构分层 2.TCP/IP 通信传输流 利用 TCP/IP 协议族进行网络通信 ...

  4. HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端

    协议简介 协议,自然语言里面就是契约,也是双方或者多方经过协商达成的一致意见; 契约也即类似于合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做; 通信协议,也即是双方通过网络通信必 ...

  5. 详解HTTP协议

    一 什么是HTTP协议 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网服务器传输超文本到本地浏览器的传送协议.HTTP 是基于 TCP/ ...

  6. rtp协议详解/rtcp协议详解

    转自:http://www.cnblogs.com/li0803/archive/2010/11/20/1882792.html 1.简介 目前,在IP网络中实现实时语音.视频通信和应用已经成为网络应 ...

  7. 详解FIX协议的原理、消息格式及配置开发

    一.定义 FIX协议是由国际FIX协会组织提供的一个开放式协议,目的是推动国际贸易电子化的进程,在各类参与者之间,包括投资经理.经纪人,买方.卖方建立起实时的电子化通讯协议.FIX协议的目标是把各类证 ...

  8. Git详解之协议/速度/安全

    协议概述 Git共享服务的实现方式大致分为四种:文件共享类型.git类型.ssh类型.http类型: 本地协议 本地协议:文件共享类型,是对Git项目,通过文件共享的方式:如NFS.FTP.samba ...

  9. 详解UDP协议

    运输层位于网络层之上,网络层提供了主机之间的逻辑通信:而运输层为运行在不同主机上的应用进程之间提供了逻辑通信.从应用程序角度看,通过逻辑通信,运行不同进程的主机好像直接相连一样.应用进程使用运输层提供 ...

随机推荐

  1. LNMP架构源码搭建(centos7)

    第一步:安装nginx 1.上传或下载nginx,并解压 yum -y install lrzsz rz .tar.gz 2.搭建nginx安装环境 yum -y install gcc-c++ zl ...

  2. 腾讯iphone面试题(转)

    1Objective-C内部的实现 2CALayer和View的关系 3 http协议,tcp/ip 4 UITableView的那些元素是可以自定义的? 5 c语言的,定义变量,比如int,在什么情 ...

  3. ios中日期处理

  4. 高性能Web动画和渲染原理系列(1)——CSS动画和JS动画

    [摘要] 介绍CSS动画和JS动画的基本特点,以及轻量级动画库velocity.js的基本用法. 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园 ...

  5. composer install 或 update 速度慢的解决方案(composer加速)

    我们在使用composer install和composer update时,有的时候安装和更新速度非常慢,我们可以通过下面的几个方法来解决这个问题. 首先查看一下当前的 composer 全局配置地 ...

  6. luogu P3572 [POI2014]PTA-Little Bird |单调队列

    从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 #include<cstdio> #include<cstring> #i ...

  7. luogu P1327 数列排序

    题目描述 给定一个数列{an},这个数列满足ai≠aj(i≠j),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换? 输入格式 第一行,正整数n (n<=10 ...

  8. 移动开发在路上-- IOS移动开发系列 网络交互四(1)

    最近一段时间上班忙的没日没夜的,不是披星戴月,就是头天早上出门,第二天早上回家...一直没出处时间来更新博客,码农之苦,说了都是泪,废话不多说,直接本主题,经过之前三篇的讲述,ios开发的东西大家或多 ...

  9. hdu4585Shaolin

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4585 题意: 第一个人ID为1,战斗力为1e9. 给定n,给出n个人的ID和战斗力. 每个人必须和战斗 ...

  10. 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...