51单片机之手撸IIC协议,并点亮oled

本文记录了学习IIC协议遇到的问题,介绍了IIC总线数据格式,包括起始、结束条件,响应信号,数据传输等。还阐述了利用IIC操作Oled(SSD1306)的方法,如页地址模式、列选择、初始化等,最后给出在Page0显示小方块和显示位图的案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里只是写录学习IIC协议遇到的问题,不会对IIC作过多的解释。有兴趣的话可以看这篇文章-I²C(IIC)总线协议详解—完整版

Oled资料​​​​​​​ 

完整代码Github

一、IIC 总线数据格式

  I²C 总线是一种两线串行的通信方式,SCL(时钟线),SDA(数据线)

  I²C 总线是一个多主机的总线,其时序如下所示:

IIC连接方式大致如下

1.1、S (起始条件), P(结束条件)

 时序如下所示:

S的条件是:SCL保持高电平期间,SDA由高电平变成低电平,产生一个下降沿。

P的条件是:SCL保持高电平期间,SDA由低电平变成高电平,产生一个上升沿。

另外图中的tHSTART所需的最小时间为0.6us,而单片机一个_nop_()空指令时间差不多比1.08us多点所以用一个_nop_()延时即可,tSSTOP也同理。

根据描述转换成以下时序代码

void iic_start() {
    // SCL保持高电平期间,SDA由高电平变成低电平,产生一个下降沿
	SCL = 1;
	SDA = 1;
    // SDA高电平延时一段时间
	_nop_();
	SDA = 0;
	_nop_();
}

void iic_stop() {
    // SCL保持高电平期间,SDA由低电平变成高电平,产生一个上升沿
	SCL = 1;
    // SDA高电平延时一段时间
	SDA = 0;
	_nop_();
	SDA = 1;
	_nop_();
}

1.2、ACK(响应信号)

 时序如下所示:

应答的条件: 在SCL高平电期间,检测到SDA是低电平

非应答的条件: 在SCL高平电期间,检测到SDA是高电平

根据条件形成如下代码:

char iic_ack() {
    // 在SCL高平电期间,检测到SDA是低电平就是应答了,高电平是非应答
	char result;
	SCL = 1;
	result = SDA;
	_nop_();
    // 检测完成之后最好将SCL拉低,如果不拉低可能会造成其它问题,我这里碰到了一直闪屏
	SCL = 0;
	_nop_();
	return result;
}

1.3、传输一个Byte

        数据的传输时序如下:

        从图中可以看出只有在SCL为低电平的时间才允许SDA改变,在SCL为高平期间不允许其改变。另外需要注意的是传输的数据顺序是从高位到低位。所以代码如下:

写一个字节操作

void iic_sendByte(char byte) {
	char temp = byte;
	int i;
	for(i = 0; i < 8; i ++) {
        // 低电平期间允许更改SDA
		SCL = 0;
        // SDA每次只取最高位
		SDA = temp & 0x80;
		_nop_();
		SCL = 1;
		_nop_();
		// 这里要注意拉低电平
		SCL = 0;
		_nop_();
		temp <<= 1;
	}
}

读一个字节操作

uint8_t iic_read_byte(void){
//在高电平期间读取数据
	uint8_t i;
	uint8_t value = 0;
	for (i = 0; i < 8; i++) {
		value <<= 1;
		IIC_SCL_1();
		iic_delay_1us();
		if (IIC_SDA_READ()) {
			value++;
		}
		IIC_SCL_0();
		iic_delay_1us();
	}
	return value;
}

1.4、写操作

由`IIC 总线格式`图片所示,数据格式为

S + 从机地址(7b) + R/W(1b) + ACK + 地址(1B) + ACK  + 循环(数据(1B) + ACK) + P

R/W = 0时为写操作。另外D/C = 1时为写命令,=0时为写数据。

对于Oled来说,Slave ID 是 0x78

对于Oled来说,写模式格式如下:

IIC bus data format
IIC 总线格式

