• 【正点原子STM32连载】 第四十二章 IIC实验 摘自【正点原子】APM32F407最小系统板使用指南


    1)实验平台:正点原子stm32f103战舰开发板V4
    2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
    3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html##

    第四十二章 IIC实验

    本章将介绍使用APM32F407驱动板载的EEPROM进行读写操作。通过本章的学习,读者将学习到使用GPIO模拟IIC时序以及EEPROM的驱动。
    本章分为如下几个小节:
    42.1 硬件设计
    42.2 程序设计
    42.3 下载验证

    42.1 硬件设计
    42.1.1 例程功能

    1. 按下KEY_UP和KEY0按键,分别对24C02进行数据的写入和读取操作,读取到的数据会显示至LCD
    2. 可通过USMART对24C02进行读写一字节数据的操作
    3. LED0闪烁,指示程序正在运行
      42.1.2 硬件资源
    4. LED
      LED0 - PF9
    5. 按键
      KEY0 - PE4
      KEY_UP - PA0
    6. USART1(PA9、PA10连接至板载USB转串口芯片上)
    7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
    8. 24C02
      IIC_SCL - PB8
      IIC_SDA - PB9
      42.1.3 原理图
      本章实验使用了板载的24C02芯片,该芯片是一个EEPROM,MCU是通过两个GPIO与该EEPROM进行连接与通信的,该EEPROM与MCU的连接原理图,如下图所示:
      在这里插入图片描述

    图42.1.3.1 EEPROM与MCU的连接原理图
    42.2 程序设计
    42.2.1 Geehy标准库的GPIO驱动
    本章实验通过控制与EEPROM连接的GPIO模拟IIC时序,实现EEPROM的读写操作,对于GPIO,主要涉及GPIO的配置和读写操作,需要一下几个步骤:
    ①:配置GPIO引脚为通用输出模式、开漏输出和禁止上拉/下拉
    ②:在与EEPROM通信时,根据需求控制指定GPIO引脚输出指定电平
    ③:在与EEPROM通信时,根据需求读取指定GPIO引脚上的输入电平
    在Geehy标准库中对应的驱动函数如下:
    ①:配置GPIO引脚
    请见第10.2.1小节中配置GPIO引脚的相关内容。
    ②:设置GPIO引脚输出电平
    请见第10.2.1小节中设置GPIO引脚输出电平的相关内容。
    ③:读取GPIO引脚输入电平
    请见第11.2.1小节中读取GPIO引脚输入电平的相关内容。
    42.2.2 IIC驱动
    本章实验使用的IIC的软件模拟的IIC,即控制GPIO模拟IIC的时序与外部器件进行通信。IIC驱动主要负责向EEPROM驱动提供IIC操作的各种函数,例如:IIC起始信号、IIC停止信号等。本章实验中,IIC的驱动代码包括myiic.c和myiic.h两个文件。
    IIC驱动中,对GPIO相关的宏定义,如下所示:

    #define IIC_SCL_GPIO_PORT	GPIOB
    #define IIC_SCL_GPIO_PIN	GPIO_PIN_8
    #define IIC_SCL_GPIO_CLK_ENABLE()							\
        do {														\
        		RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB);	\
        } while (0)
    
    #define IIC_SDA_GPIO_PORT	GPIOB
    #define IIC_SDA_GPIO_PIN	GPIO_PIN_9
    #define IIC_SDA_GPIO_CLK_ENABLE()							\
        do {														\
        		RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB);	\
        } while (0)
    
    #define IIC_SCL(x) do { x ?										\
        		GPIO_SetBit(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN) :		\
        		GPIO_ResetBit(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN);	\
        } while (0)
    
    #define IIC_SDA(x) do { x ?										\
        		GPIO_SetBit(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) :		\
        		GPIO_ResetBit(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN);	\
        } while (0)
    
    #define IIC_SDA_READ \
        GPIO_ReadInputBit(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)
    IIC驱动中,IIC的初始化函数,如下所示:
    /**
     * @brief	初始化IIC
     * @param	无
     * @retval	无
     */
    void iic_init(void)
    {
        GPIO_Config_T gpio_init_struct;
        
        /* 使能时钟 */
        IIC_SCL_GPIO_CLK_ENABLE();						/* 使能IIC SCL引脚端口时钟 */
        IIC_SDA_GPIO_CLK_ENABLE();						/* 使能IIC SDA引脚端口时钟 */
        
        /* 配置IIC SCL引脚 */
        gpio_init_struct.pin	= IIC_SCL_GPIO_PIN;			/* IIC SCL引脚 */
        gpio_init_struct.mode	= GPIO_MODE_OUT;			/* 通用输出模式 */
        gpio_init_struct.speed	= GPIO_SPEED_100MHz;		/* 高速 */
        gpio_init_struct.otype	= GPIO_OTYPE_OD;			/* 开漏输出 */
        gpio_init_struct.pupd	= GPIO_PUPD_NOPULL;			/* 禁止上拉/下拉 */
        GPIO_Config(IIC_SCL_GPIO_PORT, &gpio_init_struct);	/* 配置IIC SCL引脚 */
        
        /* 配置IIC SDA引脚 */
        gpio_init_struct.pin	= IIC_SDA_GPIO_PIN;			/* IIC SDA引脚 */
        gpio_init_struct.mode	= GPIO_MODE_OUT;			/* 通用输出模式 */
        gpio_init_struct.speed	= GPIO_SPEED_100MHz;		/* 高速 */
        gpio_init_struct.otype	= GPIO_OTYPE_OD;			/* 开漏输出 */
        gpio_init_struct.pupd	= GPIO_PUPD_NOPULL;			/* 禁止上拉/下拉 */
        GPIO_Config(IIC_SDA_GPIO_PORT, &gpio_init_struct);	/* 配置IIC SDA引脚 */
        
        iic_stop();/* 停止IIC总线上所有设备 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    可以看到,IIC的初始化实际上就是配置IIC时钟与数据信号对应的GPIO引脚。
    IIC驱动中对IIC的各种操作,例如产生IIC起始信号、产生IIC停止信号等,请读者结合IIC的时序规定查看本实验的配套实验源码。
    42.2.3 EEPROM驱动
    本章实验的EEPROM驱动主要负责向应用层提供EEPROM的初始化和读写数据等操作函数。本章实验中,EEPROM的驱动代码包括24cxx.c和24cxx.h两个文件。
    EEPROM驱动中,EEPROM的初始化函数,如下所示:

    /**
     * @brief	初始化AT24CXX
     * @param	无
     * @retval	无
     */
    void at24cxx_init(void)
    {
        iic_init();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以看到,该函数实际上就是初始化了与EEPROM通讯的IIC。
    EEPROM驱动中的其他对EEPROM的操作函数,例如:EEPROM的读写函数,请读者结合24C02 EEPROM芯片的数据手册查看本实验的配套实验源码。
    42.2.4 实验应用代码
    本章实验的应用代码,如下所示:
    /* 待写入24C02的数据 */

    static const uint8_t g_text_buf[] = {"APM32 IIC TEST"};
    
    /* 待写入24C02数据的长度 */
    #define TEXT_SIZE sizeof(g_text_buf)
    
    int main(void)
    {
        uint8_t t = 0;
        uint8_t key;
        uint8_t data[TEXT_SIZE];
        
        NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_3);	/* 设置中断优先级分组为组3 */
        sys_apm32_clock_init(336, 8, 2, 7);					/* 配置系统时钟 */
        delay_init(168);										/* 初始化延时功能 */
        usart_init(115200);									/* 初始化串口 */
        usmart_dev.init(84);								/* 初始化USMART */
        led_init();											/* 初始化LED */
        key_init();											/* 初始化按键 */
        lcd_init();											/* 初始化LCD */
        at24cxx_init();										/* 初始化AT24CXX */
        
        lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
        lcd_show_string(30, 70, 200, 16, 16, "IIC TEST", RED);
        lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
        lcd_show_string(30, 110, 200, 16, 16, "KEY_UP:Write  KEY0:Read", RED);
        
        while (at24cxx_check() != 0)/* 检测不到24C02 */
        {
        		lcd_show_string(30, 130, 200, 16, 16, "24C02 Check Failed!", RED);
        		delay_ms(500);
        		lcd_show_string(30, 130, 200, 16, 16, "Please Check!      ", RED);
        		delay_ms(500);
        		LED0_TOGGLE();
        }
        /* 24C02检测正常 */
        lcd_show_string(30, 130, 200, 16, 16, "24C02 Ready!       ", RED);
        
        while (1)
        {
        		t++;
        		key = key_scan(0);
        		
        		if (key == WKUP_PRES)		/* 写入数据 */
        		{
        			lcd_fill(0, 150, 239, 319, WHITE); 
        			lcd_show_string(30, 150, 200, 16, 16, "Start Write 24C02....", BLUE);
        			at24cxx_write(0, (uint8_t *)g_text_buf, TEXT_SIZE);
        			lcd_show_string(30, 150, 200, 16, 16, "24C02 Write Finished!", BLUE);
        		}
        		else if (key == KEY0_PRES)	/* 读取数据 */
        		{
        			lcd_show_string(30, 150, 200, 16, 16, "Start Read 24C02.... ", BLUE);
        			at24cxx_read(0, data, TEXT_SIZE);
        			lcd_show_string(30, 150, 200, 16, 16, "The Data Readed Is:  ", BLUE);
        			lcd_show_string(30, 170, 200, 16, 16, (char *)data, BLUE);
        		}
        		
        		if (t == 20)
        		{
        			LED0_TOGGLE();
        			t = 0;
        		}
        		
        		delay_ms(10);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    从本章实验的应用代码中可以看到,在初始化完EEPROM后,会检测与EEPROM的连接是否正常,若与EEPROM的连接正常,则会不断地等待按键输入,若检测到KEY_UP按键被按下,则会往EEPROM的指定地址中写入指定的数据,若检测到KEY_0按键被按下,则会从EEPROM的指定地址中读取数据,并在LCD上进行显示。
    42.3 下载验证
    在完成编译和烧录操作后,若MCU与EEPROM的连接无误,则可以在LCD上看到“24C02 Ready!”的提示信息,此时可以按下KEY_UP按键往EEPROM的指定地址写入指定数据,然后再按下KEY_0按键从EEPROM的指定地址将写入的数据读回来在LCD上进行显示,此时便可以看到在LCD上显示了“APM32 IIC TEST”的提示信息,该提示信息就是从EEPROM中读回的数据。

  • 相关阅读:
    【Axure高保真原型】知识图谱原型模板
    JavaScript:实现弧度到度算法 (附完整源码)
    大厂面试:如何用快排思想在O(n)内查找第K大元素?
    工作中常见的两种谬误
    软工作业2:个人项目
    解决Tomcat中文乱码问题——windows平台
    [原创]移远RM500U-CN模组驱动移植
    【MySQL从0到1】第六篇:内置函数
    1-氨丙基-3-甲基咪唑溴盐离子液体修饰碳量子点(L-CQDs)负载TiO2纳米颗粒(试剂)
    如何配置 logback?30分钟让你彻底学会代码熬夜敲
  • 原文地址:https://blog.csdn.net/weixin_55796564/article/details/133804382