51单片机普通IO口模拟IIC总线的程序实现

IIC是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。

IIC是总线结构,1个Master,1个或多个Slave,各Slave设备以7位地址区分,地址后面再跟1位读写位,表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址,此时每个设备有读、写两个地址,高7位地址其实是相同的。
IIC数据格式如下:
无数据:SCL=1,SDA=1;
开始位(Start):当SCL=1时,SDA由1向0跳变;
停止位(Stop):当SCL=1时,SDA由0向1跳变;
数据位:当SCL由0向1跳变时,由发送方控制SDA,此时SDA为有效数据,不可随意改变SDA;
当SCL保持为0时,SDA上的数据可随意改变;
地址位:定义同数据位,但只由Master发给Slave;
应答位(ACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=0;
否应答位(NACK):当发送方传送完8位时,发送方释放SDA,由接收

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是基于STM32F4系列单片机的IO模拟IIC读取TMP102温度的示例代码: ```c #include "stm32f4xx.h" #define SDA_PIN GPIO_Pin_9 #define SDA_GPIO_PORT GPIOB #define SDA_GPIO_CLK RCC_AHB1Periph_GPIOB #define SCL_PIN GPIO_Pin_8 #define SCL_GPIO_PORT GPIOB #define SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define I2C_SPEED 100000 void IIC_Delay(void) { uint16_t i = 7 * (SystemCoreClock / 10000000); while(i--); } void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(SDA_GPIO_CLK | SCL_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(SDA_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(SCL_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); } void IIC_Start(void) { GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); GPIO_ResetBits(SDA_GPIO_PORT, SDA_PIN); IIC_Delay(); GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); } void IIC_Stop(void) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); GPIO_ResetBits(SDA_GPIO_PORT, SDA_PIN); IIC_Delay(); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); } uint8_t IIC_WaitAck(void) { uint16_t i = 50000; GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); IIC_Delay(); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); while(GPIO_ReadInputDataBit(SDA_GPIO_PORT, SDA_PIN)) { if(!(i--)) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); return 1; } } GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); return 0; } void IIC_Ack(void) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); GPIO_ResetBits(SDA_GPIO_PORT, SDA_PIN); IIC_Delay(); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); } void IIC_NAck(void) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); IIC_Delay(); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); } void IIC_WriteByte(uint8_t byte) { uint8_t i = 8; while(i--) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); if(byte & 0x80) GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); else GPIO_ResetBits(SDA_GPIO_PORT, SDA_PIN); byte <<= 1; IIC_Delay(); GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); } GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); } uint8_t IIC_ReadByte(uint8_t ack) { uint8_t i = 8, byte = 0; GPIO_SetBits(SDA_GPIO_PORT, SDA_PIN); while(i--) { GPIO_ResetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); byte <<= 1; if(GPIO_ReadInputDataBit(SDA_GPIO_PORT, SDA_PIN)) byte |= 0x01; GPIO_SetBits(SCL_GPIO_PORT, SCL_PIN); IIC_Delay(); } if(ack) IIC_Ack(); else IIC_NAck(); return byte; } void TMP102_Init(void) { IIC_Start(); IIC_WriteByte(0x90); IIC_WaitAck(); IIC_WriteByte(0x01); IIC_WaitAck(); IIC_Stop(); } float TMP102_ReadTemp(void) { uint16_t temp; float t; IIC_Start(); IIC_WriteByte(0x90); IIC_WaitAck(); IIC_WriteByte(0x00); IIC_WaitAck(); IIC_Start(); IIC_WriteByte(0x91); IIC_WaitAck(); temp = (IIC_ReadByte(1) << 8) | IIC_ReadByte(0); IIC_Stop(); t = temp * 0.0625; return t; } int main(void) { float temperature; RCC_DeInit(); SystemInit(); IIC_Init(); TMP102_Init(); while(1) { temperature = TMP102_ReadTemp(); // 处理温度数据 } } ``` 在本例中,使用GPIO模拟IIC总线,通过模拟SCL和SDA信号来实现与TMP102的通信。首先初始化GPIO口,然后定义IIC总线的各种操作函数。在主函数中初始化TMP102,并循环读取温度数据。需要注意的是,TMP102的温度数据为16位有符号数,需要经过转换才能得到实际温度值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蛋蛋强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值