STM32模拟IIC通信

发布者:会弹琴的鲸鱼3312最新更新时间:2022-01-14 来源: eefocus关键字:STM32  模拟IIC通信  硬件IIC 手机看文章 扫描二维码
随时随地手机看文章

一、定义

IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由菲利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS),IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化了信号传输总线。


I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。


与SPI相同的是,都是多选一,即可以有多个从设备,但是一次通信的时候,只能选择其中的一个。且IIC的从设备选择上,有7位地址,谁控制了时钟线,谁就是从机,而不是像SPI那样通过片选信号线CS来选择。


二、读写AT24C02

(1)电路原理图如下:WP引脚接地,表明可读可写,如果接VCC只读不可写。

在这里插入图片描述

(2)引脚说明图如下:

在这里插入图片描述

A0-A2,接在了GND,代表是0,R/-W,W的上面是有一横的,代表0有效,读是1有效,所以读操作是0XA0,写操作是0XA1。


(3)地址说明:

在这里插入图片描述

(4)通信过程

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(1)起始信号:由上图可知,读写的速率为100KHZ,那么1/100khz= 10us,在起始信号的时候,高地电平各占一半,即至少需要持续5us。SCL持续高电平,直到SDA线由高电平到低电平变化,SCL才变为低电平。可以写出代码:


GPIO初始化

void i2c_init(void)

{

//使能GPIOB时钟

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);


//PB8 PB9初始化设置 

GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9; //8号和9号引脚

GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;     //普通输出模式,

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;     //100MHz

GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;     //上拉

GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器


//i2c引脚初始化状态,默认为高电平

SCL =1;

SDA_W=1;



}


自定义更改输入输出模式

void i2c_sda_mode(uint32_t iomode)

{


//PB9初始化设置 

GPIO_InitStructure.GPIO_Pin   =  GPIO_Pin_9; //9号引脚

GPIO_InitStructure.GPIO_Mode  = iomode; //输出模式/输入模式

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz

GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP; //上拉

GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器


}

起始信号


void i2c_start(void)

{

//保证SDA引脚为输出模式

i2c_sda_mode(GPIO_Mode_OUT);

SCL =1;

SDA_W=1;

delay_us(5);//100KHz通信速率,但是不能超过400KHz

SDA_W=0;

delay_us(5);

SCL =0; //保持占用I2C总线,允许数据改变

}


(2)结束信号

读上图,输出模式,SCL和SDA都为低电平,延时一段时间,SCL变为高电平,延时一段时间,SDA变为高电平,持续一段时间即可。


void i2c_stop(void)

{

//保证SDA引脚为输出模式

i2c_sda_mode(GPIO_Mode_OUT);



SCL =0;

SDA_W=0;

delay_us(5);

SCL =1;

delay_us(5);

SDA_W=1;

delay_us(5);

}


(3)发送1字节数据

拉低时钟SCL,允许数据进行变化,延时一段时间;

然后判断传进来的data每一位的值,如果读取的data位7为1,那么SDA=1;如果位7为0,那么SDA=0;然后拉高SCL延时一段时间,这样就完成了一位的发送,以此循环八次。因为要允许下一次循环可以改变数据,所以还要把SCL变为低电平。


void i2c_send_byte(uint8_t txd)

{

uint32_t i=0;

//保证SDA引脚为输出模式

i2c_sda_mode(GPIO_Mode_OUT);


//保证SCL引脚开始的时候为低电平,允许数据的改变

SCL =0;

delay_us(5);

//连续发送8个bit,采用最高有效位优先进行发送

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

{

if(txd & (1<<(7-i)))

SDA_W=1;

else

SDA_W=0;

delay_us(5);

//锁存数据,让从机进行识别

SCL=1;

delay_us(5);

//允许改变数据,从机无视该数据

SCL=0;

delay_us(5);

}

}


(4)等待从机应答

有应答:低电平;无应答;高电平


uint8_t i2c_wait_ack(void)

{

uint8_t ack=0;

//保证SDA引脚为输入模式

i2c_sda_mode(GPIO_Mode_IN);

SCL=1;

delay_us(5);

//有应答为低电平,无应答为高电平

if(SDA_R) //无应答

{

ack=1;

i2c_stop();

}

else //有应答

ack=0;


SCL =0; //保持占用I2C总线,允许数据改变

delay_us(5);

return ack;

}


(5)整合上面四部分的代码


void at24c02_write(uint8_t addr,uint8_t *pbuf,uint8_t len)

{

uint8_t ack=0;

//发送启动信号

i2c_start();

//发送寻址地址为0xA0,写访问操作

i2c_send_byte(0xA0);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack device address failrn");

return;

}


printf("24c02 is onlinern");


//发送数据存储地址

i2c_send_byte(addr);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack word address failrn");

return;

}

printf("24c02 word address okrn");

while(len--)

{

//发送数据

i2c_send_byte(*pbuf++);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack send data failrn");

return;

}

}

//发送停止信号,整个通信过程结束

i2c_stop();

printf("24c02 write okrn");


}


主函数调用


i2c_init();


printf("24c02 write addr 0 data is 1rn");


memset(buf,2,sizeof buf);


//页编程最大是8个字节

at24c02_write(0,buf,8);


delay_ms(500);

memset(buf,0,sizeof buf);

printf("24c02 read addr 0 data is:rn");


(6)读数据,从机发送数据,主机发送应答。

读1字节数据

uint8_t i2c_recv_byte(void)

{

uint32_t i=0;

uint8_t  rxd=0;

//保证SDA引脚为输出模式

i2c_sda_mode(GPIO_Mode_IN);


//保证SCL引脚开始的时候为低电平,允许数据的改变

SCL =0;

delay_us(5);

//连续接收8个bit,采用最高有效位优先进行接收

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

{


//delay_us(5);

//锁存数据

SCL=1;

delay_us(5);

if(SDA_R)

rxd|=1<<(7-i);

//允许改变数据

SCL=0;

delay_us(5);

}

return rxd;


}

主机发送应答

void i2c_ack(uint8_t ack)

{


//保证SDA引脚为输出模式

i2c_sda_mode(GPIO_Mode_OUT);


//保证SCL引脚开始的时候为低电平,允许数据的改变

SCL =0;

delay_us(5);


if(ack)

SDA_W=1;

else

SDA_W=0;

delay_us(5);

//锁存数据,让从机进行识别

SCL=1;

delay_us(5);

//允许改变数据,从机无视该数据

SCL=0;

delay_us(5);


}


读取数据函数

void at24c02_read(uint8_t addr,uint8_t *pbuf,uint8_t len)

{

uint8_t ack=0;

//发送启动信号

i2c_start();

//发送寻址地址为0xA0,写访问操作

i2c_send_byte(0xA0);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack device address failrn");

return;

}


printf("24c02 is onlinern");


//发送数据存储地址

i2c_send_byte(addr);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack word address 1 failrn");

return;

}

printf("24c02 word address okrn");

//重新发送启动信号

i2c_start();

//发送寻址地址为0xA1,读访问操作

i2c_send_byte(0xA1);

//等待应答

ack = i2c_wait_ack();

if(ack)

{

printf("24c02 ack device address 2 failrn");

return;

}

len=len-1;

while(len--)

{

//接收数据

*pbuf++=i2c_recv_byte();

//主动发送应答给从机

i2c_ack(0);

}

//接收数据

*pbuf=i2c_recv_byte();

//主动发送无应答给从机

i2c_ack(1);

//发送停止信号,整个通信过程结束

i2c_stop();

printf("24c02 read okrn");


}


调用

at24c02_read(0,buf,8);


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

{

printf("%02X ",buf[i]);



}


注意;在写和读直接需要加延时

关键字:STM32  模拟IIC通信  硬件IIC 引用地址:STM32模拟IIC通信

上一篇:STM32的RS485通信
下一篇:STM32模拟SPI通信

推荐阅读最新更新时间:2024-11-16 19:51

