I2C&SCCB协议的快速使用

2022/11/20
最近发现一些碎片化的知识,学完很快就忘了,想着写写博客,能加深一下理解,若日后有用得上的地方可以快速地拾掇起来。
–参考正点原子《领航者ZYNQ之嵌入式SDK开发指南》–

首先是I2C协议,有SCL,SDA两根线,在硬件上要确保这两根线上拉。
I2C&SCCB协议的快速使用_第1张图片
SCCB协议与I2C协议基本相同,可以看做是简化后的I2C协议,具体的区别在于I2C协议在数据位后跟着应答位,而SCCB应答位不关心,也就是默认从机应答了。再有就是I2C支持连续写,而SCCB不支持。

arm的sccb时序驱动代码

//产生sccb起始信号
void sccb_start(void)
{
	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);
	XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 1);

	usleep(4);

 	XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 0);  //START:when CLK is high,DATA change form high to low

 	usleep(4);

 	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);  //钳住I2C总线,准备发送或接收数据

}

//产生sccb停止信号
void sccb_stop(void)
{

	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);

	XGpioPs_WritePin(&gpiops_inst,EMIO_SDA_NUM, 0);  //STOP:when CLK is high DATA change form low to high

 	usleep(4);

	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);

	usleep(4);

	XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 1);  //发送I2C总线结束信号

}


//产生ACK应答
void sccb_ack(void)
{
	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
	XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 0);

	usleep(4);

	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);

	usleep(4);

	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);

	usleep(4);
}

//sccb发送一个字节
void sccb_send_byte(u8 txd)
{
    u8 t;

    XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);  //拉低时钟开始数据传输,时钟低电平数据有效

    for(t=0; t<8; t++)
    {
        XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, (txd&0x80)>>7);//取最高位,最高位最先发送

        txd<<=1;

        usleep(4);

        XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);

        usleep(4);

        XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);

        usleep(4);
    }
}

//SCCB接收一个字节
u8  sccb_rece_byte(void)
{
	unsigned char i=0 , rxd=0;

	XGpioPs_SetOutputEnablePin(&gpiops_inst, EMIO_SDA_NUM, 0);
	XGpioPs_SetDirectionPin(&gpiops_inst, EMIO_SDA_NUM, 0);

	XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
	usleep(4);

	for(i=0;i<8;i++ )
	{
        XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);//在时钟高电平读数据
        usleep(2);

        rxd <<= 1;
        if( XGpioPs_ReadPin(&gpiops_inst, EMIO_SDA_NUM) ) {//高位首先接收
        	rxd = rxd | 0x01;
        }
		usleep(2);

		XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
		usleep(4);
    }

	XGpioPs_SetDirectionPin(&gpiops_inst, EMIO_SDA_NUM, 1);  //SDA设置为输出
	XGpioPs_SetOutputEnablePin(&gpiops_inst, EMIO_SDA_NUM, 1);

    return rxd;

}

#快速使用

时序写好了,重点在于怎么使用。(以ov7725的操作为例)
1.找到器件
2.找到器件的寄存器
3.写或读数据
I2C&SCCB协议的快速使用_第2张图片
I2C&SCCB协议的快速使用_第3张图片

//SCCB写寄存器
void sccb_write_reg8(u8 addr , u8 data)
{

	sccb_start();//开始

	sccb_send_byte(OV7725_DEV_ID);//找到器件
	sccb_ack();//器件应答,SCCB不care

	sccb_send_byte(addr);//找到寄存器
	sccb_ack();//寄存器应答,SCCB不care

	sccb_send_byte(data);//写寄存器
	sccb_ack();

  	sccb_stop();//结束
}

//SCCB读寄存器
u8 sccb_read_reg8(u8 addr )
{
	u8 rxd;

	sccb_start();

	sccb_send_byte(OV7725_DEV_ID);//先来一次虚写操作,找到器件和寄存器
	sccb_ack();

	sccb_send_byte(addr);
	sccb_ack();

  	sccb_stop();

  	sccb_start();

	sccb_send_byte(OV7725_DEV_ID | 0x01);//改为读操作
	sccb_ack();

	rxd = sccb_rece_byte();
	sccb_ack();

  	sccb_stop();

  	return  rxd ;
}

你可能感兴趣的:(嵌入式硬件,单片机)