STM32F1使用I/0模拟I2C接口
2015-05-31 22:27
281 查看
使用模拟时序的方法,对比于硬件I2C接口来说,在实时性和传输速度上会带来一些无法避免的下降,但是I2C总线本身也不是一种速度很快的总线(据相关资料可查,最高的速度为400KHZ),同时也不需要具备很高的实时性能。
所以,模拟I2C时序完全能满足绝大部分的场合要求,并且移植性得到了很大的提高。
闲话不多说,贴上代码,大家一起分享下。
首先贴出 i2c_soft.h实现:
所以,模拟I2C时序完全能满足绝大部分的场合要求,并且移植性得到了很大的提高。
闲话不多说,贴上代码,大家一起分享下。
首先贴出 i2c_soft.h实现:
/*********************************************************************************** * 文件名 :i2c_soft.h * 描述 :使用I/0模拟I2C接口 * 实验平台:神舟III号 * 库版本 :ST3.0.0 * * 作者 :xiayufeng xiayufeng90520@163.com * 博客 :http://hi.baidu.com/xiayufeng520 **********************************************************************************/ #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"); } }测试好用,要是发现问题,可以发信联系,共同学习。
相关文章推荐
- c++学习笔记:变量
- SRS文档 王倩倩 201303014004
- NEUOJ1586 Cube Number
- DELL 12代 服务器 集成S110 RAID卡 装 2003 32bit系统
- android Alarm机制
- jQuery 标签淡入淡出 个人随笔
- Linux高级编程(一)
- vs2013+Xamarin F5提示部署不错误
- makefile 与 库的使用
- Linux高级编程(二)
- makefile 与 库的使用
- SSTable 介绍(二)
- Android-Activity配置改变
- tomcat简单的工作原理
- 单臂路由器+dhcp中继
- java之静态内部类
- 杭电ACM1395——2^x mod n = 1~~水题
- 序列变换
- set--常见成员函数及基本用法
- CSS盒模型简单用法