STM32 FSMC驱动TFTLCD 难点解析
本篇文章三个主题:FSMC有关配置、一串字符显示原理、汉字显示原理。。下面进入正题 一、FSMC的有关配置(博主用的是FSMC_A10): 来自别人家的博客http://blog.csdn.net/jxnu_xiaobing/article/details/8718566 FSMC的介绍就不介绍了,网上一大片。我们就讨论讨论为什么用FSMC的地址线与TFTLCD的RS引脚相连?以及我们如何往LCD写数据/命令? FSMC称为可变静态存储控制器。可变:之所以称为“可变”,是由于通过对特殊功能寄存器的设置,FSMC 能够根据不同的外部存储器类型,发出相应的数据/地址/控制信号类型以匹配信号的速度。(这点很重要,后文会
[单片机]
STM32定时器----多通道PWM捕获
由于项目需要利用一个定时器捕获2通道的PWM输入,所以近两天研究了一下多通道PWM的捕获。 功能实现:在头文件中修改对应通道的宏定义的值(1或者0),开启对应通道的PWM捕获。 可通过修改对应宏定义,更改定时器中断间隔,以及中断函数中的溢出次数,以此 决定定时器所能捕获的最低以及最高频率。 代码如下: /***********************************头文件********************************/ typedef struct { u16 Ccr1; //缓存CCR寄存器的值 u16 Ccr2; u16 Ccr3; u16 Ccr4;
[单片机]
<font color='red'>STM32</font>定时器----多通道PWM捕获
STM32——时钟系统
一、时钟树 普通的MCU,一般只要配置好GPIO 的寄存器,就可以使用了。STM32为了实现低功耗,设计了非常复杂的时钟系统,必须开启外设时钟才能使用外设资源。 左边开始,从时钟源一步步分配 到外设时钟。 从时钟频率来说,又分为高速时钟和低速时钟,高速时钟是提供给芯片主体的主时钟,而低速时钟只是提供给芯片中的 RTC(实时时钟)及独立看门狗使用。 从芯片角度来说,时钟源分为内部时钟与外部时钟源,内部时钟是在芯片内部 RC 振荡器产生的,起振较快,所以时钟在芯片刚上电的时候,默认使用 内部高速时钟。而外部时钟信号是由外部的晶振输入的,在精度和稳定性上都有很大优势,所以上电之后我们再通过软件配置,转而
[单片机]
STM32串口发送数据的标准函数
例子:1 void UART_Send_Message(u8 *Data,u8 lenth) { while(lenth--) { USART_SendData(USART2, *Data); while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); Data++; } } void main() { u8 Sendbuf ; Sendbuf =0xA0; Sendbuf =0xA0; Sendbuf =0xA0; UART_Send_Message(Sendbuf,3); } 例子2:
[单片机]
STM32串口USART1的使用方法和程序
通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择,支持同步单向通信和半双工单线通信。 1、STM32固件库使用外围设备的主要思路 在STM32中,外围设备的配置思路比较固定。首先是使能相关的时钟,一方面是设备本身的时钟,另一方面如果设备通过IO口输出还需要使能IO口的时钟;最后如果对应的IO口是复用功能的IO口,则还必须使能AFIO的时钟。 其次是配置GPIO,GPIO的各种属性由硬件手册的AFIO一章详细规定,较为简单。 接着相关设备需要如果需要使用中断功能,必须先配置中断优先级,后文详述。 然后是配
[单片机]
<font color='red'>STM32</font>串口USART1的使用方法和程序
stm32 12864驱动
/**************************************************************** 【文 件 名 称】lcd12864.h 【功 能 描 述】lcd12864 头文件 *****************************************************************/ #ifndef __LCD12864_H #define __LCD12864_H //**************************************************************** #include stm32f10x_gpio.h #inc
[单片机]
STM32-(SysTick定时器,EXTI外部中断/事件控制器)
Systick系统定时器 介绍:systick定时器上属于CM3内核中的一个外设,内嵌在NVIC中。系统定时器是一个24位向下计数的计数器,计数器每一次计数的时间是1/SYSTICK,一般我们设置SYSTICK为72M。当重载数值寄存器的值递减到0时,系统定时器产生一次中断,以此循环。 使用范围:1.一般用于操作系统,用于产生时基,维持操作系统的心跳。 使用的寄存器:CTRL,LOAD,VAL,CALIB; 例程1:利用systick产生1s的时基。 步骤: 1.设置重载寄存器的值 2.清除当前数值寄存器的值 3.配置控制于状态寄存器 systick配置库函数: _STATIC_INLINE uint32_t
[单片机]
STM32-(SysTick定时器,EXTI外部中断/事件控制器)
STM32开发系列之寄存器(一)按键控制LED灯
入门学习STM32开发,首先要选择一种开发方式。STM32的开发方式主要有标准库开发、寄存器开发和HAL库开发(这个我没使用过,不太了解)。比较多的人选择的开发方式是库开发,使用这两种方式比较方便,但因经过函数封装,对底层的理解不足。由于我入门也是由标准库开发入门的,所以这里想专门写一下寄存器开发,边写边学习,欢迎一起探讨。 1、一般写法 注:采用的STM32F103ZET6芯片 ST官方提供了stm32f10x.h的头文件,里面有各个寄存器的地址定义,因此可以直接操作寄存器来对IO口进行配置,下面就以案件控制LED灯为例。 在stm32f10x.h头文件里有以下的IO口的宏定义及结构体 ①假设LED灯接在GPIOB5
[单片机]
<font color='red'>STM32</font>开发系列之寄存器(一)按键控制LED灯

