11 IIC通讯协议

news/2024/11/16 11:24:53/文章来源:https://www.cnblogs.com/Lavender-edgar/p/18367589

目录
  • 前言
  • 一、IIC介绍
    • 1.IIC的时序
    • 2.使用IIC对从机寄存器的写操作流程
    • 3.使用IIC对从机寄存器的读操作流程
  • 二、软件实现IIC协议
    • 1.GPIO口配置
    • 2.IIC开始信号
    • 3.IIC结束信号
    • 4.发送数据
    • 5.接收数据
    • 6.接收ACK响应
    • 7.发送ACK和NACK响应
    • 8.对寄存器进行写处理
    • 9.对寄存器进行读处理
  • 三、硬件实现IIC协议
    • 1.初始化GPIO口
    • 2.配置IIC的时钟
    • 3.配置IIC
    • 4.对寄存器进行写处理
    • 5.对寄存器进行读处理
  • 总结

前言

IIC协议在前面03 OLED显示屏中初略的介绍了一下IIC协议,并且使用软件模拟IIC协议来和OLED显示屏进行通讯,但是之前的那一章主要是介绍如何写入数据到从设备中,没有介绍如何从从设备那接收发送过来的数据,并且还有硬件实现IIC也没有说,这一节就讲读取和硬件IIC来统一说明。

一、IIC介绍

IIC、SPI、USART等都属于通讯协议,是由飞利浦公司开发的一款同步半双工、一主一从、一主多从或多主多从的通讯协议,它有两条线组成,一根是SCL时钟线,另一根是SDA数据线。

SCL主要是提供一个时钟,只能由主设备来控制,主设备和从设备根据这一根时钟线来进行同步的数据传输。

1.IIC的时序

这里介绍一下IIC的时序,在前面讲OLED显示屏的时候是讲过该IIC的时序的,这里再介绍一下IIC的时序。

首先是开始和结束时序:

img

在IIC中,要开始进行IIC协议的通讯前需要发送一个开始信号,这个开始信号在START框中,当开始信号进行后就可以开始传送数据了,当传输完成后就需要发送一个结束信号来结束当前的IIC协议,这个信号在STOP中。

然后是发送数据时序:

img

可以看到,当SCL时钟为低电平的时候SDA的数据开始切换,当SCL上升沿的时候稳定,并将数据发送出去。

之后是读取数据时序:

img

和发送数据时一样,只不过就是在高电平时不是发送数据了,而是读取数据,SCL在低电平时,从机改变SDA的电平,当SCL上升沿时SDA稳定然后开始读取从机的数据。

最后就是读取ACK和发送ACK的时序:

img

这个就是读取和发送ack的时序,其实就是上面的读取和发送时序,很简单的。

2.使用IIC对从机寄存器的写操作流程

这个操作流程是:

  1. 发送IIC开始信号
  2. 发送从机写地址
  3. 接收从机发送的ack信号
  4. 发送需要操作的寄存器地址
  5. 接收从机发送的ack信号
  6. 发送需要写入的数据
  7. 接收从机发送的ack信号
  8. 发送IIC结束信号

这样就是一个发送数据到从机的过程。

3.使用IIC对从机寄存器的读操作流程

这个操作流程是:

  1. 发送IIC开始信号
  2. 发送从机写地址
  3. 接收从机发送的ack信号
  4. 发送需要读的寄存器地址
  5. 接收从机发送的ack信号
  6. 再次发送IIC开始信号
  7. 发送从机读地址
  8. 读取SDA线上的数据
  9. 发送NACK结束读取
  10. 发送结束信号

这样就完成了主机读取从机的数据操作。

需要注意这里接收完成后发送NACK是接收一个字节的数据才发送,当发送完NACK给从机后,从机会将SDA信号线拉高,也就是将SDA的控制权交给主机。

如果从机的这个寄存器中的数据有多个字节,那需要在第一次接收8位数据后发送一个ACK响应,当从机接收到后会继续发送数据。

