Stm32F1IIC实验

IIC简介

IIC:Inter Integrated Circuit,集成电路总线,是一种同步 串行 半双工通信总线。
总线:传输数据的通道
协议:传输数据的规则

IIC结构图

多主多从结构
在这里插入图片描述
① 由时钟线SCL和数据线SDA组成,并且都接上拉电阻,确保总线空闲状态为高电平
② 总线支持多设备连接,允许多主机存在,每个设备都有一个唯一的地址

IIC协议

可以归纳为
三个信号:起始,停止,应答信号。
两个个状态:空闲,忙碌状态

IIC协议时序

在这里插入图片描述
在这里插入图片描述

//开始传输数据(通信地址,存储地址或数据等)信号
void iic_start(void)
{ /* SCL为高电平期间, SDA从高电平往低电平跳变*/
    IIC_SDA ( 1 );	
	IIC_SCL ( 1 );
    iic_delay( );
 	IIC_SDA ( 0 );	
 	iic_delay( );
    IIC_SCL ( 0 );	
 	iic_delay( );  /* 钳住总线, 准备发送/接收数据 */
}

//数据传输停止信号
void iic_stop(void)
{ /* SCL为高电平期间, SDA从低电平往高电平跳变*/
    IIC_SDA ( 0 );	
	iic_delay( );
 	IIC_SCL ( 1 );	
 	iic_delay( );
    IIC_SDA ( 1 ); 	/* 发送总线停止信号*/
 	iic_delay( );
}

//发送应答信号
void iic_ack(void)
{ 
    IIC_SCL (0);	
	iic_delay( );
 	IIC_SDA (0);  /* 数据线为低电平,表示应答 */
 	iic_delay( );
    IIC_SCL (1); 	
 	iic_delay( );
}

//发送非应答信号
void iic_nack(void)
{ 
    IIC_SCL (0);	
	iic_delay( );
 	IIC_SDA (1);  /* 数据线为高电平,表示非应答 */
 	iic_delay( );
    IIC_SCL (1); 	
 	iic_delay( );
}

//检测应答信号
uint8_t iic_wait_ack (void) /* return 1:fail 0:succeed*/
{	
	IIC_SDA (1);  /* 主机释放SDA线 */
	iic_delay( );
	IIC_SCL (1);  /* 从机返回ACK*/ 	
 	iic_delay( );
	if ( IIC_READ_SDA ) /* SCL高电平读取SDA状态*/ 
	{
		iic_stop();	    /* SDA高电平表示从机nack */ 
		return 1;
	}
	IIC_SCL(0);	 /* SCL低电平表示结束ACK检查 */ 
 	iic_delay( );
	return 0;
}

AT24C02(EEPROM类型存储器)

EEPROM是一种掉电后数据不丢失的储存器,常用来存储一些配置信息,在系统重新上电时就可以加载。
AT24C02是一个2K bit的EEPROM存储器,使用IIC通信方式。02表示容量为2K bit

在这里插入图片描述
A0/1/2 : 设备地址决定引脚
WP : 写保护引脚(高电平有效)
SCL : 时钟线
SDA : 数据线
在这里插入图片描述
24C02由32页(page)组成且每页8Byte

通讯地址

在这里插入图片描述
当容量大于2K时(256字节(由八位表示地址))在发送存储地址时只有8位,显然8位是不能够表示2K容量以上的字节地址的,所以将向通讯地址借位。表示2K以上的地址。但是这是该容量类型的从机数量减少。
在这里插入图片描述

AT24C02读写操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AT24C02驱动步骤(掌握)

IIC配置步骤

在这里插入图片描述

AT24C02驱动步骤

在这里插入图片描述

驱动AT24C02实现读和写1字节数据实验代码

iic.h

/******************************************************************************************/
/* 引脚定义 */
//IIC的时钟线线是PB6,数据线是PB7
#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_6
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_7
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB时钟使能 */

/******************************************************************************************/

/* IO操作,实际上是操作GPIO端口的寄存器 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* ¶ÁÈ¡SDA */

void iic_init(void);
void iic_start(void);
void iic_stop(void);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte (uint8_t ack);

