ATK-MB014模块使用说明
这里以正点原子M48Z-M3最小系统板STM32F103版为例,给大家介绍一下模块和板卡的连接方法。其它板卡与模块的硬件连接方法,请大家在“ATK-MB014 EEPROM模块\3,程序源码\相应板卡例程文件夹\readme.txt”路径下查看。
EEPROM模块可通过杜邦线与正点原子M48Z-M3最小系统板STM32F103版进行连接,具体的连接关系,如下表所示:

表1.1.1 EEPROM模块与M48Z-M3最小系统板STM32F103版连接关系
在本实验中,串口会打印EEPROM模块的提示信息。需要查看这部分实验信息的用户,可用杜邦线将最小系统板STM32F103的PA9引脚和GND连接至外部的USB转串口设备,这样就可以通过XCOM上位机查看串口打印的信息了。
用户通过按键控制EEPROM的读写,按下KEY0控制24C02的写入,按下WKUP来控制24C02的读取。
开发板的LED0闪烁,提示程序运行。
打开本实验的工程文件夹,能够在./Drivers/BSP目录下看到ATK_24CXX文件夹,和IIC文件夹,其中ATK_24CXX文件夹中就包含了EEPROM模块的驱动文件,IIC文件夹中就包含了软件模拟IIC的驱动文件如下图所示:

图2.1.2.1 EEPROM模块驱动代码