二、软件实现IIC协议

1.GPIO口配置

这里用软件实现IIC协议推荐使用开漏输出,然后从机的引脚需要接上一个上拉电阻,为了防止在一条IIC总线上大家都进行推挽输出导致电流的灌制。

配置的代码如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_APB2PeriphClockCmd(MPU6050_GPIO_RCC, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = MPU6050_IIC_SCL | MPU6050_IIC_SDA;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MPU6050_GPIO, &GPIO_InitStruct);

这里直接用我写好的代码了,我把IIC引脚全部使用宏定义替换了,这样后面移植的时候好进行更改。

2.IIC开始信号

这里可以看一下上面的图:

img

在开始时,SDA是高电平,然后被拉低,而SCL是高电平,当SDA拉低后SCL才被拉低,所以代码可以这样写:

IIC_MPU6050_SCL_Set(1);
IIC_MPU6050_SDA_Set(1);IIC_MPU6050_SDA_Set(0);
IIC_MPU6050_SCL_Set(0);

这里我做了一个封装,把SDA和SCL的操作封装到一个函数中,其实本质上的操作就是GPIO_WriteBit()函数进行操作,这里就懒一下了。

3.IIC结束信号

这里就需要写一下结束信号,参考上面的图,可以看到SDA信号线一开始是低电平,然后被拉为高电平,而SCL信号线一直都是高电平,所以代码就可以这样写,先让SDA为低电平,SCL为高电平,最后拉高SDA即可:

IIC_MPU6050_SDA_Set(0);IIC_MPU6050_SCL_Set(1);
IIC_MPU6050_SDA_Set(1);

这样就完成了结束信号的编写。

4.发送数据

这里可以看一下上面的时序:

img

这里是在SCL为低电平的时候更改SDA的电平,当SCL被拉高后就会将SDA上的数据发送到从机中,所以这里的代码可以这样写,先将数据给SDA,然后拉高SCL信号线,这样就会将数据发送给从机了,然后再把SCL信号线拉低更改SDA上的数据。

也可以先拉低SCL的电平,但因为前面在开始信号的时候SCL的电平就是为低电平了,所以一开始可以不用将SCL拉低:

uint8_t i;
for (i = 0; i < 8; i++)
{IIC_MPU6050_SDA_Set(bit & (0x80 >> i));IIC_MPU6050_SCL_Set(1);IIC_MPU6050_SCL_Set(0);
}

其中

IIC_MPU6050_SDA_Set(bit & (0x80 >> i));IIC_MPU6050_SCL_Set(1);
IIC_MPU6050_SCL_Set(0);

是发送一位数据的操作,重复8次就是发送一个字节的数据了。

5.接收数据

这里看一下时序:

img

可以看到,也是在SCL为高电平的时候读出数据,所以代码可以这样写,先将SDA信号线释放,直接给高电平即可,然后当SCL拉高后读取SDA信号线上的数据,再将SDA拉低为下一次读取做准备:

uint8_t i, bit = 0;IIC_MPU6050_SDA_Set(1);       // 释放SDA信号线for (i = 0; i < 8; i++)
{bit <<= 1;IIC_MPU6050_SCL_Set(1);bit |= IIC_MPU6050_SDA_Read();IIC_MPU6050_SCL_Set(0);
}

6.接收ACK响应

这里就不多说了,直接就使用接收数据的那个逻辑即可,这里是一条数据,所以只需要执行一次即可,就不用使用循环了:

uint8_t ack = 0;
IIC_MPU6050_SDA_Set(1);       // 释放SDA信号线
IIC_MPU6050_SCL_Set(1);
ack = IIC_MPU6050_SDA_Read();
IIC_MPU6050_SCL_Set(0);

7.发送ACK和NACK响应

这个东西很简单,其实就是发送一个位即可,主要是ACK和NACK是怎么发送而已。

