STM32模拟I2C程序

发布者:Tianran2021最新更新时间:2018-05-20 来源: eefocus关键字:STM32  模拟I2C 手机看文章 扫描二维码
随时随地手机看文章

/*******************************************************************************

  测试平台:STM32F103ZET6最小系统

*******************************************************************************/

static void i2cDelay()

{

    volatile int i = 7;

    while (i)

    i--;

}


// SCL高电平期间,SDA出现下降沿为起始信号

static bool i2cStart()

{

    SDA_OUT;

    SCL_H;

    SDA_H;

    i2cDelay();

    if (!sdaRead)  // 如果SDA为低电平,则总线忙,退出

        return false;

    SDA_L;

    if (sdaRead)  // 如果SDA为高电平,则总线忙,退出

        return false;

    SDA_L;

    return true;

}


// SCL高电平期间,SDA出现上升沿为停止信号

static void i2cStop(void)

{

    SDA_OUT;

    SCL_L; 

    SDA_L;

    i2cDelay();  // STOP:when CLK is high DATA from low to high 

    SCL_H;

    SDA_H;  

    i2cDelay();

}


static void i2cAck(void)

{

    SDA_OUT;

    SCL_L;

    i2cDelay();

    SDA_L;

    i2cDelay();

    SCL_H;

    i2cDelay();

    SCL_L;

}


static void i2cNoAck(void)

{

    SDA_OUT;

    SCL_L;

    i2cDelay();

    SDA_H;

    i2cDelay();

    SCL_H;

    i2cDelay();

    SCL_L;

}


// SCL高电平期间,SDA电平被从设备拉低表示应答

static bool i2cWaitAck(void)

{

    uint8_t errTimes = 0;


    SDA_IN;

    SDA_H;

    i2cDelay();

    SCL_H;

    i2cDelay();

    while (sdaRead) {

        if (errTimes++ > 20) {

            SCL_L;

            return false;

        }           

        i2cDelay();

    }

    SCL_L;

    return true;

}


// 发送数据,数据从高位到低位传输  

static void i2cSendByte(uint8_t byte)  

{

    uint8_t i = 8;


    SDA_OUT;

    while (i--) {      

        SCL_L;  // 时钟信号为低电平期间,允许数据线电平变化

        i2cDelay();

        if (byte & 0x80)

            SDA_H;

        else

            SDA_L; 

        byte <<= 1; 

        i2cDelay();

        SCL_H;

        i2cDelay();

    }

    SCL_L;

}


static uint8_t i2cReceiveByte()  

{

    uint8_t i = 8;

    uint8_t byte = 0;


    SDA_IN;

    SDA_H;

    while (i--) {

        byte <<= 1;

        SCL_H;

        i2cDelay();

        if (sdaRead) {

            byte |= 0x01;

        }

        SCL_L;

        i2cDelay();

    }

    SCL_L;

    return byte; 

}



void i2cInit()

{

    GPIO_InitTypeDef GPIO_InitStructure;


    /* Enable GPIOB clock */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);


    /* Configure GPIOB.6 & GPIOB.7 as open-drain output */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


/**

 * 通过I2C总线写一字节数据

 * @param[in] dev:设备I2C地址

 * @param[in] reg:寄存器地址

 * @param[in] data:要写入的数据

 */

bool i2cWriteOneByte(uint8_t dev, uint8_t reg, uint8_t data)

{

    if (!i2cStart())        

        return false;

    i2cSendByte(dev << 1);  // 从机地址由高7位+读写位构成   

    if (!i2cWaitAck()) {     

        i2cStop();

        return false;

    }

    i2cSendByte(reg);       

    i2cWaitAck();

    i2cSendByte(data);     

    i2cWaitAck();

    return true;

}


/**

 *  

 * @param[in] dev:设备I2C地址

 * @param[in] reg:寄存器地址

 * @param[in] len:字节数 

 * @param[in] data:待写入的数据 

 */

