SOC:STM32F103RCT6
软件平台:STM官方库V3.5.0
开发工具:Keil
本文章将给出STM32F103RCT6控制AT24C02的代码。如有疑问和错误,欢迎留言告之。
AT24C02使用I2C进行数据访问,板子上使用STM32的I2C控制器2和AT24C02进行连接。
具体来说,PB10作为SCL和AT24C02相连,PB11作为SDL和AT24C02相连。
这里就不给出硬件连接图了,比较简单。
I2C这里使用轮询方法,不是中断,请留意。
首先,给出I2C控制器的初始化代码,和读写代码,一共三个函数,对应三个功能。
注意:这里是使用I2C控制器2。
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include
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
/* 从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");
}
如果不加延时,第二次写入时候,写入设备地址后,无法接受到ACK,程序陷入死循环。
备注:
2013.11.22 轮询版本程序