stm32专题十七:深度解析 stm32 硬件iic (i2c)

2023-10-26

首先是配置I2C的GPIO,然后配置I2C参数。就是常规配置,按流程来写不会错。

/**
 * @brief EEPROM IIC 配置
 */
void I2C_EE_config(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
	I2C_InitTypeDef I2C_InitStruct;
	
	// 开启I2C GPIO时钟
	EPROM_I2C_GPIO_APBxClkCmd(EEPROM_I2C_SCL_GPIO_CLK | EEPROM_I2C_SDA_GPIO_CLK, ENABLE);
	// 开启I2C 外设时钟
	EEPROM_I2C_APBxClkCmd(EEPROM_I2C_CLK, ENABLE);

  // I2C的引脚配置为复用开漏输出
	GPIO_InitStruct.GPIO_Pin = EPROM_I2C_SCL_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(EPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin = EPROM_I2C_SDA_GPIO_PIN;
  GPIO_Init(EPROM_I2C_SDA_GPIO_PORT, &GPIO_InitStruct);
	
	// 配置I2C参数(时钟速度、模式、占空比、自身地址、应答使能、7位设备地址)
	I2C_InitStruct.I2C_ClockSpeed = EEPROM_I2C_BAUDRATE;
	I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStruct.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR;
	I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	
	// 初始化
	I2C_Init(EEPROM_I2C, &I2C_InitStruct);
	
	// 使能串口
	I2C_Cmd(EEPROM_I2C, ENABLE);
}

EEPROM写入一个字节的代码,这里唯一值得注意的是,在检测到EV8事件时的状态。此时移位寄存器正在发送数据,而数据寄存器DR为空。发送data会被暂存到DR,直到移位寄存器发送完,再由DR转移到移位寄存器。

// 向EEPROM写入一个字节(因为EEPROM设备地址固定为0XA0)
void EEPROM_Byte_Write(uint8_t addr, uint8_t data)
{
	// 产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	// EV5事件被检测到,发送设备地址(直接填入EEPROM的设备地址:EEPROM_ADDR)
	I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	
	// EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C, addr);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);
	
	// EV8事件被检测到(此时移位寄存器正在发送数据,而数据寄存器DR为空)
	// (发送data会被暂存到DR,直到移位寄存器发送完,再由DR转移到移位寄存器)
	I2C_SendData(EEPROM_I2C, data);
	
	// DR不再填入新的数据,移位寄存器发送完最后一个字节,结束
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
	
	// 数据传输完成,产生结束信号
	I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
}

然后是读取n个字节的代码。核心思想有几个。第一,按照EEPROM的random read时序,并检测对应的事件;第二,在读入最后一个字节之前,要把应答使能设置为disable,通知EEPROM不要再发数据;第三,接收数据指针要不断递增,防止覆盖;第四,读操作完成后,重新开启应答使能。

// 从EEPROM读取多个字节
void EEPROM_Read(uint8_t addr, uint8_t *data, uint8_t numByteToRead)
{
	// 产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	// EV5事件被检测到,发送设备地址(直接填入EEPROM的设备地址:EEPROM_ADDR)
	I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	
	// EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C, addr);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);
	
	// 第二次产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	// EV5事件被检测到,发送设备地址,这里方向要选为接收
	I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Receiver);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
	
	// 判断是否为最后一个字节
	while (numByteToRead) 
	{		
		if (numByteToRead == 1)
		{
			// 最后一个字节,产生非应答
			I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
		}
		
		while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR);
		
		// EV7事件被检测到,即数据寄存器有新的有效数据
		*data = I2C_ReceiveData(EEPROM_I2C);
		
		data++;							// 指针指向下一个字节
		numByteToRead--;		
	}
	// 数据传输完成,产生结束信号
	I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
	
	// 重新配置Ack使能,以便下次通讯
	I2C_AcknowledgeConfig(EEPROM_I2C, ENABLE);
}

接下来,就是硬件i2c要注意的几个地方。事实上,直接按如下代码操作,程序会直接卡死:

int main(void)
{	
	uint8_t readData[10] = {0};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	// 写入一个字节
	EEPROM_Byte_Write(11, 0X55);
	
	
	// 读取数据
	EEPROM_Read(11, readData, 1);
	
	printf("\n接收到的数据为: %#X", readData[0]);
		
	while (1)
	{
		
	}
}

为什么?

