ARM I2C通信

1.概念

	I2C总线是PHLIPS公司在八十年代初推出的一种串行的半双工同步总线,主要用于连接整体电路

2.IIC总线硬件连接

在这里插入图片描述

1.IIC总线支持多主机多从机,但是在实际开发过程中,大多数采用单主机多从机模式
2.挂接到IIC总线上,每个从机设备都有自己的7bit从机地址
3.在总线上,发送数据的叫做发送器,接收数据叫做接收器
4.主动发起数据的叫做主机,只能被动接收数据的叫做从机
5.时钟信号由主机产生,作用:给从机,为了IIC总线上传输数据同步

3.IIC总线时序

3.1起始信号

在这里插入图片描述

在SCL为高电平期间,SDA从高到低的变化(下降沿),属于起始信号
起始信号由主机产生,起始信号产生之后,总线占用状态

3.2停止信号

在这里插入图片描述

在SCL为高电平期间,SDA从低到高的变化(上升沿),属于终止信号
停止信号由主机产生,停止信号产生之后,总线空闲状态

3.3数据传输信号(读写)

在这里插入图片描述

1.在SCL为高电平期间,数据线上的数据保持稳定,接收器从数据线上读取数据
2.在SCL为低电平期间,数据线上的数据允许变化,发送器向数据线上写入数据

3.4应答信号

在这里插入图片描述

1.每一个字节必须保证是8位长度。数据传送时,先传送高位,在发送低位,每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)
2.发送器在发送完8位数据位之后,接收器在第9个时钟周期,返回一个应答信号(0),或者非应答信号(1)
    在第9个时钟周期,接收器向数据线上写入数据
    在第9个时钟周期,发送器从数据线上读取数据
    如果读取到0,代表应答信号
    如果读取到1,代表非应答信号

3.5寻址

在这里插入图片描述

1.IIC总线上传输数据是广义的,可以传输地址信号,也可以传输数据信号
2.主机在产生起始信号之后,必须传送7位从机地址,加上读写位
3.用0表示写,用1表示读

4.IIC框图

在这里插入图片描述

5.IIC总线协议

5.1主机给从机发送一个字节

在这里插入图片描述

5.2主机给从机发送多个连续字节

在这里插入图片描述

5.3主机从从机读一个字节

在这里插入图片描述

5.4主机从从机读多个连续字节

在这里插入图片描述

6.GPIO模拟IIC协议

在这里插入图片描述

7.分析SI7006芯片手册

7.1思路

1.分析SI7006芯片手册内部实现框图
2.分析SI7006从机地址
3.分析SI7006芯片通信协议
4.分析找到采集温湿度传感器命令码
5.找到将采集的模拟量转换为数字量的公式
6.分析SI7006初始化的值

7.2从机地址

在这里插入图片描述

通过以上分析可知,si7006芯片从机地址0x40
从机地址 + 读:0x40 << 1 | 1
从机地址 + 写:0x40 << 1 | 0

7.3分析命令码

在这里插入图片描述

7.4协议

在这里插入图片描述

7.5公式

在这里插入图片描述
在这里插入图片描述

7.6初始化值

在这里插入图片描述

8.代码

// si7006.h
#ifndef __SI7006_H__
#define __SI7006_H__

#include "iic.h"
#define SI7006_SLAVE 0x40

void si7006_init(void);

unsigned short si7006_read_hum_data(unsigned char slave_addr, unsigned char cmd_code);
short si7006_read_temp_data(unsigned char slave_addr, unsigned char cmd_code);

#endif //__SI7006_H__

// si7006.c
#include "iic.h"
#include "si7006.h"
/*
 * 函数名:si7006_init
 * 函数功能:SI7006芯片的初始化
 * 函数参数:无
 * 函数返回值:无
 */
extern void delay(int ms);
// 往SI7006芯片0XE6写入0X3A
void si7006_init(void)
{
	// I2初始化
	i2c_init();
	// 发送起始信号
	i2c_start();
	// 主机发送7位从机地址+1位写位
	i2c_write_byte(0X40 << 1 | 0);
	// 等待从机回应
	i2c_wait_ack();
	// 发送寄存器地址
	i2c_write_byte(0XE6);
	// 等待从机回应
	i2c_wait_ack();
	// 发送要写的数据
	i2c_write_byte(0X3A);
	// 等待从机回应
	i2c_wait_ack();
	// 发送终止信号
	i2c_stop();
}
/*
 * 函数名:si7006_read_hum_data
 * 函数功能:读取SI7006的湿度转换结果
 * 函数参数:
 *     slave_addr : 从机地址
 *     cmd_code : 命令码
 * 函数返回值:湿度测量的数字量
 */
