STM32F030 硬件I2C驱动 AT24C16

发布者:InspiredDreamer最新更新时间:2018-06-02 来源: eefocus关键字:STM32F030  硬件I2C  驱动  AT24C16 手机看文章 扫描二维码
随时随地手机看文章

I2C 的配置


static void InitI2C()

{

  I2C_InitTypeDef I2C_InitStructure;

  GPIO_InitTypeDef GPIO_InitA;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//使能I2C1,I2C2的时钟

  RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);//时钟源设定

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1);  //配置PB8 成第二功能引脚 I2C1_SCL

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1);  //配置PB9 成第二功能引脚 I2C1_SDA

  GPIO_InitA.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

  GPIO_InitA.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitA.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitA.GPIO_OType = GPIO_OType_PP;

  GPIO_InitA.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_Init(GPIOB, &GPIO_InitA);

  I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;

  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;

  I2C_InitStructure.I2C_DigitalFilter = 0x01;

  I2C_InitStructure.I2C_OwnAddress1 = 0x00;

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStructure.I2C_Timing = 0x0090174F;

  I2C_Init(I2C1, &I2C_InitStructure);

  I2C_Cmd(I2C1, ENABLE);

}


一样的配置方案,I2C_Timing的意思请移步本博客GY30那篇文章。 

I2C引脚为PB8 与PB9(使用的C8T6,f4p6可以用PA的)


#define AT24C16_Base_Address 0xA0

void AT24C16_WriteByte(uint8_t Page,uint8_t WordAddress,uint8_t Data);

uint8_t AT24C16_ReadByte(uint8_t Page,uint8_t WordAddress);

void AT24C16_PageWrite(uint8_t Page,uint8_t WordAddress,uint8_t Length,uint8_t* Data);

void AT24C16_SequentialRead(uint8_t Page,uint8_t WordAddress, uint8_t length , uint8_t* p);


下面是相关函数:


void AT24C16_WriteByte(uint8_t Page,uint8_t WordAddress,uint8_t Data)

{

    if(WordAddress > 0x10)

    {

        return;

    }

    WordAddress |= ( Page & 0x0F ) << 4;

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),2,I2C_AutoEnd_Mode,I2C_Generate_Start_Write);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

    I2C_SendData(I2C1,WordAddress);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

    I2C_SendData(I2C1,Data);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);

}

uint8_t AT24C16_ReadByte(uint8_t Page,uint8_t WordAddress)

{

    uint8_t Recev = 0x00;

    if(WordAddress > 0x10)

    {

        return 0;

    }

    WordAddress |= ( Page & 0x0F ) << 4;

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

    I2C_SendData(I2C1,WordAddress);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET);

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);

    Recev = I2C_ReceiveData(I2C1);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);

    return Recev;

}


下面是页读取,页写入:


void AT24C16_PageWrite(uint8_t Page,uint8_t WordAddress,uint8_t Length,uint8_t* Data)

{

    uint8_t i = 0;

    if(WordAddress > 0x10)

    {

        return;

    }

    WordAddress |= ( Page & 0x0F ) << 4;

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),Length + 1,I2C_AutoEnd_Mode,I2C_Generate_Start_Write);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

    I2C_SendData(I2C1,WordAddress);

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

    {

        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

        I2C_SendData(I2C1,Data[i]);

    }

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);

}

void AT24C16_SequentialRead(uint8_t Page,uint8_t WordAddress, uint8_t length , uint8_t* p)

{

    uint8_t i;

    if(WordAddress > 0x10)

    {

        return;

    }

    WordAddress |= ( Page & 0x0F ) << 4;

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);//If Write OK

    I2C_SendData(I2C1,WordAddress);

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET);

    I2C_TransferHandling(I2C1,AT24C16_Base_Address | ( ( Page & 0xF0 ) >> 3 ),length,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);

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

    {

        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);

        p[i] = I2C_ReceiveData(I2C1);

    }

    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);

}


感觉没什么说的,GY30那篇文章基本都说完了,添点小知识点吧。