在前面接收从机发送的ACK信号可以判断是否接收的为0,如果为0就是接收成功了,所以我们知道了,ACK信号其实就是0,而NACK就是ACK信号的取反,也就是1。

这样不就清楚了吧,当发送0时就是发送ACK,当发送1时就是发送NACK。

发送ACK代码如下:

IIC_MPU6050_SDA_Set(0);
IIC_MPU6050_SCL_Set(1);
IIC_MPU6050_SCL_Set(0);

发送NACK代码如下:

IIC_MPU6050_SDA_Set(1);
IIC_MPU6050_SCL_Set(1);
IIC_MPU6050_SCL_Set(0);

代码一样,也就是发送的SDA不一样而已。

IIC协议的基础代码就写完了,后面就开始使用写好的这些封装来进行寄存器的操作了。

8.对寄存器进行写处理

这里可以看一下上面写的那个写操作:

  1. 发送IIC开始信号
  2. 发送从机写地址
  3. 接收从机发送的ack信号
  4. 发送需要操作的寄存器地址
  5. 接收从机发送的ack信号
  6. 发送需要写入的数据
  7. 接收从机发送的ack信号
  8. 发送IIC结束信号

现在来把它转换为代码的写法:

void MPU6050_WriteByte(uint8_t cmd, uint8_t date)
{// 开始IIC协议IIC_MPU6050_Start();// 写入从机的写地址IIC_MPU6050_WritBit(MPU6050_ADDR);// 等待从机发送的ACKIIC_MPU6050_ReadACK();// 写需要写入的从机寄存器地址IIC_MPU6050_WritBit(cmd);// 等待从机发送的ACKIIC_MPU6050_ReadACK();// 向从机寄存器地址中写入数据IIC_MPU6050_WritBit(date);// 等待从机发送的ACKIIC_MPU6050_ReadACK();// 结束IIC协议IIC_MPU6050_Stop();
}

这样就可以对从机的寄存器中写入一些数据了。

9.对寄存器进行读处理

这里还是看前面说的那个过程:

  1. 发送IIC开始信号
  2. 发送从机写地址
  3. 接收从机发送的ack信号
  4. 发送需要读的寄存器地址
  5. 接收从机发送的ack信号
  6. 再次发送IIC开始信号
  7. 发送从机读地址
  8. 读取SDA线上的数据
  9. 发送NACK结束读取
  10. 发送结束信号

现在来进行实现:

uint8_t MPU6050_ReadByte(uint8_t cmd)
{uint8_t byte = 0;IIC_MPU6050_Start();    // 开启IICIIC_MPU6050_WritBit(MPU6050_ADDR);    // 写入从机的写地址IIC_MPU6050_ReadACK();IIC_MPU6050_WritBit(cmd);      // 写入需要读取的寄存器地址IIC_MPU6050_ReadACK();IIC_MPU6050_Start();        // 再次开启IIC协议IIC_MPU6050_WritBit(MPU6050_ADDR | 0x01);       // 写入从机读地址IIC_MPU6050_ReadACK();byte = IIC_MPU6050_ReadBit();       // 接收读取的数据IIC_MPU6050_SendNACK();          // 发送NACK结束接收IIC_MPU6050_Stop();         // 结束IIC协议return byte;
}

这样模拟的IIC协议就写完了,大家可以使用MPU6050陀螺仪模块来进行测试,但我这手表上的陀螺仪忘记画上拉电阻了,导致读取不了数据,所以就不展示了。

三、硬件实现IIC协议

使用硬件可以节约CPU的使用率,让其可以只控制IIC控制器完成IIC协议的通讯。

当时在stm32f103中只有2个IIC通讯引脚,硬件资源还是蛮少的,但是IIC可以一主多从,其实也是够用的。

这里主要介绍一下硬件IIC产生的事件,使用硬件IIC会根据不同的时段产生一些信号,我们可以通过判断这些信号来进行相应的处理。

img