unsigned short si7006_read_hum_data(unsigned char slave_addr,
									unsigned char cmd_code)
{
	unsigned short dat;			// 保存读取到的湿度数据
	unsigned char dat_h, dat_l; // 保存读取到的数据的高八位和低八位
	// 发送起始信号
	i2c_start();
	// 主机发送7位从机地址+1位写位
	i2c_write_byte(slave_addr << 1 | 0);
	// 等待从机回应
	i2c_wait_ack();
	// 发送寄存器地址
	i2c_write_byte(cmd_code);
	// 等待从机回应
	i2c_wait_ack();
	// 发送第二次起始信号
	i2c_start();
	// 主机发送7位从机地址+1位写位
	i2c_write_byte(slave_addr << 1 | 1);
	// 等待从机回应
	i2c_wait_ack();
	// 延时等待从机测量数据
	delay(100);
	// 读取数据的高8位
	dat_h = i2c_read_byte(0); // 读取完毕发送应答信号
	// 读取数据的低8位
	dat_l = i2c_read_byte(1); // 读取完毕发送非应答信号
	// 发送停止信号
	i2c_stop();
	// 将读取到的数据整合到一起
	dat = (dat_h << 8) | dat_l;
	return dat;
}
/*
 * 函数名:si7006_read_temp_data
 * 函数功能:读取SI7006的温度转换结果
 * 函数参数:
 *     slave_addr : 从机地址
 *     cmd_code : 命令码
 * 函数返回值:温度测量的数字量
 */
short si7006_read_temp_data(unsigned char slave_addr,
							unsigned char cmd_code)
{
	short dat;		   // 保存读取到的温度数据
	char dat_h, dat_l; // 保存读取到的数据的高八位和低八位
	// 发送起始信号
	i2c_start();
	// 主机发送7位从机地址+1位写位
	i2c_write_byte(slave_addr << 1 | 0);
	// 等待从机回应
	i2c_wait_ack();
	// 发送寄存器地址
	i2c_write_byte(cmd_code);
	// 等待从机回应
	i2c_wait_ack();
	// 发送第二次起始信号
	i2c_start();
	// 主机发送7位从机地址+1位写位
	i2c_write_byte(slave_addr << 1 | 1);
	// 等待从机回应
	i2c_wait_ack();
	// 延时等待从机测量数据
	delay(100);
	// 读取数据的高8位
	dat_h = i2c_read_byte(0); // 读取完毕发送应答信号
	// 读取数据的低8位
	dat_l = i2c_read_byte(1); // 读取完毕发送非应答信号
	// 发送停止信号
	i2c_stop();
	// 将读取到的数据整合到一起
	dat = (dat_h << 8) | dat_l;
	return dat;
}

// iic.h
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// #include "gpio.h"
/* 通过程序模拟实现I2C总线的时序和协议
 * GPIOF ---> AHB4
 * I2C1_SCL ---> PF14
 * I2C1_SDA ---> PF15
 *
 * */

#define SET_SDA_OUT                     \
	do                                  \
	{                                   \
		GPIOF->MODER &= (~(0x3 << 30)); \
		GPIOF->MODER |= (0x1 << 30);    \
	} while (0)
#define SET_SDA_IN                      \
	do                                  \
	{                                   \
		GPIOF->MODER &= (~(0x3 << 30)); \
	} while (0)

#define I2C_SCL_H                   \
	do                              \
	{                               \
		GPIOF->BSRR |= (0x1 << 14); \
	} while (0)
#define I2C_SCL_L                  \
	do                             \
	{                              \
		GPIOF->BRR |= (0x1 << 14); \
	} while (0)

#define I2C_SDA_H                   \
	do                              \
	{                               \
		GPIOF->BSRR |= (0x1 << 15); \
	} while (0)
