IIC驱动OLED(SSD1306) HAL库+CubeMX

一.IIC传输数据的格式

1.写操作

2.读操作 

3.IIC信号 

二. IIC底层驱动

1.重新初始化配置延时单元

//软件延时
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp = t;while(tmp--);
}void I2C_GPIO_ReInit(void)
{/* 1. 使用结构体定义硬件GPIO对象 */GPIO_InitTypeDef GPIO_InitStruct = {0};/* 2. 将SCL和SDA的GPIO寄存器的值恢复为复位上电值 */HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);/* 3. 使能SCL和SDA的GPIO的时钟,因为他们都是GPIOF组的,所以这里只使能GPIOF的时钟 */__HAL_RCC_GPIOF_CLK_ENABLE();/* 4. 设置GPIO的模式为开漏输出模式,响应速度设置为快速响应 */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;     GPIO_InitStruct.Pin = SCL_PIN;    HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct);GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;       GPIO_InitStruct.Pin = SDA_PIN;HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);
}

 2.配置开始和结束信号

                                                      

void I2C_Start(void)
{SCL_H;SDA_H;I2C_Delay(100);SDA_L;I2C_Delay(100);
}void I2C_Stop(void)
{SDA_L;SCL_H;I2C_Delay(100);SDA_H;I2C_Delay(100);
}

3.从机接收应答位成功得到响应返回0,否则返回-1

接收应答前要先将SDA拉高

int I2C_GetAck(void)
{int i = 0;SCL_L;SDA_H;//释放控制权I2C_Delay(100);SCL_H;while(SDA_IN != 0){i++;if(i == 100)//防止超时{SCL_L;return -1;}I2C_Delay(10);}SCL_L;return 0;
}

4.主机发送应答和非应答 

void I2C_ACK(void)
{SCL_L;SDA_L;I2C_Delay(100);SCL_H;I2C_Delay(100);
}
void I2C_NACK(void)
{SCL_L;SDA_H;I2C_Delay(100);SCL_H;I2C_Delay(100);
}

5.发送字节 

void I2C_WriteByte(uint8_t data)
{uint8_t i = 0;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);if(data & 0x80){SDA_H;}else{SDA_L;}data <<= 1; // 发出1bit数据后,要更新数据,将data的次高位移位到最高位SCL_H;I2C_Delay(100);}I2C_GetAck();
}

6.接收字节 

uint8_t I2C_ReadByte(uint8_t ack)
{uint8_t i = 0;uint8_t data = 0;SDA_H;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);SCL_H;I2C_Delay(100);data <<= 1; // 更新数据前,要将上一次数据左移1位用来保存接下来的这一位数据if(SDA_IN == 1)    {                 data++;}else{data = data;}}// 根据ack决定是否发出应答if(ack == 0){I2C_ACK();}else if(ack == 1){I2C_NACK();}return data;
}

三.IIC所有代码 

