STM32(五)IIC通信原理及IO口软件模拟编程

发布者:量子启示最新更新时间:2019-08-09 来源: eefocus关键字:STM32  IIC通信  IO口  软件模拟 手机看文章 扫描二维码
随时随地手机看文章

一、IIC概述

        I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。

       它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。

       IIC是半双工通信方式。

       多主机I2C总线系统结构:

二、I2C协议

1、空闲状态

        I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。


2、开始信号

        当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。


3、停止信号

        当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。

4、应答信号

        发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 


        对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

5、数据的有效性

        I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 


即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。


6、数据传输

        在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

        ALIENTEK MiniSTM32 开发板板载的 EEPROM 芯片型号为 24C02。该芯片的总容量是 256个字节,该芯片通过 IIC 总线与外部连接。

       目前大部分 MCU 都带有 IIC 总线接口,STM32 也不例外。但是这里我们不使用 STM32的硬件 IIC 来读写 24C02,而是通过软件模拟。STM32 的硬件 IIC 非常复杂,更重要的是不稳定,故不推荐使用。


     本章实验功能简介:开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(WK_UP)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。


   

    24C02 的 SCL 和 SDA 分别连在 STM32 的 PC12 和 PC11 上。


三、代码驱动

//打开 myiic.c 文件,代码如下:

#include "myiic.h"

#include "delay.h"

//初始化IIC

void IIC_Init(void)

{      

GPIO_InitTypeDef GPIO_InitStructure;

//RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟 

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );

   

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC, &GPIO_InitStructure);

 

IIC_SCL=1;

IIC_SDA=1;

 

}

//产生IIC起始信号

void IIC_Start(void)

{

SDA_OUT();     //sda线输出

IIC_SDA=1;     

IIC_SCL=1;

delay_us(4);

  IIC_SDA=0;//START:when CLK is high,DATA change form high to low 

delay_us(4);

IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 

}   

//产生IIC停止信号

void IIC_Stop(void)

{

SDA_OUT();//sda线输出

IIC_SCL=0;

IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

  delay_us(4);

IIC_SCL=1; 

IIC_SDA=1;//发送I2C总线结束信号

delay_us(4);    

}

//等待应答信号到来

//返回值:1,接收应答失败

//        0,接收应答成功

u8 IIC_Wait_Ack(void)

{

u8 ucErrTime=0;

SDA_IN();      //SDA设置为输入  

IIC_SDA=1;delay_us(1);    

IIC_SCL=1;delay_us(1);  

while(READ_SDA)

{

ucErrTime++;

if(ucErrTime>250)

{

IIC_Stop();

return 1;

}

}

IIC_SCL=0;//时钟输出0    

return 0;  

//产生ACK应答

void IIC_Ack(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=0;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}

//不产生ACK应答     

void IIC_NAck(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=1;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}      

//IIC发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答   

void IIC_Send_Byte(u8 txd)

{                        

    u8 t;   

SDA_OUT();     

    IIC_SCL=0;//拉低时钟开始数据传输

    for(t=0;t<8;t++)

    {              

        IIC_SDA=(txd&0x80)>>7;

        txd<<=1;   

delay_us(2);   //对TEA5767这三个延时都是必须的

IIC_SCL=1;

delay_us(2); 

IIC_SCL=0;

delay_us(2);

    }  

}     

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   

u8 IIC_Read_Byte(unsigned char ack)

{

unsigned char i,receive=0;

SDA_IN();//SDA设置为输入

    for(i=0;i<8;i++ )

{

        IIC_SCL=0; 

        delay_us(2);

IIC_SCL=1;

        receive<<=1;

        if(READ_SDA)receive++;   

delay_us(1); 

    }  

    if (!ack)

        IIC_NAck();//发送nACK

    else

        IIC_Ack(); //发送ACK   

    return receive;

}

//打开 myiic.h 文件,代码如下:

//该部分为 IIC 驱动代码:

//实现包括 IIC 的初始化(IO 口)、IIC 开始、IIC 结束、ACK、IIC读写等功能

//在其他函数里面,只需要调用相关的 IIC 函数就可以和外部 IIC 器件通信了

//头文件 myiic.h 的代码,里面有两行代码为直接通过寄存器操作设置 IO 口的模式为输入还是输出

//代码如下:

#define SDA_IN() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}

#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}

//完整代码如下:

#ifndef __MYIIC_H

#define __MYIIC_H

#include "sys.h"

           

//IO方向设置

#define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}

#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}

 

//IO操作函数  

#define IIC_SCL    PCout(12) //SCL

#define IIC_SDA    PCout(11) //SDA  

#define READ_SDA   PCin(11)  //输入SDA 

 

//IIC所有操作函数

void IIC_Init(void);                //初始化IIC的IO口  

void IIC_Start(void); //发送IIC开始信号

void IIC_Stop(void);   //发送IIC停止信号

void IIC_Send_Byte(u8 txd); //IIC发送一个字节

u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节

u8 IIC_Wait_Ack(void); //IIC等待ACK信号

void IIC_Ack(void); //IIC发送ACK信号

void IIC_NAck(void); //IIC不发送ACK信号

 

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);

u8 IIC_Read_One_Byte(u8 daddr,u8 addr);   

#endif


关键字:STM32  IIC通信  IO口  软件模拟 引用地址:STM32(五)IIC通信原理及IO口软件模拟编程

上一篇:STM32模拟I2C时序读写EEPROM精简版
下一篇:stm32 mpu6050 模拟i2c实例实现

推荐阅读最新更新时间:2024-11-18 17:48