上图的硬件IIC主机发送数据的序列图,可以看到有两个,这个不用了解,一般的IIC通讯的设备都是7位地址的,我没见过10位的,所以这里只讲7位的。

当发送IIC开始信号后会产生一个EV5的事件,当发送完地址和响应后会产生一个EV6EV8_1的事件,这里只需要判断一下EV6即可,而EV8_1不需要进行判断,因为在刚开始肯定都是空的。

然后就开始发送数据到移位寄存器中,这个时候会产生一个信号EV8,当数据从移位寄存器中到数据寄存器中后这个事件就会清除。

最后不想发送数据后,就可以等待EV8_2,当移位寄存器和数据寄存器都清空了就可以发送停止位了。

发送的还是比较简单,接下来看一下接收的:

img

可以看到一下子复杂起来了,这里还是看7位的,这里是直接列出二次开启后的事件产生了,第二次产生也是产生一个EV5事件,然后接收从机读地址,还是一个EV6信号,然后到DR数据寄存器中读取数据后就会讲EV7进行清空。

这里需要注意一下,如果只读一个字节数据,那这里需要先进行结束后再去读取DR寄存器中的值,因为在接收一次后会存放到DR寄存器中,然后继续读,所以要先发送停止后再读取并发送NACK信号。

这样就能明白其中的意义了,就可以来写代码了。

1.初始化GPIO口

这里需要注意一下,因为硬件IIC是GPIO口的一个复用功能,所以要使用复用开漏输出,我在写的时候就遇到这个问题,一直读取不了数据,并且开启AFIO的时钟,代码如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};RCC_APB2PeriphClockCmd(MPU6050_GPIO_RCC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStruct.GPIO_Pin = MPU6050_IIC_SCL | MPU6050_IIC_SDA;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MPU6050_GPIO, &GPIO_InitStruct);

这样就配置好GPIO口了。

2.配置IIC的时钟

使用一个外设最重要的就是开启对应的时钟,IIC的时钟是在APB1总线下的,所以要通过APB1来进行开启:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

3.配置IIC

这里也是使用结构体的方式进行IIC的配置,使用的结构体如下:

typedef struct
{uint32_t I2C_ClockSpeed;          /*!< 指定时钟频率。此参数必须设置为低于 400kHz 的值 */uint16_t I2C_Mode;                /*!< 指定 I2C 模式。此参数的值可以是 @ref I2C_mode */uint16_t I2C_DutyCycle;           /*!< 指定 I2C 快速模式占空比。此参数的值可以是 @ref I2C_duty_cycle_in_fast_mode */uint16_t I2C_OwnAddress1;         /*!< 指定第一个设备自己的地址。此参数可以是 7 位或 10 位地址。 */uint16_t I2C_Ack;                 /*!< 启用或禁用确认。此参数的值可以是 @ref I2C_acknowledgement */uint16_t I2C_AcknowledgedAddress; /*!< 指定是确认 7 位地址还是 10 位地址。此参数的值可以是 @ref I2C_acknowledged_address */
}I2C_InitTypeDef;

这里不一个一个解释了,直接上配置代码:

I2C_InitTypeDef I2C_InitStruct = {0};
I2C_InitStruct.I2C_Ack = ENABLE;                                            // 使能ACK响应
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;      // 设置地址为7位地址
I2C_InitStruct.I2C_ClockSpeed = 50000;                                      // 时钟速率
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;                             // 快速模式的占空比
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;                                     // I2C模式
I2C_InitStruct.I2C_OwnAddress1 = 0x00;                                      // 自身地址
I2C_Init(I2C2, &I2C_InitStruct);     // 第一个是选择使用的IIC编号

可以看到上面的这个注释来进行了解,其中IIC的速率可以去看对应从机能接收的最大速率来进行配置,然后占空比其实速率不高用1:2即可,如果速度高就用6:9。

4.对寄存器进行写处理

这里不需要再自己写开始信号和结束信号,这里直接用库函数即可。