#define SCL_PIN         GPIO_PIN_6
#define SDA_PIN         GPIO_PIN_7#define SCL_PORT        GPIOB
#define SDA_PORT        GPIOB/********************** 函数宏定义
**********************/
#define SCL_H           HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 1)
#define SCL_L           HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 0)#define SDA_H           HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 1)
#define SDA_L           HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 0)
#define SDA_IN          HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN)/**  函数名:I2C_GPIO_ReInit*  功能描述:将模拟I2C的SCL和SDA引脚进行重新初始化*  输入参数:无*  输出参数:无*  返回值:无
*/
extern void I2C_GPIO_ReInit(void);/**  函数名:I2C_Start*  功能描述:模拟发出I2C的开始信号-->在SCL的高电平下,SDA的电平由高到低变化*  输入参数:无*  输出参数:无*  返回值:无
*/
extern void I2C_Start(void);/**  函数名:I2C_Stop*  功能描述:模拟发出I2C的停止信号-->在SCL的高电平下,SDA的电平由低到高变化*  输入参数:无*  输出参数:无*  返回值:无
*/
extern void I2C_Stop(void);/**  函数名:I2C_GetAck*  功能描述:模拟I2C获取从设备的响应信号-->在SCL的高电平下,从设备将SDA拉低*  输入参数:无*  输出参数:无*  返回值:成功得到响应返回0,否则返回-1
*/
extern int I2C_GetAck(void);/**  函数名:I2C_ACK*  功能描述:模拟I2C发出一个应答信号,在第九个时钟将SDA拉低*  输入参数:无*  输出参数:无*  返回值:无
*/
extern void I2C_ACK(void);/**  函数名:I2C_NACK*  功能描述:模拟I2C发出一个非应答信号,在第九个时钟将SDA拉高*  输入参数:无*  输出参数:无*  返回值:无
*/
extern void I2C_NACK(void);/**  函数名:I2C_WriteByte*  功能描述:模拟I2C发出一个字节的数据*  输入参数:data-->要发送出去的数据,范围0~255*  输出参数:无*  返回值:无
*/
extern void I2C_WriteByte(uint8_t data);/**  函数名:I2C_ReadByte*  返回值:返回读取到的数据*  输入参数:ack-->根据此参数判断在读到一个字节之后是否发出应答信号*  输出参数:无
*/
extern uint8_t I2C_ReadByte(uint8_t ack);#endif /* __DRIVER_I2C_H */
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp = t;while(tmp--);
}/**  函数名:I2C_GPIO_ReInit*  功能描述:将模拟I2C的SCL和SDA引脚进行重新初始化*  输入参数:无*  输出参数:无*  返回值:无
*/
void I2C_GPIO_ReInit(void)
{/* 1. 使用结构体定义硬件GPIO对象 */GPIO_InitTypeDef GPIO_InitStruct = {0};/* 2. 将SCL和SDA的GPIO寄存器的值恢复为复位上电值 */HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);/* 3. 使能SCL和SDA的GPIO的时钟,因为他们都是GPIOF组的,所以这里只使能GPIOF的时钟 */__HAL_RCC_GPIOF_CLK_ENABLE();/* 4. 设置GPIO的模式为开漏输出模式,响应速度设置为快速响应 */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;/* 5. 选择要设置的GPIO引脚 */GPIO_InitStruct.Pin = SCL_PIN;/* 6. 调用init函数初始化GPIO */HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct);GPIO_InitStruct.Pin = SDA_PIN;HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);
}/**  函数名:I2C_Start*  功能描述:模拟发出I2C的开始信号-->在SCL的高电平下,SDA的电平由高到低变化*  输入参数:无*  输出参数:无*  返回值:无
*/
void I2C_Start(void)
{SCL_H;SDA_H;I2C_Delay(100);SDA_L;I2C_Delay(100);
}/**  函数名:I2C_Stop*  功能描述:模拟发出I2C的停止信号-->在SCL的高电平下,SDA的电平由低到高变化*  输入参数:无*  输出参数:无*  返回值:无
*/
void I2C_Stop(void)
{SDA_L;SCL_H;I2C_Delay(100);SDA_H;I2C_Delay(100);
}/**  函数名:I2C_GetAck*  功能描述:模拟I2C获取从设备的响应信号-->在SCL的高电平下,从设备将SDA拉低*  输入参数:无*  输出参数:无*  返回值:成功得到响应返回0,否则返回-1
*/
int I2C_GetAck(void)
{int i = 0;SCL_L;SDA_H;I2C_Delay(100);SCL_H;while(SDA_IN != 0){i++;if(i == 100){SCL_L;return -1;}I2C_Delay(10);}SCL_L;return 0;
}/**  函数名:I2C_ACK*  功能描述:模拟I2C发出一个应答信号,在第九个时钟将SDA拉低*  输入参数:无*  输出参数:无*  返回值:无
*/
void I2C_ACK(void)
{SCL_L;SDA_L;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/**  函数名:I2C_NACK*  功能描述:模拟I2C发出一个非应答信号,在第九个时钟将SDA拉高*  输入参数:无*  输出参数:无*  返回值:无
*/
void I2C_NACK(void)
{SCL_L;SDA_H;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/**  函数名:I2C_WriteByte*  功能描述:模拟I2C发出一个字节的数据*  输入参数:data-->要发送出去的数据,范围0~255*  输出参数:无*  返回值:无
*/
void I2C_WriteByte(uint8_t data)
{uint8_t i = 0;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);if(data & 0x80){SDA_H;}else{SDA_L;}data <<= 1; // 发出1bit数据后,要更新数据,将data的次高位移位到最高位SCL_H;I2C_Delay(100);}I2C_GetAck();
}/**  函数名:I2C_ReadByte*  返回值:返回读取到的数据*  输入参数:ack-->根据此参数判断在读到一个字节之后是否发出应答信号*  输出参数:无
*/
uint8_t I2C_ReadByte(uint8_t ack)
{uint8_t i = 0;uint8_t data = 0;SDA_H;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);SCL_H;I2C_Delay(100);data <<= 1; // 更新数据前,要将上一次数据左移1位用来保存接下来的这一位数据if(SDA_IN == 1)    {                 data++;}else{data = data;}}// 根据ack决定是否发出应答if(ack == 0){I2C_ACK();}else if(ack == 1){I2C_NACK();}return data;
}