iic.c

//本实验是软件IIC
void iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    IIC_SCL_GPIO_CLK_ENABLE();  /* SCLÒý½ÅʱÖÓʹÄÜ */
    IIC_SDA_GPIO_CLK_ENABLE();  /* SDAÒý½ÅʱÖÓʹÄÜ */

    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /*推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉­ */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* ¸高速*/
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);    /* SCL */

    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;            /* 开漏输出*/
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);    /* SDA */
    /* SDA引脚模式设置,开漏输出,上拉,这样就不用设置IO方向了,开漏输出的时候(=1),也可以读取外部信号的高低电平*/
}

//剩余代码与IIC协议时序处代码一致

24cxx.c

//外设驱动代码
#include "./BSP/IIC/myiic.h"
#include "./BSP/24CXX/24cxx.h"
#include "./SYSTEM/delay/delay.h"

void at24c02_init(void)
{
    iic_init();
}

void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{
    /* 1发送起始信号*/
    iic_start();
    
    /* 2¡发送通讯地址·) */
    iic_send_byte(0xA0);
    
    /* 3等待应答信号 */
    iic_wait_ack();
    
    /* 4发送内存地址· */
    iic_send_byte(addr);
    
    /* 5¡¢µÈ´ýÓ¦´ðÐźŠ*/
    iic_wait_ack();
    
    /* 6发送写入数据Ý */
    iic_send_byte(data);
    
    /* 7¡¢µÈ´ýÓ¦´ðÐźŠ*/
    iic_wait_ack();
    
    /* 8发送停止信号*/
    iic_stop();
    
    /* µÈ´ýEEPROMдÈëÍê³É */
    delay_ms(10);
}

uint8_t at24c02_read_one_byte(uint8_t addr)
{
    uint8_t rec = 0;
    
    /* 1¡¢·¢ËÍÆðʼÐźŠ*/
    iic_start();
    
    /* 2¡¢·¢ËÍͨѶµØÖ·(д²Ù×÷µØÖ·) */
    iic_send_byte(0xA0);
    
    /* 3¡¢µÈ´ýÓ¦´ðÐźŠ*/
    iic_wait_ack();
    
    /* 4¡¢·¢ËÍÄÚ´æµØÖ· */
    iic_send_byte(addr);
    
    /* 5¡¢µÈ´ýÓ¦´ðÐźŠ*/
    iic_wait_ack();
    
    /* 6¡发送起始信号,这里为什么既要读操作地址又要写操作地址。 */
    iic_start();
    
    /* 7¡¢·¢ËÍͨѶµØÖ·(¶Á²Ù×÷µØÖ·) */
    iic_send_byte(0xA1);
    
    /* 8¡¢µÈ´ýÓ¦´ðÐźŠ*/
    iic_wait_ack();
    
    /* 9¡¢µÈ´ý½ÓÊÕÊý¾Ý */
    rec = iic_read_byte(0);
    /* 10¡¢·¢ËÍ·ÇÓ¦´ð£¨»ñÈ¡¸ÃµØÖ·¼´¿É£© */
    
    /* 11¡¢·¢ËÍÍ£Ö¹ÐźŠ*/
    iic_stop();
    
    return rec;
}

main.c

 uint8_t key;
    uint8_t i = 0;
    uint8_t data = 0;
    
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
    delay_init(72);                             /* 延时初始化¯ */
    usart_init(115200);                         /* ´串口初始化为115200 */
    led_init();                                 /* ³初始化LED */
    key_init();                                 /* 初始化按键 */
    at24c02_init();
    
    while (1)
    {
        key = key_scan(0);

        if (key == KEY1_PRES)
        {
            at24c02_write_one_byte(100, 66);
            printf("write data \r\n");
        }

        if (key == KEY0_PRES)
        {
            data = at24c02_read_one_byte(100);
            printf("read data:%d \r\n", data);
        }

        i++;

        if (i % 20 == 0)
        {
            LED0_TOGGLE();  /* ºìµÆÉÁ˸ */
            i = 0;
        }

        delay_ms(10);
    }

实验结果图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值