#define I2C_SDA_L                  \
	do                             \
	{                              \
		GPIOF->BRR |= (0x1 << 15); \
	} while (0)

#define I2C_SDA_READ (GPIOF->IDR & (0x1 << 15))

void delay_us(void);
void i2c_init(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(unsigned char dat);
unsigned char i2c_read_byte(unsigned char ack);
unsigned char i2c_wait_ack(void);
void i2c_ack(void);
void i2c_nack(void);

#endif

// icc.h
#include "iic.h"

extern void printf(const char *fmt, ...);
/*
 * 函数名 : delay_us
 * 函数功能:延时函数
 * 函数参数:无
 * 函数返回值:无
 * */
void delay_us(void)
{
	unsigned int i = 2000;
	while (i--)
		;
}
/*
 * 函数名 : i2c_init
 * 函数功能: i2C总线引脚的初始化, 通用输出,推挽输出,输出速度,
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_init(void)
{
	// 使能GPIOF端口的时钟
	RCC->MP_AHB4ENSETR |= (0x1 << 5);
	// 设置PF14,PF15引脚为通用的输出功能
	GPIOF->MODER &= (~(0xF << 28));
	GPIOF->MODER |= (0x5 << 28);
	// 设置PF14, PF15引脚为推挽输出
	GPIOF->OTYPER &= (~(0x3 << 14));
	// 设置PF14, PF15引脚为高速输出
	GPIOF->OSPEEDR |= (0xF << 28);
	// 设置PF14, PF15引脚的禁止上拉和下拉
	GPIOF->PUPDR &= (~(0xF << 28));
	// 空闲状态SDA和SCL拉高
	I2C_SCL_H;
	I2C_SDA_H;
}

/*
 * 函数名:i2c_start
 * 函数功能:模拟i2c开始信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_start(void)
{
	/*
	 * 开始信号:时钟在高电平期间,数据线从高到低的变化
	 *     --------
	 * SCL         \
	 *              --------
	 *     ----
	 * SDA     \
	 *          --------
	 * */
	// 确保SDA是输出状态 PF15输出
	SET_SDA_OUT;
	// 空闲状态SDA和SCL拉高
	I2C_SCL_H;
	I2C_SDA_H;
	delay_us(); // 延时等待一段时间
	I2C_SDA_L;	// 数据线拉低
	delay_us(); // 延时等待一段时间
	I2C_SCL_L;	// 时钟线拉低,让总线处于占用状态
}

/*
 * 函数名:i2c_stop
 * 函数功能:模拟i2c停止信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */

void i2c_stop(void)
{
	/*
	 * 停止信号 : 时钟在高电平期间,数据线从低到高的变化
	 *             ----------
	 * SCL        /
	 *    --------
	 *    ---         -------
	 * SDA   X       /
	 *    --- -------
	 * */
	// 确保SDA是输出状态 PF15输出
	SET_SDA_OUT;
	// 时钟线拉低
	I2C_SCL_L;
	delay_us(); // 延时等待一段时间
	I2C_SDA_L;	// 数据线拉低
	delay_us(); // 延时等待一段时间
	// 时钟线拉高
	I2C_SCL_H;
	delay_us(); // 延时等待一段时间
	I2C_SDA_H;	// 数据线拉高
}

/*
 * 函数名: i2c_write_byte
 * 函数功能:主机向i2c总线上的从设备写8bits数据
 * 函数参数:dat : 等待发送的字节数据
 * 函数返回值: 无
 * */

void i2c_write_byte(unsigned char dat)
{
	/*
	 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
	 *          时钟在高电平期间,接收器从数据线上读取数据
	 *      ----          --------
	 *  SCL     \        /        \
	 *           --------          --------
	 *      -------- ------------------ ---
	 *  SDA         X                  X
	 *      -------- ------------------ ---
	 *
	 *      先发送高位在发送低位
	 * */
	// 确保SDA是输出状态 PF15输出
	SET_SDA_OUT;
	unsigned int i;
	for (i = 0; i < 8; i++)
	{
		// 时钟线拉低
		I2C_SCL_L;
		delay_us(); // 延时
		// 0X3A->0011 1010   0X80->10000000
		if (dat & 0X80) // 最高位为1
		{
			// 发送1
			I2C_SDA_H;
		}
		else // 最高位为0
		{
			I2C_SDA_L; // 发送0
		}
		delay_us(); // 延时
		// 时钟线拉高,接收器接收
		I2C_SCL_H;
		delay_us(); // 延时,用于等待接收器接收数据
		delay_us(); // 延时
		// 将数据左移一位,让原来第6位变为第7位
		dat = dat << 1;
	}
}