四.SSD1306

1.特点

2.SSD1306设备地址

R/W#=1, it is in read mode. R/W#=0, it is in write mode.
0111 1000   0x78 写数据时的设备地址
0111 1000   0x79 读数据时的设备地址
// 第一种,分别定义读写设备地址
#define OLED_WRITE_ADDR      0x78
#define OLED_READ_ADDR       0x79// 第二种,定义基础地址,通过改变读写位来改变地址
#define OLED_ADDR       0x78
#define OLED_WRITE      0x00
#define OLED_READ       0x01

 3.SSD1306总线格式

3.1发送命令

void OLED_WriteCmd(uint8_t cmd)
{I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);//发送设备地址// I2C_WriteByte(OLED_ADDR | OLED_WRITE);I2C_WriteByte(0x00);//发送控制字节0x00I2C_WriteByte(cmd);//发送命令I2C_Stop();//停止
}

3.2发送数据

void OLED_WriteData(uint8_t data)
{I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);//发送设备地址// I2C_WriteByte(OLED_ADDR | OLED_WRITE);I2C_WriteByte(0x40);I2C_WriteByte(data);I2C_Stop();
}

3.3发送一组数据

void OLED_WriteNBytes(uint8_t *buf, uint16_t length)
{uint16_t i = 0;if(buf == NULL) return;I2C_Start();I2C_WriteByte(OLED_WRITE_ADDR);I2C_WriteByte(0x40);for(i=0; i<length; i++){I2C_WriteByte(buf[i]);}I2C_Stop();
}

4.显示到屏幕原理

  

 内部显存GDDRAM,被分成8个页从PAGE0-PAGE7,每一个PAGE有128列,可以保存128X64的数据,数据会保存到从每一页的顶行到末行,读到某个位为0时是不会显示亮度的。

5.显存数据 

页地址模式(Page)

在页地址模式下,当往显存里面写入数据后,列地址指针会自动递增1。设置好起始页和起始列之后, 就可以连续发送数据,而不用 每发送一个数据就去指定一个 页和列的地址了,如果列地址指针递增到了设置的结束列地址,那么列地址指针就会复位回到设置的起始列地址,而页地址指针是不会有变化的。为了访问下一页显存中的内容,用户必须设置新的页和列的起始地址。

  

static MEM_MODE mem_mode = PAGE_ADDR_MODE;  // 静态局部变量,保存OLED的地址模式的//发送命令0xB0-0xB7设置图像显示位置的起始页地址
void OLED_SetPageAddr_PAGE(uint8_t addr)
{if(mem_mode != PAGE_ADDR_MODE)  return;if(addr > 7)   return;OLED_WriteCmd(0xB0 + addr);
}//发送命令0x00-0x0F设置图像显示位置的起始地址的低四位
//发送命令0x10-0x1F设置图像显示位置的起始地址的高四位
void OLED_SetColAddr_PAGE(uint8_t addr)
{if(mem_mode != PAGE_ADDR_MODE)  return;if(addr > 0x7F)   return;OLED_WriteCmd(0x00 + (addr & 0x0F));OLED_WriteCmd(0x10 + (addr>>4));
}//封装成一个函数
void OLED_SetPosition(uint8_t page, uint8_t col)
{OLED_SetPageAddr_PAGE(page);OLED_SetColAddr_PAGE(col);
}

6.基础命令函数 

1.Set Contrast Control(设置对比度)

要发送两个命令,先发送0x81,后面又要发送A[7:0]这个字节,是个带参的函数,对于带参函数要进行合法性检测。这里定义的都是uint8_t类型可以不检测。