bool i2cWriteBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)

{

    uint8_t i;


    if (!i2cStart())        

        return false;

    i2cSendByte(dev << 1);          

    if (!i2cWaitAck()) {     

        i2cStop();

        return false;

    }

    i2cSendByte(dev);   

    i2cWaitAck();

    for (i = 0; i < len; i++) {

        i2cSendByte(data[i]);

        if (!i2cWaitAck()) {

            i2cStop();

            return false;

        }

    }

    i2cStop();

    return true;

}



/**

 * 从I2C设备中读取数据

 * @param[in] dev:设备I2C地址

 * @param[in] reg:寄存器地址

 * @param[in] len:数据字节数

 * @param[out] data:读出的数据

 */

bool i2cReadBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)

{

    if (!i2cStart())        

        return false;

    i2cSendByte(dev << 1);      

    if (!i2cWaitAck()) {     

        i2cStop();

        return false;

    }

    i2cSendByte(reg);     

    i2cWaitAck();

    i2cStart();           

    i2cSendByte((dev << 1) | 0x01);  // 器件地址+读命令    

    i2cWaitAck();

    while (len) {

        *data = i2cReceiveByte();

        if (len == 1)

            i2cNoAck();  // 最后一个字节不应答

        else

            i2cAck();

        data++;

        len--;

    }

    i2cStop();

    return true;

}


关键字:STM32  模拟I2C 引用地址:STM32模拟I2C程序

上一篇:STM32下模拟I2C的C语言实现
下一篇:STM32F1使用I/0模拟I2C接口

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