/*
 * 函数名:i2c_read_byte
 * 函数功能: 主机从i2c总线上的从设备读8bits数据,
 *          主机发送一个应答或者非应答信号
 * 函数参数: 0 : 应答信号   1 : 非应答信号
 * 函数返回值:读到的有效数据
 *
 * */
unsigned char i2c_read_byte(unsigned char ack)
{
	/*
	 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
	 *          时钟在高电平期间,接收器从数据线上读取数据
	 *      ----          --------
	 *  SCL     \        /        \
	 *           --------          --------
	 *      -------- ------------------ ---
	 *  SDA         X                  X
	 *      -------- ------------------ ---
	 *
	 *      先接收高位, 在接收低位
	 * */
	unsigned int i;
	unsigned char dat; // 保存接受的数据
	// 将数据线设置为输入
	SET_SDA_IN;
	for (i = 0; i < 8; i++)
	{
		// 先把时钟线拉低,等一段时间,保证发送器发送完毕数据
		I2C_SCL_L;
		delay_us();
		delay_us(); // 保证发送器发送完数据
		// 时钟线拉高,读取数据
		I2C_SCL_H;
		delay_us();
		dat = dat << 1;	  // 数值左移  0000 0000
		if (I2C_SDA_READ) // pf15管脚得到了一个高电平输入
		{
			dat |= 1; // 0000 0110
		}
		else
		{
			dat &= (~0X1);
		}
		delay_us();
	}
	if (ack)
	{
		i2c_nack(); // 发送非应答信号,不再接收下一次数据
	}
	else
	{
		i2c_ack(); // 发送应答信号
	}
	return dat;
}
/*
 * 函数名: i2c_wait_ack
 * 函数功能: 主机作为发送器时,等待接收器返回的应答信号
 * 函数参数:无
 * 函数返回值:
 *                  0:接收到的应答信号
 *                  1:接收到的非应答信号
 * */
unsigned char i2c_wait_ack(void)
{
	/*
	 * 主机发送一个字节之后,从机给主机返回一个应答信号
	 *
	 *                   -----------
	 * SCL              /   M:读    \
	 *     -------------             --------
	 *     --- ---- --------------------
	 * SDA    X    X
	 *     ---      --------------------
	 *     主  释   从机    主机
	 *     机  放   向数据  读数据线
	 *         总   线写    上的数据
	 *         线   数据
	 * */
	// 时钟线拉低,接收器可以发送信号
	I2C_SCL_L;
	I2C_SDA_H; // 先把数据线拉高,当接收器回应应答信号时,数据线会拉低
	delay_us();
	SET_SDA_IN; // 设置数据线为输入
	delay_us();
	delay_us();
	I2C_SCL_H;		  // 用于读取数据线数据
	if (I2C_SDA_READ) // PF15得到一个高电平输入,收到非应答信号
		return 1;
	I2C_SCL_L; // 时钟线拉低,让数据线处于占用状态
	return 0;
}
/*
 * 函数名: iic_ack
 * 函数功能: 主机作为接收器时,给发送器发送应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_ack(void)
{
	/*            --------
	 * SCL       /        \
	 *    -------          ------
	 *    ---
	 * SDA   X
	 *    --- -------------
	 * */
	// 保证数据线是输出
	SET_SDA_OUT;
	I2C_SCL_L; // 拉低时钟线
	delay_us();
	I2C_SDA_L; // 数据线拉低,表示应答信号
	delay_us();
	I2C_SCL_H; // 时钟线拉高,等待发送器读取应答信号
	delay_us();
	delay_us();
	I2C_SCL_L; // 数据线处于占用状态,发送器发送下一次数据
}
/*
 * 函数名: iic_nack
 * 函数功能: 主机作为接收器时,给发送器发送非应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_nack(void)
{
	/*            --------
	 * SCL       /        \
	 *    -------          ------
	 *    --- ---------------
	 * SDA   X
	 *    ---
	 * */
	// 保证数据线是输出
	SET_SDA_OUT;
	I2C_SCL_L; // 拉低时钟线
	delay_us();
	I2C_SDA_H; // 数据线拉高,表示非应答信号
	delay_us();
	I2C_SCL_H; // 时钟线拉高,等待发送器读取应答信号
	delay_us();
	delay_us();
	I2C_SCL_L; // 数据线处于占用状态,发送器发送下一次数据
}