图中相关符号解释: 

  • S: 表示起始条件
  • P: 表示结束条件
  • ACK: 表示响应
  • R/W: = 0 时表示主机写模式, = 1时表示主机读模式
  • D/C: = 0时表示后面紧跟着的Data byte是一个字节的数据,=1时是命令

主机不管是发送数据还是命令,发送一个字节之后从机(本文章说的从机就是一个使用IIC协议的Oled)都要有一个ACK回应。

对于Oled来说,写数据格式其实就是:

S + 从机地址(7bit) + R/W(1位) + ACK + 控制(1byte) + ACK+数据(1byte) + ACK + P

由上可得出oled的写命令和写数据代码

void iic_write_cmd(char cmd) {
	iic_start();
	// 01111100 + R/W(0是写操作)
	iic_sendByte(0x78);
	iic_ack();
	// C0 + D/C + XXXXXX  ==> D/C = 1 表示数据  = 0 表示命令  
	iic_sendByte(0x00);
	iic_ack();
	iic_sendByte(cmd);
	iic_ack();
	iic_stop();
}

void iic_write_data(char d) {
	iic_start();
	// 01111100 + R/W(0是写操作)
	iic_sendByte(0x78);
	iic_ack();
	// C0 + D/C + XXXXXX  ==> D/C = 1 表示数据  = 0 表示命令  
	iic_sendByte(0x40);
	iic_ack();
	iic_sendByte(d);
	iic_ack();
	iic_stop();
}

1.5、读操作

oled没有读操作。

这里说下PAJ7620(手势模块)的读格式

  • 1、主机发送起始信号(S)
  • 2、主机发送从机ID,操作是写(Slave ID)
  • 3、PAJ7620进行回应(A)
  • 4、主机发送PAJ7620的寄存器地址
  • 5、PAJ7620进行回应(A)
  • 6、主机再次发送起始信号(S)
  • 7、主机发送从机ID,操作是读(Slave ID)
  • 8、PAJ7620进行回应(A)
  • 9、之后就是PAJ7620进行数据发送
  • 10、主机发送停止读信号(P)

二、利用 IIC 操作Oled(SSD1306)

Oled 是 128 * 64的点阵图,每一个点就是一个bit。每一bit都会对应一个实际的RAM, 而这个RAM又是静态的所以会保存上一次的状态,所以有可能造成花屏的现象,当然我们可以通过将RAM的每个bit写入0就可以避免这个现象。另外对于竖直方向又分成了8个页,每个页管理一个字节。Oled有三种寻址模式分别是页地址模式,水平地址模式和垂直地址模式。这里只描述下页地址模式。

2.1、SSD1396的页结构如下所示

2.2、页地址模式的移动规律如下图所示:

从左到右将列的128位写满,如果未写满,即使切换了页,也会默认从上次写入的列的下一位开始写,而不是新页的第0列开始写入。由于只有八页所以用三个bit即可控制。

选择页的命令如下图

所以Page0到Page7的地址为0xB0~0xB7

2.3、选择页地址模式

命令如下图: 

先发送0x20命令,再发送0x02命令,即可选择页地址模式。

2.4、选择列

列选择命令如下所示:

解释如下:

128的列可以用一个字节表示,即128=0b1000 0000, 表示的围是0b0000 000到0b0111 1111。所以官方将字节的高四位用一个命令表示,低四位用一个命令表示。如上图所示,一个命令中的前四位表示的是一个地址字节的高/低四位,高四位用0b0001表示,低四位用0b0000表示。命令中的后四位表示具体列址选择。将两个命令中的后四位,组成一个字节的地址。

例1:

选择第0列,那么需要依次写入0x00、0x10命令可以切换列从新Page头开始。

0x0000 0000

0x0001 0000 

取出两个命令的后四位得出列地址0x0000 0000

例2:

选择第64列,那么需要依次写入0x00、0x14命令可以切换列从页中间开始写入。

0x0000 0000

0x0001 0100

因为 0x0100 0000 = 64

例3:

给定任意一个列,如果对应命令

