您的位置:首页 > 房产 > 建筑 > 企业网站建设太原网站建设_科技之星_营销的方法和技巧_自己建网站的详细步骤

企业网站建设太原网站建设_科技之星_营销的方法和技巧_自己建网站的详细步骤

2025/4/19 16:30:02 来源:https://blog.csdn.net/weixin_48867130/article/details/145524684  浏览:    关键词:企业网站建设太原网站建设_科技之星_营销的方法和技巧_自己建网站的详细步骤
企业网站建设太原网站建设_科技之星_营销的方法和技巧_自己建网站的详细步骤

STM32 I2C协议详解与应用实践-CSDN博客

实际项目中移植IIC协议及读写EEprom代码:

/* AT24C08,写次数达100万次SOC ,2500次充放电次数,需要500万次记录,需存储均衡
每页*/#include "FreeRTOS.h"
#include "task.h"
#include "24C08.h"
#include "CortrolMain.h"//#define	OP_READ	0xa1		// ?÷?tμ??·ò??°?áè?2ù×÷,0xa1?′?a1010 0001B
#define	EE_ADDR 0xa0		// ?÷?tμ??·ò??°D′è?2ù×÷,0xa1?′?a1010 0000B#include "include.h"
#define EE_SCL_PIN  PTB2   //模拟IIC的SCL信号  1.修改引脚即可修改IIC接口
#define EE_SDA_PIN  PTC13   //模拟IIC的SDA信号#define EE_SDA_IN()   GPIO_PDDR_REG(GPIOX[EE_SDA_PIN>> 5]) &= ~(1 << (EE_SDA_PIN&0x1f));  //GPIO_PinSetDir(EE_SDA_PIN, 0);	//输入
#define EE_SDA_OUT()  GPIO_PDDR_REG(GPIOX[EE_SDA_PIN>> 5]) |= (1 << (EE_SDA_PIN&0x1f)); //GPIO_PinSetDir(EE_SDA_PIN, 1);	//输出#define EE_SCK_OUT()  GPIO_PDDR_REG(GPIOX[EE_SCL_PIN>> 5]) |= (1 << (EE_SCL_PIN&0x1f)); //GPIO_PinSetDir(EE_SDA_PIN, 1);	//输出#define EE_IIC_SCL    PTB2_OUT                   //SCL      2.修改引脚即可修改IIC接口        
#define EE_IIC_SDA    PTC13_OUT                   //SDA	 
#define EE_READ_SDA   PTC13_INT                    //输入SDA /******************************************************************************
*函  数:void EE_IIC_Delay(void)
*功 能:IIC延时
*参  数:无
*返回值:无
*备  注: 移植时只需要将EE_IIC_Delay()换成自己的延时即可
*******************************************************************************/	
void EE_IIC_Delay(uint8_t us)
{for(int i = 0; i < 20; i++)    {__asm("NOP");//core bus 160M  情况下大概IIC速率 400K}    
}
/******************************************************************************
*函  数:void IIC_Init(void)
*功 能:IIC初始化
*参  数:无
*返回值:无
*备  注:无
*******************************************************************************/void EE_IIC_Init(void)
{			gpio_init(EE_SCL_PIN,GPO,1) ;gpio_init(EE_SDA_PIN,GPO,1) ;EE_SCK_OUT();EE_SDA_OUT();EE_IIC_SCL=1;EE_IIC_SDA=1;        
}void EE_IIC_Start(void)
{EE_SDA_OUT(); //sda线输出 EE_IIC_SDA=1;	EE_IIC_SCL=1;EE_IIC_Delay(4);EE_IIC_SDA=0; //START:when CLK is high,DATA change form high to low EE_IIC_Delay(4);EE_IIC_SCL=0; //钳住I2C总线,准备发送或接收数据 
}void EE_IIC_Stop(void)
{EE_SDA_OUT(); //sda线输出EE_IIC_SCL=0;EE_IIC_SDA=0; //STOP:when CLK is high DATA change form low to highEE_IIC_Delay(4);EE_IIC_SCL=1; EE_IIC_SDA=1; //发送I2C总线结束信号EE_IIC_Delay(4);							   	
}uint8_t EE_IIC_WaitAck(void)
{uint8_t ucErrTime=0;EE_SDA_IN(); //SDA设置为输入  (从机给一个低电平做为应答) EE_IIC_SDA=1;EE_IIC_Delay(1);	   EE_IIC_SCL=1;EE_IIC_Delay(1);;	 while(EE_READ_SDA){ucErrTime++;if(ucErrTime>250){EE_IIC_Stop();return 1;}}EE_IIC_SCL=0; //时钟输出0 	   return 0;  
} void EE_IIC_Ack(void)
{EE_IIC_SCL=0;EE_SDA_OUT();EE_IIC_SDA=0;EE_IIC_Delay(1);EE_IIC_SCL=1;EE_IIC_Delay(2);EE_IIC_SCL=0;
}void EE_IIC_NAck(void)
{EE_IIC_SCL=0;EE_SDA_OUT();EE_IIC_SDA=1;EE_IIC_Delay(1);EE_IIC_SCL=1;EE_IIC_Delay(1);EE_IIC_SCL=0;
}					 				     void EE_IIC_SendByte(uint8_t data)
{                        uint8_t t;   EE_SDA_OUT(); 	    EE_IIC_SCL=0; //拉低时钟开始数据传输for(t=0;t<8;t++){              EE_IIC_SDA=(data&0x80)>>7;EE_IIC_Delay(1);			EE_IIC_SCL=1;data<<=1;EE_IIC_Delay(1);EE_IIC_SCL=0;	   }EE_IIC_Delay(1);
} 	void EE_IIC_PageSendByte(uint16_t data)
{                        uint8_t t,DataIn;   EE_SDA_OUT(); 	    EE_IIC_SCL=0; //拉低时钟开始数据传输DataIn=data&0xff;for(t=0;t<8;t++){              EE_IIC_SDA=(DataIn&0x80)>>7;EE_IIC_Delay(1);			EE_IIC_SCL=1;data<<=1;EE_IIC_Delay(1);EE_IIC_SCL=0;	   }DataIn=(data>>8)&0xff;for(t=0;t<8;t++){              EE_IIC_SDA=(DataIn&0x80)>>7;EE_IIC_Delay(1);			EE_IIC_SCL=1;data<<=1;EE_IIC_Delay(1);EE_IIC_SCL=0;	   }EE_IIC_Delay(1);
} uint8_t EE_IIC_ReadByte(uint8_t ack)
{uint8_t i,receive=0;EE_SDA_IN(); //SDA设置为输入模式 等待接收从机返回数据for(i=0;i<8;i++ ){EE_IIC_SCL=0; EE_IIC_Delay(1);EE_IIC_SCL=1;receive<<=1;if(EE_READ_SDA)receive++; //从机发送的电平EE_IIC_Delay(1); }					 if(ack)EE_IIC_Ack(); //发送ACK elseEE_IIC_NAck(); //发送nACK  return receive;
}uint8_t EE_IIC_ReadByteFromSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t *buf)
{EE_IIC_Start();	EE_IIC_SendByte(I2C_Addr);	 //发送从机地址if(EE_IIC_WaitAck()) //如果从机未应答则数据发送失败{EE_IIC_Stop();return 1;}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_Start();EE_IIC_SendByte(I2C_Addr+1); //进入接收模式			   EE_IIC_WaitAck();*buf=EE_IIC_ReadByte(0);	   EE_IIC_Stop(); //产生一个停止条件return 0;
}uint8_t EE_EE_IIC_SendByteToSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t data)
{EE_IIC_Start();EE_IIC_SendByte(I2C_Addr); //发送从机地址if(EE_IIC_WaitAck()){EE_IIC_Stop();return 1; //从机地址写入失败}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_SendByte(data); if(EE_IIC_WaitAck()){EE_IIC_Stop(); return 1; //数据写入失败}EE_IIC_Stop(); //产生一个停止条件return 0;
}uint8_t EE_IIC_WriteByteToSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t data)
{EE_IIC_Start();EE_IIC_SendByte(I2C_Addr); //发送从机地址if(EE_IIC_WaitAck()){EE_IIC_Stop();return 1; //从机地址写入失败}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_SendByte(data); if(EE_IIC_WaitAck()){EE_IIC_Stop(); return 1; //数据写入失败}EE_IIC_Stop(); //产生一个停止条件return 0;
}
uint8_t EE_IIC_ReadMultByteFromSlave(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data)
{uint8_t count = 0;uint8_t temp;EE_IIC_Start();EE_IIC_SendByte(dev); //发送从机地址if(EE_IIC_WaitAck()){EE_IIC_Stop(); return 1; //从机地址写入失败}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_Start();EE_IIC_SendByte(dev+1); //进入接收模式	EE_IIC_WaitAck();for(count=0;count<length;count++){if(count!=(length-1))temp = EE_IIC_ReadByte(1); //带ACK的读数据else  temp = EE_IIC_ReadByte(0); //最后一个字节NACKdata[count] = temp;}EE_IIC_Stop(); //产生一个停止条件return 0;
}/******************************************************************************
*函  数:uint8_t IICwriteBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t* data)
*功 能:将多个字节写入指定设备 指定寄存器
*参  数:dev     目标设备地址
reg	   寄存器地址
length  要写的字节数
*data   要写入的数据将要存放的指针
*返回值:1成功 0失败
*备  注:无
*******************************************************************************/ 
uint8_t EE_IIC_WriteMultByteToSlave(uint8_t dev, uint8_t reg, uint8_t length, uint8_t* data)
{   uint8_t count = 0;EE_IIC_Start();EE_IIC_SendByte(dev); //发送从机地址if(EE_IIC_WaitAck()){EE_IIC_Stop();return 1; //从机地址写入失败}EE_IIC_SendByte(reg&0xff); //发送寄存器地址,就是页地址EE_IIC_WaitAck();	  for(count=0;count<length;count++){EE_IIC_SendByte(data[count]); if(EE_IIC_WaitAck()) //每一个字节都要等从机应答{EE_IIC_Stop();return 1; //数据写入失败}}EE_IIC_Stop(); //产生一个停止条件return 0;
}uint8_t EEPROM_PageWrite(uint8 PageNum, uint8_t length, uint8_t* data)
{uint8 Addr,PageAddr,i;uint16 j;//每页16个字节,24c08一共64页,页地址是页号*16/*if(PageNum<16)//0~15{PageAddr=16*PageNum;Addr=0xA0;EE_IIC_WriteMultByteToSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=16 && PageNum<=31){Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_WriteMultByteToSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=32 && PageNum<=47){Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_WriteMultByteToSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=48 && PageNum<=63){Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_WriteMultByteToSlave(Addr,PageAddr,length,data) ;}*///cht- eeprom进行写的时候,MP进行接地处理EEPROMMP(0);
//    vTaskDelay( 2/portTICK_RATE_MS );EE_IIC_Delay(20);DisableInterrupts;Addr=0xA0+((((PageNum*16)>>8)&0x07)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_WriteMultByteToSlave(Addr,PageAddr,length,data) ;EnableInterrupts;for(i=0;i<6;i++){for(j=0;j<500;j++){EE_IIC_Delay(1);}
//        vTaskDelay( 1/portTICK_RATE_MS );}EEPROMMP(1);//cht-恢复高电平,可以读return 1;
}uint8_t EEPROM_PageRead(uint8 PageNum, uint8_t length, uint8_t* data)
{uint8 Addr,PageAddr;//每页16个字节,24c08一共64页,页地址是页号*16/*if(PageNum<16)//0~15{PageAddr=16*PageNum;Addr=0xA0;EE_IIC_ReadMultByteFromSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=16 && PageNum<=31){// PageAddr=(16*PageNum)%256;Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_ReadMultByteFromSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=32 && PageNum<=47){Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_ReadMultByteFromSlave(Addr,PageAddr,length,data) ;}else if(PageNum>=48 && PageNum<=63){Addr=0xA0+((((PageNum*16)>>8)&0x03)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_ReadMultByteFromSlave(Addr,PageAddr,length,data) ;}*/Addr=0xA0+((((PageNum*16)>>8)&0x07)<<1);PageAddr=(PageNum*16)&0xff;EE_IIC_ReadMultByteFromSlave(Addr,PageAddr,length,data) ;return 1; }#define _24C08	        4
#define PAGE_SIZE		16
#define PAGE_SIZE_REM	0x0F
#define MEM_SIZE		0x03ff#define MAX_ADDR	( (MEM_SIZE+1)*DEV_24CXX_NUM-1 )
//芯片常量
#define DEV_24CXX_MAIN_ADDR	0xA0
#define DEV_24CXX_READ	    0x01
#define DEV_24CXX_WRITE	    0x00
#define IIC_SEND_ACK	    0x10
#define IIC_SEND_NOACK	    0x11#define IIC_STATE_NOACK	    0x20
#define IIC_STATE_ACK	    0x21uint16 HardAddr;
void _24CXXX_AddrProcess(unsigned int Addr)
{HardAddr = 0x00;
}void _24CXXX_WriteByte(unsigned int Addr,unsigned char Data)
{_24CXXX_AddrProcess(Addr);Addr &= MEM_SIZE;	EE_IIC_Start();EE_IIC_SendByte(DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE);EE_IIC_SendByte( ((unsigned char)(Addr>>8)) );EE_IIC_SendByte( ((unsigned char)Addr) );EE_IIC_SendByte( Data );EE_IIC_Stop();}unsigned char _24CXXX_ReadByte(unsigned int Addr)
{unsigned char temp;_24CXXX_AddrProcess(Addr);Addr &= MEM_SIZE;EE_IIC_Start();EE_IIC_SendByte(DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE);EE_IIC_SendByte( ((unsigned char)(Addr>>8)) );EE_IIC_SendByte( ((unsigned char)Addr) );EE_IIC_Start();EE_IIC_SendByte(DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_READ);temp = EE_IIC_ReadByte(IIC_SEND_NOACK);EE_IIC_Stop();return temp;
}void _24CXXX_WriteBytes(unsigned int StartAddr,unsigned char *Data,int DataNum)
{unsigned char Num;unsigned int i;unsigned int y;unsigned int yy;_24CXXX_AddrProcess(StartAddr);yy = StartAddr & MEM_SIZE;y = yy&PAGE_SIZE_REM;	//=StartAddr/PAGE_SIZEy = PAGE_SIZE - y;	    //要写的第一页中有多少个数据if( y <= PAGE_SIZE )	//写第一页(可能不到一页,以使页对齐){EE_IIC_Start();EE_IIC_SendByte( DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE );EE_IIC_SendByte( ((unsigned char)(yy>>8)) );EE_IIC_SendByte( ((unsigned char)yy) );for(i=0;i<y;i++){if( i>=DataNum ){break;}EE_IIC_SendByte( *(Data++) );			}}IIC_Stop();//DelayMs(10);vTaskDelay( 20/portTICK_RATE_MS );DataNum -= y;		//还有多少数据未写i = 0;Num = 0;			//用于记录已经写了多少页while( DataNum>0 )	//数据未写完{if( i == 0 ){yy = StartAddr+y+Num*PAGE_SIZE;_24CXXX_AddrProcess(yy);yy = yy & MEM_SIZE;EE_IIC_Start();EE_IIC_SendByte( DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE );EE_IIC_SendByte( ((unsigned char)(yy>>8)) );EE_IIC_SendByte( ((unsigned char)(yy)) );}EE_IIC_SendByte( *(Data++) );i++;if(i>=PAGE_SIZE )	//如果一页写完{i = 0;Num++;IIC_Stop();vTaskDelay( 20/portTICK_RATE_MS );}DataNum--;}if(i!=0x0000)	//如果写结束时,并未到达页的最后,则需要补上停止位{EE_IIC_Stop();vTaskDelay( 20/portTICK_RATE_MS );}	
}void _24CXXX_ReadBytes(unsigned int StartAddr,unsigned char *Data,int DataNum)
{unsigned char Num;unsigned int i;unsigned int y;unsigned int yy;_24CXXX_AddrProcess(StartAddr);yy = StartAddr & MEM_SIZE;y = yy&PAGE_SIZE_REM;	//=StartAddr/PAGE_SIZEy = PAGE_SIZE - y;				//要写的第一页中有多少个数据if( y <= PAGE_SIZE )	//写第一页(可能不到一页,以使页对齐){EE_IIC_Start();EE_IIC_SendByte( DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE );EE_IIC_SendByte( ((unsigned char)(StartAddr>>8)) );EE_IIC_SendByte( ((unsigned char)StartAddr) );EE_IIC_Start();EE_IIC_SendByte(DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_READ);for(i=0;i<y;i++){if( i>=DataNum ){break;}if( (i==DataNum-1)||(i==y-1) )	//如果是该页的最后一个数据,则NOACK*Data = EE_IIC_ReadByte(IIC_SEND_NOACK);else*Data = EE_IIC_ReadByte(IIC_SEND_ACK);Data++;			}}EE_IIC_Stop();//DelayUs(20);DataNum -= y;		//还有多少数据未写i = 0;Num = 0;			//用于记录已经写了多少页while( DataNum>0 )	//数据未写完{if( i == 0 ){yy = StartAddr+y+Num*PAGE_SIZE;_24CXXX_AddrProcess(yy);yy = yy & MEM_SIZE;EE_IIC_Start();EE_IIC_SendByte( DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_WRITE );EE_IIC_SendByte( (unsigned char)(yy>>8) );EE_IIC_SendByte( (unsigned char)(yy) );EE_IIC_Start();EE_IIC_SendByte(DEV_24CXX_MAIN_ADDR|(HardAddr<<1)|DEV_24CXX_READ);}if( (i==PAGE_SIZE-1)||(DataNum==1) )	//如果是该页或要读的最后一个数据,则NOACK*Data = EE_IIC_ReadByte(IIC_SEND_NOACK);else*Data = EE_IIC_ReadByte(IIC_SEND_ACK);Data++;i++;if(i>=PAGE_SIZE )	//如果一页写完{i = 0;Num++;EE_IIC_Stop();//DelayUs(20);}DataNum--;}if(i!=0x0000)	//如果写结束时,并未到达页的最后,则需要补上停止位{EE_IIC_Stop();}}

区分硬件IIC与软件IIC

一般使用软件模拟IIC,,可移植性高


一:模拟IIC与硬件IIC定义?


模拟I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用。

二:优缺点


1.硬件I2C的效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。
2.模拟I2C 是通过GPIO,软件模拟寄存器的工作方式,而硬件(固件)I2C是直接调用内部寄存器进行配置。如果要从具体硬件上来看,可以去看下芯片手册。因为固件I2C的端口是固定的,所以会有所区别。

三:如何区分它们

可以看底层配置,比如IO口配置,如果配置了IO口的功能(IIC功能)那就是固件IIC,否则就是模拟

可以看IIC写函数,看里面有木有调用现成的函数或者给某个寄存器赋值,如果有,则肯定是固件IIC功能,没有的话肯定是数据一个bit一个bit模拟发生送的,肯定用到了循环,则为模拟。

根据代码量判断,模拟的代码量肯定比固件的要大。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com