使用模拟时序的方法,对比于硬件I2C接口来说,在实时性和传输速度上会带来一些无法避免的下降,但是I2C总线本身也不是一种速度很快的总线(据相关资料可查,最高的速度为400KHZ),同时也不需要具备很高的实时性能。
所以,模拟I2C时序完全能满足绝大部分的场合要求,并且移植性得到了很大的提高。
闲话不多说,贴上代码,大家一起分享下。
首先贴出 i2c_soft.h实现:
/***********************************************************************************
* 文件名 :i2c_soft.h
* 描述 :使用I/0模拟I2C接口
* 实验平台:神舟III号
* 库版本 :ST3.0.0
**********************************************************************************/
#ifndef __I2C_SOFT_H
#define __I2C_SOFT_H
#include "stm32f10x.h"
#define SCL_PIN GPIO_Pin_6
#define SDA_PIN GPIO_Pin_7
#define SCL_PORT GPIOB
#define SDA_PORT GPIOB
#define SCL_RCC_CLOCK RCC_APB2Periph_GPIOB
#define SDA_RCC_CLOCK RCC_APB2Periph_GPIOB
#define SCL_H GPIOB->BSRR = GPIO_Pin_6
#define SCL_L GPIOB->BRR = GPIO_Pin_6
#define SDA_H GPIOB->BSRR = GPIO_Pin_7
#define SDA_L GPIOB->BRR = GPIO_Pin_7
#define SCL_read GPIOB->IDR & GPIO_Pin_6
#define SDA_read GPIOB->IDR & GPIO_Pin_7
#define I2C_PageSize 8 //24C02每页8字节
void I2C_GPIO_Config(void);
bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress);
bool I2C_BufferWrite(u8* pBuffer, u8 length, u16 WriteAddress, u8 DeviceAddress);
void I2C_PageWrite(u8* pBuffer, u8 length, u16 WriteAddress, u8 DeviceAddress);
bool I2C_ReadByte(u8* pBuffer, u8 length, u16 ReadAddress, u8 DeviceAddress);
void I2C_Test(void);
#endif
然后贴出 i2c_soft.c实现:
/***********************************************************************************
* 文件名 :i2c_soft.c
* 描述 :使用I/0模拟I2C接口
* 实验平台:神舟III号
* 库版本 :ST3.0.0
*
* 作者 :xiayufeng xiayufeng90520@163.com
* 博客 :http://hi.baidu.com/xiayufeng520
**********************************************************************************/
#include "i2c_soft.h"
#include "usart1.h"
extern void Delay_ms(__IO u32 nTime);
/*
* 函数名:void I2C_GPIO_Config(void)
* 描述 : I2C管脚初始化
* 输入 :无
* 输出 : 无
*/
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SCL_RCC_CLOCK | SDA_RCC_CLOCK ,ENABLE);
//初始化SCL管脚
GPIO_InitStructure.GPIO_Pin = SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(SCL_PORT, &GPIO_InitStructure);
//初始化SDA管脚
GPIO_InitStructure.GPIO_Pin = SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(SDA_PORT, &GPIO_InitStructure);
}
/*
* 函数名: void I2C_delay(void)
* 描述 : 短暂延时
* 输入 : 无
* 输出 : 无
* 说明 : 内部定义的i可以优化速度,经测试最低到5还能写入
*/
static void I2C_delay(void)
{
u8 i=100;
while(i)
{
i--;
}
}
/*
* 函数名: bool I2C_Start(void)
* 描述 : 起始信号
* 输入 : 无
* 输出 : TRUE : 成功
FALSE : 失败
* 说明 :
*/
static bool I2C_Start(void)
{
SDA_H;
SCL_H;
I2C_delay();
if(!SDA_read)
return FALSE; //SDA线为低电平则总线忙,退出
SDA_L;
I2C_delay();
if(SDA_read)
return FALSE; //SDA线为高电平则总线出错,退出
SDA_L;
I2C_delay();
return TRUE;
}
/*
* 函数名: static void I2C_Stop(void)
* 描述 : 终止信号
* 输入 : 无
* 输出 : 无
* 说明 :
*/
static void I2C_Stop(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SDA_H;
I2C_delay();
}
/*
* 函数名: static void I2C_Ack(void)
* 描述 : 应答信号
* 输入 : 无
* 输出 : 无
* 说明 :
*/
static void I2C_Ack(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/*
* 函数名: void I2C_NoAck(void)
* 描述 : 无应答信号
* 输入 : 无
* 输出 : 无
* 说明 :
*/
static void I2C_NoAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/*
* 函数名: bool I2C_Start(void)
* 描述 : 等待应答信号
* 输入 : 无
* 输出 : TRUE : 有应答
FALSE : 无应答
* 说明 :
*/
static bool I2C_WaitAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
SCL_L;
return FALSE;
}
SCL_L;
return TRUE;
}
/*
* 函数名: static void I2C_SendByte(u8 SendByte)
* 描述 : 发送一个字节
* 输入 : SendByte : 字节数据
* 输出 : 无
* 说明 : 数据从高位到低位
*/
static void I2C_SendByte(u8 SendByte)
{
u8 i=8;
while(i--)
{
SCL_L;
I2C_delay();
if(SendByte&0x80)
SDA_H;
else
SDA_L;
SendByte<<=1;
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
}
/*
* 函数名: static u8 I2C_ReceiveByte(void)
* 描述 : 读取一个字节
* 输入 : 无
* 输出 : 字节数据
* 说明 : ReceiveByte : 数据从高位到低位
*/
static u8 I2C_ReceiveByte(void)
{
u8 i=8;
u8 ReceiveByte=0;
SDA_H;
while(i--)
{
ReceiveByte<<=1;
SCL_L;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
ReceiveByte|=0x01;
}
}
SCL_L;
return ReceiveByte;
}
/*
* 函数名: bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress)
* 描述 : 写入1字节数据
* 输入 : SendByte : 要写入数据
WriteAddress : 写入地址
DeviceAddress : 器件地址
* 输出 : TRUE : 成功
FALSE : 失败
* 说明 :
*/
bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress)
{
if(!I2C_Start())
return FALSE;
I2C_SendByte(((WriteAddress & 0x0700) >>7) | DeviceAddress & 0xFFFE);//设置高起始地址+器件地址
if(!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址
I2C_WaitAck();
I2C_SendByte(SendByte);
I2C_WaitAck();
I2C_Stop();
Delay_ms(10);//注意:因为这里要等待EEPROM写完,可以采用查询或延时方式(10ms)
return TRUE;
}
/*
* 函数名: bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress)
* 描述 : 写入1串数据
* 输入 : pBuffer : 要写入数据缓冲区指针
length : 待写入长度
WriteAddress : 写入地址
DeviceAddress : 器件地址
* 输出 : TRUE : 成功
FALSE : 失败
* 说明 : 注意不能跨页写
*/
bool I2C_BufferWrite(u8* pBuffer, u8 length, u16 WriteAddress, u8 DeviceAddress)
{
if(!I2C_Start())
return FALSE;
I2C_SendByte(((WriteAddress & 0x0700) >>7) | DeviceAddress & 0xFFFE);//设置高起始地址+器件地址
if(!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址
I2C_WaitAck();
while(length--)
{
I2C_SendByte(* pBuffer);
I2C_WaitAck();
pBuffer++;
}
I2C_Stop();
Delay_ms(10);//注意:因为这里要等待EEPROM写完,可以采用查询或延时方式(10ms)
return TRUE;
}
/*
* 函数名: bool I2C_WriteByte(u8 SendByte, u16 WriteAddress, u8 DeviceAddress)
* 描述 : 写入1串数据
* 输入 : pBuffer : 要写入数据缓冲区指针
length : 待写入长度
WriteAddress : 写入地址
DeviceAddress : 器件地址
* 输出 : TRUE : 成功
FALSE : 失败
* 说明 : 跨页写入1串数据
*/
void I2C_PageWrite( u8* pBuffer, u8 length, u16 WriteAddress, u8 DeviceAddress)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
Addr = WriteAddress % I2C_PageSize; //写入地址是开始页的第几位
count = I2C_PageSize - Addr; //在开始页要写入的个数
NumOfPage = length / I2C_PageSize; //要写入的页数
NumOfSingle = length % I2C_PageSize; //不足一页的个数
if(Addr == 0) //写入地址是页的开始
{
if(NumOfPage == 0) //数据小于一页
{
I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据
}
else //数据大于等于一页
{
while(NumOfPage)//要写入的页数
{
I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress);//写一页的数据
WriteAddress += I2C_PageSize;
pBuffer += I2C_PageSize;
NumOfPage--;
Delay_ms(10);
}
if(NumOfSingle!=0)//剩余数据小于一页
{
I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据
Delay_ms(10);
}
}
}
else //写入地址不是页的开始
{
if(NumOfPage== 0) //数据小于一页
{
I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据
}
else //数据大于等于一页
{
length -= count;
NumOfPage = length / I2C_PageSize; //重新计算要写入的页数
NumOfSingle = length % I2C_PageSize; //重新计算不足一页的个数
if(count != 0)
{
I2C_BufferWrite(pBuffer,count,WriteAddress,DeviceAddress); //将开始的空间写满一页
WriteAddress += count;
pBuffer += count;
}
while(NumOfPage--) //要写入的页数
{
I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress);//写一页的数据
WriteAddress += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)//剩余数据小于一页
{
I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据
}
}
}
}
/*
* 函数名: bool I2C_ReadByte(u8* pBuffer, u8 length, u16 ReadAddress, u8 DeviceAddress)
* 描述 : 读出1串数据
* 输入 : pBuffer : 要读取数据缓冲区指针
length : 待读取长度
WriteAddress : 读取地址
DeviceAddress : 器件地址
* 输出 : TRUE : 成功
FALSE : 失败
* 说明 : 跨页写入1串数据
*/
bool I2C_ReadByte(u8* pBuffer, u8 length, u16 ReadAddress, u8 DeviceAddress)
{
if(!I2C_Start())return FALSE;
I2C_SendByte(((ReadAddress & 0x0700) >>7) | DeviceAddress & 0xFFFE);//设置高起始地址+器件地址
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte((u8)(ReadAddress & 0x00FF)); //设置低起始地址
I2C_WaitAck();
I2C_Start();
I2C_SendByte(((ReadAddress & 0x0700) >>7) | DeviceAddress | 0x0001);
I2C_WaitAck();
while(length)
{
*pBuffer = I2C_ReceiveByte();
if(length == 1)I2C_NoAck();
else I2C_Ack();
pBuffer++;
length--;
}
I2C_Stop();
return TRUE;
}
/*
* 函数名: void I2C_Test(void)
* 描述 : 测试函数
* 输入 : 无
* 输出 : 无
* 说明 : 无
*/
void I2C_Test(void)
{
u8 I2cVal_Write = 0xFE;
u8 I2cVal_Read = 0x00;
printf("Start IIC test\r\n");
printf("The Simulation_IIC has sended data:%d \r\n", I2cVal_Write);
I2C_WriteByte(I2cVal_Write, 0X01, 0xa0);
I2C_ReadByte(&I2cVal_Read, 1, 0x01 ,0xa0);
printf("The Simulation_IIC has Received data:%d \r\n", I2cVal_Read);
if(I2cVal_Read == I2cVal_Write)
{
printf("The Simulation IIC is successful!\r\n");
}
else
{
printf("The Simulation IIC is failed!\r\n");
}
}
上一篇:STM32模拟I2C程序
下一篇:STM32F407之模拟I2C(二)之24C128
推荐阅读最新更新时间:2024-03-16 16:03
- 热门资源推荐
- 热门放大器推荐