I²C控制E²PROM(软件模拟)

因为硬件控制有时会发生错误,而软件模拟准确性更高,所以,一般使用软件模拟

软件模拟,就是按照IIC的时序逻辑来模拟电平的产生。
在这里插入图片描述
如图所示,我们需要自己模拟每一种信号的发生。起始信号,停止信号,数据发送,数据接受,发送ACK和NACK,等待应答信号。

算了。。。炸了,一直改不对,找不到错在哪。。。。
错代码如下

#include "i2c.h"

void I2C_EEPROM_Config()
{
	GPIO_InitTypeDef  GPIO_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开时钟

	//初始化GPIO引脚
	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_6;//SCL
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_7;//SDA
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //这俩句不修改也行,因为和上面的一样
   	GPIO_Init(GPIOB,&GPIO_InitStruct);

}
void Start()
{
	//PB6  SCL 、PB7  SDA
	GPIO_SetBits(GPIOB,GPIO_Pin_6);//PB6、7置位 (高电平)
	GPIO_SetBits(GPIOB,GPIO_Pin_7);
	delay();
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);//PB7清0  (低电平)
	delay();
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);//PB6清0  (低电平)
	delay();
}
void Stop()
{
	//PB6  SCL 、PB7  SDA
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);
	delay();
	GPIO_SetBits(GPIOB,GPIO_Pin_6);
	delay();
	GPIO_SetBits(GPIOB,GPIO_Pin_7);
	delay();
}
uint8_t Read_Byte()//读一个字节
{
	uint8_t data=0,i=8;
	while(i--)
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
		delay();
		GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	    delay();
		data |=GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_7); //从SDA读数据
		delay();
	
	}
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
	delay();
	return data;
}
void Write_Byte(uint8_t data)
{
	uint8_t i=8;
	while(i--)
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
		delay();
		if((data&0x80)==1)
			GPIO_SetBits(GPIOB,GPIO_Pin_7);
		else 
			GPIO_ResetBits(GPIOB,GPIO_Pin_7);
		delay();
		GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	    delay();
	
		data<<=1;
	}
		GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
		delay();
}
void I2CSendAck()
{
	//ACK就是在第9个SCL高电平发一个SDA低电平
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);//SDA低电平
	delay();
	GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	delay();
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
	delay();	
	GPIO_SetBits(GPIOB,GPIO_Pin_7);//SDA高电平
	delay();
}
void I2CSendNotAck()
{
	//ACK就是在第9个SCL高电平发一个SDA高电平
	GPIO_SetBits(GPIOB,GPIO_Pin_7);//SDA高电平
	delay();
	GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	delay();
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);//SCL低电平
	delay();
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);//SDA低电平
	delay();
}
uint8_t Wait_Ack()
{
	
	uint8_t re=0;

	GPIO_SetBits(GPIOB,GPIO_Pin_7);//SDA高电平,这是CPU在释放IIC总线
	delay();
	GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	delay();
	if(GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_7)==1)//NACK
	   re=1;
	else//ACK
	   re=0;
	GPIO_SetBits(GPIOB,GPIO_Pin_6);//SCL高电平
	delay();
	return re;
}
void delay()
{
	int n=1000;
	while(n--);
}
void Write_EEPROM_Byte(uint8_t addr,uint8_t data)
{
   Start();
   Write_Byte(0xa0);  //EEPROM写地址
   Wait_Ack();
   Write_Byte(addr);  //EEPROM内部地址
   Wait_Ack();
   Write_Byte(data);  //写数据
   Wait_Ack();
   Stop();
}
uint8_t Read_EEPROM_Byte(uint8_t addr)
{
   uint8_t	data;
   Start();
   Write_Byte(0xa0);  //EEPROM写地址
   Wait_Ack();
   Write_Byte(addr);  //EEPROM内部地址
   Wait_Ack();

   Start();
   Write_Byte(0xa1);  //EEPROM读地址
   Wait_Ack();
   data=Read_Byte();  //读数据
   Wait_Ack();
   Stop();
   return data;
}
void usrt_init()
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	USART_InitTypeDef UART_InitStruct;
//配置uart的GPIO口	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//配置Rx
	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_IN_FLOATING;
		//这里应该是计算机传什么电平,就是什么电平,所以应该是浮空输入	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	//配置Tx
	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_2;
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
//配置usrt
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	UART_InitStruct.USART_BaudRate=  115200;
	UART_InitStruct.USART_WordLength=  USART_WordLength_8b;
	UART_InitStruct.USART_StopBits=  USART_StopBits_1;
	UART_InitStruct.USART_Parity=  USART_Parity_No;
	UART_InitStruct.USART_Mode=  USART_Mode_Rx|USART_Mode_Tx;
	UART_InitStruct.USART_HardwareFlowControl=  USART_HardwareFlowControl_None;
	USART_Init(USART2,&UART_InitStruct);

//串口使能
	USART_Cmd(USART2,ENABLE);
}


 
 //在这里,我们要让开发板和计算机进行通信
int fputc(int ch,FILE* f) //printf的调用,用来接受开发板的数据
{
	USART_SendData(USART2,ch);
	while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
	return ch;
}
int fgetc(FILE* f) //scanf的调用,用来向开发板发送数据
{
	
	while(USART_GetFlagStatus(USART2,USART_FLAG_RXNE)==RESET);
	return (int)USART_ReceiveData(USART2);
}

反正,在比赛时,好像是给出了IIC的软件模拟时序的代码,然后需要自己写的代码是将数据从EEPROM读取和写入的部分。

/**
  * @说明     从AT24C02指定地址读出一个字节数据
  * @参数     address:AT24C02内部存储地址
  * @返回值   val:读出数据
  */
uint8_t x24c02_read(uint8_t address)
{
	unsigned char val;
	
	I2CStart(); 
	I2CSendByte(0xa0);//EEPROM写地址
	I2CWaitAck(); 
	
	I2CSendByte(address);
	I2CWaitAck(); 
	
	I2CStart();
	I2CSendByte(0xa1); 
	I2CWaitAck();
	val = I2CReceiveByte(); 
	I2CWaitAck();
	I2CStop();
	
	return(val);
}

/**
  * @说明     向AT24C02指定地址写入一个字节数据
  * @参数     address:AT24C02内部存储地址
  * @参数     info:写入数据
  * @返回值   None
  */
void x24c02_write(unsigned char address,unsigned char info)
{
	I2CStart(); 
	I2CSendByte(0xa0); 
	I2CWaitAck(); 
	
	I2CSendByte(address);	
	I2CWaitAck(); 
	I2CSendByte(info); 
	I2CWaitAck(); 
	I2CStop();
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值