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-11 11:13

STM32 CubeMX如何生成微秒(us)级延时
会自动在tim.c里面生成代码,如下: /* Includes ------------------------------------------------------------------*/ #include tim.h /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ TIM_HandleTypeDef htim17; /* TIM17 init function */ void MX_TIM17_Init(void) { htim17.Instance = TIM17; htim17.Init.Prescaler = 0; htim17.Init.CounterM
[单片机]
<font color='red'>STM32</font> CubeMX如何生成微秒(us)级延时
关于stm32 HardFault_Handler 异常的处理 死机
在系统开发的时候,出现了HardFault_Handler硬件异常,也就是死机,尤其是对于调用了os的一系统,程序量大,检测堆栈溢出,以及数组溢出等,找了半天发现什么都没有的情况下,估计想死的心都有了。如果有些程序开始的时候一切没有问题,但是运行几个小时候,会发现死机了,搞个几天下来估计蛋都碎了一地吧。。。 一般来说运行操作系统 是以下几个问题 1.开始的时候给ucos分配的堆栈太小了,随着项目做多了,这类问题一般很容易解决 #define TASK_IO_SIZE 300 #define TASK_IO_PRIO 6 OS_STK TASK_IO_STK ; 比如修改300到 1000,做开发的时候 如果ram
[单片机]
stm32系列简介与stm32 esp32性能比较
STM32应该是比较熟悉的一个系列的单片机,而ESP32相对陌生一些。但是从名字看,两者应该都是32位单片机。那么两者之间到底有什么关联,或者性能哪个好一些,哪个差一些呢? STM32系列 意法半导体 (STMicroelectronics) 集团于1987年6月成立,是由意大利的SGS 微电子公司和法国Thomson 半导体公司合并而成。1998年5月,SGS-THOMSON Microelectronics 将公司名称改为意法半导体有限公司,意法半导体是世界最大的半导体公司之一。 STM32系列专为要求高性能、低成本、低功耗的嵌入式应用设计的ARM Cortex®-M0,M0+,M3, M4和M7内核(ST‘s produ
[单片机]
<font color='red'>stm32</font>系列简介与<font color='red'>stm32</font> esp32性能比较
STM32 APB1总线时钟配置问题
调试载波通信系统的时候遇到这样一个问题:两台设备分别为A何B,他们都使用了定时器2~4来进行通讯,A设备的PCLK1配置为HCLK,而B设备的PCLK1配置为1/2HCLK,通讯过程发现A,B两个设备偶尔能通讯偶尔不能通讯,表现出通讯部稳定。理论上应该完全不能通讯才是,深入研究STM32F101C8T6的数据手册发现问题所在,截图如下: 图1 STM32功能框图 图2 STM32 时钟系统 从图1可以看到APB1总线挂接了TIM2~4,UART2~2...WWD等设备。然后从图2中可以看到只有外设直接使用了APB1的时钟作为实际时钟,而TIM2~4根据APB1的时钟进行了调整。因此当设备B的PCLK1配置为1/2HCL
[单片机]
<font color='red'>STM32</font> APB1总线时钟配置问题
STM32 Systick定时器在实现1us延时时的问题与解决
问题: 使用systick_config()函数来实现计数,这个函数在下面代码中的 SysTick_CTRL_TICKINT_Msk 开启了中断。不论系统时钟为72Mhz或36Mhz若设置STM32每10us进入一次中断,计时是可以的;而每1us进入中断,由于中断指令较多,那么程序就会困在中断里出不来。 static __INLINE uint32_t SysTick_Config(uint32_t ticks) { if (ticks SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
[单片机]
STM32单片机实现DMA+ADC+UART功能
突然想测试一下STM32单片机ADC采样速率问题,按照常规方法,可以通过ADC采样,然后将采样值打印出来。但是这种方法在处理和打印数据的时候会占用很多时间,导致处理数据的时间超过了ADC的采样时间。于是想到了ADC采样的数据用DMA功能存储,并通过串口打印。但是串口打印依然要占用单片机时间,那能不能串口数据的输出也采用 DMA功能呢?这样ADC采样的数据通过DMA直接存储,然后串口通过DMA功能直接输出采样到的数据。这样速度程序执行速度不就极大的提升了吗?说干就干,使用STM32F103C8T6单片机,标准库函数,keil5软件,编写一个测试程序。 首先实现ADC采样并通过DMA存储 #ifndef __ADC_H #de
[单片机]
<font color='red'>STM32</font>单片机实现DMA+ADC+UART功能
STM32学习笔记--GPIO寄存器的定义
1、GPIO的寄存器按照功能可以分为以下几类: A、配置寄存器 B、数据寄存器 C、位寄存器 D、 锁定寄存器 2、对于GPIO端口,每个端口有16个引脚,每个引脚的模式由寄存器的四个位控制,每四位又分为两位控制引脚配置(CNFy ),两位控制引脚的模式及最高速度(MODEy ),其中y表示第y个引脚。配置GPIO引脚模式的一共有两个寄存器,CRH是高寄存器,用来配置高8位引脚,还有CRL配置低八位引脚。 3、端口位设置\清除寄存器(GPIOx_BSRR) 一个引脚 y 的输出数据由 GPIOx_BSRR 寄存器位的2 个位来控制分别为 BRy (Bit Reset y)和BSy (Bit Set y),BRy 位用于写 1清零
[单片机]
X-CUBE-STL:支持更多STM32, 揭开功能安全的神秘面纱
X-CUBE-STL 目前支持 STM32MP1、STM32U5、STM32L5、STM32H5和 STM32WL。实际上,这个最大的通用微控制器产品家族还在不断扩大,将会有更多的产品支持SIL2和SIL3系统。客户的开发团队可以在ST最新的产品上开发满足 IEC 61508、ISO 13849 和 IEC 61800 等要求 的应用。此外,在ST网站的功能安全网页上,开发者很容易找到各种资源,轻松快速通过工业或家电安全认证。网页上还列出了ST 授权合作伙伴以及他们提供的实时操作系统、开发工具、工程服务和培训课程,确保客户团队能够完成从概念验证到商品的市场转化。 o观看ST的功能安全网络研讨会 国际电工委员会对安全的定
[单片机]
X-CUBE-STL:支持更多<font color='red'>STM32</font>, 揭开功能安全的神秘面纱

推荐帖子

stm32103zet6的FSMC
版主你好,我现在用STM32控制DM9000,但是一直连不上网络,ARP有发送没接收.其他的读ID号,读寄存器都正常.以前是用STR710控制的,下面是用示波器观察到两块不同的板子的数据线波形,请帮我看下如何才能解决STM32的问题,imgsrc=https://bbs.eeworld.com.cn/upfiles/img/20094/2009424163533836.jpgonload=thumbImg(this)alt=/stm32103ze
jinwancai stm32/stm8
linux内核打印输出超级终端不能够显示信息
急求,内核不能输出打印信息,比如:printk(leds:registerdevicesucess!\\n);这一句,应该在超级终端上可以找到,但我按着教学视频执行了几次还是不行,然后我在网上也找了一下相关的问题,有的说可以在这个:/var/log/messages目录下找到这个打印信息,但我的也没有,想不通是什么地方出了问题linux内核打印输出超级终端不能够显示信息printk是内核状态的,你怎么用的?包含标准输入输出库了没babypig发表于2015
18811707971 Linux与安卓
以太网接口 RJ45
最近的项目用到以太网接口,参考网上的原理图使用的是HR911105A(需要使用两个),但是为了节省空间需要使用双层的,就是一个代替两个,找了两个型号HC-RJ45-059C-2*1-1和X23FB083DB2BDB057。现在又两个疑问:(1)HC-RJ45-059C-2*1-1是不是不带变压器,需要配置变压器芯片HY601742,HC-RJ45-059C-2*1-1+2个HY601742=2个HR911105A?(2)HC-RJ45-059C-2*1-1和HR911105A的
telecom ARM技术
搞不明白的问题
既然Routed=100%为什么还要报这个警呢搞不明白的问题Routed=100%是通知信息,不一定Alarminformation,或者是Errormessage在altiumdesigner查看布线完成信息有如下方法,报警的原因是因为orphanedcopper,说明顶层这几个地方的铜皮没有连上+5V的网络orphanedcopper是孤立的铜皮的意思。这应该只是一个通知信息,告诉你+5V和+9V的网络上有如下的元器件,并不是所谓的报错,报错信息
程序会不会 PCB设计
tvp5150图像有断层
我在用tvp5150进行图像采集的时候,发现在中途插拔摄像头信号的时候,图像会出现断层错位,图像的下半部分跑到上半部分了,不知道如何恢复?还有我们怎么才能知道图像出现上下错位了那?imgsrc=images/smilies/default/sad.gifsmilieid=2border=0alt=/tvp5150图像有断层同问,希望有经验的朋友给解答一下!谢谢!我的也一样,记得是使用d1的时候出现的,其他测试例程不会出现这样的问题。怀疑是同步问题。这个问题最终如何
wxdpio DSP 与 ARM 处理器
GPIO寄存器问题
#defineGPIO_BASE0x40028000/*GPIOregistersbase*/GPIO寄存器定义typedefstruct{volatileUNS_32pio_inp_state;/*Inputpinstateregister*/volatileUNS_32pio_outp_set;/*Outputpinsetregister*/volatileUNS_32pio_ou
蓝天白云 嵌入式系统
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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