图2.1.2.2 IIC驱动代码
下面将简要介绍atk_24cxx.c中几个重要的API 函数。
1. 函数atk_24cxx_write_one_byte ()
该函数实现在 AT24Cxx 芯片指定地址写入一个数据,具体的代码,如下所示:
/**
* @brief 在ATK_24CXX指定地址写入一个数据
* @param addr: 写入数据的目的地址
* @param data: 要写入的数据
* @retval 无
*/
void atk_24cxx_write_one_byte(uint16_t addr, uint8_t data)
{
/* 原理说明见:at24cxx_read_one_byte函数, 本函数完全类似 */
iic_start(); /* 发送起始信号 */
if (EE_TYPE > AT24C16) /* 24C16以上的型号, 分2个字节发送地址 */
{
iic_send_byte(0XA0); /* 发送写命令, IIC规定最低位是0, 表示写入 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr >> 8);/* 发送高字节地址 */
}
else
{
/* 发送器件 0XA0 + 高位a8/a9/a10地址,写数据 */
iic_send_byte(0XA0 + ((addr >> 8) << 1));
}
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr % 256); /* 发送低位地址 */
iic_wait_ack(); /* 等待ACK, 此时地址发送完成了 */
/* 因为写数据的时候,不需要进入接收模式了,所以这里不用重新发送起始信号了 */
iic_send_byte(data); /* 发送1字节 */
iic_wait_ack(); /* 等待ACK */
iic_stop(); /* 产生一个停止条件 */
delay_ms(10); /* EEPROM 写入比较慢,等10ms后再写下一个字节 */
}
从上述代码可以看出,该函数首先调用 iic_start 函数产生起始信号,然后调用 iic_send_byte 函数发送第 1 个字节数据设备地址,等待 24Cxx 设备返回应答信号;收到应答信号后,继续发送第 2 个 1 字节数据内存地址 addr;等待接收应答后,最后发送第 3 个字节数据写入内存地址的数据 data, 24Cxx 设备接收完数据,返回应答信号,主机调用 iic_stop 函数产生停止信号终止数据传输,最终需要延时 10ms,等待 eeprom 写入完毕。
2. 函数atk_24cxx_write_one_byte()
该函数主要实现在 AT24Cxx 芯片指定地址读出一个数据,具体代码,如下所示:
/**
* @brief 在ATK_24CXX指定地址读出一个数据
* @param readaddr: 开始读数的地址
* @retval 读到的数据
*/
uint8_t atk_24cxx_read_one_byte(uint16_t addr)
{
uint8_t temp = 0;
iic_start(); /* 发送起始信号 */
/* 根据不同的24CXX型号, 发送高位地址
* 1, 24C16以上的型号, 分2个字节发送地址
* 2, 24C16及以下的型号, 分1个低字节地址 + 占用器件地址的bit1~bit3位 用于表示高位地址, 最多11位地址
* 对于24C01/02, 其器件地址格式(8bit)为: 1 0 1 0 A2 A1 A0 R/W
* 对于24C04, 其器件地址格式(8bit)为: 1 0 1 0 A2 A1 a8 R/W
* 对于24C08, 其器件地址格式(8bit)为: 1 0 1 0 A2 a9 a8 R/W
* 对于24C16, 其器件地址格式(8bit)为: 1 0 1 0 a10 a9 a8 R/W
* R/W : 读/写控制位 0,表示写; 1,表示读;
* A0/A1/A2 : 对应器件的1,2,3引脚(只有24C01/02/04/8有这些脚)
* a8/a9/a10: 对应存储整列的高位地址, 11bit地址最多可以表示2048个位置,可以寻址24C16及以内的型号
*/
if (EE_TYPE > AT24C16) /* 24C16以上的型号, 分2个字节发送地址 */
{
iic_send_byte(0XA0); /* 发送写命令, IIC规定最低位是0, 表示写入 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr >> 8);/* 发送高字节地址 */
}
else
{
/* 发送器件 0XA0 + 高位a8/a9/a10地址,写数据 */
iic_send_byte(0XA0 + ((addr >> 8) << 1));
}
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
iic_send_byte(addr % 256); /* 发送低位地址 */
iic_wait_ack(); /* 等待ACK, 此时地址发送完成了 */
iic_start(); /* 重新发送起始信号 */
iic_send_byte(0XA1); /* 进入接收模式, IIC规定最低位是0, 表示读取 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
temp = iic_read_byte(0); /* 接收一个字节数据 */
iic_stop(); /* 产生一个停止条件 */
return temp;
}
该函数主机首先调用iic_start 函数产生起始信号,然后调用 iic_send_byte 函数发送第 1 个字节数据设备写地址,使用iic_wait_ack 函数等待 24Cxx 设备返回应答信号;收到应答信号后,继续发送第 2 个 1 字节数据内存地址 addr;等待接收应答后,重新调用 iic_start 函数产生起始信号,这一次的设备方向改变了,调用 iic_send_byte 函数发送设备读地址,然后使用 iic_wait_ack 函数去等待设备返回应答信号,同时使用 iic_read_byte 去读取从从机发出来的数据。由于 iic_read_byte 函数的形参是 0,所以在获取完 1 个字节的数据后,主机发送非应答信号,停止数据传输,最终调用 iic_stop函数产生停止信号,返回从从机 addr 中读取到的数据。
3. 函数atk_24cxx_read()和atk_24cxx_write()
为了方便多字节写入和读取,还定义了在指定地址读取指定个数的函数以及在指令地址写入指定个数的函数,代码如下:
/**
* @brief 在ATK_24CXX里面的指定地址开始读出指定个数的数据
* @param addr : 开始读出的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要读出数据的个数
* @retval 无
*/
void atk_24cxx_read(uint16_t addr, uint8_t *pbuf, uint16_t datalen)
{
while (datalen--)
{
*pbuf++ = atk_24cxx_read_one_byte(addr++);
}
}
/**
* @brief 在ATK_24CXX里面的指定地址开始写入指定个数的数据
* @param addr : 开始写入的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要写入数据的个数
* @retval 无
*/
void atk_24cxx_write(uint16_t addr, uint8_t *pbuf, uint16_t datalen)
{
while (datalen--)
{
atk_24cxx_write_one_byte(addr, *pbuf);
addr++;
pbuf++;
}
}
对于这两个函数都是调用前面的单字节操作函数去实现的,利用 for 循环,连续调用单字节操作函数去实现,这里就不多讲。
在图2.1.2.2中,myiic.c 和 myiic.h 为 IIC 驱动文件,使用软件的方式模拟IIC的通信时序。关于IIC的驱动介绍,请查看正点原子各个开发板对应的开发指南中IIC章节。
实验的测试代码为文件 demo.c,在工程目录下的 User 子目录中。测试代码的入口函数为 demo_run(),具体的代码,如下所示:
/* 要写入到24c02的字符串数组 */
const uint8_t g_text_buf[] = {"STM32 IIC TEST"};
#define TEXT_SIZE sizeof(g_text_buf) /* TEXT字符串长度 */
/**
* @brief 例程演示入口函数
* @param 无
* @retval 无
*/
void demo_run(void)
{
uint8_t key;
uint16_t i = 0;
uint8_t datatemp[TEXT_SIZE];
key_init(); /* 初始化按键 */
atk_24cxx_init(); /* 初始化24CXX */
while (atk_24cxx_check()) /* 检测不到24c02 */
{
printf("24C02 Check Failed!\r\n");
delay_ms(500);
LED0_TOGGLE(); /* 红灯闪烁 */
}
printf("24C02 Ready!\r\n");
while (1)
{
key = key_scan(0);
if (key == KEY0_PRES) /* KEY1按下,写入24C02 */
{
printf("Start Write 24C02....\r\n");
atk_24cxx_write(0, (uint8_t *)g_text_buf, TEXT_SIZE);
printf("24C02 Write Finished!\r\n"); /* 提示写入完成 */
}
if (key == WKUP_PRES) /* WKUP按下,读取字符串并显示 */
{
printf("Start Read 24C02.... \r\n");
atk_24cxx_read(0, datatemp, TEXT_SIZE);
printf("The Data Readed Is: %s\r\n", datatemp); /* 打印读到的字符串 */
}
i++;
if (i == 20)
{
LED0_TOGGLE(); /* 红灯闪烁 */
i = 0;
}
delay_ms(10);
}
}
demo_run函数的流程大致是:在demo_run 函数外部定义要写入 24C02 的字符串数组 g_text_buf。在完成用户级初始化工作后,检测 24c02 是否存在,然后通过 WKUP 去读取 0 地址存放得数据并把数据通过串口打印出来;另外还可以通过 KEY0去 0 地址处写入 g_text_buf 数据并在串口打印提示信息,完成后在串口打印“24C02 Write Finished!”。
将EEPROM模块按照第一节“硬件连接”中介绍的连接方式与开发板连接,并将实验代码编译烧录至开发板中,本实验使用串口输出调试信息,因此需将开发板的 PA9连接至 DAP 虚拟串口(或 USB 转 TTL 模块)的 RX引脚。完成连接后,可通过按键控制EEPROM读写,并通过串口调试助手查看实验信息输出,如下图所示:

图2.1.3.2 串口调试助手显示内容
当按下KEY0时,此时会将数组g_text_buf中的数据写入EEPROM模块。写入完成后,串口将打印提示信息。随后,按下WKUP,即可读取EEPROM地址0处的数据,并通过串口输出读取结果。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3078526/ ,如需转载,请注明出处,否则将追究法律责任。