有关stm32的串口发送与接收的逻辑问题
在弄毕业设计时遇到一个问题,而且这个问题困扰了我很久,究其原因是我没有一个清晰的逻辑。 首先我想实现的功能是循环向串口2发送一个命令数组,并且每发送完这个命令后,串口2接收一串数据,这个数据是由串口2连接的模块发送的。用串口2接收到后用串口1通过串口小助手打印出来。 我的问题就来了,我居然认为串口2发送出去的命令数组居然会中断串口2的接收中断!更可怕的是,我居然在串口2的接收中断中把接受到的数据用串口1打印出来。然后我就发现怎么中断不了也打印不出!我一直以为是我的发送数组函数写得有问题,或者是中断函数写错了,结果调试了很久,代码改了又改,又重新复习一遍串口知识,还是觉得自己写的串口函数都没问题。太苦恼了。 但终于我在这
[单片机]
首款Cortex-M7微控制器问世,STM32 F7将怎样惊艳市场?
意法半导体(ST)推出了首款采用ARM Cortex-M7内核的最新微控制器家族STM32 F7系列。 ST大中华与南亚区微控制器市场及应用总监 James Wiart在采访中表示,从2007年ST首先发布基于ARM Corte-M内核的STM32系列微控制器,到2010年ST首先发布全球最高性能的STM32微控制器,再到2014年STM32 F7最新系列的问世,基于ARM Cortex内核的STM32系列产品已经成为面向物联网、可穿戴设备等高性能、高复杂性应用领域的最佳选择。 ST大中华区与南亚区微控制器市场及应用总监James Wiart STM32 F7:惊艳性能的始 ST微控制器市场总监Daniel Colo
[单片机]
STM32中断设置以及中断优先级设置
最近,在做一个智能锁的项目,由于,今天碰到了一个关于中断的问题,因此,又回来好好啃一下中断配置的知识,俗话说:磨刀不误砍柴工。问题是什么呢?项目中我用到了一个触摸键盘TTP229,结果在测试键盘时,不能够输入密码?最终,调试出bug就是由于中断优先级的影响。 本项目使用到的是STM32F030C8型号的MCU,我们可以从官方下载到的标准库文件中的启动汇编文件中,查看到本型号单片机的外部中断向量表。(如下图所示) 首先,我们了解一下NVIC是什么,在core_cm0.h文件中的标准库中的NVIC结构体。 其中,我们一般只用到ISER、ICER、IP这3个寄存器。ISER用于使能中断,ICER用来清除中断,IP
[单片机]
<font color='red'>STM32</font>中断设置以及中断优先级设置
stm32在rt-thread上的PWR(电源管理)
Low-power modes有三种Sleep mode、Stop mode、Standby mode,实现如下: void SYSCLKConfig_START(void) { ErrorStatus HSEStartUpStatus; /* 使能 HSE */ RCC_HSEConfig(RCC_HSE_ON); /* 等待 HSE 准备就绪 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* 使能 PLL */ RCC_PLLCmd(ENABL
[单片机]
STM32开发笔记74: STM32L0低功耗唤醒后的时钟选择
本文介绍STM32L0系列单片机低功耗唤醒后的时钟选择。 参看已有的低功耗例程,发现都使能了HSI时钟,一致没有深究其中的具体原因,今天把它搞明白了,现记录如下: 先看一下,使能低功耗的函数: void CTarget::EnableLowPower(void) { HAL_PWREx_EnableUltraLowPower(); HAL_PWREx_EnableFastWakeUp(); __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); DisableAllIO(); } 第1句使能超低功耗,第2句使能快速唤醒,第3句选择唤醒后的主始终,第4
[单片机]
STM32之父谈2019产品蓝图:性价比、AI、开发体验
日前,在2019年STM32峰会上,STM32之父,意法半导体微控制器事业部全球市场总监Daniel Colonna介绍了STM32产品规划及生态战略。 Daniel几十年来的工作一直围绕着微控制器。自2006年起任意法半导体微控制器事业部全球市场总监 。他于1982年加入德州仪器,担任微控制器应用工程师;1986年加入Thomson-Mostek,负责8位微控制器业务;三年后,加入意法半导体法国公司,担任8位微控制器产品市场经理,并于90年代后期致力于启用ARM32位架构。 2002年,意法半导体推出首个基于ARM7的产品系列STR7,Daniel对此作出了重要贡献。后来,他带领团队启用新的Cortex-M架构,为意法半导体
[单片机]
<font color='red'>STM32</font>之父谈2019产品蓝图:性价比、AI、开发体验
两个IGBT为什么会出现同时导通的情况呢?
什么是死区时间? 数据手册的参数 如何计算合理的死区时间? STM32中配置死区时间 什么是死区时间? PWM是脉冲宽度调制,在电力电子中,最常用的就是整流和逆变。这就需要用到整流桥和逆变桥。 对三相电来说,就需要三个桥臂。以两电平为例,每个桥臂上有两个电力电子器件,比如IGBT。大致如下图所示; 这两个IGBT不能同时导通,否则就会出现短路的情况,从而对系统造成损害。 那为什么会出现同时导通的情况呢? 因为开关元器件的和严格意义并不是相同的。 所以在驱动开关元器件门极的时候需要增加一段延时,确保另一个开关管完全关断之后再去打开这个开关元器件,通常存在两种情况; 上半桥关断后,延迟一段时间再打开下半桥; 下半桥关断后,延迟一段
[单片机]
两个IGBT为什么会出现同时导通的情况呢?
STM32中断使用笔记
1.GPIO 的正确设置 GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOD clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); /* Configure PD.03, PC.04, as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPI
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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