推荐帖子

关于如何学习嵌入式 高手 们进啊
大家好,我是一名大三的学生,学的是嵌入式方向的,但我们现在才学嵌入式操作系统,都TMD还是理论,学了等于没学,就上学期还学了个汇编,现在一学期都快过完了,感觉什么关于嵌入式方面的都没学到,如果靠下学期再来学点东西,以后出去就别想混了,自己感觉嵌入式这方面以后还是有发展的,但就不知道现在该从何入手,如果按学校老师来,估计学不了什么东东,希望高手们能给我一些意见,从哪方面开始,有什么好书没,,就是关于实际操作的,关于应用程序,驱动程序的都可以。本人感觉自己C、C++还行。同道中人就进来顶一下吧高
spurray 嵌入式系统
【复旦微车规MCU FM33FT0A 系列】--LCD屏显示
经过一段时间的了解熟悉,本篇实现LCD显示功能。一.硬件了解开发板板载LCD显示屏,分辨率172(H)RGBx320(V),驱动ICST7789V3,MCU通过SPI接口驱动控制。开发板硬件原理如下图1:LCD原理图连接LCD屏引脚MCUPIN功能LCD_CSPE1片选信号,低电平有效LCD_DCPE2显示数据/命令引脚.低电平时写命令,高电平时写数据LC
dirty 汽车电子
CS+下载时找不到动态链接库
file:///C:\Users\WPJ\Documents\TencentFiles\594049947\Image\Group\MS(A0BZX%Z{3IMGTUfile:///C:\Users\WPJ\Documents\TencentFiles\594049947\Image\Group\MS(A0BZX%Z{3IMGTU这是为什么呢?打开所有工程都是这样CS+下载时找不到动态链接库更新一下,或者重新安装软件,看能不能正常下载
worldwpj 瑞萨电子MCU
感谢团购TI 430 LaunchPad的网友,让EEWORLD成长
这几天感觉经历了很多,心情也像过山车,起起伏伏。当初策划团购25元的430LaunchPad开发板活动,内部也很兴奋,觉得这是EEWORLD回馈网友的一个好机会,大家可以一起热闹、一起High。而事情就如我们预期的,网友的反响非常热烈。可是周末,当得到这块板子中没有触摸板时,整个周末也变得晦暗。因为这次团购不是生意,我想大家也都算得出来,板子+邮费。正因为如此,我们更珍惜网友的感受、更珍惜EEWORLD的信誉。我看着帖子,有些网友退货了,我理解,毕竟买到的不是自己想要的,邮费E
向农 微控制器 MCU
Din 4芯 插座 主要用在哪上面的?
RT小批量的厂家都不卖给你Din4芯插座主要用在哪上面的?
wowozx 医疗电子
NXP LPC1114资料
哪位大佬有LPC1114的详细资料,手头有个开发板,想学习一下。NXPLPC1114资料NXP官网上应该有,估计已经停产了吧,不过资料还是能用的很老的型号了,不过的确好用。我读研的时候就是这块开发板。当时还是周立功在推呢 感谢!我去看看 是的,我的就是周立功的十多年前入门单片机就学的它,也是周立功的,官网有资料,很全的。NXP的这个芯片还有产品在用吗?LPC824,LPC1768多年前都用过,现在好像没人用了
孙玉qq 综合技术交流
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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