单总线、IIC、SPI接口详解(二)
单总线 IIC SPI
大棒棒猪
发布时间: 2019-06-17
阅读: 3268

二、IIC

上篇已经描述了单总线的优缺点,以及单总线传输机制和程序的编写。接下来这篇需要来讲解IIC。先简单列举采用IIC的设备,如温湿度传感器SHT20,陀螺仪MPU6050,液晶显示屏oled,存储芯片24C02等等。

IICI2C Bus的简称,也叫集成电路总线。I2C串行总线上一般有两根信号线,一根双向数据线SDA,一根时钟线SCLI2C设备通常可以挂载多个,将I2C设备的串行数据SDA接在总线的SDA上,各设备的时钟线SCL接到总线的SCL上。绝大多数I2C设备都有一个固话的地址,只有线上传输的地址等于设备地址时,设备才会响应主机信号。主设备在很多时间都是控制SCL线的,而从设备一般只会拉低SCL用来延长总线的时钟周期信号。

接下来都以SHT2x(SHT20,SHT21等)为例,该传感器体积很小,采用DFN的封装,且可达到14bit精度。

20.png

与传感器的通讯。

1、首先通过其数据手册可以发现,所有的该传感器的I2C地址都一致(1000000)。

2、此传感器在上电之后需要至多15ms的等待时间将传感器达到空闲状态。

3、每次传输都以Start状态为开始,以Stop状态为结束。

start.png

开始传输状态,当SCL为高电平时,SDA由高电平转换为低电平。由主机控制,指示从机传输开始。

stop.png

停止传输状态,当SCL为高电平时,SDA由低电平转换为高电平。由主机控制,指示从机传输结束。


void IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure; //先使能外设IO PORTC时钟 
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOC, ENABLE );		   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure); 
	IIC_SCL=1;
	IIC_SDA=1;
}
//产生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;//钳住I2C总线,准备发送或接收数据 
	delay_us(4);
}	  
//产生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; 
	delay_us(1);
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}


4、启动传输之后,先将I2C设备地址(7位)以及SDA的方向位(1位,读为1,写为0)发送。在第八个SCL时钟的下降沿时,

从机通过拉低SDA引脚,指示传感器数据传输正常,即ACK位。SHT2X工作模式分为主机模式和非主机模式,可以通过单片机

改变传感器的工作模式。方法如下,

表.jpgstate.jpg

①主机模式下,在传感器测量过程中,SCL线被封锁。即单片机不能操作SCL线,单片机便不能对传感器传输数据。

②非主机模式下,当传感器在执行测量任务时,SCL线仍保持开放状态,可由单片机操作。

非主机模式下,传输方式如图。图中灰色部分由SHT2X控制。

测量.jpg

由于测量的最大分辨率为14bit,所以第二字节的SDA上的后两位(bit43和bit44),用来表示传输的信息,

bit43表示测量的类型(0表示温度,1表示湿度)。


float SHT2x_GetTempPoll(void)
{
    float TEMP;
    u8 ack, tmp1, tmp2;
    u16 ST;
    u16 i=0;
    IIC_Start();				//发送IIC开始信号
    IIC_Send_Byte(I2C_ADR_W);			//IIC发送一个字节 
    ack = IIC_Wait_Ack();	
    IIC_Send_Byte(TRIG_TEMP_MEASUREMENT_POLL);
    ack = IIC_Wait_Ack();
    do {
        delay_ms(100);               
        IIC_Start();				//发送IIC开始信号
        IIC_Send_Byte(I2C_ADR_R);	
    i++;
    ack = IIC_Wait_Ack();
	if(i==1000)break;
    } while(ack!=0);
    tmp1 = IIC_Read_Byte(1);
    tmp2 = IIC_Read_Byte(1);
    IIC_Read_Byte(0);
    IIC_Stop();
    ST = (tmp1 << 8) | (tmp2 << 0);
    ST &= ~0x0003;
    TEMP = ((float)ST * 0.00268127) - 46.85;
    return (TEMP);	  
}

