打印
[应用相关]

STM32外设驱动篇——AT24C02(I2C接口)

[复制链接]
2205|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
玛尼玛尼哄|  楼主 | 2016-8-8 17:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

SOC:STM32F103RCT6

软件平台:STM官方库V3.5.0

开发工具:Keil


1. 摘要

  本**将给出STM32F103RCT6控制AT24C02的代码。如有疑问和错误,欢迎留言告之。


2.硬件连接

AT24C02使用I2C进行数据访问,板子上使用STM32的I2C控制器2和AT24C02进行连接。

具体来说,PB10作为SCL和AT24C02相连,PB11作为SDL和AT24C02相连。

这里就不给出硬件连接图了,比较简单。


3. AT24C022C访问代码(轮询)

I2C这里使用轮询方法,不是中断,请留意。

首先,给出I2C控制器的初始化代码,和读写代码,一共三个函数,对应三个功能。

注意:这里是使用I2C控制器2。



沙发
玛尼玛尼哄|  楼主 | 2016-8-8 17:55 | 只看该作者
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include <stdio.h>

void I2C2_Init(I2C_InitTypeDef* I2C_InitStruct)
{
        GPIO_InitTypeDef GPIO_InitStruct;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);        
       
        /* 配置IO管脚 */
        GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;            
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;            
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_Init(GPIOB, &GPIO_InitStruct);
   
           I2C_Init(I2C2, I2C_InitStruct);
        I2C_Cmd(I2C2, ENABLE);
       
        // 配置NVIC
/*        NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn   ;                                //I2C事件中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;        //抢占优先级1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;                        //子优先级2
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                        //使能中断通道
        NVIC_Init(&NVIC_InitStructure);                                                            //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 */

        //I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE); //打开事件中断
}

/* i2c 写一个字节*/
/* Byte Write */
void I2C2_WriteByte(uint8_t DeviceAddress, uint8_t MemoryAddress, uint8_t Data)
{
        while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));           //等待I2C空闲

        //start
        I2C_GenerateSTART(I2C2, ENABLE);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS );
       
        //device address
        I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Transmitter); //写模式
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS );        
        //printf("address over\r\n") ;

        //memory address
        I2C_SendData(I2C2, MemoryAddress);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS );
                       
        //data
           I2C_SendData(I2C2, Data);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS );        

        //stop
        I2C_GenerateSTOP(I2C2, ENABLE);
}

/* i2c 读一个字节*/
/* Random Read */
uint8_t I2C2_ReadByte(uint8_t DeviceAddress, uint8_t MemoryAddress)
{
        uint8_t        Data;
       
        while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));           //等待I2C空闲  
        //start
        I2C_GenerateSTART(I2C2, ENABLE);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ); //ev5

        //device address
        I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Transmitter);  //写模式
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS );         //ev6
         
        //memory address
        I2C_SendData(I2C2,  MemoryAddress);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS ) ;
                                                                                                                                                  
        //start
        I2C_GenerateSTART(I2C2, ENABLE);
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS ) ;        

        //device address
        I2C_Send7bitAddress(I2C2, DeviceAddress, I2C_Direction_Receiver); //读模式
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS ) ;
       
        /* 按照manual的图273,先读取数据,关闭ACK应答,最后发出STOP*/          
        while( I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS );         /* 等待读取事件,再读取数据 */
           Data = I2C_ReceiveData(I2C2);
        I2C_AcknowledgeConfig(I2C2, DISABLE); //关闭应答和停止条件产生  
        printf("received\r\n");
        I2C_GenerateSTOP(I2C2, ENABLE);
       
        I2C_AcknowledgeConfig(I2C2, ENABLE);

        return Data;
}
接着给出相应的AT24C02访问代码
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include "i2c.h"
#include "delay.h"
#include <stdio.h>

/* 从AT24CXX的指定地址开始读出一个字节 */
uint8_t AT24CXX_ReadByte(uint8_t ReadAddr)
{
        return I2C2_ReadByte(0xA0, ReadAddr);
}  

/* 向AT24CXX的指定地址开始写入一个字节 */
void AT24CXX_WriteByte(uint8_t WriteAddr, uint8_t Data)
{
        I2C2_WriteByte(0xA0, WriteAddr, Data);
}

void AT24CXX_test(void)
{
        uint8_t i;
           I2C_InitTypeDef I2C_InitStructure;

        I2C_InitStructure.I2C_ClockSpeed         =  200000;           //200kHZ
           I2C_InitStructure.I2C_Mode                         =  I2C_Mode_I2C;
           I2C_InitStructure.I2C_DutyCycle         =  I2C_DutyCycle_2;        //根据datasheet,Tlow/Thigh = 2
           I2C_InitStructure.I2C_OwnAddress1         =  0xA0;                
           I2C_InitStructure.I2C_Ack                          =  I2C_Ack_Enable;
           I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
       
        I2C2_Init(&I2C_InitStructure);

        for(i = 0; i < 10; i++){       
                AT24CXX_WriteByte(i, 100 + i);
                /* NOTE: 根据datasheet,两次字节写之间必须延迟5ms,也就是stop和start之间的间隔时间*/
                delay_ms(6);  
        }
        printf("Write completed \r\n");

        for(i = 0; i < 10; i++){       
                printf("%d ", AT24CXX_ReadByte(i));
            delay_ms(6);
        }
        printf("\r\n");
}


使用特权

评论回复
板凳
玛尼玛尼哄|  楼主 | 2016-8-8 17:56 | 只看该作者
注意:两次访问间隔必须大于5ms,这是datasheet规定的。
如果不加延时,第二次写入时候,写入设备地址后,无法接受到ACK,程序陷入死循环。

使用特权

评论回复
地板
玛尼玛尼哄|  楼主 | 2016-8-8 18:45 | 只看该作者
以上内容是我从网上找来的,应该是没问题的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

174

主题

3057

帖子

2

粉丝