首先开始信号使用的是I2C_GenerateSTART(),第一个参数是IIC的编号,第二个填使能或者失能,如果要发送开始信号就填写使能。

发送完成后用I2C_CheckEvent()函数判断一下EV5信号是否产生,EV5信号的宏定义是I2C_EVENT_MASTER_MODE_SELECT,然后产生会返回SUCCESS,否则返回ERROR

然后开始发送从机地址,这里使用I2C_Send7bitAddress()函数进行发送,第一个参数是IIC的编号,第二个参数是填写从机地址,从机地址可以在数据手册中寻找,第三个参数是填写读还是写操作。

发送完成后用I2C_CheckEvent()函数判断一下EV6信号是否产生,这里就需要注意一下了,它有两个EV6信号,分别是:I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED

第一个是发送,也就是写操作的时候产生的信号,第二个是接收,也就是读操作的时候产生的信号,这里需要看你在I2C_Send7bitAddress()函数的第三个参数填写的是什么,如果是写,那就用第一个,如果是读就用第二个。

然后就是写数据,这里使用I2C_SendData函数进行写数据,第一个参数也是IIC的编号,第二个是要写入的数据。

最后使用I2C_GenerateSTOP()发送结束信号,参数和I2C_GenerateSTART()一致。

所以这里的完整代码如下:

I2C_GenerateSTART(I2C2, ENABLE);
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);      // 判断是否接收到EV5信号I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);     // 判断是否接收到EV6信号的写信号I2C_SendData(I2C2, addr);
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);     // 判断是否接收到EV8,后面还需要传输一个字节数据I2C_SendData(I2C2, dat);
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);       // 判断是否接收到EV8_2,I2C_GenerateSTOP(I2C2, ENABLE);

5.对寄存器进行读处理

主要注重于读操作即可,前面和二次的都一样,在发送地址这就有问题了,这里要的是读信号,所以得判断是否产生I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED

然后使用I2C_ReceiveData()函数进行读取,但在读取前需要用I2C_AcknowledgeConfig()函数不发送ACK,然后发送结束信号,发送完结束信号后用读取函数进行读取,最后再用I2C_AcknowledgeConfig()函数发送ACK信号。

这里我觉得麻烦,所以把I2C_CheckEvent()给封装了一下,代码如下:

uint8_t byte;I2C_GenerateSTART(I2C2, ENABLE);
MPU6050_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT);     // 检测是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);
MPU6050_WaitEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);   // 检测是否产生EV6事件I2C_SendData(I2C2, addr);
MPU6050_WaitEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTING);     // 检测是否产生EV8事件I2C_GenerateSTART(I2C2, ENABLE);
MPU6050_WaitEvent(I2C_EVENT_MASTER_MODE_SELECT);    // 检测是否产生EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Receiver);
MPU6050_WaitEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);    // 检测是否产生EV6事件I2C_AcknowledgeConfig(I2C2, DISABLE);       // 不发送ACK
I2C_GenerateSTOP(I2C2, ENABLE);        // 发送停止信号MPU6050_WaitEvent(I2C_EVENT_MASTER_BYTE_RECEIVED);        // 检测是否产生EV7事件
byte = I2C_ReceiveData(I2C2);            // 读取数据I2C_AcknowledgeConfig(I2C2, ENABLE);     // 发送ACK

总结

IIC协议其实了解了它的时序图后会发现,其实IIC是非常的简单的,其实就做个项目就可以明白了的,这一章只讲其中驱动的使用,后面我会单独出一个专题来介绍一些大型项目的实现。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断是否为同构字符串

要想解答这个算法,得明白一个概念,什么是同构字符串,来看一下定义:也就是说,s可以转化为t,对应的t也可以转化为s。解决思路: 我们进行一次的遍历,然后定义了两个dict,来记录s->t,t->s的映射,然后在后面校验一下,这两个dict的value 是否是相同的,来上代码。c…

