STM32G030C8T6:EEPROM读写实验(I2C通信)

2024-05-10 02:12

本文主要是介绍STM32G030C8T6:EEPROM读写实验(I2C通信),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本专栏记录STM32开发各个功能的详细过程,方便自己后续查看,当然也供正在入门STM32单片机的兄弟们参考;

本小节的目标是,系统主频64 MHZ,采用高速外部晶振,实现PB11,PB10 引脚模拟I2C 时序,对M24C08 的EEPROM 进行读。
原理:通过模拟I2C接(PB10:CLK,PB11:DTA)与M24C08 EEPROM进行读写实验。
涉及到的知识:配置I2C通信,STM32CubeMX的使用

文章目录

  • 1 新建工程
  • 2 配置SWD下载引脚
  • 3 配置RCC
  • 4 设置系统主频
  • 5 生成工程
  • 6 增加代码实现PB10,PB11 模拟I2C 时序,从而实现EEPROM数据读写

1 新建工程

点击File 菜单下的New Project

在这里插入图片描述

选择芯片型号,如下图所示先输入芯片型号,目前这边输入STM32G030C8,

在这里插入图片描述

双击选择,就确定了芯片型号,界面会变成如下图所示

在这里插入图片描述

2 配置SWD下载引脚

如下图所示,在Pinout&Configuration 栏目的System Core 下,先点击SYS,再勾选Serial Wire 框,
配置好SWD 下载引脚设置:

在这里插入图片描述

3 配置RCC

如下图,先点击RCC,在HSE 配置中选择Crystal/Ceramic Resonator 外部晶振设

在这里插入图片描述

4 设置系统主频

如下图, 先点击Clock Configuration 栏目,按下图的1,2,3,4 步骤完成系统64MHZ 主频设置:

在这里插入图片描述

5 生成工程

按照下图的步骤,进行项目配置,项目名称和路径设置等,生成项目的类型选择STM32CubeIDE(我这里以STM32CubeIDE为例,如果你要试用keil5,那就选择MDK-RAM,如果要使用makefile,就选择Makefile),注意项目名称和路径不要有中文名;
在这里插入图片描述

最后全部设置完毕后点击create code,生成项目代码:

在这里插入图片描述

生成的工程如下图所示:
在这里插入图片描述

6 增加代码实现PB10,PB11 模拟I2C 时序,从而实现EEPROM数据读写

如下图所示,在Core/Src下面增加24C08.c 文件,里面是用I/O 口模拟I2C 总线实现EEPROM读写驱动。

在这里插入图片描述

24C08.h:
/*
**------------------------------------------------------------------------------------------------------
** Modified by:			
** Modified date:	
** Version:
** Descriptions:		
********************************************************************************************************/
#ifndef __24C02_H
#define __24C02_H/* Includes ------------------------------------------------------------------*//* Private define ------------------------------------------------------------*/
#define AT24C01A		/* 24C01A,I2C时序和往后的24C02一样 */
//#define AT24C01		/* 24C01,I2C的时序和普通的有点不同 */#define ADDR_24LC02		0xA0
#define I2C_PAGESIZE	4		/* 24C01/01A页缓冲是4个 *//* Private function prototypes -----------------------------------------------*/
void I2C_Configuration(void);
uint8_t I2C_Read(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num);
uint8_t I2C_Write(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num);#endif /*********************************************************************************************************END FILE
*********************************************************************************************************/
24C08.c/***************************************************************************//**文件: 24C08.c作者: Zhengyu https://gzwelink.taobao.com版本: V1.0.0时间: 20200401平台:MINI-G030C8T6*******************************************************************************/#include "main.h"#define	EE_ADDR 0xa0//EEPROM地址,地址管脚全接地,为0xA0
#define EE_SCL_PIN  GPIO_PIN_10   //模拟IIC的SCL信号  1.修改引脚即可修改IIC接口
#define EE_SDA_PIN  GPIO_PIN_11   //模拟IIC的SDA信号
#define EE_IIC_SCL(val)         HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10,val)                    //SCL 输出高或者低     2.修改引脚即可修改IIC接口        
#define EE_IIC_SDA(val)         HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11,val)                    //SDA 输出高或者低 void EE_SDA_IN(void) 	//PB11配置成输入  {  __HAL_RCC_GPIOB_CLK_ENABLE();//GPIO时钟使能GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_11;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
} 
void EE_SDA_OUT(void)//PB11配置成开漏输出
{__HAL_RCC_GPIOB_CLK_ENABLE();//GPIO时钟使能GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_11;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);}void EE_SCK_OUT(void) //PB10配置成开漏输出
{__HAL_RCC_GPIOB_CLK_ENABLE();//GPIO时钟使能GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}//读DATA引脚状态
unsigned char EE_READ_SDA(void)
{
return HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11);
}	/******************************************************************************
*函  数:void EE_IIC_Delay(void)
*功 能:IIC延时
*参  数:无
*返回值:无
*备  注: 移植时只需要将EE_IIC_Delay()换成自己的延时即可,目前是在16M主频下运行,大约等待10us
*******************************************************************************/	
void EE_IIC_Delay(uint16_t us)
{uint16_t j;for(j=0;j<us;j++){for(int i = 0; i < 20; i++)    {__asm("NOP");//等待1个指令周期,系统主频16M}}}
/******************************************************************************
*函  数:void IIC_Init(void)
*功 能:IIC初始化
*参  数:无
*返回值:无
*备  注:无
*******************************************************************************/void EE_IIC_Init(void)
{			EE_SCK_OUT();//CLK引脚配置成输出EE_SDA_OUT();//DATA引脚配置成输出EE_IIC_SCL(1);//CLK引脚输出高EE_IIC_SDA(1);//DATA引脚输出高   
}
//开始	
void EE_IIC_Start(void)
{EE_SDA_OUT(); //DATA引脚配置成输出EE_IIC_SDA(1);//DATA引脚输出高	EE_IIC_SCL(1);//CLK引脚输出高EE_IIC_Delay(4);//等待大约40usEE_IIC_SDA(0); //DATA引脚输出低EE_IIC_Delay(4);//等待大约40usEE_IIC_SCL(0); //CLK引脚输出低,钳住I2C总线,准备发送或接收数据 
}//停止	  
void EE_IIC_Stop(void)
{EE_SDA_OUT(); //DATA引脚配置成输出EE_IIC_SCL(0);//CLK引脚输出低EE_IIC_SDA(0); //DATA引脚输出低EE_IIC_Delay(4);//等待大约40usEE_IIC_SCL(1); //CLK引脚输出高EE_IIC_SDA(1); //DATA引脚输出高,发送I2C总线结束信号EE_IIC_Delay(4);//等待大约40us							   	
}//等待应答
uint8_t EE_IIC_WaitAck(void)
{uint8_t ucErrTime=0;EE_SDA_IN(); //DATA引脚配置成输入  (从机给一个低电平做为应答) EE_IIC_SDA(1);EE_IIC_Delay(1);	   EE_IIC_SCL(1);EE_IIC_Delay(1);//等待约10us while(EE_READ_SDA())//一直读,直到读取到低电平应答{ucErrTime++;if(ucErrTime>250){EE_IIC_Stop();return 1;}}EE_IIC_SCL(0); //时钟输出0 	   return 0;  
} //发送应答
void EE_IIC_Ack(void)
{EE_IIC_SCL(0);EE_SDA_OUT();EE_IIC_SDA(0);EE_IIC_Delay(1);EE_IIC_SCL(1);EE_IIC_Delay(2);EE_IIC_SCL(0);
}//发送非应答
void EE_IIC_NAck(void)
{EE_IIC_SCL(0);EE_SDA_OUT();EE_IIC_SDA(1);EE_IIC_Delay(1);EE_IIC_SCL(1);EE_IIC_Delay(1);EE_IIC_SCL(0);
}					 				     //发送一个字节	  
void EE_IIC_SendByte(uint8_t data)
{                        uint8_t t;   EE_SDA_OUT(); 	    EE_IIC_SCL(0); //拉低时钟开始数据传输for(t=0;t<8;t++){              EE_IIC_SDA((data&0x80)>>7);//发送数据EE_IIC_Delay(1);			EE_IIC_SCL(1);data<<=1;EE_IIC_Delay(1);EE_IIC_SCL(0);	   }EE_IIC_Delay(1);
} 	 //读取1字节	
uint8_t EE_IIC_ReadByte(uint8_t ack)
{uint8_t i,receive=0;EE_SDA_IN(); //SDA设置为输入模式 等待接收从机返回数据for(i=0;i<8;i++ ){EE_IIC_SCL(0); EE_IIC_Delay(1);EE_IIC_SCL(1);receive<<=1;if(EE_READ_SDA())receive++; //读取从机发送的电平,如果是高,就记录高EE_IIC_Delay(1); }					 if(ack)EE_IIC_Ack(); //发送ACK elseEE_IIC_NAck(); //发送nACK  return receive;
}//从EE指定地址读取一个字节
uint8_t EE_IIC_ReadByteFromSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t *buf)
{EE_IIC_Start();	EE_IIC_SendByte(I2C_Addr);	 //发送从机地址if(EE_IIC_WaitAck()) //如果从机未应答则数据发送失败{EE_IIC_Stop();return 1;}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_Start();EE_IIC_SendByte(I2C_Addr+1); //进入接收模式			   EE_IIC_WaitAck();*buf=EE_IIC_ReadByte(0);	   EE_IIC_Stop(); //产生一个停止条件return 0;
}//发送一个字节内容到EE指定地址
uint8_t EE_EE_IIC_SendByteToSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t data)
{EE_IIC_Start();EE_IIC_SendByte(I2C_Addr); //发送从机地址if(EE_IIC_WaitAck()){EE_IIC_Stop();return 1; //从机地址写入失败}EE_IIC_SendByte(reg); //发送寄存器地址EE_IIC_WaitAck();	  EE_IIC_SendByte(data); if(EE_IIC_WaitAck()){EE_IIC_Stop(); return 1; //数据写入失败}EE_IIC_Stop(); //产生一个停止条件return 0;
}

然后如下图所示,24C08.c 文件,主要是把SCL 引脚改成PB10,SDA引脚改成PB11,还有EEPROM 驱动所需的基本I/O 操作函数,还有实现时序所需的等待函数。

然后打开main.c文件,按照下图操作添加代码:

在这里插入图片描述

extern void EE_IIC_Init(void);
extern uint8_t EE_EE_IIC_SendByteToSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t data);
extern uint8_t EE_IIC_ReadByteFromSlave(uint8_t I2C_Addr,uint8_t reg,uint8_t *buf);
unsigned char EEDATA;//存放EEPROM读取出来的数据,1个字节

在这里插入图片描述

EE_IIC_Init();//EEPROM管脚初始化,配置管脚
EE_EE_IIC_SendByteToSlave(0xA0,0x00,0x55);//0地址存储0x55
HAL_Delay(10);//等待10ms
EE_IIC_ReadByteFromSlave(0xA0,0x00,&EEDATA);//从0地址读取1字节内容到EEDATA变量

然后编译,调试,查看EEDATA变量的值,结果如下图所示:

在这里插入图片描述
我们写进去的值时0x55,最后读出来的值是85'U',查一下ASCII码:

在这里插入图片描述
0x55对应的就是85'U',证明我们的结果是对的,证明此EEPROM读写实验成功。

这篇关于STM32G030C8T6:EEPROM读写实验(I2C通信)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/975141

相关文章

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

在Spring Boot中实现HTTPS加密通信及常见问题排查

《在SpringBoot中实现HTTPS加密通信及常见问题排查》HTTPS是HTTP的安全版本,通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护,下面通过本文给大家介绍在SpringB... 目录一、HTTPS核心原理1.加密流程概述2.加密技术组合二、证书体系详解1、证书类型对比2. 证书获

ShardingSphere之读写分离方式

《ShardingSphere之读写分离方式》:本文主要介绍ShardingSphere之读写分离方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录ShardingSphere-读写分离读写分离mysql主从集群创建 user 表主节点执行见表语句项目代码读写分

Python模拟串口通信的示例详解

《Python模拟串口通信的示例详解》pySerial是Python中用于操作串口的第三方模块,它支持Windows、Linux、OSX、BSD等多个平台,下面我们就来看看Python如何使用pySe... 目录1.win 下载虚www.chinasem.cn拟串口2、确定串口号3、配置串口4、串口通信示例5

基于C#实现MQTT通信实战

《基于C#实现MQTT通信实战》MQTT消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点,下面我们就来看看C#实现... 目录1、连接主机2、订阅消息3、发布消息MQTT(Message Queueing Telemetr

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文