// main.c
#include "si7006.h"

void delay(int ms)
{
  int i, j;
  for (i = 0; i < ms; i++)
  {
    for (j = 0; j < 2000; j++)
      ;
  }
}
int main()
{
  unsigned short hum;
  short tem;
  // 进行si7006的初始化
  si7006_init();
  while (1)
  {
    // 读取湿度
    hum = si7006_read_hum_data(0X40, 0XE5);
    // 读取温度
    tem = si7006_read_temp_data(0X40, 0XE3);
    // 将温度数据和湿度数据按照转换公式进行转换
    hum = 125 * hum / 65536 - 6;
    tem = 175.72 * tem / 65536 - 46.85;
    delay(1000); // 延时打印
    // 将获取到的数据打印到串口
    printf("hum:%d\n", hum);
    printf("tem:%d\n", tem);
  }

  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251934.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一键批量改名,将西班牙语文件轻松转换为中文!

你是否曾经遇到过需要将大量西班牙语文件批量转换为中文文件的问题&#xff1f;这可能会让你感到头疼和繁琐。但是&#xff0c;现在有了我们的批量改名工具&#xff0c;你可以轻松解决这个问题&#xff01; 首先&#xff0c;进入文件批量改名高手的主页面&#xff0c;并在板块…

dockerfile,Docker镜像的创建

dockerfile&#xff1a;创建镜像&#xff0c;创建自定义的镜像。包括配置文件&#xff0c;挂载点&#xff0c;对外暴露的端口。设置环境变量。 docker的创建镜像的方式&#xff1a; 1、基于已有镜像进行创建。根据官方提供的镜像源&#xff0c;创建镜像&#xff0c;然后拉起容…

一问掌握SpringBoot常见注解,后无压力。

文章目录 一、&#x1f50e; SpringBoot常用注解大全&#x1f341;&#x1f341; 01. RequestMapping 注解&#x1f341; 1.1. RequestMapping 是什么&#xff1f;&#x1f341; 1.2. RequestMapping 特点有哪些&#xff1f;&#x1f341; 1.3. RequestMapping 作用是什么&…

GZ015 机器人系统集成应用技术样题6-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题6 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

【C++11特性篇】一文助小白轻松理解 C++中的【左值&左值引用】【右值&右值引用】

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.【左值&#xff06;左值引用】&…

josef约瑟 时间继电器 DS-23/C AC220V 10S柜内板前接线

系列型号&#xff1a; DS-21时间继电器 &#xff1b;DS-22时间继电器&#xff1b; DS-23时间继电器&#xff1b;DS-24时间继电器&#xff1b; DS-21C时间继电器&#xff1b;DS-22C时间继电器&#xff1b; DS-23C时间继电器&#xff1b; DS-25时间继电器&#xff1b;DS-26…

C语言实现Hoare版快速排序(递归版)

Hoare版 快速排序是由Hoare发明的&#xff0c;所以我们先来讲创始人的想法。我们直接切入主题&#xff0c;Hoare版快速排序的思想是将一个值设定为key&#xff0c;这个值不一定是第一个&#xff0c;如果你选其它的值作为你的key&#xff0c;那么你的思路也就要转换一下&#xf…

Gradle 之初体验

文章目录 1.安装1&#xff09;检查 JDK2&#xff09;下载 Gradle3&#xff09;解压 Gradle4&#xff09;环境变量5&#xff09;验证安装 2.优势总结 Gradle 是一款强大而灵活的构建工具&#xff0c;用于自动化构建、测试和部署项目。它支持多语言、多项目和多阶段的构建&#x…

MySQL数据库 DCL

目录 DCL概述 管理用户 权限控制 DCL概述 DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访 问权限。 管理用户 (1) 查询用户 select * from mysql.user; 查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localh…

探索AI在CRM中的潜力:智能化客户关系的构建

AI人工智能在CRM系统中的应用有&#xff1a;赋能内容生产、客户服务支持、赋能品牌推广、自动化业务流程、数据分析、辅助科学决策、给出最佳客户联系时间。合理运用CRM系统中AI人工智能助手可以让团队工作事半功倍。 1.内容生产 市场营销活动离不开内容生产&#xff0c;持续…

跟iPhone类似,不同品牌的手机、电脑随时使用“隔空投送”功能!如何开启?

iPhone的隔空投送是一个很受欢迎的功能。打开一个 App&#xff0c;然后轻点“共享”或“共享”按钮&#xff0c;再点击隔空投送&#xff0c;就可以分享图片、视频、文件出去。 然而&#xff0c;如果你用的不是苹果的产品&#xff0c;iPhone的隔空投送功能就有了“隔阂”。 不过…

黑马点评06分布式锁 2Redisson

实战篇-17.分布式锁-Redisson功能介绍_哔哩哔哩_bilibili 1.还存在的问题 直接实现很麻烦&#xff0c;借鉴已有的框架。 2.Redisson用法 3.Redisson可重入原理 在获取锁的时候&#xff0c;看看申请的线程和拿锁的线程是否一致&#xff0c;然后计算该线程获取锁的次数。一个方法…

2044回文字符串(C语言)

目录 一&#xff1a;题目 二&#xff1a;思路分析 1.什么是回文&#xff1f; 2.判断回文&#xff1a; 三&#xff1a;代码 一&#xff1a;题目 二&#xff1a;思路分析 1.什么是回文&#xff1f; 最简单的理解方式就是一个字符串正着写和倒着写一样 2.判断回文&#xff1…

001 Windows虚拟机

一、虚拟机安装Windows10 选自定义安装 升级是针对你电脑上有系统的情况下&#xff0c;你要升级&#xff1b;没有系统就选择自定义。 硬盘60G 直接单击下一步就是一个盘 如果你想对磁盘进行分区 分第一个区的时候它会去创建系统的保留分区和系统分区&#xff0c;然后还剩20…

Codeforces Round 915 (Div. 2)

Constructive Problems&#xff08;Problem - A - Codeforces&#xff09; 题目大意&#xff1a;现在有一片城市被摧毁了&#xff0c;需要进行重建&#xff0c;当一个城市水平相邻和竖直相邻的位置都至少有一个城市的时候&#xff0c;该城市可以被重建。所有城市排成n行m列的矩…

sourcetree使用详解

介绍 SourceTree 是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端管理工具&#xff0c;同时也是Mn版本控制系统工具。支持创建、克隆、提交、push、pull 和合并等操作。——百度百科 是一款比较好用的图形化GUI的git、hg管理工具。还有一些其他的可视化代码管理工具&#x…

Pycharm 如何更改成中文版| Python循环语句| for 和 else 的搭配使用

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

ASP.NET MVC权限管理系实战之一验证码功能实现

1&#xff0c;权限的管理系统&#xff1a;开发项目必备的一个的功能&#xff1b;该项目使用 ASP.NET MVC5 SqlServer EF6 IOC容器 BoostStrap 2&#xff0c;登录界面验证码功能实现&#xff0c;整体效果如下&#xff1b; 3&#xff0c;接下来就是代码部分实现&#xff0c;前端…

使用Nginx实现负载均衡的实践指南

目录 前言1 负载均衡简介2 需要实现的效果3 准备2个tomcat服务器4 配置Nginx实现负载均衡5 Nginx的服务器策略5.1 轮询&#xff08;默认&#xff09;5.2 权重&#xff08;weight&#xff09;5.3 IP哈希&#xff08;ip_hash&#xff09;5.4 响应时间公平分配&#xff08;fair&am…

朱卫明:从韶关走向世界的创作型歌手

朱卫明&#xff0c;艺名Aming&#xff0c;是一位来自广东韶关的杰出唱作音乐人。他以其独特的创作才华和深情的嗓音&#xff0c;赢得了众多歌迷的喜爱。作为一名创作型歌手&#xff0c;朱卫明用音乐传递情感&#xff0c;用歌声打动人心。 一、早年经历与音乐启蒙 朱卫明出生于…