stm32项目实战一之智能家居(三)

#I2C协议#OLED显示

USART多用于板间通信,比如和上位机通信。

IIC多用于板内通信,比如和EEPROM、OLED通信。

我们在使用STM32的IIC时,多半用软件模拟,IIC的硬件部分不太稳定,故不推荐。

IIC的连线图则是MCU(主机)和IIC协议的传感器(从机)和触摸屏(从机)和EEPROM(从机)等连接在SDA总线和SCL总线上。注:两根总线上附有上拉电阻。

SDA:数据总线

SCL:时间总线

IIC总线可以并联多个器件,每一个设备的可以作为主机或者从机,但是一般情况下MCU作为主机。

每一个设备都有对应的唯一一个地址。

IIC总线组成“线与”的关系,任何一个器件都可以拉低电平。

IIC总线时序有起始信号、数据传输和停止信号

IIC开始和结束时序图分析:

起始信号:当SCL为高电平期间,SDA由高到低的跳变;

停止信号:当SCL为高电平期间,SDA由低到高的跳变;

IIC发送数据的时序图分析:

应答位为图中A部分(ACK),ACK简称应答位,表示接收方已经成功接受了该字节。(低电平)

当应答位为NACK,一般表示接收方未能正确接受该字节。(高电平)

数据在时钟信号的上升沿到来之前就需准备好,在下降沿到来之前必须稳定。

IIC协议在此处与OLED连接只需了解MCU通过IIC协议发送命令或数据给OLED。

程序部分:

起始信号和停止信号时序图上图已经演示过,下面是起始和停止的软件部分。

/*-----------------------------------------------
函数名:产生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;//钳住IIC总线,准备发送或者接受数据 
}

/*-----------------------------------------------
函数名:产生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;//发送IIC总线结束信号
	delay_us(4);							   	
}

完成起始信号后,SCL和SDA都为低电平。

根据上图,我们给程序延时4us。

数据发送和数据接收:

程序部分:

for(mask=0x80;mask!=0;mask>>=1)
	{
		if((mask&dat) == 0)
		{
			IIC_SDA=0;
		}
		else
			IIC_SDA=1;
		delay_us(4);
		IIC_SCL=1;
		delay_us(4);
		IIC_SCL=0;
	}

比如发送0b10101101

第一次

10101101和10000000相与不等于0                                     IIC_SDA=1

第二次

10101101和01000000相与等于0                                          IIC_SDA=0

第三次

10101101和00100000相与等于1                                          IIC_SDA=1

..........

应答部分程序:

SDA_IN(); 
IIC_SDA=1;	
delay_us(4);
IIC_SCL=1;
ack=READ_SDA;
delay_us(4);
IIC_SCL=0;
return ack;

总的写入从机程序:

/*-----------------------------------------------
函数名;写入1字节                      
参	数;写入的字节                            
返回值:ack为0,表示写入成功;ack为1,表示写入失败
------------------------------------------------*/
u8 IICWrite(u8 dat)
{
	u8 ack;
	u8 mask;
	SDA_OUT();
	for(mask=0x80;mask!=0;mask>>=1)
	{
		if((mask&dat) == 0)
		{
			IIC_SDA=0;
		}
		else
			IIC_SDA=1;
		delay_us(4);
		IIC_SCL=1;
		delay_us(4);
		IIC_SCL=0;
	}
	SDA_IN(); 
	IIC_SDA=1;	
	delay_us(4);
	IIC_SCL=1;
	ack=READ_SDA;
	delay_us(4);
	IIC_SCL=0;
	return ack;	
}

与OLED的通信:

主机通过总线向从机写入从机地址,观察应答位ACK。

如果ACK返回0,表示正确写入说明从机确实存在。

如果ACK返回0,表示未正确写入说明从机确实不存在。

OLED从机地址共7位,其中高六位确定:011110x(根据oled数据手册得到)

0111100->0x3c                        0111101->0x3D

起始信号——发送字节——停止信号判断是否存在从机部分

/*-----------------------------------------------
函数名:验证从机是否存在                     
参	数:从机的地址                           
返回值:ack为0,表示从机存在;ack为1,表示从机不存在
------------------------------------------------*/
u8 IICAdress(u8 addr)
{
	u8 ack;
	IIC_Start();
	ack=IICWrite(addr<<1);
	IIC_Stop();
	return ack;

}
//配置PA7的输入输出模式
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

 OLED相关引脚的初始化部分:

/*-----------------------------------------------
函数名:OLED相关引脚初始化                    
参  数:无
返回值:无
------------------------------------------------*/
void OLED_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );	
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
 
	IIC_SCL=1;
	IIC_SDA=1;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值