iic_write_cmd(0x00 + y0 % 16);
iic_write_cmd(0x10 + y0 / 16);

2.5、oled初始化

Oled的初始化按照手册进行操作就行,这里不再描述,非常简单。

void oled_init() {
	iic_write_cmd(0xAE);//--display off
	iic_write_cmd(0x00);//---set low column address
	iic_write_cmd(0x10);//---set high column address
	iic_write_cmd(0x40);//--set start line address  
	iic_write_cmd(0xB0);//--set page address
	iic_write_cmd(0x81); // contract control
	iic_write_cmd(0xFF);//--128   
	iic_write_cmd(0xA1);//set segment remap 
	iic_write_cmd(0xA6);//--normal / reverse
	iic_write_cmd(0xA8);//--set multiplex ratio(1 to 64)
	iic_write_cmd(0x3F);//--1/32 duty
	iic_write_cmd(0xC8);//Com scan direction
	iic_write_cmd(0xD3);//-set display offset
	iic_write_cmd(0x00);//
	
	iic_write_cmd(0xD5);//set osc division
	iic_write_cmd(0x80);//
	
	iic_write_cmd(0xD8);//set area color mode off
	iic_write_cmd(0x05);//
	
	iic_write_cmd(0xD9);//Set Pre-Charge Period
	iic_write_cmd(0xF1);//
	
	iic_write_cmd(0xDA);//set com pin configuartion
	iic_write_cmd(0x12);//
	
	iic_write_cmd(0xDB);//set Vcomh
	iic_write_cmd(0x30);//
	
	iic_write_cmd(0x8D);//set charge pump enable
	iic_write_cmd(0x14);//
	
	iic_write_cmd(0xAF);//--turn on oled panel		
}

三、案例

1、在Page0显示一个8 * 8 的小方块

void main() {
	
	oled_init();
	
	// 3、addressing setting command table 第三行
	iic_write_cmd(0x20);
	iic_write_cmd(0x02);
	
	oled_clear();
	
	iic_write_cmd(0xB0);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	iic_write_data(0xff);
	
	while(1);
}

2、显示一个128 * 64的位图

 建议用Pctolcd2002取模式,软件分为了好几个模式,在下面代码是用的列行式。

#include "reg52.h"
#include <intrins.h>

sbit SDA = P0^3;
sbit SCL = P0^1;

code unsigned char peiqi[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x90,0x50,0x50,0x90,0x20,0x7E,
0xC1,0x1D,0x64,0x44,0x79,0x02,0xBC,0x90,0xD0,0x50,0x90,0x88,0x28,0x68,0xA8,0x28,
0xA8,0x04,0xE4,0x54,0x54,0x64,0x68,0x48,0x90,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x04,0xC9,0x32,0x84,0x65,0x13,0x08,
0x05,0x3C,0x46,0x92,0x81,0x05,0xB9,0x83,0x6C,0x10,0x10,0x14,0x17,0x20,0x0C,0x03,
0x07,0x08,0x13,0xA4,0xAC,0x4A,0x12,0x92,0x4F,0x20,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x07,0xF0,0xFE,0x04,0x72,0x88,0x09,
0x0A,0x8A,0x64,0x08,0xF0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x04,
0xCA,0x71,0x85,0x3C,0xC2,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x1C,0x61,0x8E,0x13,0x44,0x84,0x85,
0x05,0x04,0x02,0x01,0x03,0x04,0x09,0x1A,0x12,0x14,0x14,0x14,0x12,0x8B,0x48,0x82,
0xB1,0x4C,0xE3,0x1C,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,
0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xF0,0x08,0x08,0x48,0x08,0xA8,0x84,0x54,0xC4,0x62,0x02,0xE3,0x1C,0x06,0x02,0x04,
0x05,0x09,0x0A,0x0A,0x0A,0x02,0x0A,0x0A,0x1A,0x19,0x01,0x05,0x04,0x02,0x02,0x01,
0x03,0x0C,0x71,0x82,0x22,0xC4,0x54,0x44,0xA8,0x08,0x68,0x08,0x08,0x40,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x31,0x4A,0x8A,0x06,0x12,0x83,0xA2,0x84,0x07,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0xF8,0x03,0x3C,0xE0,0x00,0x00,0x02,0x01,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x01,0x00,0x0C,0x03,0x10,0x17,0x14,0x14,0x14,0xD4,0x34,0x84,
0x04,0xF4,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0xF4,0x04,0xC4,0x04,
0xF4,0x94,0x54,0x54,0x54,0x57,0x10,0x4F,0xA0,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x08,0x08,
0x10,0x15,0x15,0x15,0x15,0x11,0x0C,0x00,0x00,0x00,0x00,0x00,0x07,0x08,0x00,0x08,
0x0A,0x0A,0x0A,0x0A,0x08,0x00,0x01,0x90,0x90,0x00,0x80,0x80,0x90,0x90,0x80,0x20,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};