void OLED_SetContrastValue(uint8_t Value)
{OLED_WriteCmd(0x81);OLED_WriteCmd(Value);
}

2.Entire Display ON (全屏显示)

设置命令0xA5全屏点亮,设置命令0xA4熄灭

#define ENTIRE_DISP_ON()       OLED_WriteCmd(0xA5) 
#define ENTIRE_DISP_OFF()      OLED_WriteCmd(0xA4) 

 3.Set Normal/Inverse Display(设置正常/反向显示)

对于数据是逻辑1发光显示,还是逻辑0发光显示。

//阴码显示或者阳码显示
#define DISP_NORMAL()          OLED_WriteCmd(0xA6)  
#define DISP_INVERSE()         OLED_WriteCmd(0xA7)

4.Set Display ON/OFF(设置显示打开/关闭)

//打开显示或者关闭显示
#define DISP_ON()              OLED_WriteCmd(0xAF) 
#define DISP_OFF()             OLED_WriteCmd(0xAE) 

7.滚动命令功能函数

1.Continuous Horizontal Scroll Setup(水平方向左/右滚动)

typedef enum
{H_RIGHT     = 0x26,H_LEFT      = 0x27,
}H_SCROLL_DIR;  // 水平滚动方向void OLED_H_Scroll(H_SCROLL_DIR dir,uint8_t start, uint8_t fr_time, uint8_t end)
{//合法性检测,数量不一定满足0-7个if((dir!=H_RIGHT)&&(dir!=H_LEFT)) return;if(start>0x07||fr_time>0x07||end>0x07) return;OLED_WriteCmd(dir);OLED_WriteCmd(0x00);OLED_WriteCmd(start);OLED_WriteCmd(fr_time);OLED_WriteCmd(end);OLED_WriteCmd(0x00);OLED_WriteCmd(0xFF);
}

2.Continuous Vertical and Horizontal Scroll Setup(垂直方向左右滚动设置)

typedef enum
{HV_RIGHT    = 0x29,HV_LEFT     = 0x2A,
}HV_SCROLL_DIR;     // 水平和垂直滚动的方向void OLED_HV_Scroll(HV_SCROLL_DIR dir, uint8_t start, uint8_t fr_time, uint8_t end, uint8_t offset)
{if((dir!=HV_RIGHT)&&(dir!=HV_LEFT)) return;if(start>0x07||fr_time>0x07||end>0x07||offset>0x3F) return; OLED_WriteCmd(dir);OLED_WriteCmd(0x00);OLED_WriteCmd(start);OLED_WriteCmd(fr_time);OLED_WriteCmd(end);OLED_WriteCmd(offset);
}

3.开始/结束滚动

//开始或者停止滚动
#define SCROLL_ON()             OLED_WriteCmd(0x2F)
#define SCROLL_OFF()            OLED_WriteCmd(0x2E)

4.Set Vertical Scroll Area(设置垂直滚动区域)

void OLED_SetVScrollArea(uint8_t area, uint8_t row_num)
{if((area>0x3F) || (row_num>0x7F))return;OLED_WriteCmd(0xA3);OLED_WriteCmd(area);OLED_WriteCmd(row_num);
}

8.寻址设置命令表

typedef enum
{H_ADDR_MODE     = 0,    // 水平地址模式V_ADDR_MODE     = 1,    // 垂直地址模式PAGE_ADDR_MODE  = 2,    // 页地址模式
}MEM_MODE;  // 内存地址模式static MEM_MODE mem_mode = PAGE_ADDR_MODE;  // 静态局部变量,保存OLED的地址模式的

1.设置OLED在页地址模式下的显示起始column地址

void OLED_SetColAddr_PAGE(uint8_t addr)
{//先要判断当前的地址是否是页地址模式if(mem_mode != PAGE_ADDR_MODE)  return;if(addr > 0x7F)   return;OLED_WriteCmd(0x00 + (addr & 0x0F));OLED_WriteCmd(0x10 + (addr>>4));
}

 

2.Set Memory Addressing Mode(设置内存寻址模式)

void OLED_SetMemAddrMode(MEM_MODE mode)
{if((mode != H_ADDR_MODE) && (mode != V_ADDR_MODE) && (mode != PAGE_ADDR_MODE))   return;OLED_WriteCmd(0x20);OLED_WriteCmd(mode);mem_mode = mode;
}

