网易首页 > 网易号 > 正文 申请入驻

Stm32之I2C通信的使用情况,陈老师讲解【菜鸟收藏】

0
分享至

Stm32之I2C通信的使用(基于PCF8591)

I2C协议简介

I2C (Inter-Integrated Circuit),是一种串行通信总线,用于连接微控制器及其外围设备,达到主控制器和从器件间的主从双向通信,是一种同步半双工通信(两端时钟频次一致,双向通信,但不能同时进行数据收发)。

///插播一条:我自己在今年年初录制了一套还比较系统的入门单片机教程和毕业设计指导,想要的同学找我拿就行了免費的,私信我就可以哦~点我头像白色字体加我也能领取哦,记得口令陈老师///

I2C通信属于串行通信,具有两根串行信号线:数据线(SDA),时钟线(SCL)。如下图所示,主控制器与从器件(一个或多个)都通过两根信号线连接,信号线上主机和从机都能够扮演发送器和接管器的角色。为确保传输过程的指向精确性,每个接到I2C总线上的器件都有唯一的地址(7位从器件专用地址码),可达到制定从机的定向传输与群发传输。

物理层

IIC物理层

其具有以下特性:

一个 I2C 总线只运用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线即拿来表示数据,时钟线用于数据收发同步。

每个连接到总线的设备都有一个独立的地址,主机能够利用这个地址进行不同设备之间的访问。

它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。

总线通过上拉电阻接到电源,当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平,能够参见GPIO的开漏输出模式。

协议层

IIC协议层

如图为I2C通信的流程,能够总结如下(概要,详细细节还得看手册):

主机(MCU)的I2C接口发出一个起始信号(S),告诉从机(SLAVE,奴隶,很形象哈哈)我要初始传输数据啦

此时所有从机都会收到这个信号,但是,到底是哪个从机要进行数据的读写呢?,这个时候主机就会广告从机地址(SLAVE ADDRESS,注意每个从机都有唯一的地址),告诉指定的从机要和你进行通信,以及是读数据还是写数据(1为读,0为写)

被选定的从机此时要给出一个应答信号,告诉主机到底要不要进行通信

0000四.假如从机容许的话就能够进行通信了,假如要停下,主时机发送一个停下信号(P),告诉从机到此完毕

STM32的I2C架构

架构就没什么好说的了,图里一看就明白。

基于PCF8591的I2C通讯程序分析

PCF8591是一款由Philips公司开发的8-bit A/D and D/A converter,采用I2C协议通信,虽然STM32内置有ADC,但是为了练习I2C的通讯方式,还是采用这款芯片。

我们查阅其datesheet,怎么去查阅呢,抓重要关键字,address byte,确定其地址,手册上是这样写的:

The address always has to be sent as the first byte after the start condition in the I2C-bus protocol. The last bit of the address byte is the read/write-bit which sets the direction of the following data transfer

从芯片原理图得知A0,A1,A2接地,1001000X,那么其地址就是0x90或者是0x91,看是读还是写来决定,接下来看Control byte,手册上是这样写的:

The second byte sent to a PCF8591 device will be stored in its control register and is required to control the device function.

假设我需要从通道0单端输出A/D转换数据,那么control byte就是01000000 = 0x40,万事大吉 ,开写通信协议:

首先看i2c.h:

#include"stm32f10x.h"#include"delay.h"//应答信号externu8ack;

//初始化函数externvoidI2c_Init(void);

//起动总线函数externvoidStart_I2c(void);

//结束总线函数 externvoidStop_I2c(void);

//应答子函数externvoidAck_I2c(u8a);

//字节数据发送函数externvoidSendByte(unsignedcharc);

//有子地址发送多字节数据函数externu8ISendStr(unsignedcharsla,unsignedcharsuba,unsignedchar*s,unsignedcharno);

//无子地址发送多字节数据函数externu8ISendStrExt(unsignedcharsla,unsignedchar*s,unsignedcharno);

//无子地址读字节数据函数externunsignedcharRcvByte(void);

//有子地址读取多字节数据函数externu8IRcvStr(unsignedcharsla,unsignedcharsuba,unsignedchar*s,unsignedcharno);

//无子地址读取多字节数据函数externu8IRcvStrExt(unsignedcharsla,unsignedchar*s,unsignedcharno);

