【GD32F303红枫派使用手册】第二十一节 I2C-EEPROM读写实验

21.1 实验内容

通过本实验主要学习以下内容:

  • AT24C16 EEPROM的工作原理;
  • IIC模块原理以及IIC驱动原理。

21.2 实验原理

21.2.1 AT24C16 EEPROM的工作原理

下图为AT24CXX系列EEPROM相关参数,由该图可知,AT24C16的存储容量为16Kbit,共2048字节,共128页,每页为16字节。

由下图可知,AT24C16由8块组成,每块256字节。

I2C开始信号后,第一个字节为器件地址,由1010+3位块地址+1位读写标志组成, 3位块地址刚好可以表示 8个块, 所以一次写完256字节,换到下一下块的时候,要重新更改器件地址。

AT24C16支持页写入模式,一次最多可支持写入16字节。主机每发送一个字节,24c16收到确认,内部地址递增(仅限低4bit,所以1次可写16字节)。

21.2.2 IIC接口原理

GD32F30X系列MCU的I2C 接口模块实现了I2C 协议的标速模式,快速模式以及快速+模式,具备CRC 计算和校验功能、支持 SMBus(系统管理总线)和PMBus(电源管理总线),此外还支持多主机 I2C 总线架构,其主要特性如下:

◼ 并行总线至 I2C 总线协议的转换及接口;
◼ 同一接口既可实现主机功能又可实现从机功能;
◼ 主从机之间的双向数据传输;
◼ 支持 7 位和 10 位的地址模式和广播寻址;
◼ 支持 I2C 多主机模式;
◼ 支持标速(最高 100 KHz),快速(最高 400 KHz)和快速+ 模式(最高 1MHz);
◼ 从机模式下可配置的 SCL 主动拉低;
◼ 支持 DMA 模式;
◼ 兼容 SMBus 2.0 和 PMBus;
◼ 两个中断:字节成功发送中断和错误事件中断;
◼ 可选择的 PEC(报文错误校验)生成和校验。  

IIC模块结构框图如下所示。

 

21.3 硬件设计

EEPROM硬件电路图如下所示,IIC引脚使用PB10和PB11引脚,SDA和SCL总线通过4.7K电阻上拉,且对地接30pf电容以及100欧姆串阻滤波。

21.4 代码解析

21.4.1 EEPROM初始化配置函数

EEPROM初始化配置函数如下,主要实现对IIC总线引脚配置以及IIC模块配置。

C
void bsp_eeprom_init_AT24C16(void)
{driver_i2c_init(&EEPROM_I2C);
}
void driver_i2c_init(typdef_i2c_struct *i2cx)
{rcu_periph_clock_enable(i2cx->rcu_i2c_x);i2c_deinit(i2cx->i2c_x);driver_gpio_general_init(i2cx->i2c_scl_gpio);driver_gpio_general_init(i2cx->i2c_sda_gpio);        /* I2C clock configure */i2c_clock_config(i2cx->i2c_x, i2cx->frequency, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(i2cx->i2c_x, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, i2cx->slave_addr);/* enable I2C0 */i2c_enable(i2cx->i2c_x);/* enable acknowledge */i2c_ack_config(i2cx->i2c_x, I2C_ACK_ENABLE);    
}

21.4.2 EEPROM buf写入接口函数

EEPROM buf写入接口函数实现如下,通过该函数可实现对AT24C16任意地址的多字节写入。内部已根据地址和写入长度自动识别从机地址以及对应的块,然后写入正确的地址空间。

C
EEPROM_STATE eeprom_buffer_write_AT24C16(uint8_t* p_buffer, uint16_t write_address, uint16_t number_of_byte)
{uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;uint8_t deviceId;address = write_address % I2C_PAGE_SIZE;count = I2C_PAGE_SIZE - address;number_of_page =  number_of_byte / I2C_PAGE_SIZE;number_of_single = number_of_byte % I2C_PAGE_SIZE;if(write_address+write_address>EEPROM_SIZE){return EEPROM_ERROR;}/* if write_address is I2C_PAGE_SIZE aligned  */if(0 == address){while(number_of_page--){deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer,I2C_PAGE_SIZE) == DRV_ERROR){return EEPROM_ERROR;}                                                        if(eeprom_wait_standby_state(&EEPROM_I2C) == EEPROM_ERROR){return EEPROM_ERROR;}write_address +=  I2C_PAGE_SIZE;p_buffer += I2C_PAGE_SIZE;}if(0 != number_of_single){deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer, number_of_single)==DRV_ERROR){return EEPROM_ERROR;}if(eeprom_wait_standby_state(&EEPROM_I2C) == EEPROM_ERROR){return EEPROM_ERROR;}}return         EEPROM_SUCCESS;                        }else{/* if write_address is not I2C_PAGE_SIZE aligned */if(number_of_byte < count){ deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer, number_of_byte)==DRV_ERROR){return EEPROM_ERROR;}if(eeprom_wait_standby_state(&EEPROM_I2C)==EEPROM_ERROR){return EEPROM_ERROR;}}else{number_of_byte -= count;number_of_page =  number_of_byte / I2C_PAGE_SIZE;number_of_single = number_of_byte % I2C_PAGE_SIZE;if(0 != count){deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer, count)==DRV_ERROR){return EEPROM_ERROR;}if(eeprom_wait_standby_state(&EEPROM_I2C)==EEPROM_ERROR){return EEPROM_ERROR;}write_address += count;p_buffer += count;} /* write page */while(number_of_page--){deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer, I2C_PAGE_SIZE)==DRV_ERROR){return EEPROM_ERROR;}if(eeprom_wait_standby_state(&EEPROM_I2C)==EEPROM_ERROR){return EEPROM_ERROR;}write_address +=  I2C_PAGE_SIZE;p_buffer += I2C_PAGE_SIZE;}/* write single */if(0 != number_of_single){deviceId=(write_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((write_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_write(&EEPROM_I2C,deviceId,write_address,MEM_ADDRESS_8BIT,p_buffer, number_of_single)==DRV_ERROR){return EEPROM_ERROR;}if(eeprom_wait_standby_state(&EEPROM_I2C)==EEPROM_ERROR){return EEPROM_ERROR;}}}return         EEPROM_SUCCESS;        }  
}

 21.4.3 EEPROM buf读取接口函数

EEPROM buf读取接口函数实现如下,通过该函数可实现对EEPROM任意地址的多字节数据读取,内部也对读取的地址进行自动识别从机地址。

C
EEPROM_STATE eeprom_buffer_read_AT24C16(uint8_t* p_buffer, uint16_t read_address, uint16_t number_of_byte)
{uint8_t rNum=0; //读取的数据长度uint16_t lenLeft=number_of_byte;//剩余的数据长度uint8_t deviceId;//读取的器件地址if(read_address+number_of_byte>EEPROM_SIZE)//如果读取的长度加上读取地址超过了EEPROM的空间大小,则报错误{return EEPROM_ERROR;}/*calculate the current read position to know how many word can read continully*/rNum=16-read_address & 0x0F;if(rNum == 0)  rNum=16;rNum = lenLeft>=rNum ? rNum : lenLeft;//剩余未读字节数如果大于rNum, 则读rNum个,如果小于rNum,则一次读完了/*read the data from e2prom*/while(lenLeft){//这里计算页地址,当地址小于256时,右移8位会小于0,所以器件地址为基地址A1//如果读取的地址大于256时,右移8位则不会小于0,所以器件地址为 基地址A1 | 3位页地址deviceId=(read_address>>8)>0 ? (EEPROM_ADDR | (uint8_t)((read_address>>7)&0x0E)):EEPROM_ADDR ;if(driver_i2c_mem_poll_read(&EEPROM_I2C,deviceId,read_address,MEM_ADDRESS_8BIT,p_buffer,rNum)==DRV_ERROR){
//                        printf("i2c read error\r\n");return EEPROM_ERROR;}read_address+=rNum;//已经读了rNum个了,所以地址后移rNum个lenLeft-=rNum;//剩余未读数据减少rNum个p_buffer+=rNum;rNum=lenLeft>16? 16 : lenLeft;//如果剩余大于16个,则下次再读16个,如果小于,则一次读完}return EEPROM_SUCCESS;
}

21.4.4 EEPROM读写实验主函数

EEPROM读写实验主函数如下所示。通过该实验实现对AT24C16任意地址256字节的写入、读取以及校验测试。

C
int main(void)
{
          uint16_t i;
    uint8_t i2c_buffer_write[BUFFER_SIZE];
    uint8_t i2c_buffer_read[BUFFER_SIZE];
        
    bsp_eeprom_init_AT24C16();
    /* initialize i2c_buffer_write */
    for(i = 0;i < BUFFER_SIZE;i++){
        i2c_buffer_write[i]=i;
//        printf("0x%02X ",i2c_buffer_write[i]);
//        if(15 == i%16){
//            printf("\r\n");
//        }
    }
                
                if(eeprom_buffer_write_AT24C16(i2c_buffer_write,0x0153,BUFFER_SIZE)==EEPROM_SUCCESS)
                {
                        __nop();
                }
                if(eeprom_buffer_read_AT24C16(i2c_buffer_read,0x0153,BUFFER_SIZE)==EEPROM_SUCCESS)
                {
                        __nop();
                }
                    /* compare the read buffer and write buffer */
    for(i = 0;i < BUFFER_SIZE;i++){
        if(i2c_buffer_read[i] != i2c_buffer_write[i]){
                                        __nop();
//            printf("0x%02X ", i2c_buffer_read[i]);
//            printf("Err:data read and write aren't matching.\n\r");
//            return I2C_FAIL;
        }
        //printf("0x%02X ", i2c_buffer_read[i]);
//        if(15 == i%16){
//            printf("\r\n");
//        }
    }
                __nop();
//    printf("I2C-AT24C02 test passed!\n\r");
        while (1)
        {
        }
}

21.5 实验结果

将本实验历程烧录到红枫派开发板中,运行后,可通过串口打印测试结果,可实现对于AT24C16任意地址写入、读取以及校验。

由聚沃科技原创,来源于【红枫派开发板】第二十一讲 I2C-EEPROM读写实验 - 苏州聚沃电子科技有限公司 (gd32bbs.com) 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/32390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【D3.js in Action 3 精译】关于本书

文章目录 本书读者本书结构与路线图本书代码liveBook 在线论坛 D3.js 项目的传统开发步骤 本书读者 这本书适用于所有渴望在数据可视化工作中获得完全创意自由的人&#xff0c;从定制化的经典图表到创建独特的数据可视化布局&#xff0c;涵盖内容广泛&#xff0c;应有尽有。您…

重学java 80.Junit单元测试

我总是着急的解释我自己&#xff0c;却忘了厚爱无需多言 —— 24.6.21 一、Junit介绍 1.概述 Junit是一个单元测试框架,可以代替main方法去执行其他的方法 2.作用 可以单独执行一个方法,测试该方法是否能跑通 3.注意 Junit是第三方工具,所以使用之前需要导入jar包 二、J…

GraphQL vs REST:API设计的现代选择

随着技术的飞速发展&#xff0c;API&#xff08;应用程序接口&#xff09;设计成为了软件开发中不可或缺的一部分。REST&#xff08;Representational State Transfer&#xff09;和GraphQL作为两种主流的API设计风格&#xff0c;各自具有独特的优势和适用场景。本文将深入探讨…

idea导入项目右侧maven不显示的解决办法

不显示情况&#xff1a; 原因可能是读取项目出错&#xff0c;未正确加载pom文件造成的。 解决方案一&#xff1a; 关闭idea在项目目录中删除.idea文件夹重新打开项目&#xff0c;重新加载。 解决犯案二&#xff1a; 直接在pom文件中右键选择add as maven project。 解决方案三…

PythonWeb前端

摘要 学校的一门选修课&#xff0c;PythonWeb开发从入门到实践&#xff0c;用到的技术有Python,Flask,MySQL,前端三件套等&#xff0c;但因为是选修课&#xff0c;所以都只涉及到了一点点 Web前端基础 1.Web工作原理 概念&#xff1a; Web&#xff0c;万维网&#xff0c;一…

关于运用人工智能帮助自己实现英语能力的有效提升?

# 实验报告 ## 实验目的 - 描述实验的目标&#xff1a;自己可以知道&#xff0c;自己的ai学习方法是否可以有效帮助自己实现自己的学习提升。 预期结果&#xff1a;在自己利用科技对于自己进行学习的过程中&#xff0c;自己的成长速度应该是一个幂指数的增长 ## 文献回顾 根据…

Docker:centos79-docker-compose安装记录

1.安装环境&#xff1a;centos7.9 x86 2.安装最新版&#xff1a; [rootlocalhost ~]# curl -fsSL get.docker.com -o get-docker.sh [rootlocalhost ~]# sh get-docker.sh # Executing docker install script, commit: e5543d473431b782227f8908005543bb4389b8desh -c yum in…

记一次网站违规风险百度统计被禁用的经历及解决方法

今天登陆百度统计&#xff0c;提示&#xff1a;网站由于存在合规风险将被暂停使用百度统计服务。 为了满足法律法规及政府监管的最新规定和要求&#xff0c;保护广大网民的合法权益&#xff0c;您的网站由于存在合规风险将被暂停使用百度统计服务。违规域名&#xff1a;xxxxxx.…

IF膨胀时代,“水刊”当赢?2023热门“水刊”影响因子详解!

【欧亚科睿学术】 1 “四大水刊”详情 图片来源&#xff1a;欧亚科睿学术整理 “四大水刊”的影响因子均有所下跌&#xff0c;其中&#xff0c;曾经被列入中科院预警名单的期刊MEDICINE&#xff0c;其影响因子已是连续三年持续下降。从JCR分区来看&#xff0c;四本期刊分区均…

迈巴赫S480升级增强现实AR抬头显示hud比普通抬头显示HUD更好用吗