I2C_AutoEnd_Mode,顾名思义,操作length字节后自动添加STOP。 

I2C_SoftEnd_Mode ,同样顾名思义,操作length字节后需要手动添加STOP。( I2C_GenerateSTOP() ) 

这个模式比自动多了一步,需要 I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) ,Translate Completed,是否传输完成,自动模式下访问这个会得到Reset值,然而手动模式下需要访问他,然后生成Stop。


然后……差不多了吧?举个 上面网址的例子吧,我觉得很多人不会看……


所以在编写程序对AT24C16第100页的第3个字节进行写数据的时候,步骤如下: 

1)发送起始信号; 

2)发送器件地址0XA6(1010 0110,1010是固定地址,011是页地址的高三位,0表示写操作); 

3)发送操作地址0X43(0100 0011,0100是页地址的低四位,0011是页地址偏移量,即第100页内的第三个字节, 

4)发送要写的数据, 

5)发送终止信号。

我相信各位最起码都看了AT24C16的地址了,0xA0。(再次引用畅学电子网的图片) 

这里写图片描述

P0P1P2为页地址高三位,发送的字地址(WordAddress)高四位为页地址的第四位,低四位为字地址。 

AT24C16有128页,每页16bytes。所以正好匹配上。 

写的间隔至少为5ms,否则用循环等待的话I2C会卡死。


以上。 

另:代码我测试是通过的,若有Bug欢迎指出。


关键字:STM32F030  硬件I2C  驱动  AT24C16 引用地址:STM32F030 硬件I2C驱动 AT24C16

上一篇:EEPROM(AT24C16)页写算法
下一篇:单片机在清除标志位时不要用位操作

推荐阅读最新更新时间:2024-03-16 16:04

STM32的DS18B20的驱动移植
折腾了一晚上,才把DS18B20的驱动移植到STM32上来。以前在51上使用过单个和多个连接的DS18B20,有现成的程序了,以为很快就能弄好,结果还是被卡住了,下面说下几个关键点吧: 首先是延时的问题,STM32上若用软件延时的话不太好算时间,所以要么用定时器要么用SysTick这个定时器来完成延时的计算。相比之下用SysTick来的简单方便点。 接着是STM32 IO脚的配置问题,因为51是双向的IO,所以作为输入输出都比较方便。STM32的IO是准双向的IO,网上查了下资料,说将STM32的IO配置成开漏输出,然后外接上拉即可实现双向IO。于是我也按规定做了,但调了老半天都不成功,是因为DS18B20没有响应的信号。
[单片机]
LED驱动电源特点及不足
1、什么是LED驱动电源   LED驱动电源把电源供应转换为特定的电压电流以驱动led发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。而LED驱动电源的输出则大多数为可随LED正向压降值变化而改变电压的恒定电流源。LED电源核心元件包括开关控制器、电感器、开关元器件(MOSfet)、反馈电阻、输入滤波器件、输出滤波器件等等。根据不同场合要求、还要有输入过压保护电路、输入欠压保护电路,LED开路保护、过流保护等电路。   2、LED驱动电源的特点   (1)高可靠性   特别像LED路灯的驱动电源,装在高空,维修不方便,维修
[电源管理]
汽车照明应用中LED驱动器设计
  LED是一种高效环保的新型半导体光源,有其它光源无法比拟的优势。在未来汽车照明应用中前景光明。LED 可以用串联、并联等不同的方式组合成LED 阵列,以满足汽车照明强度的要求。针对LED 的发光特性,重点讨论了LED 驱动的设计及特点,同时简述了LED 目前存在的问题及解决方法。   1 汽车车灯作用及要求   目前,汽车日趋平民化,已成为主要交通工具,行车安全引起了社会广泛的关注。据不完全统计,汽车在夜晚或自然光线不足的情况下行驶的里程占总行驶里程的25%,而在此间发生的交通事故占到总事故的40%,并且一半以上的伤亡事故发生在夜间。因此,车外照明灯及信号灯是汽车安全行驶的关键部件,必须满足下列条件:   (1)汽车照明灯点亮
