I2C总线协议
2条双向串行线,一条数据线SDA,一条时钟线SCL。
SDA传输数据是大端传输,每次传输8bit,即一字节。
支持多主控(multimastering),任何时间点只能有一个主控。
总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.
系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。
1.1 I2C位传输
数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;
若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)
数据改变:SCL为低电平时,SDA线才能改变传输的bit

1.2 I2C开始和结束信号
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

1.3 I2C应答信号
Master每发送完8bit数据后等待Slave的ACK。
即在第9个clock,若从IC发ACK,SDA会被拉低。
若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:

1.4 I2C写流程
写寄存器的标准流程为:
1. Master发起START
2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3. Slave发送ACK
4. Master发送reg addr(8bit),等待ACK
5. Slave发送ACK
6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7. Slave发送ACK
8. 第6步和第7步可以重复多次,即顺序写多个寄存器
9. Master发起STOP
写一个寄存器

写多个寄存器

1.5 I2C读流程
读寄存器的标准流程为:
1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
2. Slave发送ACK
3. Master发送reg addr(8bit),等待ACK
4. Slave发送ACK
5. Master发起START
6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
7. Slave发送ACK
8. Slave发送data(8bit),即寄存器里的值
9. Master发送ACK
10. 第8步和第9步可以重复多次,即顺序读多个寄存器
读一个寄存器

读多个寄存器

2. PowerPC的I2C实现
Mpc8560的CCSR中控制I2C的寄存器共有6个。

2.1 I2CADR 地址寄存器
CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定

2.2 I2CFDR 频率设置寄存器

The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用来设置I2C总线频率
2.3 I2CCR 控制寄存器

MEN: Module Enable. 置1时,I2C模块使能
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
当1->0时,CPU发起STOP信号
当0->1时,CPU发起START信号
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)
2.4 I2CSR 状态寄存器

MCF:0 Byte transfer is in process
1 Byte transfer is completed
MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1
MBB:0 I2C bus idle
1 I2C bus busy
MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息
SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
0 Slave receive, master writing to slave
1 Slave transmit, master reading from slave
MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)
RXAK:若置1,表示收到了ACK
2.5 I2CDR 数据寄存器

