8051单片机——IIC通讯协议

一、通讯过程

        1、主器件向从器件发送数据

        (1)主设备发送起始(START)信号

        (2)主设备发送设备地址到从设备

        (3)等待从设备响应(ACK)

        (4)主设备发送数据到从设备,一般发送的每个字节数据后会跟着等待接收来自从设备的响应(ACK)

        (5)数据发送完毕,主设备发送停止(STOP)信号终止传输

        2、主器件接受从器件的数据

        (1)主设备发送起始(START)信号

        (2)主设备发送设备地址到从设备

        (3)等待从设备响应(ACK)%0D%0A

        (4) 主设备接收来自从设备的数据,一般接收的每个字节数据后会跟着向从设备发送一个响应(ACK)

        (5)一般接收到最后一个数据后会发送一个无效响应(NACK),然后主设备发送停止(STOP)信号终止传输

二、通信协议

        1、 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
I2C总线(Inter-Integrated Circuit,IIC)是一种串行通信总线,由Philips公司在20世纪80年代开发,现在已经成为了一种通用的总线标准。I2C总线可以连接多个设备,每个设备都有一个唯一的地址,可以在同一个总线上进行通信。 I2C总线由两条线组成:串行数据线(SDA)和串行时钟线(SCL)。SDA线用于数据传输,SCL线用于同步传输数据。I2C总线支持两种通信模式:主模式和从模式。在主模式下,主设备控制总线并发起数据传输;在从模式下,从设备等待主设备的控制,并响应主设备的请求。 I2C总线协议规定了通信时序、数据格式和错误处理等方面的规则。在I2C总线上进行通信需要遵循以下步骤: 1. 主设备发送起始信号; 2. 主设备发送设备地址和读写标志; 3. 从设备响应主设备的请求; 4. 主设备发送数据或请求数据; 5. 从设备响应主设备的请求; 6. 主设备发送停止信号。 以下是一个简单的通过I2C总线读取温度传感器数据的C语言程序,以Atmel公司的ATmega16单片机为例: ```c #include <avr/io.h> #include <util/delay.h> #define SCL_PIN 0 // 串行时钟线连接的引脚号,这里假设是PD0口 #define SDA_PIN 1 // 串行数据线连接的引脚号,这里假设是PD1口 #define DEVICE_ADDR 0x90 // 温度传感器的地址 void i2c_start(void) { PORTD |= (1 << SCL_PIN) | (1 << SDA_PIN); _delay_us(5); PORTD &= ~(1 << SDA_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); } void i2c_stop(void) { PORTD &= ~(1 << SDA_PIN); _delay_us(5); PORTD |= (1 << SCL_PIN) | (1 << SDA_PIN); _delay_us(5); } void i2c_write(unsigned char data) { unsigned char i; for(i = 0; i < 8; i++) { if(data & 0x80) PORTD |= (1 << SDA_PIN); else PORTD &= ~(1 << SDA_PIN); data <<= 1; PORTD |= (1 << SCL_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); } // 接收应答信号 PORTD |= (1 << SDA_PIN); PORTD |= (1 << SCL_PIN); _delay_us(5); if(PIND & (1 << SDA_PIN)) // 应答失败 PORTD &= ~(1 << SCL_PIN); _delay_us(5); } unsigned char i2c_read(unsigned char ack) { unsigned char i, data = 0; for(i = 0; i < 8; i++) { PORTD |= (1 << SCL_PIN); _delay_us(5); data <<= 1; if(PIND & (1 << SDA_PIN)) data |= 0x01; PORTD &= ~(1 << SCL_PIN); _delay_us(5); } // 发送应答信号 if(ack) PORTD &= ~(1 << SDA_PIN); else PORTD |= (1 << SDA_PIN); PORTD |= (1 << SCL_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); return data; } int main() { unsigned char temp_l, temp_h, temp; DDRC = 0xFF; DDRD = (1 << SCL_PIN) | (1 << SDA_PIN); i2c_start(); i2c_write(DEVICE_ADDR | 0x01); // 读取温度传感器数据 temp_h = i2c_read(1); temp_l = i2c_read(0); i2c_stop(); temp = (temp_h << 8) | temp_l; temp = temp >> 5; temp = temp * 0.0625; PORTC = temp; // 将温度值输出到LED灯 return 0; } ``` 在这个程序中,我们假设串行时钟线连接在PD0口,串行数据线连接在PD1口。程序的逻辑如下: 1. 配置PD0和PD1为输出引脚; 2. 发送起始信号; 3. 发送温度传感器的地址,并指定读取数据; 4. 接收温度值的高8位,并发送应答信号; 5. 接收温度值的低8位,并发送非应答信号; 6. 发送停止信号; 7. 计算温度值,并输出到LED灯上。 在程序中,我们定义了三个函数:`i2c_start`,`i2c_stop`和`i2c_write`,用于发送起始信号、停止信号和写入数据。我们还定义了一个函数`i2c_read`,用于读取数据,并发送应答信号或非应答信号。 需要注意的是,I2C总线上的数据传输需要遵循具体设备的通信协议和时序要求,不同设备之间可能存在差异。因此,在实际应用中需要根据具体设备的要求进行通信协议的编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值