STM32——硬件IIC主机通信

发布者:CaptivatingEyes最新更新时间:2019-02-12 来源: eefocus关键字:STM32  硬件IIC  主机通信 手机看文章 扫描二维码
随时随地手机看文章

前言:

  根据网上的资料,大部分网友表示STM32自带的硬件IIC存在bug,读写时很容易卡死。自己在调试的时候也出现卡死的情况,最后一点一点调试,也还是调通了。本文将记录自己调试STM32硬件IIC主机的一些心得体会。硬件IIC从机通信见另一篇文章:传送门 。


硬件平台:STM32F205


软件平台:keil v5


函数库:标准库


硬件IIC主机初始化

IIC的发送时序本文不不做介绍了,网上资料比较多。 

下面看下STM32中IIC的相应设置。 

首先是IIC的管脚配置。


void I2C1_GPIO_Configuration(void)

{

  GPIO_InitTypeDef  GPIO_InitStructure;


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//必须设置为开漏输出,实现iic的线与逻辑

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_PuPd =   GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1); 

    GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);

}


  注意上述管脚配置中GPIO_InitStructure.GPIO_PuPd必须配置为GPIO_PuPd_NOPULL,若配置为 GPIO_PuPd_UP或GPIO_PuPd_DOWN,IIC总线会一直繁忙,导致总线出错,检测不到IIC从机。


IIC工作参数配置

void I2C1_Configuration(void)

{

    I2C_InitTypeDef I2C_InitStructure;


    I2C_DeInit(I2C1);

    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

    I2C_InitStructure.I2C_OwnAddress1 = 0XA0;//主机的地址        

    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

    I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;

    I2C_InitStructure.I2C_ClockSpeed = 100000;//100KHZ

    I2C_Init(I2C1, &I2C_InitStructure);

    I2C_Cmd(I2C1, ENABLE);                                             

}


IIC初始化函数

void I2C1_Init(void)

{

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);   

    I2C1_GPIO_Configuration();

    I2C1_Configuration();

}


IIC主机写入数据

IIC主机读写函数是IIC通信的重点,下面先来看下IIC主机写入数据的序列图。 

 这里写图片描述 

主机发送数据的流程: 

1) 主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始 

2) 主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0) 

3) 相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0) 

4) 主机收到从机的应答信号后开始发送第一个字节的数据 

5) 从机收到数据后返回一个应答信号 ACK 

6) 主机收到应答信号后再发送下一个数据字节 

7) 当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信。 

主机发送数据的程序


uint8_t I2C_Master_BufferWrite(I2C_TypeDef * I2Cx, uint8_t* pBuffer, uint32_t NumByteToWrite, uint8_t SlaveAddress)

{

    if(NumByteToWrite==0)

        return 1;

    /* 1.开始*/

    I2C_GenerateSTART(I2Cx, ENABLE);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));


    /* 2.设备地址·/写 */

    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Transmitter);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));


    /* 3.连续写数据 */

    while(NumByteToWrite--)

    {

      I2C_SendData(I2Cx, *pBuffer);

      while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

      pBuffer++;

    }


    /* 4.停止 */

    I2C_GenerateSTOP(I2Cx, ENABLE);

    while ((I2Cx->CR1&0x200) == 0x200);

    return 0;

}


IIC主机读取数据

下面再来看下IIC主机读取数据的序列图。

这里写图片描述

IIC主机读取数据的具体流程: 

1) 主机发送启动信号后,接着发送命令字节(其中 R/W=1) 

2) 对应的从机收到地址字节后,返回一个应答信号并向主机发送数据 

3) 主机收到数据后向从机反馈一个应答信号 

4) 从机收到应答信号后再向主机发送下一个数据 

5) 当主机完成接收数据后,向从机发送一个“非应答信号(ACK=1)”,从机收到ACK=1 的非应答信号后便停止发送 

6) 主机发送非应答信号后,再发送一个停止信号,释放总线结束通信.


uint8_t I2C_Master_BufferRead(I2C_TypeDef * I2Cx, uint8_t* pBuffer, uint32_t NumByteToRead, uint8_t SlaveAddress)

{

    if(NumByteToRead==0)

        return 1;


    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));  

    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    /* 1.开始*/

    I2C_GenerateSTART(I2Cx, ENABLE);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    /* 2.设备地址·/写 */

    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Transmitter);

    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));


    /* 3.开始*/

    I2C_GenerateSTART(I2Cx, ENABLE);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    /* 4.设备地址·/读 */

    I2C_Send7bitAddress(I2Cx, SlaveAddress, I2C_Direction_Receiver);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));


    /* 5.连续写数据 */

    while (NumByteToRead)

    {

        if(NumByteToRead==1)

        {

            I2C_AcknowledgeConfig(I2Cx, DISABLE);

            I2C_GenerateSTOP(I2Cx, ENABLE);//6.停止,非应答

        }


        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));  /* EV7 */

        *pBuffer++ = I2C_ReceiveData(I2Cx);

        NumByteToRead--;

    }


    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return 0;

}   

关键字:STM32  硬件IIC  主机通信 引用地址:STM32——硬件IIC主机通信

上一篇:STM32——硬件IIC从机通信
下一篇:STM32——多通道ADC的DMA方式采集方法

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

