×
嵌入式 > 技术百科 > 详情

【青风带你学stm32f051系列教程】第11课 I2C读写EEPROM

发布时间:2020-06-17 发布时间:
|

I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。

只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL;串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器; 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;

I2C的使用实际上是严格遵循I2C总线协议进行的,下面我们结合STM32F051一一进行分析:

首先看I2C总线硬件:

硬件准备:

青风STM32F051开发板采用从机挂24c02,24c02是比较常见的eeprom,具有标志的

i2c总线,通过SCL和SDA和stm32f051上的PB8 和PB9相连。

SCL(serial clock):称为串行时钟线

SDA(serial data ):称为串行数据线

那么如下图所示,i2c总线上在传输数据的时候具有四种类型信号:分别为开始信号,停止信号,重新开始信号和应答信号。

开始信号Start:此时SCL处于高电平,SDA由高电平跳转到低电平,产生开始信号。

停止信号Stop:SCL同样需要处于高电平,SDA则由低电平跳转到高电平,产生停止信号

重新开始信号:它本质上是一个开始信号,信号电平和开始信号一样,是在连续传输信号时进行使用。

应答信号:接收数据的IC在接收到8位数据后,会向主设备发出一个特定的低电平脉冲,这就是应答信号。应答信号一般在第9个周期出现,每位信号必须跟一位应答信号,表示数据已经接收。

如下图所示:

上面两个图表示了数据连续传输的基本格式,那么下面我们就来学习如何通过I2C对24c02进行读写。

软件准备:

采样库函数编写程序,工程配置如下图所示,用户需要调用stm32f0xx_i2c.c库函数。需要编写i2c_eeprom.c驱动文件和主函数main.c。

首先谈谈24C02的驱动函数i2c_eeprom,c的编写,串行E2PROM是基于I2C-BUS 的存储器件,遵循二线制协议,由于其具有接口方便,体积小,数据掉电不丢失等特点。对于只用一片24C02器件的系统,因为不需要分辨不同的地址,只要WP保护功

能正常就可以了,这只要断开WP与CPU连线且保持高电平,再试一下系统数据读写功能是否正常就可以了。ATMEL24C02为标准的芯片Twr实际在2ms左右。

首先需要对stm32f051的i2c接口进行初始化,如下代码,首先对IO端口进行配置:

[c]
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);//使能GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE); //使能i2c时钟

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//配置端口复用
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOB , &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB , &GPIO_InitStruct);
GPIO_PinAFConfig( GPIOB , GPIO_PinSource8, GPIO_AF_1);
GPIO_PinAFConfig( GPIOB ,GPIO_PinSource9, GPIO_AF_1); //设置复用通道
}

 


[/c]
IO端口的复用设置好后,需要配置I2C的一些基本参数,这些参数在stm32f0xx_i2c.h文档中通过结构体进行了定义,如下面代码:
[c]

typedef struct
{
uint32_t I2C_Timing; //i2c时钟配置
uint32_t I2C_AnalogFilter; //i2c模拟滤波
uint32_t I2C_DigitalFilter; //i2c数字滤波
uint32_t I2C_Mode; //i2c模式配置
uint32_t I2C_OwnAddress1; //设备地址配置
uint32_t I2C_Ack; //i2c应答
uint32_t I2C_AcknowledgedAddress; //i2c确定是7bit或者10bit应答地址
}I2C_InitTypeDef;

[/c]
在编写24c02的驱动文件时,按照上面的结构体进行配置,可以配置为如下情况:
[c]


void I2C_Configuration(void)//i2c的初始化
{
I2C_InitTypeDef I2C_InitStruct;

I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;//配置模式
I2C_InitStruct.I2C_AnalogFilter = I2C_AnalogFilter_Enable;//使能模拟噪声滤波
I2C_InitStruct.I2C_DigitalFilter = 0x00;
I2C_InitStruct.I2C_OwnAddress1 =0x00;
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;//使能应答
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //配置格式为7bit
I2C_InitStruct.I2C_Timing = 0x00210507;//设置时钟寄存器的值
I2C_Cmd(I2C1, ENABLE);//使能i2c
I2C_Init(I2C1, &I2C_InitStruct);//调入结构体
}

 

[/c]
按照上面的要求配置好了i2c的端口后,下一步就是考虑如何通过i2c进行读写了,下图是i2c主机从从机读数据的过程:

首先是开始信号,然后发送从机地址,写选通,给一个应答信号。然后写入要访问的地址。

再次应答。从新开始信号,发送从机地址,从机地址是外挂总线地址。然后读选通,主机等待从机的应答信号,当接收应答后,开始读取数据。

而24C02写和读是按照页进行。而按页写最大页面不超过8个字节,超过后会发送覆盖。此时采用缓冲进行处理和分配,下面几个函数就是写缓冲和写页面:

[c]

uint32_t sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead);

[/c]

读缓冲函数:uint8_t* pBuffer:缓冲指针。

uint16_t ReadAddr:读的地址。

uint16_t* NumByteToRead:读字节数

[c]

uint32_t sEE_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite);

[/c]

写页函数:uint8_t* pBuffer, 缓冲指针

uint16_t WriteAddr, 写的地址

uint8_t* NumByteToWrite 写字节数

[c]

void sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite);

[/c]

写缓冲函数:uint8_t* pBuffer, 缓冲指针

uint16_t WriteAddr, 写的地址

uint8_t* NumByteToWrite 写字节数

[c]

uint32_t sEE_WaitEepromStandbyState(void);

[/c]

等待EEPROM待机状态

主函数首先向24c02写入一个数据,然后读出这个数据。对比两个数据是否一样,判断读写是否正确:

[c]

uint8_t temp1[]="qfstm32";

uint8_t temp2[];
int main(void)

{
SystemInit();
LCD_init(); // 液晶显示器初始化

LCD_Clear(WHITE); // 全屏显示白色
POINT_COLOR = BLACK; // 定义笔的颜色为黑色
BACK_COLOR = WHITE; // 定义笔的背景色为白色
I2C_EE_Init();
SPI_FLASH_Init();
LCD_DrawRectage(0, 0, 320, 20, DARKBLUE); // 画一个深蓝色边框的矩形

LCD_ShowString(2,2,"实验十一");
LCD_ShowString(100,2,"i2c读24c02实验");
sEE_WriteBuffer(temp1, 0x050, 8);
LCD_ShowString(2,40,"24c02写入值:");
LCD_ShowString(100,40,temp1);
NumDataRead=8;
sEE_ReadBuffer(temp2, 0x050,(uint16_t *)(&NumDataRead));
LCD_ShowString(2,60,"24c02读出值:");
LCD_ShowString(100,60,temp2);

if(*temp1 != *temp2)
{
LCD_ShowString(50,80,"读取EEROR");
}
else
{
LCD_ShowString(50,80,"读取sccess");
}

while(1)
{}
}

 

[/c]

实验现象:

整个操作的显示如下:

 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
分拣机器人的工作原理是什么