完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
stm32的IIC
软件模拟和硬件的区别 IIC是常用的半双工总线,用来传递数据,好像st公司为了不交钱,自己做的IIC绕开了飞利浦的协议,但是不是很稳定,所以这次使用软件来模仿IIC的通信 其实都一样的,就是之前编写arm的时候,IIC要配置自己的时钟源,然后对寄存器编写来控制发送和读入,软件模拟就是照着时间来对两条总线发送高低电频. 硬件IIC :比较复杂,速度更快,精度更高,还可以使用DMA,但是只能用于固定管脚 使用IO口进行IIC传输 三个主要信号: 开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据 结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。 应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲 6种iic的表示:空闲状态,开始信号,停止信号,应答信号,数据的有效性,数据传输 编写代码前进行定义 //IO方向设置 #define SDA_IN() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=0<<5*2;} //PH5输入模式 #define SDA_OUT() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=1<<5*2;} //PH5输出模式 //IO操作函数 #define IIC_SCL PHout(4) //SCL #define IIC_SDA PHout(5) //SDA #define READ_SDA PHin(5) //输入SDA 空闲状态 I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。 此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高 所以我们进行初始化IO口,进行拉高(上拉,变成高电压),用推挽输出(可靠性高) void IIC_Init(void) { RCC->AHB1ENR|=1<<7; //使能PORTH时钟 GPIO_Set(GPIOH,PIN4|PIN5,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PH4/PH5设置 IIC_SCL=1; IIC_SDA=1; } 这时候就不会启动IIC 开始信号 SCL为高的时候,SDA突然进行从高到低的跳变,说明已经开始传输数据 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总线,准备发送或接收数据 } 停止信号 根据上面的图,当SCL已经拉高的时候,SDA再进行拉高 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); } 应答信号 在每次数据发送后,主机就等着从机发送应答信号,表示啊啊啊我已经收到了 主机在发送完第八位时候,从机就能拉低信号,所以从机器先拉低data信号 当scl信号变低就知道发生了应答信号. 对于我们的STM32来说肯定是做主机,所以可以对从机发送ACK应答 也可不发送应答(NAck) 发送ACK应答 先让data变低,再让SCL变低,再让SCL变高,以至于SCL检测的时候,DATA都是低的 void IIC_Ack(void) { IIC_SDA=0; IIC_SCL=0; SDA_OUT(); 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发送一个字节(8bit) 想当于一个bit发送八次,我们定一个周期是6us,那么前后4us是给data电频变得稳定留的,中间2us来进行检测SCL拉高电频,这样子重复八次 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); } } 24C02型E2PROM 硬件连接 从原理图上看出SCL和SDA连接到了PH4,5 EEPROM的A0,1,2,接地------>这个芯片的地址为000 WP—>使能保护,我们就不用保护了,直接接入地 寻找EEPROM地址 打开EEPROM的datasheet 看到设备地址的标注方法,我们是2k的芯片,A120都是接地,所以读取的时候 0b10100001 写的时候找到的地址是0b10100000 根据EEPROM的不同写数据也有判断 写EEPROM 开始信号–>写模式下从机地址–>写数据的地址–>数据–>停止信号 void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) { IIC_Start(); if(EE_TYPE>AT24C16) { IIC_Send_Byte(0XA0); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr>>8);//发送高地址 } else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr%256); //发送低地址 //上面根据不同写数据也有不同的判断 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 delay_ms(10); } 读EEPPROM 开始信号—>写模式下从机地址—>写数据的地址—>读模式下从机地址—>从机返回数据—>停止 u8 AT24CXX_ReadOneByte(u16 ReadAddr) { u8 temp=0; IIC_Start(); //开始信号 if(EE_TYPE>AT24C16)//判断iic大小 { IIC_Send_Byte(0XA0); //发送写模式下从机地址 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr>>8);//发送高地址 } else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr%256); //发送低地址 IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0XA1); //进入接收模式 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 return temp; } io口扩展芯片PCF8574 芯片PCF8574介绍 PCF8574 包含一个 8 位准双向口和一个 IIC 总线接口。PCF8574 电流消耗很低且口输出锁 存具有大电流驱动能力可直接驱动 LED 它还带有一条中断接线(INT)可与 MCU 的中断逻辑 相连,通过 INT 发送中断信号,远端 I/O 口不必经过 IIC 总线通信就可通知 MCU 是否有数据 从端口输入 寻址 用一个IIC可以扩展出8个IO口,连接图在上面所示,因为只有一个芯片,所以地址全部接地,寻址全填0就好 所以我们操控从机读操作就是地址为 01000001 从机写操作就是操作地址为 01000000 控制芯片 对芯片写入数据 PCF8574T 的从机地址+写信号(R/W=0),然后等待 PCF8574T 的应答信号,在应答成功后,发送数据(DATA1)给 PCF8574T 就可以了,发送完数据,就可以控制8个IO端口 void PCF8574_WriteOneByte(u8 DataToWrite) { IIC_Start(); IIC_Send_Byte(PCF8574_ADDR|0X00); //发送器件地址0X40,写数据 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop(); //产生一个停止条件 delay_ms(10); } 用之前写好的IIC控制函数就很简单了 读芯片上的IO值 首先发送 PCF8574T 的从机地址+读信号(R/W=1),然后等待应答,接着从机发送数据,最后发送stop信号 u8 PCF8574_ReadOneByte(void) { u8 temp=0; IIC_Start(); IIC_Send_Byte(PCF8574_ADDR|0X01); //进入接收模式 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); IIC_Stop(); //产生一个停止条件 return temp; } |
|
|
|
只有小组成员才能发言,加入小组>>
3322 浏览 9 评论
3000 浏览 16 评论
3497 浏览 1 评论
9070 浏览 16 评论
4090 浏览 18 评论
1191浏览 3评论
613浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2341浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1899浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-28 22:22 , Processed in 1.174022 second(s), Total 76, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号