【嵌入式】微芯旺KungFu32A156MQT使用I2C读取EEPROM AT24C02
相关资料
对于I2C,需要对GPIO的输出模式进行配置,以下是相关资料
(74条消息) IIC输出模式选择推挽输出还是开漏输出?_i2c是开漏输出还是推挽输出_wangdahang的博客-CSDN博客
(74条消息) IIC信号为什么要加上拉电阻_iic为什么加上拉电阻_小鱼教你模数电的博客-CSDN博客
[求助]请问STM32F4的GPIO管脚可以同时配置成输入、输出模式吗 - STM32/STM8单片机论坛 - ST MCU意法半导体官方技术支持论坛 - 21ic电子技术开发论坛
出现问题
出现的问题是I2C可以发送信号,但是接收不了信号,最后发现是GPIO口配置成了推挽模式,总线上无法实现线与功能。最后将GPIO设置为开漏模式,并上拉GPIO就解决了问题。
代码
首先是设置GPIO
//GPIOx设置为输出 //输入: GPIOx : 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。 // GpioPin : 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。 void Lp_Gpio_Output_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_Struct_Init(&GPIO_InitStructure); GPIO_InitStructure.m_Pin = GpioPin; GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED; //初始化 GPIO输出速度 GPIO_InitStructure.m_Mode = GPIO_MODE_OUT; //初始化 GPIO方向为输出 GPIO_InitStructure.m_PullUp = GPIO_PULLUP; //初始化 GPIO上拉 GPIO_InitStructure.m_PullDown = GPIO_NOPULL; //初始化 GPIO不下拉 GPIO_InitStructure.m_OpenDrain =GPIO_POD_OD; //初始化 GPIO为开漏 GPIO_Configuration(GPIOx,&GPIO_InitStructure); } //描述 : GPIOx设置为输入 //输入 : GPIOx : 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。 // GpioPin : 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。 void Lp_Gpio_Input_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin) { GPIO_Reset(GPIOx);//初始化复位GPIOx外设,使能GPIOx外设时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_Struct_Init(&GPIO_InitStructure); GPIO_InitStructure.m_Pin = GpioPin; GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED; //初始化 GPIO输出速度 GPIO_InitStructure.m_Mode = GPIO_MODE_IN; //初始化 GPIO方向为输入 GPIO_InitStructure.m_PullUp = GPIO_PULLUP; //初始化 GPIO上拉 GPIO_InitStructure.m_PullDown = GPIO_NOPULL; //初始化 GPIO不下拉 GPIO_InitStructure.m_OpenDrain =GPIO_POD_OD; //初始化 GPIO为开漏 GPIO_Configuration(GPIOx,&GPIO_InitStructure); }
iic代码
/* * Lp_Software_I2c.h * * Created on: 2023-2-22 * Author: l22200182 */ #ifndef LP_SOFTWARE_I2C_H_ #define LP_SOFTWARE_I2C_H_ #include <stdint.h> #include "Lp_Gpio.h" //设置GPIO #define SDA_GPIO_SFR GPIOF_SFR #define SDA_PIN_MASK GPIO_PIN_MASK_3 #define SCL_GPIO_SFR GPIOF_SFR #define SCL_PIN_MASK GPIO_PIN_MASK_2 //设置GPIO函数 void Lp_I2c_Set_SDA(BitAction BitsValue); //设置SDA输出 void Lp_I2c_Set_SCL(BitAction BitsValue); //设置SCL输出 BitAction Lp_I2c_Read_SDA(); //读取SDA输入 //I2C函数 void Lp_Software_I2c_Start(void); //产生I2C起始信号 void Lp_Software_I2c_Stop(void); //产生I2C停止信号 void Lp_Software_I2c_Ack(void); //产生ACK应答信号 void Lp_Software_I2c_Nack(void); //产生NACK非应答信号 uint8_t Lp_Software_I2c_Wait_Ack(void); //等待ACK应答信号到来 void Lp_Software_I2c_Write_Byte(uint8_t dat); //I2C发送一个字节 uint8_t Lp_Software_I2c_Read_Byte(uint8_t ack); //I2C读取一个字节 #endif /* LP_SOFTWARE_I2C_H_ */
/* * Lp_Software_I2c.c * * Created on: 2023-2-22 * Author: l22200182 */ #include "Lp_Software_I2c.h" //设置SDA电平 void Lp_I2c_Set_SDA(BitAction BitsValue){ Lp_Gpio_Set_Bit(SDA_GPIO_SFR,SDA_PIN_MASK,BitsValue); } //设置SCL电平 void Lp_I2c_Set_SCL(BitAction BitsValue){ Lp_Gpio_Set_Bit(SCL_GPIO_SFR,SCL_PIN_MASK,BitsValue); } //读取SDA电平 BitAction Lp_I2c_Read_SDA(){ return Lp_Gpio_Read_Bit(SDA_GPIO_SFR,SDA_PIN_MASK); } //产生I2C起始信号 void Lp_Software_I2c_Start(void) { Lp_I2c_Set_SDA(SET); systick_delay_us(10); Lp_I2c_Set_SCL(SET); systick_delay_us(10); Lp_I2c_Set_SDA(RESET); systick_delay_us(10); Lp_I2c_Set_SCL(RESET); systick_delay_us(10); } //产生I2C停止信号 void Lp_Software_I2c_Stop(void){ Lp_I2c_Set_SDA(RESET); systick_delay_us(10); Lp_I2c_Set_SCL(SET); systick_delay_us(10); Lp_I2c_Set_SDA(SET); systick_delay_us(10); } //产生ACK应答 void Lp_Software_I2c_Ack(void) { Lp_I2c_Set_SCL(RESET); Lp_I2c_Set_SDA(RESET); systick_delay_us(10); Lp_I2c_Set_SCL(SET); systick_delay_us(10); Lp_I2c_Set_SCL(RESET); } //产生NACK非应答 void Lp_Software_I2c_Nack(void) { Lp_I2c_Set_SCL(RESET); Lp_I2c_Set_SDA(SET); systick_delay_us(10); Lp_I2c_Set_SCL(SET); systick_delay_us(10); Lp_I2c_Set_SCL(RESET); } //等待应答信号到来 //输出: 1,接收应答信号失败 // 0,接收应答信号成功 uint8_t Lp_Software_I2c_Wait_Ack(void) { int time_temp=0; Lp_I2c_Set_SCL(SET); systick_delay_us(10); while(Lp_I2c_Read_SDA()) { time_temp++; if(time_temp>10000){ Lp_Software_I2c_Stop();//超时 return 1; } } Lp_I2c_Set_SCL(RESET); return 0; } //I2C发送一个字节 //输入: 要发送的字节 void Lp_Software_I2c_Write_Byte(uint8_t dat) { uint8_t i=0; Lp_I2c_Set_SCL(RESET); for(i=0;i<8;i++){ if((dat&0x80)>0) Lp_I2c_Set_SDA(SET); else Lp_I2c_Set_SDA(RESET); dat<<=1; systick_delay_us(10); Lp_I2c_Set_SCL(SET); systick_delay_us(10); Lp_I2c_Set_SCL(RESET); systick_delay_us(10); } } //I2C读取一个字节 //输入: ack :ack=1时发送ACK,ack=0发送Nack //输出: receive :读到的字节 uint8_t Lp_Software_I2c_Read_Byte(uint8_t ack) { uint8_t i=0,receive=0; for(i=0;i<8;i++ ){ Lp_I2c_Set_SCL(RESET); systick_delay_us(10); Lp_I2c_Set_SCL(SET); receive<<=1; if(Lp_I2c_Read_SDA())receive++; systick_delay_us(10); } if (!ack) Lp_Software_I2c_Nack(); else Lp_Software_I2c_Ack(); return receive; }
AT24C02代码
/* * AT24C02.h * * Created on: 2023-2-22 * Author: l22200182 */ #ifndef AT24C02_H_ #define AT24C02_H_ #include <stdint.h> #include "Lp_Software_I2c.h" #include "Lp_Usart.h" #define EEPROM_ADDRESS 0x0 void AT24C02_Write_One_Byte(uint8_t addr,uint8_t dat); //在AT24C02写入一个数据 uint8_t AT24C02_Read_One_Byte(uint8_t addr); //在AT24C02写入一个数据 void AT24C02_test(void); #endif /* AT24C02_H_ */
/* * AT24C02.c * * Created on: 2023-2-22 * Author: l22200182 */ #include "AT24C02.h" //在AT24C02写入一个数据 //输入: addr:写入数据的目的地址 // dat :要写入的数据 void AT24C02_Write_One_Byte(uint8_t addr,uint8_t dat) { Lp_Software_I2c_Start(); Lp_Software_I2c_Write_Byte(0XA0); Lp_Software_I2c_Wait_Ack(); Lp_Software_I2c_Write_Byte(addr); Lp_Software_I2c_Wait_Ack(); Lp_Software_I2c_Write_Byte(dat); Lp_Software_I2c_Wait_Ack(); Lp_Software_I2c_Stop(); systick_delay_ms(10); } //在AT24C02写入一个数据 //输入: 数据的地址 //返回: 读取的数据 uint8_t AT24C02_Read_One_Byte(uint8_t addr) { uint8_t temp=0; Lp_Software_I2c_Start(); Lp_Software_I2c_Write_Byte(0XA0); Lp_Software_I2c_Wait_Ack(); Lp_Software_I2c_Write_Byte(addr); Lp_Software_I2c_Wait_Ack(); Lp_Software_I2c_Start(); Lp_Software_I2c_Write_Byte(0XA1); Lp_Software_I2c_Wait_Ack(); temp=Lp_Software_I2c_Read_Byte(0); Lp_Software_I2c_Stop(); return temp; } void AT24C02_test(void){ Lp_Usart_Init(); //初始化Usart0串口 systick_delay_ms(250); uint8_t save_value=89; AT24C02_Write_One_Byte(EEPROM_ADDRESS,66); save_value=AT24C02_Read_One_Byte(EEPROM_ADDRESS); printf("%d\n",save_value); }
main函数
#include "main.h" int main(){ SystemInit(120); //初始化时钟 systick_delay_init(120); //初始化延时 Lp_Usart_Init(); //初始化Usart0串口 systick_delay_ms(100); AT24C02_Write_One_Byte(EEPROM_ADDRESS,66); //写入 systick_delay_ms(100); uint8_t save_value=AT24C02_Read_One_Byte(EEPROM_ADDRESS); //读取 printf("%d\n",save_value); while(1){ } }
如果没有串口,可以直接用DEBUG查看save_value的数值
标签:
嵌入式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了