因为我们是写完立刻读取,而没有缓冲时间。实际上,之前我在EEPROM那篇博客中,有强调一个问题。EEPROM需要写入时间,在这期间内,不响应外部发送的数据,因此,不会产生应答。而在我们的读取函数中,(实际上是发送起始信号后,再发送设备地址然后等待响应),由于EEPROM还在写入,不会响应读取函数中的应答,所以程序会在这里卡死掉while()死循环。

https://blog.csdn.net/dingyc_ee/article/details/100042665

程序卡死的地方:

// 从EEPROM读取多个字节
void EEPROM_Read(uint8_t addr, uint8_t *data, uint8_t numByteToRead)
{
	// 产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	// EV5事件被检测到,发送设备地址(直接填入EEPROM的设备地址:EEPROM_ADDR)
	I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
	
    // 程序会一直卡死在接下来这个while中
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);

解决的方案,就是上面提到的确认轮询。通过不断的产生起始 + 设备地址信号,并检测EEPROM的应答,来判断EEPROM是否已经写入完成,如果应答,则表示写入完成,产生结束条件。这里还有几个操蛋的地方,事件检测函数直接不能用(程序中注释的代码,一用就会出错,我也不知道为什么,好像说是因为这个函数会检测好几个标志位),只能检测响应的标志位。确认轮询的代码如下:

// 确认轮询,等待EEPROM完成写入时序的操作(不断产生:起始 + 设备地址)
void EEPROM_WaitForWriteEnd(void)
{
	do 
	{
		// 产生起始信号
		I2C_GenerateSTART(EEPROM_I2C, ENABLE);
		
		// 这个函数会出错 while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
		while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_SB) == RESET);
		
		// EV5事件被检测到,发送设备地址(直接填入EEPROM的设备地址:EEPROM_ADDR)
		I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
	}
	// 如果EEPROM不响应,则一直产生起始信号,直到响应为止
	// 这个函数会出错 while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	while (I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_ADDR) == RESET);
	
	
	// 如果检测到EEPROM的响应,认为内部写入时序完成,产生结束信号
	I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
}

然后在主函数中进行调用,结果正确:

int main(void)
{	
	uint8_t readData[10] = {0};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	// 写入一个字节
	EEPROM_Byte_Write(11, 0X55);
	
	// 确认轮询操作,等待EEPROM写入完成
	EEPROM_WaitForWriteEnd();
	
	// 读取数据
	EEPROM_Read(11, readData, 1);
	
	printf("\n接收到的数据为: %#X", readData[0]);
		
	while (1)
	{
		
	}
}

串口输出数据如下:

测试读两个数据:

int main(void)
{	
	uint8_t readData[10] = {0};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	// 写入一个字节
	EEPROM_Byte_Write(11, 0X55);
	
	// 确认轮询操作,等待EEPROM写入完成
	EEPROM_WaitForWriteEnd();
	
	EEPROM_Byte_Write(12, 0X56);
	EEPROM_WaitForWriteEnd();
	
	// 读取数据
	EEPROM_Read(11, readData, 2);
	
	printf("接收到的数据为: %#X, %#X\n", readData[0], readData[1]);
		
	while (1);
}

结果如下,说明多字节读取函数正确。

接下来实现页写入的函数(每次不能超过8字节,否则会卷回来到本页起始,覆盖掉之前数据)

// 向EEPROM写入多个字节(页写入),最大不能超过8字节
void EEPROM_Page_Write(uint8_t addr, uint8_t *data, uint8_t numByteToRead)
{
	// 产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	// EV5事件被检测到,发送设备地址(直接填入EEPROM的设备地址:EEPROM_ADDR)
	I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDR, I2C_Direction_Transmitter);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	
	// EV6事件被检测到,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C, addr);
	
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);
	
	while (numByteToRead)
	{
		// EV8事件被检测到
		I2C_SendData(EEPROM_I2C, *data);
		
		// DR不再填入新的数据,移位寄存器发送完最后一个字节,结束
		while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
	
		data++;							// 指针指向下一个字节
		numByteToRead--;		
	}
	// 数据传输完成,产生结束信号
	I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
}

测试代码:

int main(void)
{	
	uint8_t i = 0;
	uint8_t readData[8] = {0};
	uint8_t writeData[8] = {1, 2, 3, 4, 5, 6, 7, 8};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	EEPROM_Page_Write(16, writeData, 8);

	// 确认轮询操作,等待EEPROM写入完成
	EEPROM_WaitForWriteEnd();

	EEPROM_Read(16, readData, 8);
	
	for (i = 0; i < 8; i++)
	{
		printf("%4d", readData[i]);
	}
	printf("\n");
		
	while (1);
}

测试结果:

