【嵌入式】微芯旺KungFu32A156MQT使用I2C读取EEPROM AT24C02

相关资料

对于I2C,需要对GPIO的输出模式进行配置,以下是相关资料

(74条消息) IIC输出模式选择推挽输出还是开漏输出?_i2c是开漏输出还是推挽输出_wangdahang的博客-CSDN博客

(74条消息) 模拟IIC——关于模拟IIC的IO口的配置选取推挽输出还是开漏输出,以及是否需要更改IO口输入输出模式和是否需要对IO配置上拉_51传统io用作iic要上拉吗_我和你拼了'的博客-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的数值

posted @ 2023-02-22 09:33  海底淤泥  阅读(310)  评论(0编辑  收藏  举报