void iic_start() {
	SCL = 1;
	SDA = 1;
	_nop_();
	SDA = 0;
	_nop_();
}

void iic_stop() {
	SCL = 1;
	SDA = 0;
	_nop_();
	SDA = 1;
	_nop_();
}

char iic_ack() {
	char result;
	SCL = 1;
	result = SDA;
	_nop_();
	SCL = 0;
	_nop_();
	return result;
}

void iic_sendByte(char byte) {
	char temp = byte;
	int i;
	for(i = 0; i < 8; i ++) {
		SCL = 0;
		SDA = temp & 0x80;
		_nop_();
		SCL = 1;
		_nop_();
		// 拉低电平
		SCL = 0;
		_nop_();
		temp <<= 1;
	}
}

void iic_write_cmd(char cmd) {
	iic_start();
	// 01111100 + R/W(0是写操作)
	iic_sendByte(0x78);
	iic_ack();
	// C0 + D/C + XXXXXX  ==> D/C = 1 表示数据  = 0 表示命令  
	iic_sendByte(0x00);
	iic_ack();
	iic_sendByte(cmd);
	iic_ack();
	iic_stop();
}

void iic_write_data(char d) {
	iic_start();
	// 01111100 + R/W(0是写操作)
	iic_sendByte(0x78);
	iic_ack();
	// C0 + D/C + XXXXXX  ==> D/C = 1 表示数据  = 0 表示命令  
	iic_sendByte(0x40);
	iic_ack();
	iic_sendByte(d);
	iic_ack();
	iic_stop();
}


void oled_init() {
	iic_write_cmd(0xAE);//--display off
	iic_write_cmd(0x00);//---set low column address
	iic_write_cmd(0x10);//---set high column address
	iic_write_cmd(0x40);//--set start line address  
	iic_write_cmd(0xB0);//--set page address
	iic_write_cmd(0x81); // contract control
	iic_write_cmd(0xFF);//--128   
	iic_write_cmd(0xA1);//set segment remap 
	iic_write_cmd(0xA6);//--normal / reverse
	iic_write_cmd(0xA8);//--set multiplex ratio(1 to 64)
	iic_write_cmd(0x3F);//--1/32 duty
	iic_write_cmd(0xC8);//Com scan direction
	iic_write_cmd(0xD3);//-set display offset
	iic_write_cmd(0x00);//
	
	iic_write_cmd(0xD5);//set osc division
	iic_write_cmd(0x80);//
	
	iic_write_cmd(0xD8);//set area color mode off
	iic_write_cmd(0x05);//
	
	iic_write_cmd(0xD9);//Set Pre-Charge Period
	iic_write_cmd(0xF1);//
	
	iic_write_cmd(0xDA);//set com pin configuartion
	iic_write_cmd(0x12);//
	
	iic_write_cmd(0xDB);//set Vcomh
	iic_write_cmd(0x30);//
	
	iic_write_cmd(0x8D);//set charge pump enable
	iic_write_cmd(0x14);//
	
	iic_write_cmd(0xAF);//--turn on oled panel		
}


