在本文中,我们将解释如何与外部EEPROM沟通使用I2C通信协议的AVR ATMEGA32 MCU。因此,让我们开始使用AVR Atmega32的EEPROM(AT24C16A)接口教程。
你通常需要一个外部EEPROM.当你的系统有一组用户可配置的设置,你需要保存,即使当系统关机;这样系统在下次启动时就会以这些配置启动。
在这种情况下,使用外部EEPROM为您提供了具有更大存储空间的优势(而不是在Atmega32中的内部EEPROM内置),除了保持用户配置,即使MCU失败也是如此。
在本文中,我们将使用Atmel EEPROM AT24C16A。它是一个16K位存储器,组织成每个8位的2048字(2048字节)。它有8个大头针,如下图所示。
A0,A1和A2引脚应留下未连接此特定EEPROM.以下绘图显示如何将其引脚连接到ATMEGA32 I2C引脚。您必须确保引脚7(WP连接到地面),因为此引脚是硬件写保护,除非接地,否则不会允许对存储器的任何写入操作。
I2C通信协议
I2C是一种总线接口连接,其包含在许多设备中,例如传感器,RTC(实时时钟)和EEPROM。它也被称为双线串行接口(TWI),它是低速设备之间的通信,用于在短距离内可靠的通信。I2C协议仅使用2个引脚,一个用于时钟(SCL)和一个用于数据(SDA)。在Atmega32中,这些引脚是PIN22(SCL)和PIN23(SDA)。它们分别在I / O端口C引脚0和1上复用。
因此,我们将首先使用AVR微控制器配置和启动I2C协议,然后我们将学习如何与EEPROM通信。
I2C在AVR ATMEGA32上的配置:
为了激活I2C协议,在主模式下,在Atmega32上需要配置3个寄存器:TWBR、TWSR和TWCR。我们将再次使用TWCR寄存器(在本教程的后面阶段)来操作通信。
TWBR:TWI比特率寄存器:
R / W. | R / W. | R / W. | R / W. | R / W. | R / W. | R / W. | R / W. |
TWBR7 | TWBR6 | TWBR5 | TWBR4 | TWBR3 | TWBR2 | TWBR1 | TWBR0 |
这是一个7位的寄存器,其值用于确定数据将在两个通信设备之间交换的比特率。用来计算这个比特率的公式如下
其中(TWBR)是TWI比特率寄存器中的值,TWPS是TWSR寄存器中的2位(TWPS0)&(TWPS1)的值,这将在接下来解释。
出于本练习的目的,我们将把值0x07放在TWBR寄存器中。
TWSR: TWI状态寄存器:
R | R | R | R | R | R | R / W. | R / W. |
TWS7 | TWS6 | TWS5 | TWS4 | TWS3 | - - - - - - | TWPS1. | TWPS0. |
在该寄存器中,我们只需要配置用于确定如上所述的比特率的位(TWPS0和TWPS1)。上述等式中的TWP的值如下确定
TWPS1. | TWPS0. | TWPS. |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 2 |
1 | 1 | 3. |
在本文示例中,我们将把这些2位清除为零。
TWCR:TWI控制寄存器:
R / W. | R / W. | R / W. | R / W. | R | R / W. | 1 | R / W. |
TWINT | TWEA | TWSTA | TWSTO | TWWC | 差不多 | - - - - - - | Twe. |
该7位寄存器用于控制TWI的操作。现在,我们只需要设置差不多位(bit2),它启用I2C模块并覆盖其引脚(端口C引脚0和1)的I/O功能。
到目前为止已完成我们现在可以为I2C初始化写一个函数,如下所示:
void TWI_Init (void) {TWSR=0;TWBR = 0 x07;TWCR | =(1 < <差不多);}
I2C操作
为了开始使用I2C进行通信,您需要通过以下步骤进行:
- 通过控制TWI总线,通过将启动信号发送到自由时。
- 启动TWI数据传输
- 接收双胞胎数据。
- 停止传输并释放TWI总线。
我们将在下面详细解释这些步骤。
通过向其发送启动信号来控制TWI总线:
单片机作为TWI总线上的主人并对其进行控制,单片机感知到总线空闲,然后发出Start信号。这样做后,MCU捕获总线,其他设备不能发送数据,直到MCU释放总线,以避免数据冲突。之后,单片机就可以开始发送数据了。
在本节中,我们将为双线串行总线写入MCU的函数。
- 设置TWCR寄存器的TWEN位,确保I2C使能。
- 在TWCR寄存器的TWINT位上写1以清除中断标志。
当I2C模块完成其当前工作并准备从SW获取更多命令时,硬件将该位设置为1。此外,清除此位会立即启动I2C模块。因此,每次我们想要启动I2C模块时,必须确保首先清除这个位,并轮询它,直到它再次变为1,因为这表明I2C已经成功执行了任务。
注意:这个位永远不会被MCU硬件清除,你必须通过软件清除它。 - 向TWSTA寄存器中写入1。
设置该位使MCU在速率上发送总线上的起始信号,以声明MCU当前正在控制总线并开始传输数据。 - 轮询TWINT位(之前已清除),直到它变为1。一旦设置了这个位,就意味着MCU已经成功地将总线控制为一个主总线。
*投票:是启动只有当位的值更改为我们想要的值时才退出的无限循环。这在下面的代码中展示。
#define get_bit(reg,bitnum)((reg&(1 << bitnum))>> bitnum)//获取用于获得某个位的值的位宏。void twi_start(void){twcr =(1 << Twint)|(1 << TWSTA)|(1 << TWEN);while(get_bit(twcr,twint)== 0)//在twint = 0 {}}上轮询
2.启动TWI数据传输:
控制总线后,MCU可以向其发送信息。这通过以下步骤实现:
- 将您需要发送在TWI数据寄存器中的数据。
- 向TWCR寄存器的TWEN位写1,以确保I2C开启。
- 向TWCR寄存器的TWINT位写1,确保TWINT位被清除。
- 轮询Twint位(先前清除)直到变为1.一旦设置该位,就意味着传输完成。
下面是函数代码:
void TWI_Write (char data) {TWDR=data;TWCR = (1 < < TWINT) |(1 < <差不多);while (get_bit(TWCR,TWINT)==0) {}}
3.接收TWI数据:
接收TWI数据比传输更容易。您需要遵循以下步骤:
- 向TWCR寄存器的TWEN位写1,以确保I2C开启。
- 向TWCR寄存器的TWINT位写1,确保TWINT位被清除。
- 轮询Twint位直到它变为1。
- 从TWDR寄存器读取数据。
此功能如下所示编码:
void twi_read_nack(char * ptr)//函数参数是一个指向mcu中的内存位置的指针,以将所接收的数据存储在{twcr =(1 << Twint)|(1 << Twen)中;while(get_bit(twcr,twint)== 0){} * ptr = twdr;}
4.停止传输并释放TWI总线:
一旦完成数据传输,就应该释放总线,以便其他设备使用它。这是通过以下步骤实现的:
- 向TWCR寄存器的TWEN位写1,以确保I2C开启。
- 向TWCR寄存器的TWINT位写1,确保TWINT位被清除。
- 将1写入TWCR寄存器的TWSTO位,发送停止信号并释放总线。
代码如下:
空白TWI_Stop (void) {TWCR = (1 < < TWSTO) |(1 < <差不多)| (1 < < TWINT);}
EEPROM.
现在我们已经看到了在Atmega32上启动和操作I2C所需的所有功能,让我们看看如何将其与EEPROM一起使用。
EEPROM写数据
要将数据写入EEPROM,您需要使用MCU软件进行下面给出的步骤:
- 控制I2C总线。
- 发送EEPROM的从地址。其构造如下:
- 地址的前4位是1010
- 接下来的3位表示内存页码。
- 最后一位指示内存操作是否是读取或写入。(写作)
7 6 5 4 3. 2 1 0 1 0 1 0 P2. P1. P0. 读/写指示器
- 再次发送开始信号
- 发送内存地址以读取。
- 接收从EEPROM读取的数据。
- 发送停止信号释放I2C总线。
此功能可以编码如下:
void EEPROM_Read (char address, char* ptr) //函数参数是EEPROM中读取的地址和MCU中存储读取数据的内存位置的指针{TWI_Start();TWI_Write (0 xa8);TWI_Write(地址);TWI_Start ();TWI_Write (0 xa9);TWI_Read_Nack (ptr);TWI_Stop ();}
现在,让我们把所有的作品放在一起!
下面的程序结合了我们上面写的所有功能,并使用它们对EEPROM的值写入EEPROM,再次检索它,将检索到的数据与写入写入的数据进行比较,如果它们相等(这应该是情况),将检索到的数据与绿色LED进行比较。
#define f_cpu 8000000ul #define get_bit(reg,bitnum)((reg&(1 << bitnum))>> bitnum)//获取用于获得某个位值的位宏。#include#include void twi_init(void);void twi_start(void);void twi_stop(void);void twi_write(char数据);void twi_read_nack(char * ptr);void EEPROM_WRITE(CHAR数据,CHAR地址);void EEPROM_READ(CHAR地址,CHAR * PTR);void twi_init(void){// set_bit(twcr,6);TWSR = 0; TWBR=0x07; TWCR|=(1< EEPROM与ATmega32连接的照片(在PCB上)
演示视频
评论被关闭。