历史上的今天
返回首页

历史上的今天

今天是:2024年11月26日(星期二)

正在发生

2018年11月26日 | STM32Cube MX 下IIC的配置与使用

2018-11-26 来源:eefocus

本文介绍了在STM32下的IIC的基本使用方法,通过对板载具备IIC接口EEPROM的读写,完成对IIC驱动程序的测试。


硬件平台:STM32F107VCT6开发板


软件平台:STM32Cube MX + MDK5.22


1. 进行STM32Cube MX的配置



配置PB6和PB7为输出模式,同时配置了USART1进行串口调试使用。然后生成工程。


2. 打开工程,可以看到GPIO的初始化状态



3. 模拟IIC驱动程序源文件代码


/**


  * @file  iic_dup.c


  * @brief IIC上层程序


  * @par   date        version    author    remarks


  *        2016-03-21  v1.0       zbt       初次创建


  *


  */

 


/** 头文件包含区 ------------------------------------------------ */


#include "iic_dup.h"


 

/** 私有宏(类型定义) -------------------------------------------- */ 


#define IIC1_SCL(pin_status)        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, pin_status);


#define IIC1_SDA(pin_status)        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, pin_status);


#define IIC1_SCL_IS_HIGH()          (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) != GPIO_PIN_RESET)


#define IIC1_SDA_IS_HIGH()          (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) != GPIO_PIN_RESET)

 

/** 私有变量 --------------------------------------------------- */

 

 

/** 外部变量 --------------------------------------------------- */

 

/** 私有函数原型 ----------------------------------------------- */


static void iic_delay(void);

 

/** 公有函数 --------------------------------------------------- */


/**


  * @brief  IIC启动


  * @param  None


  * @retval None


  * @note   当SCL处于高电平状态时,SDA出现一个下降沿


            即产生IIC启动信号


  */


void iic_start(void)


{

   

IIC1_SCL(GPIO_PIN_SET);


    /** SDA产生一个下降沿 */


    IIC1_SDA(GPIO_PIN_SET);


    iic_delay(); 

    

    IIC1_SDA(GPIO_PIN_RESET);


    iic_delay(); 


    IIC1_SCL(GPIO_PIN_RESET);   /**< 拉低准备发送数据 */


    iic_delay();   


}

 


/**


  * @brief  IIC停止


  * @param  None


  * @retval None


  * @note   当SCL处于高电平状态时,SDA出现一个上升沿


            即产生IIC停止信号


  */


void iic_stop(void)


{


    IIC1_SCL(GPIO_PIN_RESET);


    iic_delay();


    /** SDA产生一个上升沿 */


    IIC1_SDA(GPIO_PIN_RESET);


    iic_delay();

    

    IIC1_SCL(GPIO_PIN_SET);


    iic_delay();


    IIC1_SDA(GPIO_PIN_SET);


    iic_delay();


}

 

/**


  * @brief  IIC发送1byte数据


  * @param  None


  * @retval None


  * @note   


  */


void iic_sendbyte(uint8_t byte)


{


    uint8_t i;

    

    /** 发送一个字节的高7位 */

  

  for (i = 0; i < 8; i++)


    {


        if (byte & 0x80)


        {


            IIC1_SDA(GPIO_PIN_SET);


        }


        else


        {


            IIC1_SDA(GPIO_PIN_RESET);


        }


        

        iic_delay();


        IIC1_SCL(GPIO_PIN_SET);


        iic_delay();


        IIC1_SCL(GPIO_PIN_RESET)


        if (i == 7)


        {


            IIC1_SDA(GPIO_PIN_SET);


        }

        

        byte <<= 1;


        iic_delay();


    }      


}

 

/**


  * @brief  IIC读取1byte数据


  * @param  None


  * @retval None


  * @note             


  */


uint8_t iic_readbyte(void)


{


    uint8_t i;


    uint8_t recv_value = 0;

    

    IIC1_SDA(GPIO_PIN_SET);


    iic_delay();

    


    for (i = 0; i < 8; i++)


    {


        IIC1_SCL(GPIO_PIN_SET);


        iic_delay();


        recv_value <<= 1;


        if (IIC1_SDA_IS_HIGH())


        {


            recv_value |= 0x01;


        }


        else


        {


            recv_value &= ~0x01;


        }

        

        iic_delay();


        IIC1_SCL(GPIO_PIN_RESET);


    }

    


    return recv_value;


}

 

/**


  * @brief  IIC等待应答信号


  * @param  None


  * @retval ack_status: 应答状态,0表示应答,1表示设备无响应


  */


uint8_t iic_wait_ack(void)


{


    uint8_t ack_status = 0;

    


    /** 在等待应答信号之前,要释放总线,即将SDA置位 */


    IIC1_SDA(GPIO_PIN_SET);


    iic_delay();


    IIC1_SCL(GPIO_PIN_SET);


    iic_delay();

    

    if (IIC1_SDA_IS_HIGH())


    {    


        ack_status = 1;


        iic_stop();


    }


    else


    {


        ack_status = 0;


    }

    

    IIC1_SCL(GPIO_PIN_RESET);


    iic_delay();

    

    return ack_status;


}

 

/**


  * @brief  主机(主控制器)产生应答信号


  * @param  None


  * @retval None


  */


void iic_ack(void)


{


    IIC1_SDA(GPIO_PIN_RESET);


    iic_delay();

    

    IIC1_SCL(GPIO_PIN_SET);


    iic_delay();


    IIC1_SCL(GPIO_PIN_RESET);


    iic_delay();

    

    IIC1_SDA(GPIO_PIN_SET);


}

 

/**


  * @brief  主机(主控制器)产生不应答信号


  * @param  None


  * @retval None


  */


void iic_nack(void)


{


    IIC1_SDA(GPIO_PIN_SET);


    iic_delay();

    

    IIC1_SCL(GPIO_PIN_SET);


    iic_delay();


    IIC1_SCL(GPIO_PIN_RESET);


    iic_delay();


}

 

/**


  * @brief  检测IIC总线上的设备状态


  * @param  device_addr: 从机设备地址 


  * @retval ack_status: 0 (正常)or 1(异常)


  * @note   主机发送设备地址等待从机应答,若有从机正确的应答信号


            则表明IIC总线上挂接了设备,否则表示IIC总线上未检测到


            设备


  */


uint8_t iic_check_device_status(uint8_t device_addr)


{


    uint8_t ack_status;

    

    if (IIC1_SCL_IS_HIGH() && IIC1_SDA_IS_HIGH())


    {


        iic_start();

        

        iic_sendbyte(device_addr | IIC_WRITE);


        ack_status = iic_wait_ack();

 

        iic_stop();

        

        return ack_status;    


}

    

    return 1;


}

 

/** 私有函数 --------------------------------------------------- */


/**


  * @brief  用于模拟IIC时的简单延时


  * @param  None


  * @retval None


  */


static void iic_delay(void)


{


    uint8_t i = 0;


    uint8_t delay = 5;

    

    while (delay--)


    {


        i = 10;


        while (i--);


    }


}


4. AT24C02部分驱动代码


/**


  * @file  at24c02.c


  * @brief at24c02驱动程序


  * @par   date        version    author    remarks


  *        2016-03-21  v1.0       zbt       初次创建


  *


  */

 

/** 头文件包含区 ------------------------------------------------ */


#include "at24c02.h"


#include "iic_dup.h"

 

/** 私有宏(类型定义) -------------------------------------------- */ 


#define AT24C02_DEVICE_ADDR         0xA0


#define AT24C02_PAGE_SIZE           8


#define AT24C02_MEM_SIZE            256


#define AT24C02_ADDR_BYTE           1

 

/** 私有变量 --------------------------------------------------- */


uint8_t test_buffer[AT24C02_MEM_SIZE];

 

/** 外部变量 --------------------------------------------------- */

 

/** 私有函数原型 ----------------------------------------------- */


//static void AT24C02_ack(void);


static void AT24C02_error_handle(void);


static void AT24C02_read_test(void);


static void AT24C02_write_test(void);


static void AT24C02_erase_test(void);

 

/** 公有函数 --------------------------------------------------- */


/**


  * @brief  AT24C02与主控制器的IIC通讯测试代码


  * @param  None


  * @retval None


  */


void AT24C02_iic_test(void)


{


    iic_stop();     /**< 必须先复位IIC总线上的设备到待机模式 */


    HAL_Delay(10);

    

    /** 检测总线上是否挂接了IIC设备(此处为AT24C02) */


    if (iic_check_device_status(AT24C02_DEVICE_ADDR) == 0)


    {


        printf("iic device exists\n");


    }


    else


    {


        printf("no iic device exists\n");


    }

    

    AT24C02_write_test();


    HAL_Delay(5);


    AT24C02_read_test();


    HAL_Delay(5);


    AT24C02_erase_test();


}

 

/**


  * @brief  从AT24C02中读取数据


  * @param  read_data: 读取到的数据


  * @param  start_addr: 读取数据的起始地址


  * @param  data_length: 数据的长度


  * @retval None


  */


void AT24C02_read_data(uint8_t *read_data, uint16_t start_addr, uint16_t data_length)


{


    uint16_t i;

    

    iic_start();


    iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_WRITE);


//    AT24C02_ack();


    if (iic_wait_ack() != 0)


    {


        AT24C02_error_handle();


        printf("first read error\r\n");


    }

    

    if (AT24C02_ADDR_BYTE == 1)

 

   {


        iic_sendbyte((uint8_t)start_addr & 0xff);


//        AT24C02_ack();


        if (iic_wait_ack() != 0)


        {


            AT24C02_error_handle();


            printf("addr byte error\r\n");


        }

    }

    

    iic_start();


    iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_READ);


//    AT24C02_ack();


    if (iic_wait_ack() != 0)

   

{

 

       AT24C02_error_handle();


        printf("read data error\r\n");


    }


     for (i = 0; i < data_length; i++)

    

{


        read_data[i] = iic_readbyte();

        

        if (i != data_length - 1)


        {


            iic_ack();      /**< 读完非最后一个字节后, 产生应答信号 */


        }


        else


        {


            iic_nack();     /**< 最后一个字节读完后 产生非应答信号 */


        }


//        printf("read data is %d\n", read_data[i]);  /**< 调试代码 */


    }

iic_stop();


}

 

/**


  * @brief  通过IIC向AT24C02写数据


  * @param  write_data:  要写入AT24C02的数据指针


  * @param  start_addr:  要写入AT24C02的起始地址


  * @param  data_length: 要写入AT24C02的数据长度


 * @retval None


 */


void AT24C02_write_data(uint8_t *write_data, uint16_t start_addr, uint16_t data_length)


{


    uint16_t i, j;


    uint16_t start_addr_dup;

    

    start_addr_dup = start_addr;


    for (i = 0; i < data_length; i++)


    {

        

        if ((i == 0) || (start_addr_dup & (AT24C02_PAGE_SIZE - 1)) == 0)


        {


            iic_stop();

            

            for (j = 0; j < 2000; j++)

       

     {


                iic_start();

         

       iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_WRITE);

                

                if (iic_wait_ack() == 0)

       

         {

   

                 break;


                }


            }


            if (j >= 2000)


            {


                printf("j = 1000\r\n");


                AT24C02_error_handle();


            }

            

            if (AT24C02_ADDR_BYTE == 1)


            {


                iic_sendbyte((uint8_t)start_addr_dup & 0xff);


//                AT24C02_ack();


                if (iic_wait_ack() != 0)


                {


                    AT24C02_error_handle();


                    printf("addr_byte wrong\r\n");


                }


            }


        }

        

        iic_sendbyte(write_data[i]);


//        AT24C02_ack();


        if (iic_wait_ack() != 0)


        {


            AT24C02_error_handle();


            printf("write failed\r\n");


        }

        

//        printf("write_data is %d \n", write_data[i]);    /**< 调试代码 */ 


        start_addr_dup++;


    }

    

    iic_stop();


}

 

/** 私有函数 --------------------------------------------------- */


/** 以下为测试用程序 ------------------------------------------- */


/**


  * @brief  AT24C02读取数据测试


  * @param  None


  * @retval None


  */


static void AT24C02_read_test(void)


{


    uint16_t i;

    

    AT24C02_read_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));

    

    printf("read data is:\n");


    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)


    {


        printf("%d ", test_buffer[i]);


    }

    

    printf("\r\nread test ok\r\n");


}

 

/**


  * @brief  AT24C02写数据测试


  * @param  None


  * @retval None


  */

static void AT24C02_write_test(void)

{

    uint16_t i;

    

    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)

    {

        test_buffer[i] = i;

    }

    

    AT24C02_write_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));

    

    printf("write data is:\n");


    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)


    {


        printf("%d ", test_buffer[i]);


    }

    

    printf("\r\nwrite test ok\r\n");


}

 

/**

  * @brief  AT24C02擦除数据测试


  * @param  None


  * @retval None


  */


static void AT24C02_erase_test(void)


{


    uint16_t i;

    

    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)


    {


        test_buffer[i] = 0xff;


    }

    

    AT24C02_write_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));

    

    printf("erase value is: \n");


    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)


    {


        printf("%d ", test_buffer[i]);


    }

    

    printf("\r\nerase test ok\r\n");


}


/** 以上为测试用程序 ------------------------------------------- */

 

/**


  * @brief  AT24C02应答错误处理程序


  * @param  None


  * @retval None


  */


static void AT24C02_error_handle(void)


{


    iic_stop();


//    printf("At24C02 read failed\r\n");   /**< 调试用 */


}

 

//static void AT24C02_ack(void)


//{


//    if (iic_wait_ack() != 0)


//    {


//        AT24C02_error_handle();


//    }


//}


5. 在主函数中添加 AT24C02_iic_test(); 进行读写测试成功。

推荐阅读

史海拾趣

博通集成(BEKEN)公司的发展小趣事

为了加快市场拓展和技术创新步伐,博通集成积极寻求与产业链上下游企业的战略合作。公司与多家知名企业建立了紧密的合作关系,共同推动无线通讯技术的发展和应用。通过战略合作,博通集成不仅获得了更多的市场资源和技术支持,还实现了与合作伙伴的共赢发展。

Axiohm公司的发展小趣事

Axiohm公司最初是一家小型电子元件制造商,面对激烈的市场竞争,公司创始人李先生意识到唯有技术创新才能脱颖而出。他带领团队投入大量研发资源,成功开发出一种具有高性价比的新型半导体材料。这一创新不仅降低了生产成本,还提高了产品的性能稳定性,迅速赢得了市场的青睐。随着销量的不断增长,Axiohm逐渐在电子行业中崭露头角。

E-Switch公司的发展小趣事

自1979年成立以来,E-Switch公司始终将创新作为发展的核心动力。在公司成立初期,面对激烈的市场竞争,E-Switch决定走差异化路线,专注于开发和生产高品质的开关产品。通过不断的技术创新和产品优化,E-Switch逐渐在电子行业中树立了自己的品牌形象。

EG & G Inc公司的发展小趣事

近年来,电子行业面临着诸多变革和挑战,如技术更新换代加速、市场需求变化等。为了应对这些变革,EG & G Inc公司不断进行战略调整和业务优化。公司加大了对新技术和新产品的研发力度,同时注重提高生产效率和降低成本。此外,公司还积极探索新的商业模式和市场机会,以保持其在行业中的领先地位并实现持续发展。

以上五个故事概述了EG & G Inc公司在电子行业中的重要发展历程和关键事件。这些故事不仅展示了公司的实力和成就,也反映了其在不断变革的市场环境中保持竞争力和持续发展的能力。

General Electric Company公司的发展小趣事
内部集成了频率补偿机制,确保在高频信号下电路的稳定性。
Eby Company公司的发展小趣事

eBay一直致力于创新和改革,以适应不断变化的市场环境。例如,eBay推出了“新卖家金鹰计划”,旨在通过多项专属服务扶持新卖家拓展全球市场。此外,eBay还不断更新其技术平台,提高交易效率和用户体验。这些创新和改革措施使eBay能够在竞争激烈的电子行业中保持领先地位。

问答坊 | AI 解惑

单片机初学者,请进

本人是一毕业就去了深圳创业,算算时间也有差不多5年了吧,期间一直在做单片机方面的项目开发工作,现在在做嵌入式ARM的相关开发,单片机带给人的乐趣是无穷的。我个人感觉这个行业还是很有前景的。希望在校的大学生们好好利用宝贵时间多学点知识, ...…

查看全部问答>

汽车电子资料大放送~资料、文章、方案...敬请下载~

1.大众车系元件功能与检测资料下载>>https://bbs.eeworld.com.cn/thread-281-1-52.html 2.DS2705主控制器数据资料>> https://bbs.eeworld.com.cn/thread-25994-1-16.html 3.CAN总线在混和动力汽车电机控制系统中的应用>> https://bbs.eeworld ...…

查看全部问答>

mc39i tcp只能收发不了

使用外置协议栈,UDP,收发正常, TCP 3次握手过后 tcp只能接收.发送到 服务端的数据,收不到包, 发收的整个包 协议解析正常…

查看全部问答>

如何定制支持MFC的SDK

现在想把原来在WINCE5.0开发的MFC程序移植到WINCE6.0上面, 但一直不能成功.特来请教下: 我现在的环境是VS2005+WINCE6.0  之前在网上找了下, 说是WINCE6.0默认是不支持MFC的.要手动添加几个DLL文件. 现在我也把 MFC80ENU.DLL加进去了, ...…

查看全部问答>

串口调试工具发送文件和字符串的区别,香水看看

                                 我用串口调试工具来调试STM107的虚拟串口例程,发送同样字节的数据,使用串口调试工具下面的字符串输入就正常,而 ...…

查看全部问答>

单片机测量电流电压

用单片机做一个电压,电流检测装置。 (1)电压的范围:DC10-36V,要求精度1%以内。 (2)电流DC 0.1-3A,要求精度1%以内。         怎么控制这个精度问题?请各位大侠给点意见!…

查看全部问答>

16路量入,16路量出。IO不够用了,用什么芯片扩展呢??

有的人说PCA9534A,有的说输入用244,输出用373。怎么选择呢??…

查看全部问答>

求问FPGA的流水线技术

现在在做一个算法的实现,本来用了迭代结构已经实现了,当我想提高速度用流水线结构实现时,发现最高时钟频率居然比迭代结构时候还低,这个感觉跟理论对不上啊。我就是在迭代结构中需要反馈的信号都换成寄存器了,展开成很多级的。 想请问一下有遇 ...…

查看全部问答>