Gradle编译项目Druid找不到tools.jar和jconsole.jar

原因:jdk11之后不支持druid的两个依赖 方法一:<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version>方法二:<!-- <exclusions> <exclusion> …

鸿蒙开发ArkUI沉浸式导航

1.沉浸式导航的效果是占用底部顶部或者其他挖孔区域的位置 沉浸式的样式 非沉浸式的样式 2.实现方式有三种实现放1.全局(Ability)2.页面3.指定元素全局的实现方式(Ability) 在你的Ability 中设置 在页面创建完成后 (onWindowStageCreate) 中onWindowStageCreate(windowStage…

Python 实现Word和TXT文本相互转换

Word文档(.doc或.docx)和纯文本文件(.txt)是两种常用的文件格式。Word文档通常用于复杂的文档处理和排版,而纯文本文件则用于存储和传输纯文本信息。了解如何在这两种格式之间进行转换能提高工作效率,并便于文件管理。本文将详细介绍如何使用Python实现Word和TXT文件格式…

Python一些简单基础的模板化语法

字符串的格式化 %s:可以接收任何类型的传值(%d只可以接收整型int)单个值 "my age is %s" %"18.56"按照值对应 res = "my name is %s,my age is %s" %("xj",18)按照字典传值 res = "my name is %(name)s,my name is %(age)s&q…

Windows下cmd中cd命令不起作用的原因和解决办法

Windows下cmd中cd命令不起作用的原因和解决办法如图:cd命令无效 原因:windows系统cmd换目录跨磁盘的话需要先进行磁盘的转换

VisualStudio 产生的.sdf和.ipch文件删除、不生成

前言全局说明VisualStudio 产生的.sdf和.ipch文件删除、不生成一、说明 环境: Windows 7 旗舰版 Visual Studio 2013二、原因 某天,打算给 vs2013 的一个工程,打包备份,打包后,发现压缩包有 90MB ,看到数字确实很惊讶。 因为这个工程就是画了几个按钮的小功能,怎么会这么…

Docker 容器中镜像导出/导入

利用容器中镜像导出/导入 创建一个简单的Docker镜像 利用docker ps -a命令查看要导出的镜像。 导出 查看要导出的镜像 [root@localhost ~]# docker ps -adocker export命令进行镜像导出。 [root@localhost ~]# docker export 418ae > nginx-docker.tar导入 [vipsoft@kafka1h…

算法与数据结构——时间复杂度

时间复杂度 运行时间可以直观且准确地反映算法的效率。要准确预估一段代码的运行时间,应该进行如下操作。确定运行平台,包括硬件配置、编程语言、系统环境等,这些因素都会影响代码的运行效率。 评估各种计算操作的运行时间,例如加法操作需要1ns,乘法操作需要10ns,打印操作…

算法与数据结构——了解复杂度(迭代与递归)

复杂度分析 算法效率评估 在算法设计中,我们追求以下两个层面的目标。找到问题解法:算法需要再规定的输入范围内可靠地求得问题的正确解 寻求最优解法:同一个问题可能存在多种解法,我们希望找到尽可能高效的算法。也就是说,在能够解决问题的前提下,算法效率已经成为衡量算…

算法与数据结构——了解复杂度

复杂度分析 算法效率评估 在算法设计中,我们追求以下两个层面的目标。找到问题解法:算法需要再规定的输入范围内可靠地求得问题的正确解 寻求最优解法:同一个问题可能存在多种解法,我们希望找到尽可能高效的算法。也就是说,在能够解决问题的前提下,算法效率已经成为衡量算…

算法与数据结构——复杂度分析

复杂度分析 算法效率评估 在算法设计中,我们追求以下两个层面的目标。找到问题解法:算法需要再规定的输入范围内可靠地求得问题的正确解 寻求最优解法:同一个问题可能存在多种解法,我们希望找到尽可能高效的算法。也就是说,在能够解决问题的前提下,算法效率已经成为衡量算…