然后看i2c.c,实际上的i2c协议很复杂,下面使用操作GPIO的方式来模拟I2C通信(不使用库函数操作),不是想要了解其中的原理可直接复制网络上现成的资源,每个芯片的i2C通信方式也略有差别,具体如何实现还是要看datesheet怎么写的。

/*************************此部分为I2C总线的驱动程序*************************************/

#include"i2c.h" //变量定义和函数声明全在此文件中/************************************硬件接口******************************/#define i2c_port GPIOB#define SData GPIO_Pin_7 //PB7; //I2C 时钟 #define SCLK GPIO_Pin_6 //PB6; //I2C 数据 /********************************宏定义*******************************************/#define SCL(x) x ? GPIO_SetBits(GPIOB , SCLK) : GPIO_ResetBits(GPIOB , SCLK)#define SDA(x) x ? GPIO_SetBits(GPIOB , SData) : GPIO_ResetBits(GPIOB , SData)/********************************变量*******************************************/u8ack;

/******************************************************************* 初始化函数 函数原型: void I2c_Init(); 功能: 初始化引脚 ********************************************************************/

voidI2c_Init(void){

GPIO_InitTypeDefGPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);

GPIO_InitStructure.GPIO_Pin=SData|SCLK;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//设置为开漏输出,实现线与功能GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(i2c_port,&GPIO_InitStructure);}

