STM32F1使用I/0模拟I2C接口

发布者:喜从中来最新更新时间:2018-05-20 来源: eefocus关键字:STM32F1  I  模拟I2C接口 手机看文章 扫描二维码
随时随地手机看文章

使用模拟时序的方法,对比于硬件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");  

    }  

       


关键字:STM32F1  I  模拟I2C接口 引用地址:STM32F1使用I/0模拟I2C接口

上一篇:STM32模拟I2C程序
下一篇:STM32F407之模拟I2C(二)之24C128

推荐阅读最新更新时间:2024-03-16 16:03

s3c2440裸机-I2c编程-3.i2c中断服务程序
Start信号之后,发出设备地址,在第9个时钟就会产生一个中断,我们根据i2c的流程图来编写中断程序。 每传输完一个数据将产生一个中断,I2C操作的主体在中断服务程序,它可以分为两部分:写操作,读操作。 完整code如下: static p_i2c_msg p_cur_msg; int isLastData(void) { if (p_cur_msg- cnt_transferred == p_cur_msg- len - 1) return 1; /* 正要开始传输最后一个数据 */ else return 0; } void resume_iic_with_
[单片机]
MSP430F5529 I2C 程序
MSP430板子到了好久,一直没有时间来写程序,前两天终于有空了,把I2C调试了下,参照TI给的例程,把发送和接收整合到一起。期间中断屏蔽处理的不好,经常进不了中断。网上也没有可参照的例程。只有仔细读了MSP430F55xx的用户手册,才调通。用户手册才是王道呀! #include msp430.h #include i2c.h extern unsigned char RXData,TXData,TXByteCtr,ATXData ; void I2C_Init(uint8_t SlaveAddress) { P3SEL |= 0x03; // Assign I2C pins to USCI_B0 UCB0CTL1 |=
[单片机]
s3c2440之IIS(4)S3C2440的I2S控制器
一、I2S控制器结构框图 S3C2440A的Inter-IC Sound (IIS)总线接口作为一个编解码接口连接外部8/16位立体声音频解码IC用于迷你碟机和可携式应用。IIS总线接口支持IIS总线数据格式和MSB-justified数据格式。该接口对FIFO的访问采用了DMA模式取代了中断。它可以在同一时间接收和发送数据。 图1 结构框图 1 、总线接口,寄存器组和状态机(BRFC):总线接口逻辑和FIFO 访问由状态机控制。 2、5 位双预定标器(IPSR):一个预定标器用于IIS 总线接口的主时钟发生器,另外一个用作外部编解码时钟发生器。 3、64 位FI
[单片机]
s3c2440之IIS(4)S3C2440的<font color='red'>I</font>2S控制器
STM32之I2C例程(24C02)
#include stm32f10x.h #include #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_DELAY (I2C_de
[单片机]
恩智浦推出新一代安全高能效i.MX 91系列,为广泛的边缘应用扩展Linux功能
i.MX 9 系列的新成员简化了高性价比边缘设备的开发过程,助力构建需要安全性、高性能表现以及Linux支持的可扩展、高可靠性的平台 中国上海——2023年6月1日—— 恩智浦半导体(NXP Semiconductors N.V.,)正式发布i.MX 91应用处理器系列。 凭借恩智浦二十多年来在开发多市场应用处理器方面的领先优势,i.MX 91系列提供了安全、多功能、高能效的优化组合,可满足下一代基于Linux®的物联网和工业应用的需求。 产品重要性 新发布的协议改变了物联网和工业市场新产品类别的方向,如面向未来智能家居的可互操作安全连接标准Matter,或面向电动汽车充电器的ISO 15118-20标准。此类新产品通
[嵌入式]
STM32学习之路:I2C的基本读写
宏定义: /*I2C传输速度,最高为400kHz*/ #define I2C_SPEED 400000 /* STM32 自身的 I2C 地址, 这个地址只要与 STM32 外挂的 I2C 器件地址不一样即可 */ #define I2C_OWN_ADDR 0x77 /*EEPROM地址*/ #define EEPROM_ADDR (0x50 1) //0xA0 #define EEPROM_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define EEPROM_SCL_PIN GPIO_Pin_6 #define EEPROM_SCL_GPIO_PORT GPIOB #de
[单片机]
STM32从入门到精通—I2C 简介
I2C端口,即内部集成电路接口,I2C总线接口用作微控制器和I2C串行总线之间的接口,提供多主模式功能,可以控制所有I2C总线特定的序列、协议、仲裁和时序。它支持标准和快速模式。 I2C可用于多种用途,包括CRC生成和验证、SMBus(系统管理总线)以及PMBus(电源管理总线)。 I2C主要特性 并行总线/I2C协议转换器 多主模式功能:同一接口既可用作主模式也可用作从模式 I2C主模式特性: 1. 时钟生成 2. 起始位和停止位生成 I2C从模式特性: 1. 可编程I2C地址检测 2. 双寻址模式,可对2个从地址应答 3. 停止位检测 7位/10位寻址以及广播呼叫的生成和检测 支持不同的通信速度: 1
[单片机]
国国家仪器公司首次发布配备多核英特尔®酷睿™i7处理器的NI CompactRIO以及最小的单板式RIO设备
    美国国家仪器 有限公司(National Instruments,简称NI)宣布扩大其日益增长的NI可重新配置的I / O(RIO)平台,发布拥有其最高性能的首款多核NI CompactRIO系统以及最小的NI单卡式RIO设备。最新发布的NI cRIO – 908X系统配备英特尔®酷睿™i7双核处理器,增强了数据处理能力,Xilinx Spartan - 6现场可编程门阵列(FPGA)和可选Windows Embedded Standard 7(WES7)操作系统配置,可用于需要兼顾优异性能以及CompactRIO的坚固可靠性的监测和控制应用。在高容量和OEM应用方面,新发布的NI sbRIO-9605/06最小尺寸为102
[工业控制]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved