【ZYNQ】EMIO 模拟 IIC 驱动示例
创始人
2025-05-29 13:39:05

IIC 简介

IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。
在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。

IIC 总线在传送数据过程中共有三种类型信号, 分别是:开始信号、结束信号和应答
信号。

  • 开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
  • 结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
  • 应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
    表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接
    收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为
    受控单元出现故障。

这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。IIC 总线时序图如
图所示:

在这里插入图片描述

为驱动实验室自研基于 DAC60502 的双通道电流输出模块,使用 EMIO 模拟 IIC 实现。

在这里插入图片描述

问:为啥不用硬件 IIC

答:就想用模拟的嘿嘿嘿

用软件模拟 IIC,最大的好处就是方便移植,同一个代码兼容所有 MCU,任何一个微控制器
只要有 IO 口,就可以很快的移植过去,而且不需要特定的 IO 口。

EMIO 模拟 IIC 驱动示例代码

  • iic_io.c
/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date           Author       Notes*/
#include "iic_io.h"extern XGpioPs GpioPs;void SCL_OUT(void)
{XGpioPs_SetDirectionPin(&GpioPs, SCL_PIN, GPIO_MODEL_OUTPUT);XGpioPs_SetOutputEnablePin(&GpioPs, SCL_PIN, GPIO_OUTPUT_ENABLE);
}void SCL_HIGH(void)
{XGpioPs_WritePin(&GpioPs, SCL_PIN, GPIO_SET);
}void SCL_LOW(void)
{XGpioPs_WritePin(&GpioPs, SCL_PIN, GPIO_RESET);
}void SDA_IN(void)
{XGpioPs_SetDirectionPin(&GpioPs, SDA_PIN, GPIO_MODEL_INPUT);
}uint32_t SDA_READ(void)
{return XGpioPs_ReadPin(&GpioPs, SDA_PIN);
}void SDA_OUT(void)
{XGpioPs_SetDirectionPin(&GpioPs, SDA_PIN, GPIO_MODEL_OUTPUT);XGpioPs_SetOutputEnablePin(&GpioPs, SDA_PIN, GPIO_OUTPUT_ENABLE);
}void SDA_HIGH(void)
{XGpioPs_WritePin(&GpioPs, SDA_PIN, GPIO_SET);
}void SDA_LOW(void)
{XGpioPs_WritePin(&GpioPs, SDA_PIN, GPIO_RESET);
}int IIC_Init(void)
{SCL_OUT();SCL_HIGH();SDA_OUT();SDA_HIGH();return 0;
}
  • iic_io.h
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date           Author       Notes*/
#ifndef __IIC_IO_H__
#define __IIC_IO_H__#include "xgpiops.h"#define SCL_PIN     54
#define SDA_PIN     55#define GPIO_RESET      		0
#define GPIO_SET        		1#define GPIO_MODEL_INPUT    	0
#define GPIO_MODEL_OUTPUT  		1#define GPIO_OUTPUT_DISABLE     0
#define GPIO_OUTPUT_ENABLE      1void SCL_OUT(void);
void SCL_HIGH(void);
void SCL_LOW(void);void SDA_IN(void);
uint32_t SDA_READ(void);void SDA_OUT(void);
void SDA_HIGH(void);
void SDA_LOW(void);int IIC_Init(void);#endif
  • iic_ctrl.c
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date           Author       Notes*/
#include "iic_ctrl.h"
#include "sleep.h"#define I2C_DELAY(...)	usleep(__VA_ARGS__)void IIC_Start(void)
{SDA_OUT();SDA_HIGH();SCL_HIGH();I2C_DELAY(4);SDA_LOW();I2C_DELAY(4);SCL_LOW();I2C_DELAY(2);
}void IIC_Stop(void)
{SDA_OUT();SCL_LOW();SDA_LOW();I2C_DELAY(4);SCL_HIGH();SDA_HIGH();I2C_DELAY(4);
}// 1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{uint8_t ucErrTime=0;SDA_OUT();SDA_HIGH();I2C_DELAY(1);SCL_HIGH();I2C_DELAY(1);SDA_IN();while(SDA_READ()){ucErrTime++;if(ucErrTime > 250){IIC_Stop();return 1;}}SCL_LOW();return 0;  
}//产生ACK应答
void IIC_Ack(void)
{SCL_LOW();SDA_OUT();SDA_LOW();I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();
}
//不产生ACK应答
void IIC_NAck(void)
{SCL_LOW();SDA_OUT();SDA_HIGH();I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();
}				void IIC_Write_Byte(uint8_t data)
{uint8_t  i = 0;SDA_OUT();SCL_LOW();for(i=0; i<8; i++){if(data & 0x80 )SDA_HIGH();elseSDA_LOW();data <<= 1;I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();I2C_DELAY(2);}
}// ack = 1,发送 ACK
// ack = 0,发送 nACK
uint8_t IIC_Read_Byte(uint8_t ack)
{uint8_t i = 0, data = 0;SDA_IN();for(i = 0; i < 8; i++){SCL_LOW();I2C_DELAY(2);SCL_HIGH();data <<= 1;if(SDA_READ())data++;I2C_DELAY(1);}if(!ack)IIC_NAck();elseIIC_Ack();return data;
}void IIC_Write_UINT16(uint8_t dev_addr, uint8_t wr_addr, uint16_t data)
{IIC_Start();IIC_Write_Byte(dev_addr);IIC_Wait_Ack(); IIC_Write_Byte(wr_addr);IIC_Wait_Ack(); IIC_Write_Byte(data >> 8);IIC_Wait_Ack(); IIC_Write_Byte(data & 0xFF);IIC_Wait_Ack();  	IIC_Stop();I2C_DELAY(800);
}uint16_t IIC_Read_UINT16(uint8_t dev_addr, uint8_t rd_addr)
{uint16_t data;IIC_Start();IIC_Write_Byte(dev_addr);IIC_Wait_Ack();IIC_Write_Byte(rd_addr);IIC_Wait_Ack(); IIC_Start();  	IIC_Write_Byte(dev_addr + 1);IIC_Wait_Ack();data = IIC_Read_Byte(1);data = (data <<8 ) + IIC_Read_Byte(0);IIC_Stop();return data;
}
  • iic_ctrl.h
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date           Author       Notes*/
#ifndef __I2C_CTRL_H__
#define __I2C_CTRL_H__#include "iic_io.h"void IIC_Start(void);
void IIC_Stop(void);
uint8_t IIC_Wait_Ack(void);
void IIC_Ack(void);	    
void IIC_NAck(void);
void IIC_Write_Byte(uint8_t value );
uint8_t IIC_Read_Byte(uint8_t addr);
void IIC_Write_UINT16(uint8_t dev_addr, uint8_t wr_addr, uint16_t data);
uint16_t IIC_Read_UINT16(uint8_t dev_addr, uint8_t rd_addr);#endif

相关内容

热门资讯

【文化中国行】“圈”出幸福感!... (来源:工人日报) 阅读提示 近年来,嘉兴市总工会以全总“559”部署和省总工会“137...
特色养殖“驮”起增收梦 投喂黑驴。本报记者 栾雨嘉 摄本报记者 栾雨嘉12月12日,黄南藏族自治州尖扎县措周乡俄什加村的肉驴...
内蒙古粮食产量达840.7亿斤 (来源:内蒙古日报)转自:内蒙古日报本报12月13日讯  (记者  韩雪茹)据12月12日国家统计局...
北疆楷模黄启东先进事迹报告会举... (来源:内蒙古日报)转自:内蒙古日报本报呼和浩特12月13日讯  (记者  皇甫秀玲)12月11日,...
全球最大储能电站在巴彦淖尔投运 (来源:内蒙古日报)转自:内蒙古日报本报巴彦淖尔12月13日电  (记者  薄金凤)12月12日,内...