/******************************************************************* 起动总线函数 函数原型: void Start_I2c(); 功能: 启动I2C总线,即发送I2C起始条件. ********************************************************************/voidStart_I2c(){

SDA(1);//SDA=1; 发送起始条件(S)的数据信号delay_us(1);

SCL(1);//SCL=1;delay_us(5);//起始条件建立时间大于4.7us,延时,关于建立时间与保持时间,这些是数字电路中的重要概 念,不再解释。SDA(0);//SDA=0; /*发送起始信号*/delay_us(5);// 起始条件锁定时间大于4μsSCL(0);//SCL=0; /*钳住I2C总线,准备发送或接收数据 */delay_us(2);}

/******************************************************************* 结束总线函数 函数原型: void Stop_I2c(); 功能: 结束I2C总线,即发送I2C结束条件. ********************************************************************/voidStop_I2c(){

SDA(0);//SDA=0;发送结束条件的数据信号delay_us(1);//发送结束条件的时钟信号SCL(1);//SCL=1;结束条件建立时间大于4μsdelay_us(5);

SDA(0);//SDA=1;发送I2C总线结束信号delay_us(4);}

/******************************************************************* 字节数据发送函数 函数原型: void SendByte(UCHAR c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。********************************************************************/voidSendByte(unsignedcharc){

unsignedcharBitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++)//要传送的数据长度为8位{

if((c<<BitCnt)&0x80)SDA(1);//SDA=1; 判断发送位elseSDA(0);// SDA=0 delay_us(1);

SCL(1);//SCL=1 置时钟线为高,通知被控器开始接收数据位delay_us(5);//保证时钟高电平周期大于4μsSCL(0);//SCL = 0}

delay_us(2);

SDA(1);//SDA=1 位发送完后释放数据线,准备接收应答位delay_us(2);

SCL(1);//SCL=1delay_us(3);

if(GPIO_ReadInputDataBit(GPIOB,SData)==1)ack=0;

elseack=1;//判断是否接收到应答信号SCL(0);//SCL=0;delay_us(3);}

/******************************************************************* 字节数据接收函数 函数原型: UCHAR RcvByte();功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号), 发完后请用应答函数应答从机。 ********************************************************************/unsignedcharRcvByte(){

unsignedcharretc;

unsignedcharBitCnt;

retc=0;

SDA(1);//SDA=1 置数据线为输入方式for(BitCnt=0;BitCnt<8;BitCnt++)

delay_us(1);

SCL(0);//SCL=0 置时钟线为低,准备接收数据位delay_us(5);//时钟低电平周期大于4.7μsSCL(1);//SCL=1 置时钟线为高使数据线上数据有效delay_us(2);

retc=retc<<1;

if(GPIO_ReadInputDataBit(GPIOB,SData)==1)retc=retc+1;// SDA == 1读数据位,接收的数据位放入retc中 delay_us(2);

SCL(0);// SCL=0;delay_us(2);

return(retc);}

/******************************************************************** 应答子函数函数原型: void Ack_I2c(bit a);功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)********************************************************************/voidAck_I2c(u8a){

if(a==0)

SDA(0);//SDA=0;在此发出应答或非应答信号 else

SDA(1);//SDA=1;delay_us(3);

SCL(1);//SCL=1; delay_us(4);//时钟低电平周期大于4μsSCL(0);//SCL=0; 清时钟线,钳住I2C总线以便继续接收delay_us(2);}

pcf8591.h:

#ifndef __pcf8591_H__#define __pcf8591_H__#include"sys.h"#include"i2c.h"u8DACconversion(unsignedcharsla,unsignedcharc,unsignedcharVal);u8ISendByte(unsignedcharsla,unsignedcharc);u8IRcvByte(unsignedcharsla);

#endif

pcf8591.c:

#include"pcf8591.h"/*******************************************************************DAC 变换, 转化函数 *******************************************************************/u8DACconversion(unsignedcharsla,unsignedcharc,unsignedcharVal){

Start_I2c();//启动总线SendByte(sla);//发送器件地址if(ack==0)return(0);

SendByte(c);//发送控制字节if(ack==0)return(0);

SendByte(Val);//发送DAC的数值 if(ack==0)return(0);

Stop_I2c();//结束总线return(1);}

/*******************************************************************ADC发送字节[命令]数据函数 *******************************************************************/u8ISendByte(unsignedcharsla,unsignedcharc){

Start_I2c();//启动总线SendByte(sla);//发送器件地址if(ack==0)return(0);//应答信号SendByte(c);//发送数据if(ack==0)return(0);

Stop_I2c();//结束总线return(1);}

/*******************************************************************ADC读字节数据函数 *******************************************************************/unsignedcharIRcvByte(unsignedcharsla){unsignedcharc;

Start_I2c();//启动总线SendByte(sla+1);//发送器件地址,由于是读取,所以加1if(ack==0)return(0);

c=RcvByte();//读取数据0

Ack_I2c(1);//发送非就答位Stop_I2c();//结束总线return(c);}

最后看main.c的操作

#include"sys.h"#include"delay.h"#include"i2c.h"#include"usart.h"#include"pcf8591.h"#define PCF8591 0x90 vu16date;

intmain(void){

I2c_Init();

uart_init(115200);

delay_init();

while(1)

ISendByte(PCF8591,0x40);

date=IRcvByte(PCF8591);//printf("Send:%d \n\r",date);

delay_ms(500);

以后会更新更多基于IIC协议的器件通信,也会给出库函数版本的操作

总结

实现I2C通信,以下几个要点:

·datasheet中找到address byte,以及相关寄存器的规则

·配置I2C端口以及相关时钟

·根据I2C协议编写通信代码

需要学习单片机的朋友 ,做毕业设计的同学,参加竞赛,关注我们,口令陈老师,与导师一起学习成长,共同进步,还有更多资料领取。

说了这么多,大家记得留意下方评论第一条(或者私信我)有干货~

-END-

*本文系网络转载,版权归原作者所有,如有侵权请联系删除

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
宝马绝地求生!59万一口气降到37.65万,奥迪Q5见了都要好好思量

宝马绝地求生!59万一口气降到37.65万,奥迪Q5见了都要好好思量

户外小阿隋
2024-06-02 17:13:43
越闹越大了,王阳老婆都发声了

越闹越大了,王阳老婆都发声了

李保军财经
2024-06-01 21:21:17
莫言:一个人最大的悲哀,就是轻易向别人透露着这4 个隐私,很蠢

莫言:一个人最大的悲哀,就是轻易向别人透露着这4 个隐私,很蠢

历史微鉴
2024-05-04 18:53:09
李建成死后不久,罗艺起兵谋反被杀,李世民:不杀他,我寝食难安

李建成死后不久,罗艺起兵谋反被杀,李世民:不杀他,我寝食难安

史笔似尘钩
2024-06-02 21:38:27
两幅世界名画:安帅再现墨镜雪茄!4巨头女神像前举杯 5人29冠

两幅世界名画:安帅再现墨镜雪茄!4巨头女神像前举杯 5人29冠

念洲
2024-06-03 06:02:39
TA:皇马将向17岁青训小将保罗-亚戈提供到2026年的新合同

TA:皇马将向17岁青训小将保罗-亚戈提供到2026年的新合同

直播吧
2024-06-03 00:33:08
“香会”智库报告偏颇指责中国,中国学者当场反驳引起共鸣

“香会”智库报告偏颇指责中国,中国学者当场反驳引起共鸣

环球网资讯
2024-06-02 22:07:35
有一说一,如果东契奇率领独行侠夺冠,将带来5个连锁反应!

有一说一,如果东契奇率领独行侠夺冠,将带来5个连锁反应!

元爸体育
2024-06-02 18:58:29
世预赛36强赛形势!10队基本出线,死亡之组诞生,中国队还需3分

世预赛36强赛形势!10队基本出线,死亡之组诞生,中国队还需3分

刺头体育
2024-06-02 16:29:46
挑战者之姿!欧文4次总决赛之旅的对手都是当赛季联盟第一

挑战者之姿!欧文4次总决赛之旅的对手都是当赛季联盟第一

直播吧
2024-06-02 21:01:09
于洋:合作黄渤没火,演雪中悍刀行没红,如今凭《庆余年2》出圈

于洋:合作黄渤没火,演雪中悍刀行没红,如今凭《庆余年2》出圈

娱乐多谋
2024-06-01 17:46:07
真受不了这个状元!拿着两亿顶薪,当老大不合格,当老二还不合格

真受不了这个状元!拿着两亿顶薪,当老大不合格,当老二还不合格

球毛鬼胎
2024-06-02 17:07:20
父亲把3套拆迁房全给了弟弟,为了争夺房产,我被弟媳打了一巴掌

父亲把3套拆迁房全给了弟弟,为了争夺房产,我被弟媳打了一巴掌

HL木子娱乐
2024-06-02 03:32:32
有近300个股票存在巨大风险,A股考验3000点,这些票大家赶紧避开

有近300个股票存在巨大风险,A股考验3000点,这些票大家赶紧避开

鹏哥投研
2024-06-02 22:46:34
四大银行 存款利率最新调整变化:2024年6月,全新存款利率利息表

四大银行 存款利率最新调整变化:2024年6月,全新存款利率利息表

平说财经
2024-06-02 13:18:55
就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

小乐讲故事
2023-05-17 09:52:08
【荷兰】荷兰媒体全方位报道中国航天器抵达月球背面

【荷兰】荷兰媒体全方位报道中国航天器抵达月球背面

一网荷兰
2024-06-03 01:03:32
中国必须直面的灵魂拷问!公方彬:面对俄乌战争,世界有无公理?

中国必须直面的灵魂拷问!公方彬:面对俄乌战争,世界有无公理?

瑜说还休
2024-05-30 11:32:43
路线转换失败?所以长身的她只能突破极限了!

路线转换失败?所以长身的她只能突破极限了!

孤独的独角兽影视
2024-06-01 11:20:02
文淇是怎么当上明星的?就这长相,能混到一线估计难上加难!

文淇是怎么当上明星的?就这长相,能混到一线估计难上加难!

小娱乐悠悠
2024-06-02 09:34:17
2024-06-03 07:12:49
单片机陈老师
单片机陈老师
点击头像,了解跟多
25文章数 37关注度
往期回顾 全部

科技要闻

黄仁勋:2026年将推下代GPU架构平台Rubin

头条要闻

女子称穿7cm厚洞洞鞋下楼时崴脚摔倒 左腿粉碎性骨折

头条要闻

女子称穿7cm厚洞洞鞋下楼时崴脚摔倒 左腿粉碎性骨折

体育要闻

从0-1到2-1!石宇奇绝地反击逆转队友李诗沣,豪夺赛季第3冠

娱乐要闻

白玉兰提名:胡歌、范伟争视帝

财经要闻

新造车5月销量: 小鹏乏力 问界暂"缺席"

汽车要闻

吉利银河E5 Flyme Auto智能座舱首发

态度原创

房产
艺术
本地
公开课
军事航空

房产要闻

重磅!琼海出台楼市新政:住房出租、挂牌计划出售,都可减套数!

艺术要闻

穿越时空的艺术:《马可·波罗》AI沉浸影片探索人类文明

本地新闻

食味印象|歙县限定!枇杷味儿的清甜初夏

公开课

近视只是视力差?小心并发症

军事要闻

美国中央司令部称拦截胡塞武装射向美军舰的导弹

无障碍浏览 进入关怀版