IIC协议

一.IIC总线介绍

    IIC(Inter-Integrated Circuit 集成电路)总线是Philips公司在八十年代初推出的一种串行、半双工的总线, 主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步;I2C总线硬件结构简单,简化了PCB布线,降低了系统成本,提高了系统可靠性,因此在各个领域得到了广泛应用。

    I2C总线是一种多主机总线,连接在 I2C总线上的器件分为主机从机。主机有权发起和结束一次通信,从机只能被动呼叫;当总线上有多个主机同时启用总线时,I2C也具备冲突检测和仲裁的功能来防止错误产生;每个连接到I2C总线上的器件都有一个唯一的地址(7bit) ,传输数据的设备间是简单的主/从关系,每个器件都可以作为主机也可以作为从机(但同一时刻只能有一个主机),总线上的器件增加和删除不影响其他器件正常工作;I2C总线在通信时总线上发送数据的器件为发送器,接收数据的器件为接收器。I2C总线可以通过外部连线进行在线检测,便于系统故障诊断和调试,故障可以立即被寻址,软件也有利于标准化和模块化,缩短开发时间。

    串行的8位双向数据传输速率在标准模式下可达100Kbit/s,快速模式下可达400Kbit/s,高速模式下可达3.4Mbit/s。

二.通信过程

1. 主机发送起始信号启用总线;

2. 主机发送一个字节数据指明从机地址和后续字节的传送方向;

3. 被寻址的从机发送应答信号回应主机;

4. 发送器发送一个字节数据;

5. 接收器发送应答信号回应发送器;

6. 循环步骤4、5;

7. 通信完成后主机发送停止信号释放总线;

注意:

*第4步和第5步用的是发送器和接收器,不是主机和从机,这是由第一个字节的最后一位决定主给从发,还是从给主发。也就是说, 第一个字节和最后的停止信号一定是主机发给从机,但中间就不一定了。

*发送数据过程中不允许改变发送方向。

三.IIC总线的信号类型

IIC总线在传送数据过程中共有3种类型信号: 开始信号、结束信号和响应信号。

开始信号(S)和结束信号(P)

开始信号:SCL 为高电平时,SDA由高电平向低电平跳变, 开始传送数据。

结束信号:SCL 为高电平时,SDA由低电平向高电平跳变, 结束传送数据。

起始信号和停止信号都是由主机发出,起始信号产生后总线处于占用状态,停止信号产生后总线被释放,处于空闲状态。空闲时,SCL与SDA都是高电平。

停止情况有两种:

1. 主机不想发了,就发送停止信号;

2. 从机不想接了,不应答,主机就发送停止信号结束此次通信。

 响应信号(ACK)

接收器在接收到8位数据后,在第9个时钟周期,拉低SDA电平。


 

注意:SDA上传输的数据必须在SCL为高电平期间保持稳定,为低电平期间变化。

SDA和SCL发送数据时的电平转换图


 

四、IIC总线的数据传输格式

    IIC总线通信时每个字节为8位长度,数据传送时,先传送最高位(MSB),后传送低位,发送器发送完一个字节数据后接收器必须发送1位应答位来回应发送器,即一帧共有9位。



 

启动一个传输时,主机先发送S信号,然后发出8位数据。这8位数据中前7位为从机的地址,第8位表示传输的方向(0表示写操作,1表示读操作)。从机收到后会发出一个ACK信号。主机接收器在接收到最后一个字节后,也不会发出ACK信号。于是,从机发送器释放SDA线,以允许主机发出P信号结束传输。

五.项目实战

接下来我以TM1637数码管为例,应用IIC协议原理显示时间。

写SRAM数据固定地址模式



 

#include "gpio.h"
#include "main.h"
#include "rtc.h"
#include <stdio.h>

#define TM1637_CLK_H() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_SET)
#define TM1637_CLK_L() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_RESET)
#define TM1637_DIO_H() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_SET)
#define TM1637_DIO_L() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_RESET)
#define TM1637_DELAY_TIME 2

//共阴极数码管真值表
const uint8_t segmentMap[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, // 0-7
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, // 8-9,A-F
0x00
};

//开始信号
void tm1637_start_signal(){
	TM1637_CLK_H();
	TM1637_DIO_H();
	HAL_Delay(TM1637_DELAY_TIME);
	TM1637_DIO_L();
	HAL_Delay(TM1637_DELAY_TIME);
}

//停止信号
void tm1637_stop_signal(){
	TM1637_CLK_L();
	TM1637_DIO_L();
	HAL_Delay(TM1637_DELAY_TIME);
	TM1637_CLK_H();
	HAL_Delay(TM1637_DELAY_TIME);
	TM1637_DIO_H();
	HAL_Delay(TM1637_DELAY_TIME);
}

//应答信号
void tm1637_ack(){
	TM1637_CLK_L();
	HAL_Delay(TM1637_DELAY_TIME);
	TM1637_CLK_H();
	HAL_Delay(TM1637_DELAY_TIME);
}

//发送一个字节
void tm1637_write_byte(uint8_t data){
	int i;
	for(i=0;i<8;i++){
		TM1637_CLK_L();
		HAL_Delay(TM1637_DELAY_TIME);
		if((data >> i) & 0x1){
			TM1637_DIO_H();
		}else{
			TM1637_DIO_L();
		} 
	TM1637_CLK_H();
	HAL_Delay(TM1637_DELAY_TIME);
	}
}

//发送命令
void tm1637_send_cmd(uint8_t cmd){
	tm1637_start_signal();
	tm1637_write_byte(cmd);
	tm1637_ack();
	tm1637_stop_signal();
}

//给指定地址发送数据
void tm1637_send_data_to_addr(uint8_t addr,uint8_t data){
	tm1637_start_signal();
	tm1637_write_byte(addr);
	tm1637_ack();
	tm1637_write_byte(data);
	tm1637_ack();
	tm1637_stop_signal();
}

//测试
void tm1637_test(){
	// 设置时间和日期
	//HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc,RTC_TimeTypeDef *sTime,uint32_tFormat)
	RTC_TimeTypeDef sTime;
	HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
	//HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc,RTC_DateTypeDef *sDate,uint32_tFormat)
	RTC_DateTypeDef sDate;
	HAL_RTC_SetDate(&hrtc,&sDate,RTC_FORMAT_BIN);
	// 获取时间和日期
	//HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc,RTC_TimeTypeDef *sTime,uint32_tFormat)
	HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
	//HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc,RTC_DateTypeDef *sDate,uint32_tFormat)	
	HAL_RTC_GetDate(&hrtc,&sDate,RTC_FORMAT_BIN);
	
	//显示时间
	while(1){
	tm1637_send_cmd(0x44);
	tm1637_send_data_to_addr(0xC0,segmentMap[sTime.Hours/10]);
	tm1637_send_data_to_addr(0xC1,segmentMap[sTime.Hours%10] | 0x80); 
	tm1637_send_data_to_addr(0xC2,segmentMap[sTime.Minutes/10]);
	tm1637_send_data_to_addr(0xC3,segmentMap[sTime.Minutes%10]);
	tm1637_send_cmd(0x8F);	
	HAL_Delay(1000);
	}
}
	

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值