STM32软件模拟IIC

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Pain_Love/article/details/54947671

                               IIC总线

一、与IIC有关的知识

(1)IIC属于半双工通信方式

(2)IIC的协议

    1.空闲状态:IIC的SCL和SDA两条线均处于高电平状态,此时即释放总线

    2.起始信号(Start):SCL为高电平期间,SDA产生一个下降沿信号

    3.停止信号(End):SCL为高电平期间,SDA产生一个上升沿信号

    4.应答信号ACK: 发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

    5.数据有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。

    6.数据传输:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

(3)24C02

    1.写数据流程

第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地
址,并且在读写方向上选择“写”操作。
第二步,发送数据的存储地址。24C02 一共256 个字节的存储空间,地址从0x00~0xFF,
我们想把数据存储在哪个位置,此刻写的就是哪个地址。
第三步,发送要存储的数据第一个字节、第二个字节„„注意在写数据的过程中,
EEPROM 每个字节都会回应一个“应答位 0”,来告诉我们写 EEPROM 数据成功,如果没有
回应答位,说明写入不成功。字

    2.读数据流程:

第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地
址,并且在读写方向上选择“写”操作。这个地方可能有同学会诧异,我们明明是读数据为
何方向也要选“写”呢?刚才说过了, 24C02 一共有 256 个地址,我们选择写操作,是为了
把所要读的数据的存储地址先写进去,告诉 EEPROM 我们要读取哪个地址的数据。这就如
同我们打电话,先拨总机号码( EEPROM 器件地址),而后还要继续拨分机号码(数据地址),
而拨分机号码这个动作,主机仍然是发送方,方向依然是“写”。
第二步,发送要读取的数据的地址,注意是地址而非存在 EEPROM 中的数据,通知
EEPROM 我要哪个分机的信息。
第三步,重新发送 I2C 起始信号和器件地址,并且在方向位选择“读”操作。
这三步当中,每一个字节实际上都是在“写”,所以每一个字节EEPROM 都会回应一个
“应答位0”。
第四步,读取从器件发回的数据,读一个字节,如果还想继续读下一个字节,就发送一
个“应答位 ACK(0)”,如果不想读了,告诉EEPROM,我不想要数据了,别再发数据了,那
就发送一个“非应答位 NAK(1)”

3.24C02地址

   24C02的 7 位地址中,其中高 4 位是固定的 0b1010,而低 3 位的地址取决于具体电路的设计,由芯片上的 A2、 A1、 A0 这 3 个引脚的实际电平决定,高为1,低为0.最低位是数据方向位(R/W)0表示接下来要发送数据(写),1表示接下来是请求数据(读)。

二、用到的知识

1.    GPIO、串口

2.    IIC、24C02

三、功能

先在24c02的一个地址中写入一个字符,然后在读取该位置的字符并通过串口显示出来。

#include "iic.h"

#define iicsda PBout(7)
#define iicscl PBout(6)
#define iicsdain PBin(7)

void SDAOUT(void)//sda×÷ΪÍÆÍìÊä³ö
{
  GPIO_InitTypeDef GPIO_InitTypeStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7;
	GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitTypeStruct);
}

void SDAIN(void)//SDA×÷Ϊ¸¡¿ÕÊäÈë
{
  GPIO_InitTypeDef GPIO_InitTypeStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_7;
	GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitTypeStruct);
}

void Myiic_INIT()//IIC³õʼ»¯
{
	GPIO_InitTypeDef GPIO_InitTypeStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitTypeStruct);
	
	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
}

void Myiic_Start(void)//ÆðʼÐźÅ
{
  SDAOUT();
	iicsda=1;
	iicscl=1;
	delay_us(4);
  iicsda=0;
	delay_us(4);
	iicscl=0;
}

void Myiic_Stop(void)//Í£Ö¹ÐźÅ
{
  SDAOUT();
	iicscl=0;
	iicsda=0;
	delay_us(4);
	iicscl=1;
	iicsda=1;
	delay_us(4);
}

u8 Myiic_Wait_Ack(void)//µÈ´ýACK
{
  u8 time=0;
	SDAIN();
	iicsda=1;
	delay_us(1);
	iicscl=1;
	delay_us(1);
	while(iicsdain)
	{
	  time++;
		if(time>250)
		{
			Myiic_Stop();
			return 1;
		}
	}
	iicscl=0;
	return 0;
}

void Myiic_ACK(void)//²úÉúACKÓ¦´ð
{
  iicscl=0;
	SDAOUT();
	iicsda=0;
  delay_us(2);
	iicscl=1;
	delay_us(2);
	iicscl=0;
}

void Myiic_NACK(void)//²»²úÉúÓ¦´ðλ
{
  iicscl=0;
	SDAOUT();
	iicsda=1;
  delay_us(2);
	iicscl=1;
	delay_us(2);
	iicscl=0;
}

void Myiic_Sendbyte(u8 w)//·¢ËÍÒ»¸ö×Ö½Ú
{
	u8 i;
  SDAOUT();
	iicscl=0;
	for(i=0;i<8;i++)
	{
	  iicsda=(w&0x80)>>7;
		w<<=1;
		delay_us(2);
		iicscl=1;
		delay_us(2);
		iicscl=0;
		delay_us(2);
	}
}

u8 Myiic_Readbyte(unsigned char ack)//¶ÁÈ¡Ò»¸ö×Ö½Ú
{
  unsigned char i=0,r=0;
	SDAIN();
	for(i=0;i<8;i++)
	{
	  iicscl=0;
		delay_us(2);
		iicscl=1;
		r<<=1;
		if(iicsdain)
			r++;
		delay_us(1);
	}
	if(!ack)
		Myiic_NACK();
	else
		Myiic_ACK();
	return r;
}







展开阅读全文

没有更多推荐了,返回首页