3.Set Column Address(在水平和垂直模式下的起始column地址和终止column地址)

void OLED_SetColAddr_HV(uint8_t start, uint8_t end)
{if(mem_mode == PAGE_ADDR_MODE)      return;if((start > 127) || (end > 127))    return;OLED_WriteCmd(0x21);OLED_WriteCmd(start);OLED_WriteCmd(end);
}

4.分别在水平垂直模式和页地址模式的起始页地址和结束页地址

//函数名:OLED_SetPageAddr_HV
//功能描述:设置OLED在水平地址模式或垂直地址模式下像素显示的起始页地址和结束页地址
void OLED_SetPageAddr_HV(uint8_t start, uint8_t end)
{if(mem_mode == PAGE_ADDR_MODE)      return;if((start > 7) || (end > 7))        return; OLED_WriteCmd(0x22);OLED_WriteCmd(start);OLED_WriteCmd(end);
}// 函数名:OLED_SetPageAddr_PAGE
//功能描述:设置OLED在页地址模式下的显示起始页地址
void OLED_SetPageAddr_PAGE(uint8_t addr)
{if(mem_mode != PAGE_ADDR_MODE)  return;if(addr > 7)   return;OLED_WriteCmd(0xB0 + addr);
}

 

9.硬件配置功能函数

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

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

相关文章

安装最新版WebStorm来开发JavaScript应用程序

安装最新版WebStorm来开发JavaScript应用程序 Install the Latest Version of JetBrains WebStorm to Develop JavaScript Applications By JacksonML 2023-11-25 1. 系统要求 WebStorm是个跨平台集成开发环境&#xff08;IDE&#xff09;。按照JetBrains官网对WebStorm软件…

【C++】类型转换 ② ( C++ 静态类型转换 static_cast | C 语言隐式转换弊端 | 代码示例 )

文章目录 一、静态类型转换 static_cast1、C 静态类型转换 static_cast2、C 语言隐式转换弊端3、代码示例 在之前写过一篇 C 类型转换的博客 【C 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 ) , 简单介绍了 C 类…

大数据基础 HDFS客户端操作

一、Maven概述 Maven是一个专门用于管理和构建Java项目的工具。我们之所以要使用Maven&#xff0c;是因为Maven可以为我们提供一套标准化的项目结构、一套标准化的构建流程和一套方便的依赖管理机制&#xff0c;这些功能可以使得我们的项目结构更加清晰&#xff0c;导入jar包的…

初学vue3与ts:setup与setup()下的数据写法

把setup写在script里 <template><div><div class"index-title">script setup</div><div class"title">字符串&#xff1a;</div><div class"title-sub">ref版&#xff1a;{{strRef}}</div><…

cocos游戏引擎制作的滚动框地图防止误点操作的简单方法

本篇文章主要讲解&#xff0c;使用cocos creator 来解决在我们日常滚动框开发中&#xff0c;滚动和触摸存在冲突的情况&#xff0c;导致的误触行为的解决办法。 日期&#xff1a;2023年11月25日 具体事项 说明&#xff1a;在我们滚动滚动框时&#xff0c;会出现误点的情况&…

Drools 7 JMX Mbean 及Metric 分析

Mbean mbean的打开很简单&#xff0c;使用jmx启动参数&#xff1a; -Dcom.sun.management.jmxremote.port9999 -Ddrools.mbeansenabled -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse 但通过jconsole能直观看到的东西也很…

利用 LD_PRELOAD 环境变量

文章目录 原理LD_PRELOAD介绍如何上传.so文件 例题 [虎符CTF 2022]ezphp 原理 LD_PRELOAD介绍 LD_PRELOAD是Linux系统的一个环境变量&#xff0c;它可以影响程序的运行时的链接&#xff08;Runtime linker&#xff09;&#xff0c;它允许你定义在程序运行前优先加载的动态链接…

DDD落地:从阿里单据系统,看DDD在大厂如何落地?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 谈谈你的DDD落地经验&#xff1f; 谈谈你对DDD的理解&#x…

职场份子钱随不随?这20个真相你需要知道!

职场份子钱随不随&#xff1f;这20个真相你需要知道&#xff01; 1.千万不要在老婆面前夸小姨子水灵。 2.盖世功劳&#xff0c;当不得一个矜字&#xff1b;弥天罪过&#xff0c;当不得一个悔字。 3.愚蠢的人永远只会根据答案判断难度。 4.改变自己的是神&#xff0c;企图改…

【数据库】表的连接在执行时的算法解析,嵌套循环连接算法的几种实现,多表连接中表的数量会影响什么

嵌套循环连接 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定期更新…

[论文阅读]CBAM——代码实现和讲解

CBAM 论文网址&#xff1a;CBAM 论文代码&#xff1a;CBAM 本文提出了一种卷积块注意力模块&#xff08;CBAM&#xff09;&#xff0c;它是卷积神经网络&#xff08;CNN&#xff09;的一种轻量级、高效的注意力模块。该模块沿着通道和空间两个独立维度依次推导注意力图&#x…

每日一题2023.11.26——打印沙漏【PTA】

题目要求&#xff1a; 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印 ************ *****所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&#xff1b;各行符号中心对齐&#xff1b;相邻两行符号数差2&#xff1b;…

设计一个算法,将链表中所有结点的链接方向“原地”逆转,即要求仅利用原表的存储空间,换句话说,要求算法的空间复杂度为O(1)

设计一个算法&#xff0c;将链表中所有结点的链接方向“原地”逆转&#xff0c;即要求仅利用原表的存储空间&#xff0c;换句话说&#xff0c;要求算法的空间复杂度为O&#xff08;1&#xff09; 代码思路&#xff1a; 这里要求不用额外空间&#xff0c;那么就要考虑链表自身的…

Liunx系统使用超详细(一)

目录 一、Liunx系统的认识 二、Liunx和Windows区别 三、Liunx命令提示符介绍 四、Liunx目录结构 一、Liunx系统的认识 Linux系统是一种开源的、类Unix操作系统内核的实现&#xff0c;它基于Unix的设计原理和思想&#xff0c;并在全球范围内广泛应用。以下是对Linux系统的详…

MVCC多版本并发控制相关面试题整理

多版本并发控制是一种用于支持并发事务的数据库管理系统技术&#xff0c;它允许多个事务同时访问数据库&#xff0c;而不会相互干扰或导致数据不一致。MVCC通过在数据库中维护不同版本的数据来实现这一目标&#xff0c;从而允许每个事务看到一致的数据库快照。 并发导致的问题…

【数据结构】树与二叉树(廿二):树和森林的遍历——后根遍历(递归算法PostOrder、非递归算法NPO)

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例3. Father链接结构4. 儿子链表链接结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法5.3.3 树和森林的遍历1. 先根遍历&#xff08;递归、非…

qt5.15.2及6.0以上版本安装

文章目录 下载在线安装器安装打开软件 下载在线安装器 因为从qt5.15开始不支持离线下载安装了&#xff0c;只能通过在线安装的方式进行安装。 下载在线安装下载器&#xff1a; 这个在线安装下载器网上也都是可以找到。 这里是其放到网盘上的下载地址&#xff1a; 链接&#x…

DL Homework 8

目录 习题5-2 证明宽卷积具有交换性&#xff0c; 即公式(5.13)&#xff0e; 习题5-4 对于一个输入为100 100 256的特征映射组&#xff0c; 使用3 3的卷积核&#xff0c; 输出为100 100 256的特征映射组的卷积层&#xff0c; 求其时间和空间复杂度&#xff0e; 如果引入一…

Openwrt linux 启动流程

OpenWRT 启动流程 内核启动过程&#xff1a;【/init/mian.c】 Uboot --> start_kernel() --> rest_init() --> kernel_thread(kernel_init) --> kernel_init_freeable() 初始化过程&#xff1a; Linux Kernel(kernel_init) --> /etc/preinit --> /sbin/in…

2023 年最新百度智能云千帆大模型 Node.Js 本地测试 / 微信机器人详细教程

千帆大模型概述 一站式企业级大模型平台&#xff0c;提供先进的生成式AI生产及应用全流程开发工具链。直接调用ERNIE-Bot 4.0及其他主流大模型&#xff0c;并提供可视化开发工具链&#xff0c;支持数据闭环管理、专属大模型定制、大模型训练调优、插件编排等功能。 千帆大模型…