增强AR实景抬头显示HUD&#xff08;Augmented Reality Head-Up Display&#xff09;是一种更高级的驾驶辅助技术&#xff0c;相比于普通抬头显示HUD&#xff0c;它提供了更丰富、更具沉浸感的驾驶体验。以下是它比普通抬头显示HUD多的一些功能&#xff1a; • 信息呈现方式&am…

MySQL数据库笔记(二)

第一章 单行函数 1.1 什么是函数 函数的作用是把我们经常使用的代码封装起来,需要的时候直接调用即可。这样既提高了代码效率,又提高了可维护性。在SQL中使用函数,极大地提高了用户对数据库的管理效率。 1.2 定义 操作数据对象。 接受参数返回一个结果。 只对一行进行…

【React】AntD组件的使用--极客园--02.登录模块

基本结构搭建 实现步骤 在 Login/index.js 中创建登录页面基本结构在 Login 目录中创建 index.scss 文件&#xff0c;指定组件样式将 logo.png 和 login.png 拷贝到 assets 目录中 代码实现 pages/Login/index.js import ./index.scss import { Card, Form, Input, Button }…

Nginx - 反向代理、负载均衡、动静分离、底层原理(案例实战分析)

目录 Nginx 开始 概述 安装&#xff08;非 Docker&#xff09; 配置环境变量 常用命令 配置文件概述 location 路径匹配方式 配置反向代理 实现效果 准备工作 具体配置 效果演示 配置负载均衡 实现效果 准备工作 具体配置 实现效果 其他负载均衡策略 配置动…

VUE3脚手架工具cli配置搭建及创建VUE工程

1、VUE的脚手架工具(CLI&#xff09; 开发大型vue的时候&#xff0c;不能通过html编写一个大型的项目&#xff0c;这个时候需要用到vue的脚手架工具 通过vue的脚手架&#xff0c;可以快速的生成vue工程 1.1、安装nodejs和npm 【下载nodejs】 https://nodejs.org/en 【安装…

IDEA快速入门06-插件

六、插件 6.1 IDEA插件介绍和管理 手动演示IDEA中怎么下载插件&#xff0c;管理插件等。 File -> Settings -> Plugins 6.2 Alibaba Java Coding Guidelines 6.2.1 实时检查 6.2.2 主动检查 选中【项目名称】或者【某一个具体类】&#xff0c;右键点击【编码规约扫…

atcoder abc 358

A welcome to AtCoder Land 题目&#xff1a; 思路&#xff1a;字符串比较 代码&#xff1a; #include <bits/stdc.h>using namespace std;int main() {string a, b;cin >> a >> b;if(a "AtCoder" && b "Land") cout <&…

汽车OTA--Flash RWW属性为什么这么重要

目录 1. OTA与RWW 1.1 FOTA需求解读 1.2 什么是RWW 2.主流OTA方案 2.1 单Bank升级 2.2 基于硬件A\B SWAP的FOTA方案 2.3 基于软件实现的FOTA方案 3.小结 1. OTA与RWW 1.1 FOTA需求解读 CP AUTOSAR R19-11首次提出了FOTA的概念&#xff0c;针对FOTA Target ECU提出了多…

状态压缩DP——AcWing 291. 蒙德里安的梦想

状态压缩DP 定义 状态压缩DP是一种利用二进制数来表示状态的动态规划算法。它通过将状态压缩成一个整数&#xff0c;从而减少状态数量&#xff0c;提高算法效率。 运用情况 状态压缩DP通常用于解决具有状态转移和最优解性质的问题&#xff0c;例如组合优化、图论、游戏等问…

AI大眼萌探索 AI 新世界:Ollama 使用指南【1】

在人工智能的浪潮中&#xff0c;Ollama 的出现无疑为 Windows 用户带来了一场革命。这款工具平台以其开创性的功能&#xff0c;简化了 AI 模型的开发与应用&#xff0c;让每一位爱好者都能轻松驾驭 AI 的强大力量。大家好&#xff0c;我是AI大眼萌&#xff0c;今天我们将带大家…

GPT-4o一夜被赶超,Claude 3.5一夜封王|快手可灵大模型推出图生视频功能|“纯血”鸿蒙大战苹果AI|智谱AI“钱途”黯淡|月之暗面被曝进军美国

快手可灵大模型推出图生视频功能“纯血”鸿蒙大战苹果AI&#xff0c;华为成败在此一举大模型低价火拼间&#xff0c;智谱AI“钱途”黯淡手握新“王者”&#xff0c;腾讯又跟渠道干上了“美食荒漠”杭州&#xff0c;走出一个餐饮IPOGPT-4o一夜被赶超&#xff0c;Anthropic推出Cl…