二、IIC
上篇已经描述了单总线的优缺点,以及单总线传输机制和程序的编写。接下来这篇需要来讲解IIC。先简单列举采用IIC的设备,如温湿度传感器SHT20,陀螺仪MPU6050,液晶显示屏oled,存储芯片24C02等等。
IIC为I2C Bus的简称,也叫集成电路总线。I2C串行总线上一般有两根信号线,一根双向数据线SDA,一根时钟线SCL。I2C设备通常可以挂载多个,将I2C设备的串行数据SDA接在总线的SDA上,各设备的时钟线SCL接到总线的SCL上。绝大多数I2C设备都有一个固话的地址,只有线上传输的地址等于设备地址时,设备才会响应主机信号。主设备在很多时间都是控制SCL线的,而从设备一般只会拉低SCL用来延长总线的时钟周期信号。
接下来都以SHT2x(SHT20,SHT21等)为例,该传感器体积很小,采用DFN的封装,且可达到14bit精度。
与传感器的通讯。
1、首先通过其数据手册可以发现,所有的该传感器的I2C地址都一致(1000000)。
2、此传感器在上电之后需要至多15ms的等待时间将传感器达到空闲状态。
3、每次传输都以Start状态为开始,以Stop状态为结束。
开始传输状态,当SCL为高电平时,SDA由高电平转换为低电平。由主机控制,指示从机传输开始。
停止传输状态,当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工作模式分为主机模式和非主机模式,可以通过单片机
改变传感器的工作模式。方法如下,
①主机模式下,在传感器测量过程中,SCL线被封锁。即单片机不能操作SCL线,单片机便不能对传感器传输数据。
②非主机模式下,当传感器在执行测量任务时,SCL线仍保持开放状态,可由单片机操作。
非主机模式下,传输方式如图。图中灰色部分由SHT2X控制。
由于测量的最大分辨率为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、电路连接:
①单主机单从机,如下图
②单个主机和多个从机的连接
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时钟一般为72Mhzvoid 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。代码如下: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位数据位,可以更换为更长。代码如下: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(); //等待写入结束 }
原创作品,未经权利人授权禁止转载。详情见转载须知。 举报文章
我要举报该内容理由
×