stm32—GPIO操作(库函数)
GPIO的8种方式 1、浮空输入GPIO_IN_FLOATING ——浮空输入,可以做KEY识别,RX1 2、带上拉输入GPIO_IPU——IO内部上拉电阻输入 3、带下拉输入GPIO_IPD—— IO内部下拉电阻输入 4、模拟输入GPIO_AIN ——应用ADC模拟输入,或者低功耗下省电 5、开漏输出GPIO_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能 6、推挽输出G
[单片机]
STM32库文件分析补充
1.没有加入stm32f10x_it.c 初始化文件找不到中断向量。 2.没有加入CM3文件夹的的头文件,编译器自动将类型定义链接到MDK的库中, C:\Program Files\MDK380a\ARM\INC\ST\STM32F10x\stm32f10x_type.h(23): error: #256: invalid redeclaration of type name s32 (declared at line 312 of C:\Program Files\MDK380a\ARM\INC\ST\STM32F10x\stm32f10x.h ) 这个error是因为在程序中用到了s32这个类型,但是程序中没有包含这个stm
[单片机]
Cortex-M3内核的异常中断
有许多朋友在学习,或者开发 STM32 时都遇到过HardFault_Handler的情况。 那么,又有多少人认真去分析过Fault这类异常中断呢? 下面结合STM32F1(Cortex‐M3内核)来给大家讲述一下这些异常中断的内容。 1Cortex‐M3异常 说起Fault,我们就要说一下Cortex‐M3的异常。 Cortex‐M3 在内核上搭载了一个异常响应系统, 支持为数众多的系统异常和外部中断。 CM3部分异常列表: 这些异常中断的优先级,有些却是固定的,有些是可以通过软件来配置,如UART发送中断、DMA中断等。 相信大家看到这个列表不会陌生,因为在STM32的启动代码,中断代码中都会看到这些异常。 比如在st
[单片机]
Cortex-M3内核的异常中断
stm32 启动文件的选择
最近在网上看到一些关于STM32启动文件的问题帖,都是类似这样的问题: 随便选两个 startup_stm32f10x_ld、hd、md这3个启动文件有什么不同??? 官网固件库中的启动文件有啥区别,怎么选择? 搜索了论坛,也看了一下,有一些回答,但是都不太全或者不甚明了。其实我以前也不清楚,当然我是新手,只不过是个爱折腾的新手,因为我觉得,这个有必要弄清楚。一是启动文件在一个工程中有着不可取代的作用,二是对于STM32这个让人蛋疼而又强大的东东,经常是新手乱添加启动文件或者去找一下工程例子 依葫芦画瓢 的添加,试问你的MCU和人家工程例子的就是一样,换一款型号,要命 ?所有说,基于这些,我就说一说我的认识: 注意此处只针
[单片机]
<font color='red'>stm32</font> 启动文件的选择
STM32之RCC
STM32 RCC复位与时钟配置,我首先忽略掉复位,首先学习时钟配置,复位以后用到再学习 STM32有多个时钟源,分别是 HSI:上电默认启动,因精度不高所以先不采用,以后如果需要再使用 HSE:外部高速时钟,系统时钟一般采用它,经过PLL倍频作为系统同时钟 LSE:外部低速时钟,一般专门用于RTC,等到RTC模块时再使用 LSI:内部低速时钟,精度不高,一般用于IWDGCLK 时钟系统框图如下: STM32中各个模块都有自己的时钟,当使用相应的模块时首先记得把此模块时钟开启 本次学习使用标准固件库3.3.0 好了,看明白上图咱就开始吧: void RCC_Configurati
[单片机]
<font color='red'>STM32</font>之RCC
关于PWM模式
首先,本人虽然初学STM32但极力反对一种误人子弟的观点:“对于STM32这样级别的MCU,有库函数就不用去看寄存器怎么操作的了!” 好了,言归正传,最近总看到很多朋友对于PWM这个实验有很多的疑惑,看到原子也在极力的回复也挺累的(体谅一下幸苦的原子大神,(*^__^*) ),所以我打算写这么一篇文字来阐述一下我个人对STM32的PWM的理解。 首先来说,你要使用PWM模式你得先选择用那个定时器来输出PWM吧!除了TIM6、TIM7这两个普通的定时器无法输出PWM外,其余的定时器都可以输出PWM,每个通用定时器可以输出4路PWM,高级定时器TIM1、TIM8每个可输出7路PWM,这里为了方便起见,我们选择与实验相同的TIM3的
[单片机]
stm32 SWD模式 下载
我们比较常用的是Jlink下载器 ,这种下载器有一个缺点就是使用的Jtag 20PIN接口,太多的PIN会导致一些小型的PCB板很拥挤,也会增加布线的难度。 而使用SWD接口下载调试,只需要要使用4个PIN: GND, RST, SWDIO, SWDCLK ,而且下载速度可以达到10M/s,优势显而易见。 我们所使用的Jtag 20PIN引脚图: 相关原理图: SWD 仿真模式概念简述 一、SWD 和传统的调试方式区别 SWD 模式比 JTAG 在高速模式下面更加可靠。 在大数据量的情况下面 JTAG 下载程序会失败, 但是 SWD 发生的几率会小很多。基本使用 JTAG 仿真模式的
[单片机]
<font color='red'>stm32</font> SWD模式 下载
stm32外设的使能,失能,复位的区别
首先明确的是,在STM32中所有外设正常工作的前提是使能了相应的外设,有的可能只用使能一个(如GPIO),有的使能两个(如GPIO和USART),有的可能需要使能三个(如GPIO,AFIO,TIM)。总而言之,只有使能了外设时钟外设才能工作。 所以外设使能实际使能的是外设的时钟,而与之相应的外设失能也是使外设时钟失能。外设失能后配置外设是没有作用的除非重新使能。 与以上两个不同的是外设复位,它是通过改变外设的复位寄存器来实现复位功能的,所以并不会去改变外设的时钟状态,再次使用这个外设不需要重新使能时钟,但是其他相关的一些配置还是必须的(如GPIO的输入输出状态会恢复默认值,需要重新配置)。
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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