void oled_clear() {
	int i, j;
	for(i = 0; i < 8; i ++) {
		iic_write_cmd(0xB0+i);
		iic_write_cmd(0x00);
		iic_write_cmd(0x10);
		for(j = 0; j < 128; j ++) {
			iic_write_data(0);
		}
	}
}


void oled_image(unsigned char *image)
{
	unsigned char i; 
	unsigned int j;
	
	for(i=0;i<8;i++){
		iic_write_cmd(0xB0 + i);
		iic_write_cmd(0x00);
		iic_write_cmd(0x10);
	
		for(j = 128 * i; j<(128 * (i+1));j++){
			iic_write_data(image[j]);
		}
	}
}

void main() {
	
	oled_init();
	
	// 3、addressing setting command table 第三行
	iic_write_cmd(0x20);
	iic_write_cmd(0x02);
	
	oled_clear();
	
	oled_image(peiqi);
	
	while(1);
}

闪屏视频:

oled 闪屏

<think>好的,用户想了解MySQLlast_insert_id()函数的用法和相关问题。首先,我需要回顾一下这个函数的基本定义和常见用途。last_insert_id()用于获取最后一次插入操作生成的自增ID,这在插入数据后需要获取新记录的ID时非常有用,尤其是在处理关联表时。 接下来,我应该考虑用户可能的实际应用场景。比如,用户可能在插入一条记录后,需要立即使用这个ID来更新其他表,或者在日志记录中使用。这时候正确获取最后一个自增ID就显得很重要了。 然后,我需要确认函数的行为细节。例如,当一次插入多行数据时,last_insert_id()会返回第一个插入行的ID,而不是最后一个。这一点用户可能会忽略,需要特别说明。同时,如果插入操作没有生成任何自增ID(比如表没有自增列),函数会返回0,这也需要提到。 还要考虑不同连接中的行为。每个连接都有自己的last_insert_id()值,互不影响。这对于多线程或并发操作的环境很重要,用户需要知道这个函数是连接特定的。 接下来,示例部分很重要。用户可能需要具体的SQL语句来理解如何使用这个函数。比如,插入数据后立即查询last_insert_id(),或者在同一个连接中连续插入时的情况。另外,多行插入的例子也能帮助用户理解返回值的规则。 此外,用户可能遇到的问题包括函数返回0的情况,或者在不同连接中获取不到预期的ID。这时候需要解释可能的原因,比如没有自增列、插入失败,或者是在不同的连接中查询。 还需要提到事务的影响,如果在事务中插入但未提交,last_insert_id()是否会受到影响?根据MySQL的文档,即使在事务中,只要插入操作执行了,last_insert_id()就会更新,即使事务回滚,这个值可能不会被重置,这一点需要注意。 最后,生成相关的问题可以帮助用户进一步探索。比如,函数在多行插入时的行为、并发情况下的处理、与事务的交互,以及常见错误排查。这些扩展问题能引导用户更全面地理解和应用这个函数。 总结起来,回答需要覆盖基本用法、行为细节、示例演示、注意事项以及相关问题,确保用户能够正确使用last_insert_id()并避免常见错误。</think>### MySQLLAST_INSERT_ID()函数详解 #### 一、基本特性 1. **功能定义**:`LAST_INSERT_ID()`用于获取当前会话中**最近一次成功插入**的自增列(AUTO_INCREMENT)值 2. **作用范围**:返回值仅在当前数据库连接中有效,不同客户端的连接互不影响[^3] 3. **返回值特性**: - 单行插入返回新生成的自增ID - 多行插入返回**第一个插入行的ID**(例如批量插入5条记录时返回第一条的ID) - 未插入数据时返回0 #### 二、典型使用场景 ```sql -- 示例1:基本用法 CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) ); INSERT INTO users (username) VALUES ('john_doe'); SELECT LAST_INSERT_ID(); -- 返回新插入的id值 -- 示例2:多表关联插入 INSERT INTO orders (user_id, amount) VALUES (LAST_INSERT_ID(), 100.00); -- 使用
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俯仰一世_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值