引言
好的,紧接着就又是一个新的实验,我也是想抓紧给大家分享完这几个基础实验之后,继续给大家介绍一些完整的项目,以及其他领域的项目。
那么这个实验呢是关于EEPROM 的读写实验,STM32的EEPROM实验是指在STM32微控制器上使用内部的EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦除可编程只读存储器)进行实验。EEPROM是一种非易失性存储器,可以存储数据并在需要时进行读取和写入操作,而且数据在掉电情况下也能够保持。
实验准备
仍然是不需要接线,下载程序,全速运行,在 Keil5 环境下全速运行,能看到 EEPROM 的 0 地址 EEDATA 这个变量值就是初始化时候写进 EEPROM 0 地址的值,说明 EEPROM 读写正常。
老样子,直接上代码!!!
24C08.C
#include "sys.h"
#include "delay.h"
#define AT24C08_READ_ADDR 0xA1//读数据时的地址
#define AT24C08_WRITE_ADDR 0xA0//写数据时的地址
//IIC2初始化
void IIC_Init(void)
{
I2C_InitTypeDef I2C_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2|RCC_APB2Periph_AFIO,ENABLE);
I2C_DeInit(I2C2);//使用I2C2
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址,随便写的
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;//100K
I2C_Init(I2C2, &I2C_InitStructure);
I2C_Cmd(I2C2,ENABLE);
}
/*
函数功能: 发送起始信号
当时钟线为高电平的时候,数据线由高电平变为低电平的过程
*/
void IIC_SendStart(void)
{
I2C_GenerateSTART(I2C2,ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
{
//可以加入超时退出机制
}
}
/*
函数功能: 停止信号
当时钟线为高电平的时候,数据线由低电平变为高电平的过程
*/
void IIC_SendStop(void)
{
I2C_GenerateSTOP(I2C2,ENABLE);
delay_ms(5);
}
void IIC_SendAddr(u8 addr)
{
I2C_SendData(I2C2,addr);//发送数据(地址)
while(!I2C_CheckEvent(I2C2, I2C_FLAG_ADDR&0xFFFFFF))//等待地址发送完成
{
//可以加入超时退出机制
}
}
/*
函数功能: 发送数据
*/
void IIC_SendOneByte(u8 addr)
{
I2C_SendData(I2C2,addr);//发送数据
while(!I2C_CheckEvent(I2C2, I2C_FLAG_BTF&0xFFFFFF))//等待发送完成
{
//可以加入超时退出机制
}
}
/*
函数功能: 接收一个字节数据
*/
u8 IIC_RecvOneByte(void)
{
u8 data=0;
I2C_AcknowledgeConfig(I2C2,ENABLE);//使能应答
while(!I2C_CheckEvent(I2C2, I2C_FLAG_RXNE&0xFFFFFF))//等待数据
{
//可以加入超时退出机制
}
data=I2C_ReceiveData(I2C2);//接收数据
I2C_AcknowledgeConfig(I2C2,DISABLE);//关闭应答使能
return data;
}
/*
函数功能: 写一个字节
函数参数:
u8 addr 数据的位置(0~1023)
u8 data 数据范围(0~255)
*/
void AT24C08_WriteOneByte(u16 addr,u8 data)
{
u8 read_device_addr=AT24C08_READ_ADDR;
u8 write_device_addr=AT24C08_WRITE_ADDR;
if(addr<256*1) //第一个块
{
write_device_addr|=0x0<<1;
read_device_addr|=0x0<<1;
}
else if(addr<256*2) //第二个块
{
write_device_addr|=0x1<<1;
read_device_addr|=0x1<<1;
}
else if(addr<256*3) //第三个块
{
write_device_addr|=0x2<<1;
read_device_addr|=0x2<<1;
}
else if(addr<256*4) //第四个块
{
write_device_addr|=0x3<<1;
read_device_addr|=0x3<<1;
}
addr=addr%256; //得到地址范围
IIC_SendStart();//起始信号
IIC_SendAddr(write_device_addr);//发送设备地址
IIC_SendOneByte(addr); //数据存放的地址
IIC_SendOneByte(data); //发送将要存放的数据
IIC_SendStop(); //停止信号
delay_ms(10); //等待写
}
/*
函数功能: 读一个字节
函数参数:
u8 addr 数据的位置(0~1023)
返回值: 读到的数据
*/
u8 AT24C08_ReadOneByte(u16 addr)
{
u8 data=0;
u8 read_device_addr=AT24C08_READ_ADDR;
u8 write_device_addr=AT24C08_WRITE_ADDR;
if(addr<256*1) //第一个块
{
write_device_addr|=0x0<<1;
read_device_addr|=0x0<<1;
}
else if(addr<256*2) //第二个块
{
write_device_addr|=0x1<<1;
read_device_addr|=0x1<<1;
}
else if(addr<256*3) //第三个块
{
write_device_addr|=0x2<<1;
read_device_addr|=0x2<<1;
}
else if(addr<256*4) //第四个块
{
write_device_addr|=0x3<<1;
read_device_addr|=0x3<<1;
}
addr=addr%256; //得到地址范围
IIC_SendStart();//起始信号
IIC_SendAddr(write_device_addr);//发送设备地址
IIC_SendOneByte(addr); //将要读取数据的地址
IIC_SendStart();//起始信号
IIC_SendAddr(read_device_addr);//发送设备地址
data=IIC_RecvOneByte();//读取数据
IIC_SendStop(); //停止信号
return data;
}
/*
函数功能: 从指定位置读取指定长度的数据
函数参数:
u16 addr 数据的位置(0~1023)
u16 len 读取的长度
u8 *buffer 存放读取的数据
返回值: 读到的数据
*/
void AT24C08_ReadByte(u16 addr,u16 len,u8 *buffer)
{
u16 i=0;
IIC_SendStart();//起始信号
IIC_SendAddr(AT24C08_WRITE_ADDR);//发送设备地址
IIC_SendOneByte(addr); //将要读取数据的地址
IIC_SendStart();//起始信号
IIC_SendAddr(AT24C08_READ_ADDR);//发送设备地址
for(i=0;i<len;i++)
{
buffer[i]=IIC_RecvOneByte();//读取数据
}
IIC_SendStop(); //停止信号
}
/*
函数功能: AT24C08页写函数
函数参数:
u16 addr 写入的位置(0~1023)
u8 len 写入的长度(每页16字节)
u8 *buffer 存放读取的数据
*/
void AT24C08_PageWrite(u16 addr,u16 len,u8 *buffer)
{
u16 i=0;
IIC_SendStart();//起始信号
IIC_SendAddr(AT24C08_WRITE_ADDR);//发送设备地址
IIC_SendOneByte(addr); //数据存放的地址
for(i=0;i<len;i++)
{
IIC_SendOneByte(buffer[i]); //发送将要存放的数据
}
IIC_SendStop(); //停止信号
delay_ms(10); //等待写
}
/*
函数功能: 从指定位置写入指定长度的数据
函数参数:
u16 addr 数据的位置(0~1023)
u16 len 写入的长度
u8 *buffer 存放即将写入的数据
返回值: 读到的数据
*/
void AT24C08_WriteByte(u16 addr,u16 len,u8 *buffer)
{
u8 page_byte=16-addr%16; //得到当前页剩余的字节数量
if(page_byte>len) //判断当前页剩余的字节空间是否够写
{
page_byte=len; //表示一次性可以写完
}
while(1)
{
AT24C08_PageWrite(addr,page_byte,buffer); //写一页
if(page_byte==len)break; //写完了
buffer+=page_byte; //指针偏移
addr+=page_byte;//地址偏移
len-=page_byte;//得到剩余没有写完的长度
if(len>16)page_byte=16;
else page_byte=len; //一次可以写完
}
}
24C08.H
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_EVAL_I2C_EE_H
#define __STM32_EVAL_I2C_EE_H
#include "sys.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void IIC_Init(void);
extern void AT24C08_WriteOneByte(u16 addr,u8 data);
extern u8 AT24C08_ReadOneByte(u16 addr);
extern void AT24C08_WriteByte(u16 addr,u16 len,u8 *buffer);
extern void AT24C08_ReadByte(u16 addr,u16 len,u8 *buffer);
#ifdef __cplusplus
}
#endif
#endif /* __STM32_EVAL_I2C_EE_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
再给大家一个main.C
#include "delay.h"
#include "sys.h"
#include "24C08.h"
//IIC 初始化PB10,PB11
void GPIO_Config_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能端口时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //AF功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化
}
uint8_t EEDATA;//单字节读写变量
uint8_t Sendbuff[17]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};//多字节写缓冲
uint8_t Recvbuff[17];//多字节读缓冲
//主函数,采用外部8M晶振,72M系统主频,可以在void SetSysClock(void)函数中选择主频率设置
int main(void)
{
delay_init(); //延时函数初始化,通过Systick中断实现1ms延时功能
GPIO_Config_Init(); //初始化IIC的GPIO口PB10,PB11,开漏
IIC_Init();//IIC初始化,配置速度为100K,I2C2
AT24C08_WriteOneByte(0,0x33);//0地址写入0x33
EEDATA= AT24C08_ReadOneByte(0);//从0地址读数据存到EEDATA
//AT24C08_WriteByte(0,17,Sendbuff);多字节读写示列
//AT24C08_ReadByte(0,17,Recvbuff);多字节读写示列
while(1)
{
}
}
代码的注释相对来说还是比较详细的,就不啰嗦的给大家介绍了!!!依旧是希望大家实验顺利哦。