精华内容
下载资源
问答
  • IIC读取:SDA_in SDA_out的意思

    千次阅读 2018-06-07 16:03:11
    slaveack = SDA_read ; SCL_L; I2C_delay(); SDA_out; if(slaveack) return 0; else return 1; } 其中的两条语句的解析: #define SDA_in {GPIOB->MODER&=~(3(11*2));GPIOB->MODER|=0*2;}  #define ...
    IIC读取语句里的语句:
    uchar DAC5571_check(void)
    {
            uchar slaveack;
            SDA_in;                       
            SCL_H;                     
            I2C_delay();                  
            slaveack = SDA_read ;         
            SCL_L;                     
            I2C_delay();                  
            SDA_out;                    
            if(slaveack)    return 0;       
            else            return 1;  
    }    
    其中的两条语句的解析:
    #define SDA_in  {GPIOB->MODER&=~(3<<(11*2));GPIOB->MODER|=0<<11*2;}    
    #define SDA_out {GPIOB->MODER&=~(3<<(11*2));GPIOB->MODER|=1<<11*2;}

    语句的意思是:~(3<<(11*2)) :相当于11左移22位,也就是22和23位都是1,再取反就是00,GPIOB->MODER和22、23位(00)取与运算,则为00,同理00左移22位再和GPIOB->MODER取或运算(不变);
    对应下表的指示00代表 输入复位状态。
    #define SDA_out {GPIOB->MODER&=~(3<<(11*2));GPIOB->MODER|=1<<11*2;}
    前面的一句和上面的分析一样不变,关键是后一句GPIOB->MODER|=1<<11*2,01左移22位,表示22为1,23位为0,再取或则22位为1,23位保持不变即是为0;显然对应下面的通用输出模式。
    因为我们的器件作为从机 要读取从机的地址故数据方向为从机到MCU的传输,所以IO口作为输入,同时用完以后恢复输出模式。

    寄存器在STM32F4中文参考手册里的定义是:


    展开全文
  • #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3;} //修改SDA线的状态 #define IIC_SCL PCout(12) //输出SCL #define IIC_SDA PCout(11) //输出SDA #define READ_SDA PCin(11) //读入SDA ①初始...

    第七课,IIC通信协议

     

    目录

    第七课,IIC通信协议

    一.IIC的原理

    1.硬件原理

    2.各种状态

    二.IIC的代码实现

    0宏定义代码

    ①初始化IO口,可将两个口都写为输出口。且将两根线电压拉高。

    ②起始、停止信号的编写

    ③主机的接收应答信号:

    ④ACK和NACK的发送

    ⑤发送一个字节(8位)

    ⑥接收一个字节(8位)

    三.模板!

    1.宏定义

    2.IIC


    一.IIC的原理

    1.硬件原理

    I2C所使用的数据传输线有两根,一根时钟线SCL,一根信号线SDA。

    2.各种状态

    ①空闲状态:两根线同时为高电平

    ②起始信号:SCL仍为高,而SDA由高到底

    ③停止信号:SCL仍为高,而SDA由低到高(前三者可以对比记忆)

    ④应答信号:(ACK和NACK)应答信号是指,在一次传输数据的过程中,只能传输8位有效位,在第9个周期时,发出一个信号,表明数据信号完全成功接收。可能难以理解,应用正点原子的话,自行体会:

    发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
    应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;
    应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 
    对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,
    并且确保在该时钟的高电平期间为稳定的低电平。 
    如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,
    以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

    ⑤数据的有效性:在时钟到达高电平之前,数据位必须保持稳定(高或低)。也就是说,数据线必须必时钟线先变化,以便时钟线动作的时候能够有稳定的信号可读。

    ⑥数据的传送:没有过多的说明,按位发送。数据位的传输是边沿触发。

    二.IIC的代码实现

    0宏定义代码

    #define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
    #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}       //修改SDA线的状态
    #define IIC_SCL    PCout(12) //输出SCL
    #define IIC_SDA    PCout(11) //输出SDA	 
    #define READ_SDA   PCin(11)  //读入SDA

    ①初始化IO口,可将两个口都写为输出口。且将两根线电压拉高。

    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	  
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOC, &GPIO_InitStructure);
     
    	IIC_SCL=1;
    	IIC_SDA=1;

    ②起始、停止信号的编写

    起始:

    SDA_OUT();//SDA线设为输出模式	  	  
    IIC_SCL=1;//SCL线确保为高
    delay_us(4);
    IIC_SDA=0;//SDA变低,产生开始信号
    delay_us(4);
    IIC_SCL=0;//SCL变低,准备产生数据位的改变
    

    停止:

    
    SDA_OUT();//更改SDA为输出模式
    IIC_SCL=0;//★先拉低SCL线,确保SDA能够改变(参照读位的思想)
    IIC_SDA=0;
    delay_us(4);
    IIC_SCL=1;//拉高时钟线
    IIC_SDA=1;//产生停止信号
    delay_us(4);							   	
    

    ③主机的接收应答信号:

    //返回1失败,返回0成功
    u8 IIC_Wait_Ack(void)
    {
    	u8 ucErrTime=0;
    	SDA_IN();      //SDA设为输入
    	IIC_SDA=1;
        delay_us(1);	   
    	IIC_SCL=1;
        delay_us(1);	 
    	while(READ_SDA)//检测SDA是否输出0
    	{
    		ucErrTime++;
    		if(ucErrTime>250)
    		{
    			IIC_Stop();//超时,停止IIC的传输
    			return 1;
    		}
    	}
    	IIC_SCL=0;  
    	return 0;  
    } 

    ④ACK和NACK的发送

    void IIC_Ack(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=0;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }
    
    void IIC_NAck(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=1;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }

    ⑤发送一个字节(8位)

    涉及到位操作代码,自己体会

    void IIC_Send_Byte(u8 txd)
    {                        
        u8 t;   
    	SDA_OUT(); 	    
        IIC_SCL=0;//拉低时钟线,开始传输
        for(t=0;t<8;t++)
        {              
            IIC_SDA=(txd&0x80)>>7;
            txd<<=1; 	  
    		delay_us(2);   //发送信号
    		IIC_SCL=1;
    		delay_us(2); 
    		IIC_SCL=0;	
    		delay_us(2);
        }	 
    } 

    ⑥接收一个字节(8位)

    返回一个u8

    ack = 1时,发送ACK, =0,发送NACK
    u8 IIC_Read_Byte(unsigned char ack)
    {
    	unsigned char i,receive=0;
    	SDA_IN();//SDAÉèÖÃΪÊäÈë
        for(i=0;i<8;i++ )
    	{
            IIC_SCL=0; 
            delay_us(2);
    		IIC_SCL=1;
            receive<<=1;
            if(READ_SDA)receive++;   
    		delay_us(1); 
        }					 
        if (!ack)
            IIC_NAck();
        else
            IIC_Ack();
        return receive;
    }

    三.模板!

    1.宏定义

    //SDA线模式选择
    #define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
    #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
    
    //操作口
    #define IIC_SCL    PCout(12)
    #define IIC_SDA    PCout(11)
    #define READ_SDA   PCin(11)
    
    //函数声明
    
    #define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
    #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
    
    #define IIC_SCL    PCout(12)
    #define IIC_SDA    PCout(11)
    #define READ_SDA   PCin(11)

    2.IIC

    void IIC_Init(void)
    {					     
    	GPIO_InitTypeDef GPIO_InitStructure;
    	//RCC->APB2ENR|=1<<4;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	
    	   
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOC, &GPIO_InitStructure);
     
    	IIC_SCL=1;
    	IIC_SDA=1;
    }
    
    void IIC_Start(void)
    {
    	SDA_OUT();
    	IIC_SDA=1;	  	  
    	IIC_SCL=1;
    	delay_us(4);
     	IIC_SDA=0;
    	delay_us(4);
    	IIC_SCL=0;
    }	  
    
    void IIC_Stop(void)
    {
    	SDA_OUT();
    	IIC_SCL=0;
    	IIC_SDA=0;
     	delay_us(4);
    	IIC_SCL=1; 
    	IIC_SDA=1;
    	delay_us(4);							   	
    }
    
    u8 IIC_Wait_Ack(void)
    {
    	u8 ucErrTime=0;
    	SDA_IN();
    	IIC_SDA=1;delay_us(1);	   
    	IIC_SCL=1;delay_us(1);	 
    	while(READ_SDA)
    	{
    		ucErrTime++;
    		if(ucErrTime>250)
    		{
    			IIC_Stop();
    			return 1;
    		}
    	}
    	IIC_SCL=0; 
    	return 0;  
    } 
    
    void IIC_Ack(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=0;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }
    
    void IIC_NAck(void)
    {
    	IIC_SCL=0;
    	SDA_OUT();
    	IIC_SDA=1;
    	delay_us(2);
    	IIC_SCL=1;
    	delay_us(2);
    	IIC_SCL=0;
    }					 				     
    void IIC_Send_Byte(u8 txd)
    {   //1有应答  0无应答                   
        u8 t;   
    	SDA_OUT(); 	    
        IIC_SCL=0;
        for(t=0;t<8;t++)
        {              
            IIC_SDA=(txd&0x80)>>7;
            txd<<=1; 	  
    		delay_us(2);
    		IIC_SCL=1;
    		delay_us(2); 
    		IIC_SCL=0;	
    		delay_us(2);
        }	 
    } 	    
    
    u8 IIC_Read_Byte(unsigned char ack)//1ACK 0NACK
    {
    	unsigned char i,receive=0;
    	SDA_IN();
        for(i=0;i<8;i++ )
    	{
            IIC_SCL=0; 
            delay_us(2);
    		IIC_SCL=1;
            receive<<=1;
            if(READ_SDA)receive++;   
    		delay_us(1); 
        }					 
        if (!ack)
            IIC_NAck();
        else
            IIC_Ack();
        return receive;
    }

     

     

     

     

    展开全文
  • 起因 最近在学习stm32开发板,最近学习到了需要IIC通信的MPU6050六轴传感器,看了正点原子的例程,发现其中有很多位操作不是很理解。经过补习了一番C语言,总结了一些位操作的知识。... SDA_OUT(); ...

    起因

    最近在学习stm32开发板,最近学习到了需要IIC通信MPU6050六轴传感器,看了正点原子的例程,发现其中有很多位操作不是很理解。经过补习了一番C语言,总结了一些位操作的知识。

    接下来直接贴代码+讲解操作

    1.

    void IIC_Send_Byte(u8 txd)
    {                        
        u8 t;   
    	SDA_OUT(); 	    
        IIC_SCL=0;//拉低时钟开始数据传输
        for(t=0;t<8;t++)
        {              
            IIC_SDA=(txd&0x80)>>7;
            txd<<=1; 	  
    		delay_us(2);   //对TEA5767这三个延时都是必须的
    		IIC_SCL=1;
    		delay_us(2); 
    		IIC_SCL=0;	
    		delay_us(2);
        }	 
    } 	    
    

    首先让我们看一下这个函数,里面多次用到了IIC_SDA=(txd&0x80)>>7; 这个方法,0x80实际上就是二进制的10000000,txd&0x80就是取txd低八位的最高位(如果不能理解就先向下看), 此时的“>>7”是将结果右移七位,若txd = 10010110, 那么结果就是 00000001;这里的操作是取变量txd的最高位,然后通过循环将txd的值赋给IIC_SDA。因为IIC通信是从最高位开始读取,所以要进行这样一部操作。

    2.

    u8 IIC_Read_Byte(unsigned char ack)
    {
    	unsigned char i,receive=0;
    	SDA_IN();//SDA设置为输入
        for(i=0;i<8;i++ )
    	{
            IIC_SCL=0; 
            delay_us(2);
    		IIC_SCL=1;
            receive<<=1;
            if(READ_SDA)receive++;   
    		delay_us(1); 
        }					 
        if (!ack)
            IIC_NAck();//发送nACK
        else
            
    		IIC_Ack(); //发送ACK   
        return receive;
    }
    
    

    这个函数应该比较好理解
    receive<<=1;
    if(READ_SDA)receive++;
    READ_SDA是在IO上直接读取到的数据0/1
    如果SDA = 1 的话,receive则会+1,反之则不操作,相当于对最低位进行赋值。
    之后再将receive左移一位,达成逐位赋值的效果。

    3.

    u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
    { 
     	IIC_Start(); 
    	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
    	if(IIC_Wait_Ack())	//等待应答
    	{
    		IIC_Stop();		 
    		return 1;		
    	}
        IIC_Send_Byte(reg);	//写寄存器地址
        IIC_Wait_Ack();		//等待应答
        IIC_Start();
    	IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令	
        IIC_Wait_Ack();		//等待应答 
    	while(len)
    	{
    		if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送nACK 
    		else *buf=IIC_Read_Byte(1);		//读数据,发送ACK  
    		len--;
    		buf++; 
    	}    
        IIC_Stop();	//产生一个停止条件 
    	return 0;	
    }
    

    首先看IIC_Send_Byte((addr<<1)|0); 这句,因为寄存器内最低位为设置读/写,所以要将addr左移一位并对最低位赋值 x|0x|1

    在这里我要说一下这个指针 *buf

    u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz) 
    {
        u8 buf[6],res;  
    	res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
    	if(res==0)
    	{
    		*gx=((u16)buf[0]<<8)|buf[1];  
    		*gy=((u16)buf[2]<<8)|buf[3];  
    		*gz=((u16)buf[4]<<8)|buf[5];
    	} 	
        return res;;
    }
    

    例程中调用的时候是这么写的

    res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
    

    首先为什么len的入口参数为6,因为我们读取了三个数据,gx,gy,gy,
    由于每一个都是16位,所以要分高低位分别读取,所以len为6。
    其次
    *gx=((u16)buf[0]<<8)|buf[1];
    *gy=((u16)buf[2]<<8)|buf[3];
    *gz=((u16)buf[4]<<8)|buf[5];
    为什么这么写
    在read_len函数中我们将所有的值都赋给了 *buf这个指针,正确来讲是赋给了 *buf指针所指的内存区域,
    *buf每+1就会指向距离现在位置8byte距离的下一个内存区域,(u8 *buf)
    所以进行上述操作,就可以将read到的每一个8byte大小的数据,通过指针 *buf 从内存空间依次获取,重新组装,从而得到我们需要的u16大小的gx,gy,gz的值了。

    4.

    void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)
    {
    	u8 tbuf[28]; 
    	u8 i;
    	for(i=0;i<28;i++)tbuf[i]=0;//清0
    	tbuf[0]=(aacx>>8)&0XFF;
    	tbuf[1]=aacx&0XFF;
    	tbuf[2]=(aacy>>8)&0XFF;
    	tbuf[3]=aacy&0XFF;
    	tbuf[4]=(aacz>>8)&0XFF;
    	tbuf[5]=aacz&0XFF; 
    	tbuf[6]=(gyrox>>8)&0XFF;
    	tbuf[7]=gyrox&0XFF;
    	tbuf[8]=(gyroy>>8)&0XFF;
    	tbuf[9]=gyroy&0XFF;
    	tbuf[10]=(gyroz>>8)&0XFF;
    	tbuf[11]=gyroz&0XFF;	
    	tbuf[18]=(roll>>8)&0XFF;
    	tbuf[19]=roll&0XFF;
    	tbuf[20]=(pitch>>8)&0XFF;
    	tbuf[21]=pitch&0XFF;
    	tbuf[22]=(yaw>>8)&0XFF;
    	tbuf[23]=yaw&0XFF;
    	usart1_niming_report(0XAF,tbuf,28);//飞控显示帧,0XAF
    } 
    

    最后是这个函数,里面有这样一个操作:

    tbuf[0]=(aacx>>8)&0XFF;
    tbuf[1]=aacx&0XFF;

    这里tbuf[0]为高八位,tbuf[1]为第八位, 以此类推。
    这里我要说一下为什么要 &0XFF,(&11111111);
    accy等变量都是16位数据,而对一个变量进行&0xFF操作就是取它的低八位
    让一个16位的变量最终返回的值为一个八位数据
    之前的IIC_SDA=(txd&0x80)>>7; 也有着异曲同工之处,

    至此就是我对例程中的一些奇葩操作的理解了。

    展开全文
  • stm32f103--IIC实验

    千次阅读 2019-09-19 22:19:33
    它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。I2C 总线在传送数据过程中共有三种类型信号, 它们分别....

    IIC简介(Inter-Integrated Circuit)

    IIC总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。

    开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。(必备条件)
    结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
    应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

    IIC总线时序图

    在这里插入图片描述

    代码如下

    //IIC 初始化
    void IIC_Init(void)
    {
    	GPIO_InitTypeDef GPIO_Initure;
    	__HAL_RCC_GPIOH_CLK_ENABLE(); //使能 GPIOH 时钟
    	//PH4,5 初始化设置
    	GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;
    	GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
    	GPIO_Initure.Pull=GPIO_PULLUP; //上拉
    	GPIO_Initure.Speed=GPIO_SPEED_FAST; //快速
    	HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    	IIC_SDA(1);
    	IIC_SCL(1); 
    }
    //产生 IIC 起始信号
    void IIC_Start(void)
    {
    	SDA_OUT(); //sda 线输出
    	IIC_SDA(1);
    	IIC_SCL(1);
    	delay_us(4);
    	IIC_SDA(0);//START:when CLK is high,DATA change form high to low 
    	delay_us(4);
    	IIC_SCL(0);//钳住 I2C 总线,准备发送或接收数据
    }
    //产生 IIC 停止信号
    void IIC_Stop(void)
    {
    	SDA_OUT();//sda 线输出
    	IIC_SCL(0);
    	IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
    	delay_us(4);
    	IIC_SCL(1); 
    	IIC_SDA(1);//发送 I2C 总线结束信号
    	delay_us(4);
    }
    //等待应答信号到来
    //返回值:1,接收应答失败
    // 0,接收应答成功
    u8 IIC_Wait_Ack(void)
    {
    	u8 ucErrTime=0;
    	SDA_IN(); //SDA 设置为输入
    	IIC_SDA(1);delay_us(1);
    	IIC_SCL(1);delay_us(1);
    	while(READ_SDA){
    		ucErrTime++;
    		if(ucErrTime>250)
    		{
    			IIC_Stop();
    			return 1;
    		}
    	 }
    	IIC_SCL(0);//时钟输出 0 
    	return 0; 
    } 
    //产生 ACK 应答
    void IIC_Ack(void)
    {
    	IIC_SCL(0);
    	SDA_OUT();
    	IIC_SDA(0);
    	delay_us(2);
    	IIC_SCL(1);
    	delay_us(2);
    	IIC_SCL(0);
    }
    //不产生 ACK 应答
    void IIC_NAck(void)
    {
    	IIC_SCL(0);
    	SDA_OUT();
    	IIC_SDA(1);
    	delay_us(2);
    	IIC_SCL(1);
    	delay_us(2);
    	IIC_SCL(0);
    }
    //IIC 发送一个字节
    //返回从机有无应答
    //1,有应答
    //0,无应答
    void IIC_Send_Byte(u8 txd)
    { 
    	u8 t; 
    	SDA_OUT(); 
    	IIC_SCL(0);//拉低时钟开始数据传输
    	for(t=0;t<8;t++)
    	{ 
    		IIC_SDA((txd&0x80)>>7);
    		txd<<=1; 
    		delay_us(2); //对 TEA5767 这三个延时都是必须的
    		IIC_SCL(1);
    		delay_us(2); 
    		IIC_SCL(0);
    		delay_us(2);
    	}
    } 
    //读 1 个字节,ack=1 时,发送 ACK,ack=0,发送 nACK 
    u8 IIC_Read_Byte(unsigned char ack)
    {
    	unsigned char i,receive=0;
    	SDA_IN();//SDA 设置为输入
    	for(i=0;i<8;i++ )
    	{
    		IIC_SCL(0); 
    		delay_us(2);
    		IIC_SCL(1);
    		receive<<=1;
    		if(READ_SDA)receive++; 
    		delay_us(1); 
    	}
    	if (!ack)
    		IIC_NAck();//发送 nACK
    	else
    		IIC_Ack(); //发送 ACK 
    	return receive;
    }
    

    包含的宏定义

    #ifndef __MYIIC_H
    #define __MYIIC_H
    #include "sys.h"
       	   		   
    //IO方向设置
    #define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
    #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
    
    //IO操作函数	 
    #define IIC_SCL    PCout(12) //SCL
    #define IIC_SDA    PCout(11) //SDA	 
    #define READ_SDA   PCin(11)  //输入SDA 
    
    //IIC所有操作函数
    void IIC_Init(void);                //初始化IIC的IO口				 
    void IIC_Start(void);				//发送IIC开始信号
    void IIC_Stop(void);	  			//发送IIC停止信号
    void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
    u8 IIC_Read_Byte(unsigned char ack);		//IIC读取一个字节
    u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
    void IIC_Ack(void);					//IIC发送ACK信号
    void IIC_NAck(void);				//IIC不发送ACK信号
    
    void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
    u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
    #endif
    
    

    24cxx.c

    //初始化 IIC 接口
    void AT24CXX_Init(void)
    {
    	IIC_Init();		//IIC 初始化
    }
    //在 AT24CXX 指定地址读出一个数据
    //ReadAddr:开始读数的地址
    //返回值 :读到的数据
    u8 AT24CXX_ReadOneByte(u16 ReadAddr)
    {
    	u8 temp=0;
    	IIC_Start(); 
    	if(EE_TYPE>AT24C16)
    	{
    		IIC_Send_Byte(0XA0); //发送写命令
    		IIC_Wait_Ack();
    		IIC_Send_Byte(ReadAddr>>8);//发送高地址
    	}else 
    		IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址 0XA0,写数据
    	IIC_Wait_Ack(); 
    	IIC_Send_Byte(ReadAddr%256); //发送低地址
    	IIC_Wait_Ack();
    	IIC_Start(); 
    	IIC_Send_Byte(0XA1); //进入接收模式
    	IIC_Wait_Ack();
    	temp=IIC_Read_Byte(0);
    	IIC_Stop();//产生一个停止条件
    	return temp;
    }
    //在 AT24CXX 指定地址写入一个数据
    //WriteAddr :写入数据的目的地址
    //DataToWrite:要写入的数据
    void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
    {
    	IIC_Start(); 
    	if(EE_TYPE>AT24C16)
    	{
    		IIC_Send_Byte(0XA0); //发送写命令
    		
    		IIC_Wait_Ack();
    		IIC_Send_Byte(WriteAddr>>8);//发送高地址
    	}else
    		 IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址 0XA0,写数据
    	IIC_Wait_Ack();
    	IIC_Send_Byte(WriteAddr%256); //发送低地址
    	IIC_Wait_Ack(); 
    	IIC_Send_Byte(DataToWrite); //发送字节
    	IIC_Wait_Ack(); 
    	IIC_Stop();//产生一个停止条件
    	delay_ms(10);
    }
    //在 AT24CXX 里面的指定地址开始写入长度为 Len 的数据
    //该函数用于写入 16bit 或者 32bit 的数据.
    //WriteAddr :开始写入的地址
    //DataToWrite:数据数组首地址
    //Len :要写入数据的长度 2,4
    void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
    { 
    	u8 t;
    	for(t=0;t<Len;t++)
    	{
    		AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    	}
     }
    //在 AT24CXX 里面的指定地址开始读出长度为 Len 的数据
    //该函数用于读出 16bit 或者 32bit 的数据.
    //ReadAddr :开始读出的地址
    //返回值 :数据
    //Len :要读出数据的长度 2,4
    u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
    { 
    	u8 t;
    	u32 temp=0;
    	for(t=0;t<Len;t++)
    	{
    		temp<<=8;
    		temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); 
    	}
    	return temp;
    }
    //检查 AT24CXX 是否正常
    //这里用了 24XX 的最后一个地址(255)来存储标志字.
    
    //如果用其他 24C 系列,这个地址要修改
    //返回 1:检测失败
    //返回 0:检测成功
    u8 AT24CXX_Check(void)
    {
    	u8 temp;
    	temp=AT24CXX_ReadOneByte(255);//避免每次开机都写 AT24CXX
    	if(temp==0X55)
    			return 0;
    		else//排除第一次初始化的情况
    		{
    		AT24CXX_WriteOneByte(255,0X55);
    		temp=AT24CXX_ReadOneByte(255);
    		if(temp==0X55)return 0;
    		}
    	return 1;
    }
    //在 AT24CXX 里面的指定地址开始读出指定个数的数据
    //ReadAddr :开始读出的地址 对 24c02 为 0~255
    //pBuffer :数据数组首地址
    //NumToRead:要读出数据的个数
    void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
    {
    	while(NumToRead)
    	{
    		*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
    		NumToRead--; 
    		}
    	} 
    //在 AT24CXX 里面的指定地址开始写入指定个数的数据
    //WriteAddr :开始写入的地址 对 24c02 为 0~255
    //pBuffer :数据数组首地址
    //NumToWrite:要写入数据的个数
    void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
    {
    	while(NumToWrite--) {
    		AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
    		WriteAddr++;
    		pBuffer++;
    	}
     }
    

    主函数

    //要写入到 24c02 的字符串数组
    const u8 TEXT_Buffer[]={"Apollo STM32F7 IIC TEST"};
    #define SIZE sizeof(TEXT_Buffer)
    int main(void)
    {
    	u8 key;
    	u16 i=0;
    	u8 datatemp[SIZE]; 
    	Cache_Enable(); //打开 L1-Cache
    	HAL_Init(); //初始化 HAL 库
    	Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz 
    	delay_init(216); //延时初始化
    	uart_init(115200); //串口初始化
    	LED_Init(); //初始化 LED
    	KEY_Init(); //初始化按键
    	SDRAM_Init(); //初始化 SDRAM
    	AT24CXX_Init(); //初始化 24C02
    	POINT_COLOR=RED;
    }
    
    展开全文
  • STM32F10x_模拟I2C读写EEPROM综合版(切换SDA方向、检测ACK位)。
  • 模拟IIC移植

    千次阅读 2014-09-02 22:01:13
    SDA_IN();//SDA设置为输入  for(i=0;i;i++ ) {  IIC_SCL0;   delay_us(2); IIC_SCL1;  receive; delay_us(2);  if(READ_SDA)receive++; delay_us(1);   }   // if (!ack) /...
  • 因为有READ_SDA做判断, 理一下程序思路, 如果READ_SDA为零: 自然receive最低位为零和读入的READ_SDA读到的输入一致,然后通过移位操作读到的最新的一位移到倒数第二位。 然后第二次判断READ_SDA,如果这时READ_...
  • IIC读取语句里的语句: uchar DAC5571_check(void) { uchar slaveack; SDA_in; SCL_H; I2C_delay(); slaveack = SD...
  • STM32的IIC应用详解3

    千次阅读 多人点赞 2018-07-23 17:42:25
    分享:  这两天将STM32的IIC按照原子哥的程序,大致走了一遍,多少对IIC不是那么地陌生了,也多少有了自己的一些感悟,在这里,将这...SDA是串行数据线,上面走命令和数据,而SCL只是一条时钟线,其保证数据是按照...
  • iIC协议简析

    2020-03-11 21:03:19
    下面我们从iic的物理层和协议层说起 物理层 I2C 通讯设备之间的常用连接方式 ...(2) 一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线 (SCL)。数据线即用来表示数据...
  • } void IIC_Start(void) { SDA_OUT(); //sdaÏßÊä³ö IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL=0; } void IIC_...
  • IIC通信协议

    2020-06-18 14:48:14
    IIC通信协议 1、开始信号和停止信号 开始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而... SDA_OUT(); //sda线输出模式 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA..
  • 图解I2C写法

    2019-05-27 13:23:07
    标准I2c是从高位到低位发送 //IO 口模拟起始信号 ... I2C_SDA_OUT(); //对于有准双向的IO口,可以不设置SDA的输入输出模式。比如51单片机。 I2C_SDA_H; I2C_SCL_H; delay_us(5); I2C_SDA_L; ...
  • #define I2C_SDA_READ() GPIO_ReadInputDataBit(GPIO_PORT_I2C, I2C_SDA_PIN) /* 读SDA口线状态 */ #else /* 这个分支选择直接寄存器操作实现IO读写 */ /* 注意:如下写法,在IAR最高级别优化时,会被编译器错误...
  • EEPROM_I2C_SDA_READ() GPIO_ReadInputDataBit(EEPROM_I2C_GPIO_PORT, EEPROM_I2C_SDA_PIN) /* 读SDA口线状态 */ #else /* 这个分支选择直接寄存器操作实现IO读写 */ /*注意: 如下写法,在IAR最高级别优化...
  • STM32--模拟I2C_2402--SDA_H,SDA_L

    千次阅读 2011-01-02 10:10:00
    ================================= I2C的引脚配置: /* Configure I2C1 pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_...
  • IIC总线

    2019-07-08 10:23:41
    SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8;} //配置PB7为上拉/下拉输入模式 # define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3;} //配置PB7为通用推挽输出模式(50MHz) I2...
  • stm32模拟IIC操作

    2020-05-23 00:25:27
    #define IIC_READ 0x1C #define clk_hight (HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET)) //本程序IIC的时钟线接在PB6,置高 #define clk_low (HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, G
  • [root@rac2 ~]# tail -50 /var/log/...Nov 14 19:08:54 rac2 kernel: XFS (dm-0): Metadata CRC error detected at xfs_dir3_block_read_verify+0x5e/0x110 [xfs], xfs_dir3_block block 0x305ced8 Nov 14 19...
  • 《手把手教你学STM32》—MPU6050六轴传感器实验

    万次阅读 多人点赞 2018-10-16 19:14:17
    res=MPU_Read_Byte(MPU_DEVICE_ID_REG); if(res==MPU_ADDR)//器件ID正确 { MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考 MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪...
  • I2C详解

    千次阅读 2017-06-08 09:14:35
    I2C 1,概念:I2C是一种较高速的,半双工,同步的通信总线。 较高速:标准模式是100Kbps,快速模式是400Kbps,高速模式是3.4Mbps 半双工:可以接收和发送数据,但不能同时。...SDA – 数据传输线;
  • i2c_smbus_read_byte — SMBus “receive byte” protocol Synopsis s32 fsfunci2c_smbus_read_byte ( const struct i2c_client * client);   Arguments client Handle to...
  • STM32中的模拟IIC使用

    2017-04-28 14:52:00
    SDA_OUT(); //sda线输出 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL=0;//钳制SCL总线,准备发送和接...
  • FDC2214电容传感器驱动程序

    千次阅读 2018-07-24 14:48:00
    FDC_SDA_OUT(); // sda线输出 34 FDC_IIC_SDA= 1 ; 35 FDC_IIC_SCL= 1 ; 36 FDC_IIC_Delay(); 37 FDC_IIC_SDA= 0 ; // START:when CLK is high,DATA change form high to low 38 FDC_IIC_...
  • stm32学习笔记(8)IIC实验

    千次阅读 2019-09-22 14:36:12
    #define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3;} //IO 操作函数 #define IIC_SCL PCout(12) //SCL #define IIC_SDA PCout(11) //SDA #define READ_SDA PCin(11) //输入 SDA //IIC 所有操作函数 void IIC...
  • IIC总线理解

    千次阅读 2016-07-19 17:30:31
    SDA_OUT(); //将引脚设置为输入模式 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0; delay_us(4); IIC_SCL=0; //拉低,时刻等待数据的到来 } //结束函数 void IIC_Stop(void) { SDA_...
  • DS3231时钟模块使用,IIC协议实践。(基于STM32)

    千次阅读 多人点赞 2021-03-20 10:32:05
    APB2PeriphClockCmd #define IIC_SCLSDA_GPIO_RCC RCC_APB2Periph_GPIOA //使用4线串行接口时使用 #define IIC_SDA PAout(11) #define IIC_SCL PAout(12) #define READ_SDA GPIO_ReadInputDataBit(IIC_SDA_GPIOx...
  • STM32模拟I2C读取MPU9250数据

    万次阅读 热门讨论 2016-12-06 19:06:07
     if(I2C_SDA_GET) /* CPU读取SDA口线状态 */  {  return 1;  }  else  {  re = 0;  }  I2C_SCL_L;  i2c_Delay();    return re; } /*************************************...
  • stm 32 gpio 模拟 i2c 备忘

    千次阅读 2013-07-05 13:32:54
    #define READ_SDA (GPIO_ReadInputDataBit(IIC_SDA_PORT, IIC_SDA_PIN)) #define IIC_SCL_PORT GPIOD #define IIC_SCL_CLK RCC_APB2Periph_GPIOD #define IIC_SCL_PIN GPIO_Pin_8 #define IIC...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 38,986
精华内容 15,594
关键字:

read_sda