接下来,演示的是一些很不好的操作,如果写入的数据超过一页,诗句是怎么被覆盖掉的?我们尝试向一页中写入10个数据,然后读取这一页(8)个数据,看看会有什么现象:

测试代码:

int main(void)
{	
	uint8_t i = 0;
	uint8_t readData[8] = {0};
	uint8_t writeData[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	EEPROM_Page_Write(16, writeData, 10);

	// 确认轮询操作,等待EEPROM写入完成
	EEPROM_WaitForWriteEnd();

	EEPROM_Read(16, readData, 8);
	
	for (i = 0; i < 8; i++)
	{
		printf("%4d", readData[i]);
	}
	printf("\n");
		
	while (1);
}

接下来就是见证奇迹的时刻,最后的9 10两个数据,把之前的1 2给覆盖掉了

还有一个问题,关于地址对齐。AT24C02每页为8字节,所以每页的起始地址为0 8 16...,如果我们以对齐的地址来写入,则数据和地址都是正确的。但是,如果我们错开地址,会如何?接下来,从地址2开始连续写入8字节,然后读取8字节,观察结果

测试代码:

int main(void)
{	
	uint8_t i = 0;
	uint8_t readData[8] = {0};
	uint8_t writeData[8] = {1, 2, 3, 4, 5, 6, 7, 8};
	
	USART_config();
	I2C_EE_config();
	
	printf("这是一个IIC通讯实验\n");
	
	EEPROM_Page_Write(2, writeData, 8);

	// 确认轮询操作,等待EEPROM写入完成
	EEPROM_WaitForWriteEnd();

	EEPROM_Read(2, readData, 8);
	
	for (i = 0; i < 8; i++)
	{
		printf("%4d", readData[i]);
	}
	printf("\n");
		
	while (1);
}

测试结果:

可以看到,前面6个数据是正确的,而后2个数据是错误的。分析:后面两个数据,由于反卷,直接写到了第一页的开始两个字节,而我们读取到的数据,则是第二页的前2个数据,验证一下:

测试代码:

int main(void)
{	
	uint8_t i = 0;
	uint8_t readData[8] = {0};
	uint8_t writeData[8] = {1, 2, 3, 4, 5, 6, 7, 8};
	
	USART_config();
	I2C_EE_config();

	printf("这是一个IIC通讯实验\n");
	

	// 读取第一页的前2个数据
	EEPROM_Read(0, readData, 2);
	// 读取第二页的前2个数据
	EEPROM_Read(8, (readData + 2), 2);
	
	printf("读取第一页的前2个数据\n");
	for (i = 0; i < 2; i++)
	{
		printf("%4d", readData[i]);
	}
	printf("\n");
	
	printf("读取第二页的前2个数据\n");
	for (i = 2; i < 4; i++)
	{
		printf("%4d", readData[i]);
	}
	printf("\n");
		
	while (1);
}

测试结果:

与设想的一致。7 8由于反卷,写入到了第一页的前两个字节。而我们读数据时,地址是直接递增的,所以在读取完前6个后,按顺序(不会反卷)读取第二页的数据,因此会导致出错。

那么,我们在使用EEPROM进行页写入时,一定要注意地址8字节对齐,否则会出错,而且极难被发现。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32专题十七:深度解析 stm32 硬件iic (i2c) 的相关文章

  • Acwing 908. 最大不相交区间数量

    include
  • VTM中YUV-PSNR的计算

    名词解释 参见文章cnblogs 什么是SAD SAE SATD SSD SSE MAD MAE MSD MSE PSNR的计算 较为标准的MSE计算公式和PSNR计算公式如下 引用链接 CSDN 图像的峰值信噪比 PSNR 的计算方法 这
  • linux用户态使用gpio中断方法

    一 用户空间gpio的调用文件 用户空间访问gpio 即通过sysfs接口访问gpio 下面是 sys class gpio目录下的三种文件 export unexport文件 gpioN指代具体的gpio引脚 gpio chipN指代gp
  • 数字化转型的成熟度模型

    来啦 坐 我是冠军 数据赋能 IT团队技术管理实战 作者 四季逗文风创始人 这是 数字化转型系列 第五篇 数字化转型的成熟度模型 一句话解释下 要想搞清楚企业数字化转型的目标 就需要确定企业现在处于什么数字化阶段 只有如此 才可以根据现状目
  • Golang

    欢迎关注 全栈工程师修炼指南 公众号 点击 下方卡片 即可关注我哟 设为 星标 每天带你 基础入门 到 进阶实践 再到 放弃学习 专注 企业运维实践 网络安全 系统运维 应用开发 物联网实战 全栈文章 等知识分享 花开堪折直须折 莫待无花空
  • 2023校招联想汽车C++开发一面

    飞书面试 C 开发 全程无手撕代码 开放性面试 1 翻译英文 给几段英文句子 是和专业相关的 要求英译汉 2 给好几组计算机专业名词 从中选择最熟悉的 进行解释 比如https dns smtp等等 3 一个电路 求其中一个电阻电压 4 代
  • NB!更方便Xshell本地密码破解工具

    工具介绍 XshellCrack是基于SharpXDecrypt的二次开发 用go语言重写 增加了注册表查询设置 更方便xshell本地密码破解 关注 Hack分享吧 公众号 回复关键字 230717 获取下载链接 工具使用 Usage r
  • JavaScript--修改 HTML 元素

    这些是一些用于修改 HTML 元素的常见方法 1 document createElement element 创建 HTML 元素节点 可以使用这个方法创建一个新的 HTML 元素 例如 document createElement di
  • Docker进阶学习:Compose配置编写规则

    docker compose yaml 是Compose的核心 以下是compose的官方文档地址 https docs docker com compose compose file compose file structure and
  • rabbitmq集群故障处理

    rabbitmq集群故障处理 故障现象 rabbitmq启动失败 手动kill掉rabbit的后台进程 杀完后进程又会自动起来 故障处理 1 手动更改rabbitmq故障节点的erl crash dump为erl crash dump ba
  • JavaScript 的面向对象基础,设计模式中的原型模式(设计模式与开发实践 P2)

    文章目录 1 1 动态类型语言和鸭子类型 1 2 多态 1 3 封装 封装数据 封装实现 封装类型 1 4 原型模式和基于原型继承的 JavaScript 对象系统 C 原型模式 JS 原型模式 在学习 JS 设计模式之前需要了解一些设计模
  • 嵌入式开发课程简介

    最近几年 几乎所有的IT企业对应届毕业生都有抱怨 动手能力太差 编程水平低下 大学期间 老师授课以理论为主 学生缺少各种实践 这造成很多学生就业难 学生找不到工作 而企业招不到合适的人 本课程不仅系统的梳理了一遍工作中常用的知识 更是通过大
  • LLM论文周报|来自清华、MetaAI、Nous Research等机构论文研究

    大模型 LLM 是一种人工智能模型 旨在理解和生成人类语言 它们在大量的文本数据上进行训练 可以执行广泛的任务 包括文本总结 翻译 情感分析等等 LLM的特点是规模庞大 包含数十亿的参数 帮助它们学习语言数据中的复杂模式 这些模型通常基于深
  • 安装搭建悟空CRM 网络错误,请检查您的网络 问题处理

    1 很多朋友在GitHub上面下载的悟空crm最新版程序 进行安装搭建后发现 运行程序打开显示 悟空软件 但是登录进去管理界面的时候就提示说 网络请求失败 请稍候再试 怎么办呢 2 导入服务端根文件夹数据库文件public sql 5kcr
  • Kubernetes 网络概念及策略控制(叶磊)

    本文将主要分享以下 5 方面的内容 Kubernetes 基本网络模型 Netns 探秘 主流网络方案简介 Network Policy 的用处 思考时间 Kubernetes 基本网络模型 本节来介绍一下 Kubernetes 对网络模型

随机推荐

  • SpringBoot 集成MyBatis-Plus提示反序列化异常:cannot deserialize from Object value (no delegate- or property-bas

    SpringBoot集成MyBatis Plus 实现HTPP POST提交实体对象提示如下错误片段 重点错误信息字段 cannot deserialize from Object value no delegate or property
  • ECharts折线图+联动+dataZoom

  • SpringBoot配置数据源DataSource

    使用properties文件配置springboot默认数据源 这种方式十分简单 只用在application properties文件中配置数据库连接属性即可 spring datasource url jdbc mysql localh
  • 7-22 龟兔赛跑 (20分)

    思路 当时间为10的倍数的时候看看兔子的路程有没有乌龟的长 若比乌龟长 则兔子开始休息三十分钟 其中有一个测试点就是注意兔子在休息中时间t到了 代码如下 include
  • ERROR: Invalid requirement: ‘_libgcc_mutex=0.1=main‘ XXX Hint: = is not a valid operator. Did you me

    问题如图所示 我是在GitHub加载environment yml文件时 遭遇这种情况 其实 这也不难解决 其一将environment yml文件中dependencices中 报错的部分依赖项 放到 pip 下 或者将 libgcc m
  • 探索将大语言模型用作推荐系统

    编者按 目前大语言模型主要问答 对话等场景 进行被动回答 是否可以将大模型应用于推荐系统 进行主动推送呢 这篇文章回顾了可以将大模型作为推荐系统的理论基础 并重点描述了基于英文和阿拉伯语的购物数据集微调T5 large模型 探索将LLMs用
  • d3dcompiler_43.dll文件丢失怎么修复,最新修复方法分享

    本教程操作系统 Windows系统 d3dcompiler 43 dll是电脑文件中的dll文件 动态链接库文件 如果计算机中丢失了某个dll文件 可能会导致某些软件和游戏等程序无法正常启动运行 并且导致电脑系统弹窗报错 在我们打开软件或者
  • PyTorch Lightning错误TypeError: lr_scheduler_step() takes 3 positional arguments but 4 were given

    问题 使用PyTorch Lightning时对lr scheduler step定义如下 def lr scheduler step self scheduler metric scheduler step 出错 TypeError lr
  • Ubuntu 安装 cmake

    目录 1 下载cmake安装包 2 开始安装 3 查看cmake版本 参考链接 https blog csdn net qq 27350133 article details 121994229 1 下载cmake安装包 cmake安装包下
  • Jmeter实现websocket协议接口测试

    一 为了方便使用 首先将jmeter设置成中文 有两种方法 1 在Jmeter界面进行设置 Options gt Choose Language gt Chinese Simplified 这种方法在关闭jmeter重启后又会恢复成默认的英
  • 最优化理论·非线性最小二乘

    最优化理论 非线性最小二乘 标签 空格分隔 数学 非线性最小二乘问题是椭圆拟合中最易遇到的优化问题 本文主要对非线性二乘的基本分析做简单介绍 1 什么是最小二乘问题 目标函数能够写为m个函数平方和的优化问题 其中 每个函数 f i x
  • 高内聚、低耦合

    http www cnblogs com robnetcn archive 2012 04 15 2449008 html 起因 模块独立性指每个模块只完成系统要求的独立子功能 并且与其他模块的联系最少且接口简单 两个定性的度量标准 耦合性
  • crunch 字典生成 hashcat 破解密码

    crunch crunch 9 9 t 2003 gt gt 999 txt 生成9位密码 b 指定文件输出的大小 避免字典文件过大 c 指定文件输出的行数 即包含密码的个数 d 限制相同元素出现的次数 e 定义停止字符 即到该字符串就停止
  • 配置Tomcat数据源和连接池

    修改C Tomcat 6 0 conf context xml 在
  • TCP/IP网络编程(一)

    TCP IP网络编程 第一章 理解网络编程和套接字 实现 先准备一个linux的操作系统然后用xshell连上 CentOS7安装以及Xshell连接常见问题解决 jump into zehe的博客 CSDN博客 下载gcc root lo
  • R语言使用choose函数计算排列组合:组合数(输入两个参数、combination)

    R语言使用choose函数计算排列组合 组合数 输入两个参数 combination 目录 R语言使用choose函数计算组合数 输入两个参数 combination R 语言特点 R语言使用choose函数计算组合数 输入两个参数 com
  • Java高频面试复习题,助你面试成功

    前言 2022年对程序员来说是特别严峻的一年 也是大改革的一年 大部分人因为今年 疫情 的原因纷纷离开了自己原有的岗位 也有人抓住机会逆流而上拿到更高的待遇 2022年金九银十已经到来了 试问你进入了自己心仪的企业了吗 拿到自己满意的薪资待
  • 利用Chrome网络请求调试页面跳转问题

    背景 现在大量的信息系统都是基于WEB服务 这些WEB服务糅合了单点登录 权限控制 网关 代理等多种技术手段 当请求一个页面时 发现它跳转的目标竟然让人匪夷所思 完全不是意想中的样子 怎样捕捉这些跳转信息 并进行分析 是解决跳转问题的有效手
  • Android studio 入门第一个APP

    开发第一应用 可以开发属于自己的应用 是否有点小激动 好吧 让我们开始 首先点击Start a new Android Studio Project创建工程 接下来需要输入应用名称 第一个字母要大写 公司域以及指定应用存放目录 点击Next
  • stm32专题十七:深度解析 stm32 硬件iic (i2c)

    首先是配置I2C的GPIO 然后配置I2C参数 就是常规配置 按流程来写不会错 brief EEPROM IIC 配置 void I2C EE config void GPIO InitTypeDef GPIO InitStruct I2C