[电源管理]
汽车照明应用中LED<font color='red'>驱动</font>器设计
PowerintLNK419EG18WT8管灯LED驱动设计方案(DER298)
LED驱动器采用LinkSwitchTM-PH系列LNK419EG,输入电压90VAC到265VAC,输出电压200V/90mA.拓扑采用单级非隔离降压-升压,具有紧凑和低元件数的特点,线路和负载调整有于2%,110VAC的效率大于89.5%, THD小于20%,而230VAC时的效率大于90%,THD小于28%.本文介绍了设计方案DER298的主要特性,优势和指标,电路图和材料清单. Constant Current ( 2% Regulation), Non-Isolated Buck-Boost, Power Factor Corrected,18 W LED Driver Using LinkSwitchTM-PH
[电源管理]
PowerintLNK419EG18WT8管灯LED<font color='red'>驱动</font>设计方案(DER298)
字符设备驱动程序之同步互斥阻塞
1. 原子操作 原子操作指的是在执行过程中不会被别的代码路径所中断的操作。 常用原子操作函数举例: atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0 atomic_read(atomic_t *v); //返回原子变量的值 void atomic_inc(atomic_t *v); //原子变量增加1 void atomic_dec(atomic_t *v); //原子变量减少1 int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。 2. 信号量 信号量(semaphore)
[单片机]
LED照明企业蓄势待发 驱动技术亟待提升
受能源危机的影响,全球各国相继通过立法和政府引导等方式,加快 LED灯取代白炽灯的步伐。市场的增长要求LED照明解决方案能够从整体上进一步提高光效,增进成本效益,以适应LED照明在更大范围内的普及应用。   在驱动方面,虽然LED灯具的售价在近年来保持下降的趋势,然而,驱动成本的下降空间并不大。这就要求厂商通过制造工艺的改进,驱动方案的创新,并且紧跟灯具电源设计的最新发展动向,开发出高成本效益的驱动。高集成度将是 LED 驱动 的发展方向,在内部集成更多的元件、功能以实现高性价比的驱动。   LED灯具   目前,LED照明放量在即,照明是行业下一个趋势性投资机会。LED光源产品价格大幅下降,在国内LED光源与同等光效的节能灯
[电源管理]
LED照明企业蓄势待发 <font color='red'>驱动</font>技术亟待提升
LED照明的驱动电源的一些问题
  在当前生活中,为了节能省电,LED得到了很大的推广,但LED都需要有个电源驱动,其好坏会直接影响LED的寿命,因此如何做好一个LED驱动电源是LED电源设计者的重中之重。本文介绍了一些LED驱动电源的问题,希望能够对工程师提供一点帮助。   1, 驱动电路直接影响LED寿命   我们所说的LED驱动包括数字驱动和模拟驱动两类,数字驱动指数字电路驱动,包括数字调光控制,RGB全彩变幻等。模拟驱动指模拟电路驱动,包括AC恒流开关电源,DC恒流控制电路。驱动电路由电子元件组成,包括半导体元件,电阻,电容,电感等,这些元件都有使用寿命,任何一个器件失效都会导致整个电路的失效或者部分功能失效。 LED的使用寿命是5-10万小时,按5
[电源管理]
单通道MOSFET或IGBT栅极驱动器集成电路IR2117
    摘要: IR2117是美国IR公司专为驱动单个MOSFET或IGBT而设计的栅极驱动器集成电路。文中介绍了它的引脚排列、功能特点和参数限制,同时剖析了它的内部结构和工作原理,最后给出了其典型应用电路图和应用举例。     关键词: 栅极 悬浮 自举 欠压 IR2117 IR2117是美国IR公司专为驱动单个MOSFET或IGBT而设计的栅极驱动器,它采用高压集成电路技术和无闩锁CMOS技术,并采用双直插式封装,可用于工作母线电压高达600V的系统中。其输入与标准的CMOS电平兼容,输出驱动特性可满足交叉导通时间最短的大电流驱动输出级的设计要求。其悬浮通道与自举技术的应用使其可直接用来驱动一个工作于母线
[半导体设计/制造]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved