TP50、TP90、TP99、TP999等TP系列或者95line、99.9line 等line系列的含义

本文介绍了TP50、TP90、TP99、TP999等TP系列以及95line、99.9line等性能监控指标的含义。通过查阅美团CAT技术文档、JMeter指标和维基百科,解释了这些指标计算方法,指出它们描述的是Top Percentile,即样本数据中特定百分位的值。例如,95Line表示95%的请求在特定时间内完成,99.9Line则对应99.9%的请求。 Std代表标准差,反映数据波动。总之,TP系列和line系列虽说法不同,但本质上表示相同的性能指标。

前几天优化服务性能在cat看到了一些title
在这里插入图片描述
大部分都很好理解
其中95line、99.9line是什么就不时很理解了
找到了美团的CAT技术文档
在这里插入图片描述
所以是怎么算的呢?

查询百度没查到什么特别符合的结果查到了TP90、TP95、TP99、TP999等
而TP系列大部分人给的解释是:Top Percentile Top百分数
看了这些指标的描述发现,这些TP系列跟95line 99.9line的指标好像是一个意思。
继续查 找了个JMeter 有一个 99.9% Line 这样的指标 99.9% Line 就跟CAT里面的99.9 Line 95Line 几乎一样了,查了一下JMeter的 99.9% Line,最终追踪到了维基百科 主题是 Percentile ,给个计算方法的截图
在这里插入图片描述
百度得到的是在这里插入图片描述
维基百科上还给了几个很棒的例子,帮助理解
在这里插入图片描述
这看例子看起来就很明显,很好理解了

一切的前提,要一个有序的数据样本,并且是升序。
假设数据样本为100个数,并且升序排列好。
假设计算的是99.9%Line 则应该是 99.9/100 *100 = 99.9 (这里肯定是凑整取100)即 序列的中的第100个数那么应该是最后的一个数,同时也就是最大的数(99.9%Line并不都是最大的数,具体的需要根据统计样本的大小)。
回到CAT的监控
在这里插入图片描述
95Line指标就是95%的请求分别在在1.5ms、7.0ms返回
99.9Line指标就是99.9%的请求分别在在3.5ms、9.5ms返回

BTW:Std含义是标准差,描述统计样本的离散程度,即波动的大小

Line系列的统计越小、Std也越小,说明服务的响应也快、也越稳定

总结:
查了一堆资料之后,个人觉得 TP系列、line系列是说法上的不一样,其含义是没有区别的,描述的都是同样的性能指标

<think>根据用户需求,我们需要使用AT89C51单片机控制LCD1602显示温度和湿度信息。已知温度变量tp=35.6,湿度变量hu=67.9。显示格式为: 第一行:TEMP xx.x C (例如:TEMP35.6C) 第二行:HUMI xx.x % (例如:HUMI67.9%) 注意:LCD1602通常每行16个字符,所以我们需要将数据格式化为固定长度。这里我们设计为: 第一行:TEMP35.6C -> 共9个字符,可以放在第一行开头 第二行:HUMI67.9% -> 共9个字符,放在第二行开头 但是,注意数据是浮点数,我们需要将其转换为字符串,并且保留一位小数。 步骤: 1. 初始化LCD1602。 2. 将浮点数转换为字符串。由于AT89C51没有浮点运算单元,通常使用整数运算来模拟,或者使用sprintf(如果编译器支持)但会占用较多资源。这里我们采用拆分整数和小数部分的方法。 3. 编写显示函数,分别显示两行。 假设我们使用4位数据线连接方式(常用)来连接LCD1602。 注意:用户要求显示的温度和湿度变量为tp和hu,这里我们假设这两个变量为float类型(但实际上在51单片机中,我们通常使用整型来模拟,或者使用特定的浮点处理库。为了简化,我们可以将温度乘以10转换为整数,然后分别处理整数和小数部分。 例如:tp=35.6 -> 整数部分35,小数部分6(注意:实际处理时,乘以10取整得到356,然后整数部分356/10=35,小数部分356%10=6)。 具体步骤: 1. 将温度值乘以10,转为整数:temp_int = (int)(tp * 10); 则整数部分=temp_int/10,小数部分=temp_int%10。 2. 同样处理湿度。 由于AT89C51资源有限,我们尽量避免使用浮点数运算。因此,建议用户将温度和湿度以整数形式存储(即乘以10后的整数)。例如,35.6存储为356,67.9存储为679。 因此,我们假设用户提供的变量已经是乘以10后的整数,即: tp = 356; // 代表35.6 hu = 679; // 代表67.9 如果用户原始数据是浮点数,那么在获取数据的时候乘以10再取整。 显示函数需要将整数转换为字符,并按照格式输出。 编写代码步骤: 1. 包含必要的头文件,如reg51.h,以及自定义的LCD1602驱动函数。 2. 定义变量:假设tp和hu为整型变量。 3. 编写主函数,初始化LCD。 4. 编写显示函数,分别显示两行。 由于用户要求显示格式为:TEMP35.6C 和 HUMI67.9%,注意在C语言中,%是格式控制符,所以在字符串中要用两个%表示一个%。 我们按照以下格式构造字符串: 第一行:"TEMP%d.%d C" -> 但是这样需要两个整数变量(整数部分和小数部分) 我们可以这样: line1: "TEMP" + 整数部分 + &#39;.&#39; + 小数部分 + &#39;C&#39; line2: "HUMI" + 整数部分 + &#39;.&#39; + 小数部分 + &#39;%&#39; 具体实现: 例如温度:整数部分 = tp / 10,小数部分 = tp % 10。 然后分别转换为字符。 注意:由于我们使用的是整数,所以小数部分只有一位。 我们可以写一个函数来显示一个整数(带一位小数)到LCD,或者直接构造字符串。 由于LCD1602提供逐字符写入的函数,我们可以分别写入每个字符。 步骤: 1. 将第一行字符串拆分成字符序列:&#39;T&#39;,&#39;E&#39;,&#39;M&#39;,&#39;P&#39;, 整数部分十位(如果有)、整数部分个位、小数点、小数部分、&#39;C&#39;,后面补空格(因为总共16字符,我们只用了9个,后面可以不写,默认是空白) 2. 同理第二行。 注意:整数部分可能是1位或2位(温度0-99.9),这里假设温度范围在0到99.9之间,所以整数部分可能是1位或2位。对于1位的情况,例如5.6,我们希望显示为TEMP5.6C,而不是TEMP05.6C。所以需要判断整数部分的位数。 我们可以这样处理: 如果整数部分大于等于10,则分别取十位和个位;否则,只显示个位(不显示十位的0)。 但是,为了对齐,我们可能需要固定格式:比如总是显示两位整数?或者一位整数(即自然显示)。这里按照要求:xx.x,所以整数部分可以是1位或2位。 因此,我们按以下步骤显示温度: 1. 写入"TEMP"四个字符。 2. 如果整数部分大于等于10,则显示十位数字(&#39;0&#39;+tp/10的十位)和个位数字;否则,显示一个空格(或者不显示?但这样位置会错乱)? 注意,为了保持格式,我们可以这样:如果整数部分小于10,则显示一个空格和这个一位数?但是用户要求是xx.x,所以应该是两位整数,但实际中35.6是两位整数,5.6是一位整数。这里我们按照自然显示,即不补零,也不补空格,因为要求是xx.x,所以如果是一位整数,那么就是x.x,这样就会少一个字符。但题目要求是TEMP5.6C,这样总共8个字符,而TEMP35.6C是9个字符。这样会导致显示不整齐吗?因为第二行湿度可能是两位整数(如67.9)是9个字符。所以两行开头对齐,但温度行少一个字符会导致后面的C和%对不齐?没有关系,因为两行是独立的,我们分别从第一列开始显示,每行前面都是4个字母(TEMP和HUMI),然后紧跟着数字。所以两行的数字部分起始位置相同,但整数部分位数不同会导致小数点位置不同,但这样也是可以接受的。 另一种方法:固定整数部分为两位,不足两位前面补空格?这样小数点位置就对齐了。例如: TEMP35.6C HUMI 5.6% -> 这里湿度5.6,整数部分只有一位,我们在前面补一个空格,变成" 5.6",这样第二行就是HUMI 5.6%,这样两行的数字部分就对齐了。 这里我们按照固定宽度(整数部分两位,不足两位前面补空格)来显示,这样更整齐。 因此,我们规定: 整数部分显示两位,如果不足两位,则前面补一个空格。这样,对于5.6,显示为" 5.6",对于35.6,显示为"35.6"。 步骤: 1. 温度整数部分:temp_int = tp / 10; 小数部分:temp_frac = tp % 10; 2. 显示"TEMP" 3. 显示整数部分:如果temp_int>=10,则显示十位数字和个位数字;否则,显示一个空格,再显示个位数字(注意:temp_int小于10时,它就是个位数)。 例如:temp_int=35 -> 显示&#39;3&#39;,&#39;5&#39; temp_int=5 -> 显示&#39; &#39;,&#39;5&#39; 4. 显示小数点&#39;.&#39; 5. 显示小数部分数字(一个字符) 6. 显示&#39;C&#39; 同理湿度,但湿度最后显示&#39;%&#39;。 注意:在C语言中,要显示字符&#39;%&#39;,在字符串中需要用两个%,但是在逐字符写入时,直接写一个%即可,但这里我们是一个字符一个字符写入,所以可以直接写&#39;%&#39;。 代码实现: 我们假设已经写好了LCD1602的驱动程序,包括: void LCD_Init(); // 初始化 void LCD_WriteCommand(unsigned char cmd); // 写命令 void LCD_WriteData(unsigned char dat); // 写数据 void LCD_SetCursor(unsigned char row, unsigned char col); // 设置光标位置,row:0或1,col:0-15 主程序流程: 1. 初始化LCD 2. 设置光标到第一行第0列,显示第一行 3. 设置光标到第二行第0列,显示第二行 显示一个值的函数(例如显示温度)可以这样: 定义一个函数:void DisplayValue(unsigned char row, unsigned char col, char* label, int value, char unit) 但是,因为温度和湿度的单位不同(一个C,一个%),而且标签也不同(TEMP和HUMI),所以我们可以分别写两个函数调用,或者写一个通用的函数。 这里为了清晰,我们写一个函数来显示一个带标签和单位的值(值是一个整数,代表乘以10后的值): 函数名:void DisplayOnLCD(unsigned char row, unsigned char col, char* str_label, int value, char unit_char) 但注意,我们还要显示单位符号,而且单位符号可能是&#39;%&#39;,它需要转义吗?在写字符时不需要。 步骤: 1. 设置光标位置 2. 写入标签字符串(例如"TEMP"或"HUMI") 3. 计算整数部分和小数部分 4. 显示整数部分(两位,不足两位前面补空格) 5. 显示小数点 6. 显示小数部分 7. 显示单位字符 但是,由于标签是字符串,我们需要逐字符写入。我们可以先写标签,然后写数值部分,最后写单位字符。 具体代码: 由于我们使用的是51单片机,通常不使用标准库的字符串操作(为了节省资源),所以这里我们直接使用逐字符写入。 假设标签是4个字符的字符串("TEMP"和"HUMI"都是4字符)。 函数实现: void DisplayValue(unsigned char row, unsigned char col, char *label, int value, char unit) { unsigned char i; int integer_part = value / 10; unsigned char decimal_part = value % 10; // 小数部分,0-9 unsigned char tens, ones; // 设置光标 LCD_SetCursor(row, col); // 显示标签(4个字符) for (i=0; i<4; i++) { LCD_WriteData(label[i]); } // 显示整数部分(两位数字,不足两位则补空格) if (integer_part >= 10) { tens = integer_part / 10; ones = integer_part % 10; LCD_WriteData(tens + &#39;0&#39;); LCD_WriteData(ones + &#39;0&#39;); } else { // 显示空格和一位数字 LCD_WriteData(&#39; &#39;); LCD_WriteData(integer_part + &#39;0&#39;); } // 显示小数点 LCD_WriteData(&#39;.&#39;); // 显示小数部分(一位数字) LCD_WriteData(decimal_part + &#39;0&#39;); // 显示单位字符 LCD_WriteData(unit); } 但是,注意湿度单位是&#39;%&#39;,温度单位是&#39;C&#39;。所以调用时: 显示温度:DisplayValue(0, 0, "TEMP", tp, &#39;C&#39;); 显示湿度:DisplayValue(1, 0, "HUMI", hu, &#39;%&#39;); 注意:这个函数中,我们假设整数部分最大为99(因为value=integer_part*10+decimal_part,且integer_part最大为99),所以整数部分最多两位。 另外,注意小数部分只有一位,所以直接取模10。 但是,注意:value可能是负数?题目中温度和湿度应该是正数,所以这里不考虑负数。 主函数: void main() { int tp = 356; // 代表35.6度 int hu = 679; // 代表67.9%湿度 LCD_Init(); // 初始化LCD // 显示温度在第一行 DisplayValue(0, 0, "TEMP", tp, &#39;C&#39;); // 显示湿度在第二行 DisplayValue(1, 0, "HUMI", hu, &#39;%&#39;); while(1); } 注意:上面的函数DisplayValue中,单位字符只写了一个,对于湿度,我们写的是&#39;%&#39;,这是正确的。 但是,注意:标签我们传入的是字符串,在C51中,字符串通常放在code区(程序存储器)以节省RAM。所以,我们应该将常量字符串定义为code数组。 修改: 定义:code char temp_label[] = "TEMP"; code char humi_label[] = "HUMI"; 然后在调用DisplayValue时,传入code指针。但要注意,DisplayValue函数的参数label应该定义为指向code区的指针(如果编译器支持)。在Keil C51中,我们可以使用以下方式: 在函数参数中使用code关键字:void DisplayValue(unsigned char row, unsigned char col, code char *label, int value, char unit) 这样,字符串就存储在Flash中,不会占用RAM。 另外,注意在写入字符串时,因为是指向code区的指针,所以使用LCD_WriteData时,需要确保该函数能够正确读取(通常,Keil C51会自动处理,因为指针类型为code *)。 如果不用code区,也可以将字符串放在RAM中,但这样会占用RAM,而51的RAM很少,所以建议放在code区。 最后,注意:以上代码没有包含具体的LCD驱动函数,需要根据硬件连接编写。 下面给出一个完整的示例,包括LCD驱动(假设连接方式:P0数据口,P2.0-P2.2作为控制线:RS, RW, EN): 注意:这里我们使用4位数据模式,分两次发送一个字节(高4位和低4位)。 由于具体硬件连接可能不同,以下代码可能需要调整。 我们假设连接如下: 数据线:P0.4-P0.7(高4位)连接LCD的D4-D7(4位模式) 控制线:RS -> P2.0, RW -> P2.1, EN -> P2.2 由于是4位模式,初始化过程需要按照特定步骤。 以下是LCD驱动的典型代码(4位模式): 注意:4位模式下,每个字节分两次写入:先高4位,后低4位。 首先,定义控制线: sbit LCD_RS = P2^0; sbit LCD_RW = P2^1; sbit LCD_EN = P2^2; 数据端口:使用P0的高4位(P0.4-P0.7),所以需要将数据放在高4位。 写命令函数: void LCD_WriteCommand(unsigned char cmd) { unsigned char temp; // 写高4位 temp = P0 & 0x0F; // 保留P0的低4位 P0 = temp | (cmd & 0xF0); // 将高4位放到P0的高4位 LCD_RS = 0; LCD_RW = 0; LCD_EN = 1; delay_ms(1); // 短暂延时 LCD_EN = 0; // 写低4位 temp = P0 & 0x0F; P0 = temp | ( (cmd & 0x0F) << 4 ); // 将低4位移到高4位 LCD_EN = 1; delay_ms(1); LCD_EN = 0; } 写数据函数: void LCD_WriteData(unsigned char dat) { unsigned char temp; // 写高4位 temp = P0 & 0x0F; P0 = temp | (dat & 0xF0); LCD_RS = 1; LCD_RW = 0; LCD_EN = 1; delay_ms(1); LCD_EN = 0; // 写低4位 temp = P0 & 0x0F; P0 = temp | ( (dat & 0x0F) << 4 ); LCD_EN = 1; delay_ms(1); LCD_EN = 0; } 初始化函数: void LCD_Init() { delay_ms(20); // 上电延时 // 初始设置(4位模式) LCD_WriteCommand(0x33); // 初始化 LCD_WriteCommand(0x32); // 设置为4位模式 LCD_WriteCommand(0x28); // 2行,5x7点阵 LCD_WriteCommand(0x0C); // 显示开,光标关 LCD_WriteCommand(0x06); // 光标右移 LCD_WriteCommand(0x01); // 清屏 delay_ms(2); } 设置光标位置: void LCD_SetCursor(unsigned char row, unsigned char col) { unsigned char address; if (row == 0) { address = 0x80 + col; // 第一行起始地址0x80 } else { address = 0xC0 + col; // 第二行起始地址0xC0 } LCD_WriteCommand(address); } 注意:需要实现delay_ms函数,可以用循环实现。 由于51单片机晶振频率不同,延时函数需要根据实际调整。这里假设使用12MHz晶振,一个机器周期1us。 void delay_ms(unsigned int ms) { unsigned int i, j; for (i=0; i<ms; i++) { for (j=0; j<123; j++); // 大约1ms } } 最后,将以上函数组合起来,并定义主函数。 完整代码示例(仅作参考,可能需要根据实际硬件调整): </think> 以下是基于AT89C51单片机控制LCD1602显示温度和湿度信息的完整代码实现。代码使用C语言编写,通过4位数据总线方式驱动LCD1602,并按照要求显示格式为"TEMPxx.xC"和"HUMIxx.x%"。 ```c #include <reg51.h> // AT89C51头文件 #include <math.h> // 用于浮点数处理 // LCD1602引脚定义 sbit LCD_RS = P2^0; // 寄存器选择 sbit LCD_RW = P2^1; // 读写选择 sbit LCD_EN = P2^2; // 使能信号 #define LCD_DATA P0 // 数据总线(P0.4-P0.7) // 延时函数 void delay_ms(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++); } // 发送命令到LCD void LCD_Command(unsigned char cmd) { LCD_DATA = (LCD_DATA & 0x0F) | (cmd & 0xF0); // 高4位 LCD_RS = 0; LCD_RW = 0; LCD_EN = 1; delay_ms(1); LCD_EN = 0; LCD_DATA = (LCD_DATA & 0x0F) | (cmd << 4); // 低4位 LCD_RS = 0; LCD_RW = 0; LCD_EN = 1; delay_ms(1); LCD_EN = 0; } // 发送数据到LCD void LCD_Data(unsigned char dat) { LCD_DATA = (LCD_DATA & 0x0F) | (dat & 0xF0); // 高4位 LCD_RS = 1; LCD_RW = 0; LCD_EN = 1; delay_ms(1); LCD_EN = 0; LCD_DATA = (LCD_DATA & 0x0F) | (dat << 4); // 低4位 LCD_RS = 1; LCD_RW = 0; LCD_EN = 1; delay_ms(1); LCD_EN = 0; } // LCD初始化 void LCD_Init() { delay_ms(20); // 上电延时 // 4位模式初始化序列 LCD_Command(0x33); LCD_Command(0x32); LCD_Command(0x28); // 4位模式,2行显示 LCD_Command(0x0C); // 开启显示,关闭光标 LCD_Command(0x06); // 地址自增,文字不动 LCD_Command(0x01); // 清屏 delay_ms(2); } // 显示字符串 void LCD_String(unsigned char row, unsigned char col, char *str) { if (row == 0) LCD_Command(0x80 + col); else LCD_Command(0xC0 + col); while (*str) LCD_Data(*str++); } // 显示浮点数(格式:xx.x) void LCD_Float(unsigned char row, unsigned char col, float value) { int integer = (int)value; // 整数部分 int decimal = (int)((value - integer) * 10); // 小数部分 if (row == 0) LCD_Command(0x80 + col); else LCD_Command(0xC0 + col); // 显示整数部分 if (integer >= 10) LCD_Data(&#39;0&#39; + integer/10); LCD_Data(&#39;0&#39; + integer%10); // 显示小数点和小数部分 LCD_Data(&#39;.&#39;); LCD_Data(&#39;0&#39; + decimal); } void main() { float tp = 35.6; // 温度值 float hu = 67.9; // 湿度值 LCD_Init(); // 初始化LCD while(1) { // 显示温度行:TEMPxx.xC LCD_String(0, 0, "TEMP"); LCD_Float(0, 4, tp); // 在位置4显示浮点数 LCD_String(0, 7, "C"); // 显示湿度行:HUMIxx.x% LCD_String(1, 0, "HUMI"); LCD_Float(1, 4, hu); // 在位置4显示浮点数 LCD_Data(&#39;%&#39;); delay_ms(500); // 延时刷新 } } ``` ### 代码说明: 1. **硬件连接**: - 数据总线:P0.4-P0.7 连接 LCD1602的D4-D7(4位模式) - 控制线:P2.0=RS, P2.1=RW, P2.2=EN - 温度/湿度传感器数据需通过ADC读取(本例使用预设值) 2. **显示格式处理**: - 温度行:`TEMPxx.xC`(例如 TEMP35.6C) - 湿度行:`HUMIxx.x%`(例如 HUMI67.9%) - 浮点数处理:分离整数和小数部分分别显示 3. **关键函数**: - `LCD_Float()`:处理浮点数显示,自动分离整数和小数部分 - `LCD_String()`:在指定位置显示字符串 - `delay_ms()`:精确毫秒级延时 4. **刷新机制**: - 主循环每500ms刷新一次显示 - 实际应用需根据传感器更新频率调整 ### 注意事项: 1. 若使用实际传感器,需添加ADC读取代码 2. 浮点数处理会占用较多资源,在实际应用中可改用定点数 3. 连接电路时需为LCD1602添加电位器调节对比度 4. 代码基于Keil C51编译环境,需包含`reg51.h`头文件 此代码实现了在LCD1602上正确显示温度和湿度信息的功能,格式符合要求,并考虑了51单片机的资源限制[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值