float SHT2x_GetHumiPoll(void)
{
    float HUMI;
    u8 ack, tmp1, tmp2;
    u16 SRH;
    u16 i=0;
    
    IIC_Start();				//发送IIC开始信号
    IIC_Send_Byte(I2C_ADR_W);			//IIC发送一个字节 
    ack = IIC_Wait_Ack();	
    IIC_Send_Byte(TRIG_HUMI_MEASUREMENT_POLL);
    ack = IIC_Wait_Ack();    
    do {
       delay_ms(100);               
        IIC_Start();				//发送IIC开始信号
        IIC_Send_Byte(I2C_ADR_R);	
	i++;
	ack = IIC_Wait_Ack();
	if(i==100)break;
    } while(ack!=0);
    
    tmp1 = IIC_Read_Byte(1);
    tmp2 = IIC_Read_Byte(1);
    IIC_Read_Byte(0);
    IIC_Stop(); 
    SRH = (tmp1 << 8) | (tmp2 << 0);
    SRH &= ~0x0003;
    HUMI = ((float)SRH * 0.00190735) - 6;
    return (HUMI);
}
 5、软复位
该命令用于无需关闭和再次打开电源的情况下,重新启动传感器系统。接收到这个命令之后,
传感器系统开始重新初始化,并恢复默认设置状态。
u8 SHT2x_SoftReset(void) //SHT20软件复位
{
	u8 err=0;
	IIC_Start();
     IIC_Send_Byte(0x80);
	err = IIC_Wait_Ack();
	IIC_Send_Byte(0xFE);
	err = IIC_Wait_Ack();
	IIC_Stop();
	return err;
}

SPI总线

一、概述

SPI为串行外设接口的缩写,SPI为高速全双工同步通信总线,共使用4根线。SPI以主从方式工作,通常可以一个主设备和一个或多个从设备。需要至少4根线。MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。CS是从设备是否被主设备选中的引脚,当被选中时(通常以CS为低电平选中),主设备与从设备的操作才有效。

1、采用SPI总线的常用设备。

    常用的设备有:①W25Qxx的大容量FLASH存储芯片。②SPI的小OLED屏幕。③RC522的射频RFID读卡器④MCP2515的CAN总线模块等等

2、SPI总线的优点。

    ①仅占用4个引脚,节约了芯片的管脚。②简单易用。③支持高速(100Mhz以上)④支持全双工

3、SPI的缺点

    ①没有应答机制确认是否接收到数据②没有寻址机制,只能靠片选选择不同设备③典型应用只支持单主控

4、SPI协议

    SPI也为串行通讯协议,数据通过MISO和MOSI一位一位的传进传出,SCLK提供时钟脉冲,且该信号只由主设备控制,从设备不能控制。普通的串行通讯一次需连续传送8bit,而SPI允许一位一位的传送,且可暂停。

二、硬件连接

SPI总线定义两个及两个以上设备间的数据通信,提供时钟信号的为主机,接收时钟信号的设备为从机。

1、电路连接:

①单主机单从机,如下图

SPI.jpg



   ②单个主机和多个从机的连接

多spi.jpg

2、SPI相关寄存器

以STM32为例,与SPI相关寄存器有:

SPI控制寄存器1(SPI_CR1)

SPI控制寄存器2(SPI_CR2)

SPI状态寄存器  (SPI_SR)

SPI数据寄存器  (SPI_DR)

SPI_I2S配置寄存器(SPI_I2S_CFGR)

SPI_I2S预分频寄存器(SPI_I2SPR)


3、SPI传输模式

通过控制SPI控制寄存器1中的CPOL和CPHA位,将SPI分为4种传输模式。

Mode0 CPOL=0,CPHA=0

Mode1 CPOL=0,CPHA=1

Mode2 CPOL=1,CPHA=0

Mode3 CPOL=1,CPHA=1

时钟极性CPOL:SPI空闲时,时钟信号sclk的电平(1:空闲时高电平,0:空闲时低电平)