这个寄存器储存CPU将要传输的数据。
3. PPC-Linux中I2C的实现
内核代码中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
最重要的函数是mpc_xfer.
- static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
- struct i2c_msg *pmsg;
- int i;
- int ret = 0;
- unsigned long orig_jiffies = jiffies;
- struct mpc_i2c *i2c = i2c_get_adapdata(adap);
- mpc_i2c_start(i2c); // 设置I2CCR[MEN], 使能I2C module
- /* Allow bus up to 1s to become not busy */
- //一直读I2CSR[MBB],等待I2C总线空闲下来
- while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
- if (signal_pending(current)) {
- pr_debug("I2C: Interrupted\n");
- writeccr(i2c, 0);
- return -EINTR;
- }
- if (time_after(jiffies, orig_jiffies + HZ)) {
- pr_debug("I2C: timeout\n");
- if (readb(i2c->base + MPC_I2C_SR) ==
- (CSR_MCF | CSR_MBB | CSR_RXAK))
- mpc_i2c_fixup(i2c);
- return -EIO;
- }
- schedule();
- }
- for (i = 0; ret >= 0 && i < num; i++) {
- pmsg = &msgs[i];
- pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
- pmsg->flags & I2C_M_RD ? "read" : "write",
- pmsg->len, pmsg->addr, i + 1, num);
- //根据消息里的flag进行读操作或写操作
- if (pmsg->flags & I2C_M_RD)
- ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
- else
- ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
- }
- mpc_i2c_stop(i2c); //保证为I2CCSR[MSTA]为0,保证能触发STOP
- return (ret < 0) ? ret : num;
- }
- static int mpc_write(struct mpc_i2c *i2c, int target,
- const u8 * data, int length, int restart)
- {
- int i;
- unsigned timeout = i2c->adap.timeout;
- u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */ //以防万一,保证I2C模块使能起来
- if (!restart)
- writeccr(i2c, CCR_MEN);
- /* Start as master */ //写了I2CCR[CCR_MSTA],触发CPU发起START信号
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
- /* Write target byte */ //CPU发送一个字节,slave I2C addr和0 (写操作bit)
- writeb((target << 1), i2c->base + MPC_I2C_DR);
- if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK
- return -1;
- for (i = 0; i < length; i++) {
- /* Write data byte */
- writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data
- if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK
- return -1;
- }
- return 0;
- }
- static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
- {
- unsigned long orig_jiffies = jiffies;
- u32 x;
- int result = 0;
- if (i2c->irq == 0)
- { //循环读I2CSR,直到I2CSR[MIF]置1
- while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
- schedule();
- if (time_after(jiffies, orig_jiffies + timeout)) {
- pr_debug("I2C: timeout\n");
- writeccr(i2c, 0);
- result = -EIO;
- break;
- }
- }
- x = readb(i2c->base + MPC_I2C_SR);
- writeb(0, i2c->base + MPC_I2C_SR);
- } else {
- /* Interrupt mode */
- result = wait_event_interruptible_timeout(i2c->queue,
- (i2c->interrupt & CSR_MIF), timeout * HZ);
- if (unlikely(result < 0)) {
- pr_debug("I2C: wait interrupted\n");
- writeccr(i2c, 0);
- } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
- pr_debug("I2C: wait timeout\n");
- writeccr(i2c, 0);
- result = -ETIMEDOUT;
- }
- x = i2c->interrupt;
- i2c->interrupt = 0;
- }
- if (result < 0)
- return result;
- if (!(x & CSR_MCF)) {
- pr_debug("I2C: unfinished\n");
- return -EIO;
- }
- if (x & CSR_MAL) { //仲裁失败
- pr_debug("I2C: MAL\n");
- return -EIO;
- }
- if (writing && (x & CSR_RXAK)) {//写后没收到ACK
- pr_debug("I2C: No RXAK\n");
- /* generate stop */
- writeccr(i2c, CCR_MEN);
- return -EIO;
- }
- return 0;
- }
- static int mpc_read(struct mpc_i2c *i2c, int target,
- u8 * data, int length, int restart)
- {
- unsigned timeout = i2c->adap.timeout;
- int i;
- u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */ //以防万一,保证I2C模块使能
- if (!restart)
- writeccr(i2c, CCR_MEN);
- /* Switch to read - restart */
- //注意这里,再次把CCR_MSTA置1,再触发 START
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
- /* Write target address byte - this time with the read flag set */
- //CPU发送slave I2C addr和读操作1
- writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
//等待Slave发ACK
- if (i2c_wait(i2c, timeout, 1) < 0)
- return -1;
- if (length) {
- if (length == 1)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
- else //为什么不置 TXAK
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
- /* Dummy read */
- readb(i2c->base + MPC_I2C_DR);
- }
- for (i = 0; i < length; i++) {
- if (i2c_wait(i2c, timeout, 0) < 0)
- return -1;
- /* Generate txack on next to last byte */
- //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK
- if (i == length - 2)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
- /* Generate stop on last byte */
- //注意这里CCR_MSTA [1->0] CPU会触发STOP
- if (i == length - 1)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
- data[i] = readb(i2c->base + MPC_I2C_DR);
- }
- return length;
- }
文章来源:http://dpinglee.blog.163.com/blog/static/14409775320112239374615/
1.I2C协议
2条双向串行线,一条数据线SDA,一条时钟线SCL。
SDA传输数据是大端传输,每次传输8bit,即一字节。
支持多主控(multimastering),任何时间点只能有一个主控。
总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.
系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。
1.1 I2C位传输
数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;
若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)
数据改变:SCL为低电平时,SDA线才能改变传输的bit

1.2 I2C开始和结束信号
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

1.3 I2C应答信号
Master每发送完8bit数据后等待Slave的ACK。
即在第9个clock,若从IC发ACK,SDA会被拉低。
若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:

1.4 I2C写流程
写寄存器的标准流程为:
1. Master发起START
2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3. Slave发送ACK
4. Master发送reg addr(8bit),等待ACK
5. Slave发送ACK
6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7. Slave发送ACK
8. 第6步和第7步可以重复多次,即顺序写多个寄存器
9. Master发起STOP
写一个寄存器

写多个寄存器

1.5 I2C读流程
读寄存器的标准流程为:
1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
2. Slave发送ACK
3. Master发送reg addr(8bit),等待ACK
4. Slave发送ACK
5. Master发起START
6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
7. Slave发送ACK
8. Slave发送data(8bit),即寄存器里的值
9. Master发送ACK
10. 第8步和第9步可以重复多次,即顺序读多个寄存器
读一个寄存器

读多个寄存器

2. PowerPC的I2C实现
Mpc8560的CCSR中控制I2C的寄存器共有6个。

2.1 I2CADR 地址寄存器
CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定

2.2 I2CFDR 频率设置寄存器

The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用来设置I2C总线频率
2.3 I2CCR 控制寄存器

MEN: Module Enable. 置1时,I2C模块使能
MIEN:Module Interrupt Enable. 置1时,I2C中断使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
当1->0时,CPU发起STOP信号
当0->1时,CPU发起START信号
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1时,CPU在9th clock发送ACK拉低SDA
RSTA:Repeat START. 置1时,CPU发送REPEAT START
BCST:置1,CPU接收广播信息(信息的slave addr为7个0)
2.4 I2CSR 状态寄存器

MCF:0 Byte transfer is in process
1 Byte transfer is completed
MAAS:当CPU作为Slave时,若I2CDR与会话中Slaveaddr匹配,此bit被置1
MBB:0 I2C bus idle
1 I2C bus busy
MAL:若置1,表示仲裁失败
BCSTM:若置1,表示接收到广播信息
SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
0 Slave receive, master writing to slave
1 Slave transmit, master reading from slave
MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)
RXAK:若置1,表示收到了ACK
2.5 I2CDR 数据寄存器