基于STM32的税控器方案
随着金税工程的推广,税控市场将得到迅猛发展,税控器作为四大税控产品之一,其市场份额不容小觑,税控厂家需要为产品的性能、成本做多方面考量。之前各个厂家的税控器方案,可能因为成本的考虑选择了8位 单片机 ,也有因为性能扩展的需要选择16位、32位MCU作为税控器主控芯片。今天, ST (意法半导体公司)延续了其之前基于STR7的税控器体系架构,并借鉴在STR9银税一体机方案中的经验,推出了一款采用STM32这一高性能、低成本芯片的税控器方案。 方案介绍 与以往方案(图1)对比,STM32方案(图2)结构简单,模块功能化,减少了外部数据总线的数量,有效减小制板面积,很好地保证了系统的可靠性及安全性。ST还提供详细的设计报告,无论是
[单片机]
基于<font color='red'>STM32</font>的税控器方案
STM32之模拟I2C读取加速度传感器
前言:由于之前学会了SPI,软硬件SPI都会了,发现只要读懂时序图,其他都是小菜一碟,I2C也是如此,不过本少爷还是花了1天时间去理解了I2C的一些知识,发现模拟比硬件更能理解其中的工作原理,虽然速度慢点。 废话:时间有限,暂时写一点核心内容,该内容本人从MMA8451Q加速度传感器的手册上读的。坑爹的新浪居然不支持我上传图片,很无奈 正文: ------------------------------------------------模拟I2C---------------------------------------------------- 1.start 2.写入7位device地址+1位写W 3.等待从设备握
[单片机]
再造STM32---第十一部分:GPIO—位带操作
本章参考资料:《STM32F4xx 中文参考手册》存储器和总线构架章节、 GPIO 章节,《Cortex®-M4 内核编程手册》 2.2.5 Bit-banding。学习本章时,配套这些参考资料学习效果会更佳。 11.1 位带简介: 位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。 51 单片机中通过关键字 sbit 来实现位定义, F429 中没有这样的关键字,而是通过访问位带别名区来实现。 在 F429 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,另一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的
[单片机]
再造STM32---第十一部分:GPIO—位带操作
STM32学习笔记整理之(2)——外部中断
学习STM32也快一年了,现在工作的内容跟用的是STM32平台的,趁着年前工作量比较小,总结一下STM32的基础知识,不出意外的话将会连续发布完整的笔记整理,学习的时候主要是跟着野火教程学的,然后在整理出适合自己的笔记。 2.1 NVIC配置 1、中断分组 在配置优先级的时候,NVIC 只可以配置 16 种中断向量的优先级,抢占优先级和响应优先级的数量由一个 4 位的数字来决定,把这个 4 位数字的位数分配成抢占优先级部分和响应优先级部分。 有 5 组分配方式: 第0组:所有4位用来配置响应优先级。 第1组:最高1位配抢占优先级,低3位配响应优先级。2^1=2 种抢占优先级(0,1),2^3=8 种响应优先级, 第2组:2位
[单片机]
STM32学习笔记-STM32堆栈区(一)
一个由C/C++编译的程序占用的内存分为以下几个部分: 栈区(stack):编译器自动分配释放,存放函数的参数值,局部变量的值等。操作方式类似于数据结构中的栈。 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。 文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放 程序代码区—存放函数体的二进制代码 编译后,各个区存储内容举例说明如下:
[单片机]
STM32再学习――启动流程分析
  我们写嵌入式程序,基本上采用C语言来编写,以main( )作为程序的入口。但实际上,mian()并不是最先要执行的,在这之前需要做一些基本的工作,如堆、栈的定义;main函数的复位连接等,这些工作就需要一个专门的启动程序来完成,由于需要做的工作内容不多,并且需要更直接的管理内存,一般采用汇编编写。   无论是STM32、ARM系列的单片机,还是简单的如51,PIC等,都以为上述原因,需要启动程序,只不过51,PIC等单片机的启动程序已经在相应的IDE编译、链接的时候隐含的编译了,故在写单片机程序的时候无需考虑。而STM32的启动有相应的启动文件,本文将采用KEIL MDK自带的启动文件STM32F10x.s进行分析。
[单片机]
STM32中,关于中断函数调用全局变量的问题
首先是问题的描述:硬件单片机型号,STM32F103VET6,IDE:keil 5。想通过它实现的一个功能是,通过两个按键控制一个RGB灯的闪烁开始和停止。两个按键通过外部中断上升沿检测,贴一下最开始的代码。 void KEY1_IRQHandler(void) { //确保是否产生了EXTI Line中断 if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) { run_flag=0x01; EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); } } void KEY2_IRQHandler
[单片机]
基于STM32物联网开发板(4)--LCD屏
1.概述 屏幕尺寸为1.3寸,分辨率240*240,颜色格式RGB565,驱动IC:ST7789VW; 超大可视角度:大于160°(显示屏中可视角度最大的一种屏幕); 宽电压供电(3V~5V),兼容3.3V和5V电平逻辑,无需电平转换芯片; 采用7线制SPI接口; 工作温度范围为工业级(-20℃~60℃); 军工级工艺标准,长期稳定工作; 硬件接口: 引脚 说明 LEDK PB0背光 CS PA4片选 SCL PA5时钟 SDA PA7主机输出 RES PB1复位脚(电平复位) D/C PC4数据命令选择脚 2.通讯协议 ST7789VW是一款用于262K彩色图形型TFT-LCD的单片
[单片机]
基于<font color='red'>STM32</font>物联网开发板(4)--LCD屏
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

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

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

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