时钟相位CPHA:SPI在SCLK第几个边沿开始采样(0:第一个边沿开始,1:第二个边沿开始)

其中常用的为Mode0和Mode3。


4、以STM32为例,SPI初始化程序以及设置速度程序如下:

void SPI1_Init(void)
{	 
	RCC->APB2ENR|=1<<2;       //PORTA时钟使能 	 
	RCC->APB2ENR|=1<<12;      //SPI1时钟使能 
		   
	//这里只针对SPI口初始化
	GPIOA->CRL&=0X000FFFFF; 
	GPIOA->CRL|=0XBBB00000;//PA5.6.7复用 	    
	GPIOA->ODR|=0X7<<5;    //PA5.6.7上拉
		
	SPI1->CR1|=0<<10;//设置为双线双向全双工工作模式	
	SPI1->CR1|=1<<9; //内部NSS信号管理:设置为软件管理
	SPI1->CR1|=1<<8;  
 
	SPI1->CR1|=1<<2; //设置SPI为主机
	SPI1->CR1|=0<<11;//SPI发送接收8位帧数据
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1 空闲信号下的时钟极性
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1 时间相位
	SPI1->CR1|=7<<3; //Fsck=Fcpu/256 设置SPI分频系数
	SPI1->CR1|=0<<7; //定义数据以MSB位开始 
	SPI1->CR1|=1<<6; //SPI设备使能
	SPI1_ReadWriteByte(0xff);//启动传输(主要作用:维持MOSI为高)		 
} 
//SpeedSet:0~7
//SPI速度=fAPB2/2^(SpeedSet+1)
//APB2时钟一般为72Mhz
void SPI1_SetSpeed(u8 SpeedSet)
{
	SpeedSet&=0X07;			//限制范围
	SPI1->CR1&=0XFFC7; 
	SPI1->CR1|=SpeedSet<<3;	        //设置SPI1速度  
	SPI1->CR1|=1<<6; 		//SPI设备使能 
}
5、SPI读写操作及时序
1、SPI的读取,以读取W25X16的ID为例,顺序为:主机拉低CS引脚,选中W25X16,主机控制SCLK引脚产生时钟信号。主机控制MOSI引脚,发送读取ID的指令0x90。
紧接着发送24位地址码。最后,读取MISO引脚,查看W25x16返回给主机的ID。
时序.jpg
代码如下:
u16 SPI_Flash_ReadID(void)
{
	u16 Temp = 0;	  
	SPI_FLASH_CS=0;				    
	SPI1_ReadWriteByte(0x90);//发送读取ID命令	    
	SPI1_ReadWriteByte(0x00); 	    
	SPI1_ReadWriteByte(0x00); 	    
	SPI1_ReadWriteByte(0x00); 	 			   
	Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
	Temp|=SPI1_ReadWriteByte(0xFF);	 
	SPI_FLASH_CS=1;				    
	return Temp;
}  
2、SPI的写入,同样以W25X16为例,指定地址写入数据的时序如下如所示,图中仅用16位数据位,可以更换为更长。
写.jpg
代码如下:
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
    u16 i;  
    SPI_FLASH_Write_Enable();                  //SET WEL 
    SPI_FLASH_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_PageProgram);      //发送写页命令 (0x02)  
    SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址    
    SPI1_ReadWriteByte((u8)((WriteAddr)>>8));   
    SPI1_ReadWriteByte((u8)WriteAddr);   
    for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循环写数  
    SPI_FLASH_CS=1;                            //取消片选 
    SPI_Flash_Wait_Busy();					   //等待写入结束
} 


原创作品,未经权利人授权禁止转载。详情见转载须知 举报文章

展开查看更多
点赞 (1)
打赏
当前打赏0人    
大棒棒猪 擅长:工控电子 设计,制造及服务 计算机网络 智能硬件
评论(0)

登录后可评论,请 登录注册

相关文章推荐
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回

我要举报该内容理由

×
请输入您举报的理由(50字以内)