因为硬件控制有时会发生错误,而软件模拟准确性更高,所以,一般使用软件模拟
软件模拟,就是按照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();
}