这个寄存器储存CPU将要传输的数据。
3. PPC-Linux中I2C的实现
内核代码中,通过I2C总线存取寄存器的函数都在文件drivers/i2c/busses/i2c-mpc.c中
最重要的函数是mpc_xfer.
- static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum)
- {
- struct i2c_msg *pmsg;
- int i;
- int ret = 0;
- unsigned long orig_jiffies = jiffies;
- struct mpc_i2c *i2c = i2c_get_adapdata(adap);
- mpc_i2c_start(i2c); // 设置I2CCR[MEN], 使能I2C module
- /* Allow bus up to 1s to become not busy */
- //一直读I2CSR[MBB],等待I2C总线空闲下来
- while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
- if (signal_pending(current)) {
- pr_debug("I2C: Interrupted\n");
- writeccr(i2c, 0);
- return -EINTR;
- }
- if (time_after(jiffies, orig_jiffies + HZ)) {
- pr_debug("I2C: timeout\n");
- if (readb(i2c->base + MPC_I2C_SR) ==
- (CSR_MCF | CSR_MBB | CSR_RXAK))
- mpc_i2c_fixup(i2c);
- return -EIO;
- }
- schedule();
- }
- for (i = 0; ret >= 0 && i < num; i++) {
- pmsg = &msgs[i];
- pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
- pmsg->flags & I2C_M_RD ? "read" : "write",
- pmsg->len, pmsg->addr, i + 1, num);
- //根据消息里的flag进行读操作或写操作
- if (pmsg->flags & I2C_M_RD)
- ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
- else
- ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
- }
- mpc_i2c_stop(i2c); //保证为I2CCSR[MSTA]为0,保证能触发STOP
- return (ret < 0) ? ret : num;
- }
- static int mpc_write(struct mpc_i2c *i2c, int target,
- const u8 * data, int length, int restart)
- {
- int i;
- unsigned timeout = i2c->adap.timeout;
- u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */ //以防万一,保证I2C模块使能起来
- if (!restart)
- writeccr(i2c, CCR_MEN);
- /* Start as master */ //写了I2CCR[CCR_MSTA],触发CPU发起START信号
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
- /* Write target byte */ //CPU发送一个字节,slave I2C addr和0 (写操作bit)
- writeb((target << 1), i2c->base + MPC_I2C_DR);
- if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK
- return -1;
- for (i = 0; i < length; i++) {
- /* Write data byte */
- writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着发数据,包括reg addr和data
- if (i2c_wait(i2c, timeout, 1) < 0) //等待slave 发ACK
- return -1;
- }
- return 0;
- }
- static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
- {
- unsigned long orig_jiffies = jiffies;
- u32 x;
- int result = 0;
- if (i2c->irq == 0)
- { //循环读I2CSR,直到I2CSR[MIF]置1
- while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
- schedule();
- if (time_after(jiffies, orig_jiffies + timeout)) {
- pr_debug("I2C: timeout\n");
- writeccr(i2c, 0);
- result = -EIO;
- break;
- }
- }
- x = readb(i2c->base + MPC_I2C_SR);
- writeb(0, i2c->base + MPC_I2C_SR);
- } else {
- /* Interrupt mode */
- result = wait_event_interruptible_timeout(i2c->queue,
- (i2c->interrupt & CSR_MIF), timeout * HZ);
- if (unlikely(result < 0)) {
- pr_debug("I2C: wait interrupted\n");
- writeccr(i2c, 0);
- } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
- pr_debug("I2C: wait timeout\n");
- writeccr(i2c, 0);
- result = -ETIMEDOUT;
- }
- x = i2c->interrupt;
- i2c->interrupt = 0;
- }
- if (result < 0)
- return result;
- if (!(x & CSR_MCF)) {
- pr_debug("I2C: unfinished\n");
- return -EIO;
- }
- if (x & CSR_MAL) { //仲裁失败
- pr_debug("I2C: MAL\n");
- return -EIO;
- }
- if (writing && (x & CSR_RXAK)) {//写后没收到ACK
- pr_debug("I2C: No RXAK\n");
- /* generate stop */
- writeccr(i2c, CCR_MEN);
- return -EIO;
- }
- return 0;
- }
- static int mpc_read(struct mpc_i2c *i2c, int target,
- u8 * data, int length, int restart)
- {
- unsigned timeout = i2c->adap.timeout;
- int i;
- u32 flags = restart ? CCR_RSTA : 0;
- /* Start with MEN */ //以防万一,保证I2C模块使能
- if (!restart)
- writeccr(i2c, CCR_MEN);
- /* Switch to read - restart */
- //注意这里,再次把CCR_MSTA置1,再触发 START
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
- /* Write target address byte - this time with the read flag set */
- //CPU发送slave I2C addr和读操作1
- writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
//等待Slave发ACK
- if (i2c_wait(i2c, timeout, 1) < 0)
- return -1;
- if (length) {
- if (length == 1)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
- else //为什么不置 TXAK
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
- /* Dummy read */
- readb(i2c->base + MPC_I2C_DR);
- }
- for (i = 0; i < length; i++) {
- if (i2c_wait(i2c, timeout, 0) < 0)
- return -1;
- /* Generate txack on next to last byte */
- //注意这里TXAK置1,表示CPU每收到1byte数据后,会发送ACK
- if (i == length - 2)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
- /* Generate stop on last byte */
- //注意这里CCR_MSTA [1->0] CPU会触发STOP
- if (i == length - 1)
- writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
- data[i] = readb(i2c->base + MPC_I2C_DR);
- }
- return length;
- }
I2C总线协议的更多相关文章
- [I2C]I2C总线协议图解
转自:http://blog.csdn.net/w89436838/article/details/38660631 1 I2C总线物理拓扑结构 I2C 总线在物理连接上非常简单,分别由S ...
- I2C总线协议的简要说明
为了快速的了解I2C总线协议,此处采用另类的方式进行说明. 倘若你和另外一个人只能通过一个开关加灯泡的装置在不同的两个房间进行交流,以下是很简单能说明的一个模型: 你的房间有一个开关,另外一间房间有一 ...
- I2C总线协议的总结介绍
在看天翔哥的视频之后,他强调要把I2C协议好好研究一下,那么就对一些基本的通信手段是十分有帮助的..那么就来了解一下I2C总线协议的一些知识吧. I2C(Inter-Integrated Circui ...
- I2C总线协议的软件模拟实现方法
I2C总线协议的软件模拟实现方法 在上一篇博客中已经讲过I2C总线通信协议,本文讲述I2C总线协议的软件模拟实现方法. 1. 简述 所谓的I2C总线协议的软件模拟实现方法,就是用软件控制GPIO的输入 ...
- I2C总线协议图解(转载)
转自:http://blog.csdn.net/w89436838/article/details/38660631 另外,https://blog.csdn.net/qq_38410730/arti ...
- I2C 总线协议
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能 ...
- 【转】I2C总线协议
I2C总线(Inter Integrated-Circuit)是由PHILIPS公司在上世纪80年代发明的一种电路板级串行总线标准,通过两根信号线——时钟线SCL和数据线SDA——即可完成主从机的单工 ...
- I2C总线协议学习笔记 (转载)
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能有一 ...
- I2C总线协议详解
I2C总线定义 I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.I2C总线产生于在80年代,最初为音 ...
随机推荐
- X11 FRAMEBUFFER QT
之前对X11 FRAMEBUFFER理解的不够,现在总结一下Qt Embedded是挪威Trolletch公司的图形化界面开发工具Qt的嵌入式版本,它通过QtAPI与LinuxI/O以及Framebu ...
- 关于comparator接口和comparable接口以及它们各自的方法compare()和compareTo()
在今天做的LeetCode的题中有两道都出现了利用接口实现对象的排序.两题的相关链接: 1.利用comparable接口对对象排序 2.利用comparator接口实现排序 因为之前都没接触过这两个接 ...
- OpenCV学习(10) 图像的腐蚀与膨胀(1)
建议大家看看网络视频教程:http://www.opencvchina.com/thread-886-1-1.html 腐蚀与膨胀都是针对灰度图的形态学操作,比如下面的一副16*16的灰度图. ...
- 程序编译是出现"field has incomplete type"问题的解决
在编译程序是出现了如下错误, 类或结构体的前向声明只能用来定义指针对象或引用,因为编译到这里时还没有发现定义,不知道该类或者结构的内部成员,没有办法具体的构造一个对象,所以会报错. 将类成员改成指针就 ...
- fonts.conf 中文手册
FONTS-CONF(5) FONTS-CONF(5) 名称 fonts.conf -- 字体配置文件 文件概要 /etc/fonts/fonts.conf /etc/fonts/fonts.dtd ...
- kubernetes基础概念
kubernetes是基于容器技术的分布式架构领先方案.具有完备的集群管理能力,包括多层次的安全防护和准入机制.多租户应用支撑能力.透明的服务注册和服务发现机制.内建智能负载均衡器.强大的故障发现和自 ...
- c# 使用api函数 ShowWindowAsync 控制窗体
1.需要匯入 System.Runtime.InteropServices 命名空間 2.宣告 ShowWindowAsync 函數 [DllImport("user32.dll" ...
- Zclip:复制页面内容到剪贴板兼容各浏览器
WEB开发中,要让用户复制页面中的一段代码.URL地址等信息,为了避免用户拖动鼠标再进行右键复制操作而可能出现的差错,我们可以直接在页面中放置一个复制按钮,只需要轻轻一点这个复制按钮,内容将会被复制, ...
- 在 WF 4 中编写自定义控制流活动
在 WF 4 中编写自定义控制流活动 Leon Welicki 控制流是指组织和执行程序中各个指令的方法. 在 Windows Workflow Foundation 4 (WF 4) 中,控制流活动 ...
- 探寻不同版本号的SDK对iOS程序的影响
PDF版本号:http://pan.baidu.com/s/1eQ8DVdo 结论: 同样的代码.使用不同版本号的SDK来编译.会影响MachO头中的值, 从而使程序表现出不同的外观. 代码: - ( ...