stm32 IIC通信

8 AT24CXX_ReadOneByte(u16 ReadAddr)
{                                  
        u8 temp=0;                                                                                                                                                               
    IIC_Start();  
        if(EE_TYPE>AT24C16)
        {
                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;
}

Device address :


这段代码我的理解为

就是完成了readByte,类似于上图的ByteWrite



因为 u16 ReadAddr是十六位的,高8位是device地址,低8位为读数据的地址。先发送0xA0 这个是EEPROM的基地址(个人这么认为),选取哪个页地址或者哪块EEPROM取决于ReadAddr的高8位,最后一位是读写,%256是页地址。....未完待续


10bit的寻址扩展可能寻址的数目.有7bit地址和10bit地址的设备可以连接到相同的I2C总线上,而且7bit寻址和10bit寻址都可以用在所有的总线速度模式下.不过,10bit寻址用的不多.

10bit的从机地址由开始条件(S)或重复开始条件(Sr)后的两个字节组成.第一个字节的前7位是1111 0XX,XX是10bit地址的最高有效位的前两位.第一个字节的第8bit是读写位,决定传输方向.

尽管1111 XXX有8种可能的组合,然后只有1111 0XX这四种可以用于10bit寻址.剩下的1111 1XX这四种是为将来I2C扩展用的.


        AT24C02A:2K的容量,32pages,每个page8个字节,总共256字节.读写需要8bit的word address.


主器件通过发送一个起始信号启动发送过程,然后发送它所要寻址的从器件的地址。8位从器件地址的高4位D7~D4固定为1010(如图7.52所示),接下来的3位D3~D1(A2、A1、A0)为器件的片选地址位,或作为存储器页地址选择位,用来定义哪个器件以及器件的哪个部分被主器件访问,最多可以连接8个CAT24WC01/02、4个CAT24WC04、2个CAT24WC08、8个CAT24WC32/64、4个CAT24WC256器件到同一总线上,这些位必须与硬连线输入脚A2、A1、A0相对应。1个CAT24WC16/128可单独被系统寻址。


AT系列的从01-16,你所说的硬件引脚A0 A1 A2在不同容量下使用方法是不同的。
01/02 的确是使用A012作为固定的器件地址;
04只使用A2 A1,而A0是不接的,在I2C的7bit地址中,这个A0的位置就由P0代替,这样软件可配置P0的值,来选择对应的page。
08只使用A2
16不使用A012任何一个。这三个全部用来在I2C的地址中选择page。

其他系列的EEPROM不知道如何配置的。但AT的只要看一下spec就明白了。


AT系列,每个page是256 Bytes,而且都有专门的Byte Write和Page Write时序的


其实这些EEPROM寻址由高字节地址和页内地址决定的。
1. 一个页一般是256B,8bit地址就可以全部寻址,如果小于256B就不用说了;
2. 对于容量大于256B的芯片, 需要分情况考虑. 如果总线上多于一个芯片,则必须用slave地址后四位的高位作为硬件地址, 后四位的地位作为片内页地址寻址. 比如说4*256B芯片, 总线最多挂2块, A2和高四位用于芯片寻址, A1A0用于片内寻址各个页面(4=2^2); 如果是8*256B的芯片, 那么A2A1A0均需要用作片内寻址(8=2^3), 所以总线上只能挂一片这样的芯片.
3. 对于Page Mode/Byte Mode, 这里的Page和上面2中的页不是一个概念. 这里是讲的是地址位底字节地址的后3位(如果page大小是8B时, 并不总是这样)在连续一次写时会做自动回滚的运算, 其实就是内部的计数器只有3位(如果page大小是8B时, 并不总是这样).这样当连续写超过一个Page的数据时页内计数器就溢出了,也就是地址回滚到刚开始的地方了. 这里的地址是也内地址.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以!以下是一个简单的C语言代码示例,演示如何在STM32微控制器上实现I2C从机通信。 ```c #include "stm32f4xx.h" #define SLAVE_ADDRESS 0x50 // 从机地址 void I2C1_EV_IRQHandler(void) { if(I2C_GetITStatus(I2C1, I2C_IT_ADDR)) // 接收到地址匹配事件 { I2C_ClearITPendingBit(I2C1, I2C_IT_ADDR); // 清除地址匹配中断标志位 } if(I2C_GetITStatus(I2C1, I2C_IT_RXNE)) // 接收缓冲区非空(接收到数据) { uint8_t data = I2C_ReceiveData(I2C1); // 读取接收到的数据 // 处理接收到的数据 } } int main(void) { GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 使能I2C1时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // 使能GPIOB时钟 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PB6 -> I2C1_SCL, PB7 -> I2C1_SDA GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 复用功能 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // GPIO速度 GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // 开漏输出 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 上拉 GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化GPIOB GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); // 设置PB6复用为I2C1 GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // 设置PB7复用为I2C1 NVIC_InitStruct.NVIC_IRQChannel = I2C1_EV_IRQn; // I2C1事件中断 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级0 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; // 子优先级0 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断 NVIC_Init(&NVIC_InitStruct); // 初始化NVIC I2C_DeInit(I2C1); // 复位I2C1外设 I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C模式 I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50%占空比(标准模式) I2C_InitStruct.I2C_OwnAddress1 = SLAVE_ADDRESS; // 设置从机地址 I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 使能应答 I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址模式 I2C_InitStruct.I2C_ClockSpeed = 100000; // I2C时钟速度(100kHz) I2C_Init(I2C1, &I2C_InitStruct); // 初始化I2C1 I2C_ITConfig(I2C1, I2C_IT_RXNE, ENABLE); // 使能接收缓冲区非空中断 I2C_ITConfig(I2C1, I2C_IT_ADDR, ENABLE); // 使能地址匹配中断 I2C_Cmd(I2C1, ENABLE); // 使能I2C1外设 while(1) { // 主程序逻辑 } } ``` 这是一个简单的从机代码示例,初始化了I2C1外设,并设置了从机地址为0x50。在`I2C1_EV_IRQHandler`函数中,可以处理接收到的数据。在主程序中,你可以添加自己的逻辑来处理接收到的数据。 请注意,以上代码是基于STM32F4系列微控制器的。如果你使用的是其他系列的STM32,请根据具体型号和硬件连接进行适当的修改。同时,还需要根据你的项目需求进行适当的配置和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值