BSRR = GPIO_Pin_6) define SCL_L (GPIOB->BRR = GPIO_Pin_6" />

STM32之I2C例程(24C02)

发布者:SparklingMoon最新更新时间:2019-03-08 来源: eefocus关键字:STM32  I2C例程  24C02 手机看文章 扫描二维码
随时随地手机看文章

#include "stm32f10x.h"

#include


#define SCL_H  (GPIOB->BSRR = GPIO_Pin_6)

#define SCL_L  (GPIOB->BRR = GPIO_Pin_6)

#define SDA_H  (GPIOB->BSRR = GPIO_Pin_7)

#define SDA_L  (GPIOB->BRR = GPIO_Pin_7)

#define SCL_READ (GPIOB->IDR & GPIO_Pin_6)

#define SDA_READ (GPIOB->IDR & GPIO_Pin_7)

#define I2C_DELAY (I2C_delay())


/* RCC时钟配置 */

void RCC_config(void)

 ErrorStatus HSEStartUpStatus;


 /* RCC寄存器设置为默认配置 */

 RCC_DeInit();

 /* 打开外部高速时钟 */

 RCC_HSEConfig(RCC_HSE_ON);

 /* 等待外部高速时钟稳定 */

 HSEStartUpStatus = RCC_WaitForHSEStartUp();

 if(HSEStartUpStatus == SUCCESS) 

 { 

  /* 设置HCLK = SYSCLK */

  RCC_HCLKConfig(RCC_SYSCLK_Div1);

  /* 设置PCLK2 = HCLK */

  RCC_PCLK2Config(RCC_HCLK_Div1);

  /* 设置PCLK1 = HCLK / 2 */

  RCC_PCLK1Config(RCC_HCLK_Div2);

//  /* 设置FLASH代码延时 */

//  FLASH_SetLatency(FLASH_Latency_2);

//  /* 使能预取址缓存 */

//  FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

  /* 设置PLL时钟源为HSE倍频9 72MHz */

  RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

  /* 使能PLL */

  RCC_PLLCmd(ENABLE);

  /* 等待PLL稳定 */

  while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

  /* 设置PLL为系统时钟源 */

  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

  /* 等待系统时钟源切换到PLL */

  while(RCC_GetSYSCLKSource() != 0x08);

 }

}


/* GPIO配置 */

void GPIO_config(void)

{

 GPIO_InitTypeDef GPIO_InitStructure;


 /* 时钟配置 */

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);


 /* SDA、SCL开漏输出 */

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;

 GPIO_Init(GPIOB, &GPIO_InitStructure);

}


/* 毫秒延时函数 */

void delay_ms(uint16_t time)

{    

 uint16_t i = 0; 


 while(time--)

 {

  i = 12000;

  while(i--);    

 }

}


/* I2C延时函数 */

void I2C_delay(void)  

{     

 uint8_t i = 100;  


 while(i)   

 {      

  i--;   

 }

}


/* I2C开始信号 */

bool I2C_Start(void)  

{

 SDA_H;

 SCL_H;

 I2C_DELAY;

 if(!SDA_READ)  

  return false;

 

 SDA_L;

 I2C_DELAY;  

 if(SDA_READ)   

  return false;

 

 SDA_L;

 I2C_DELAY;

 

 return true;  


/* I2C停止信号 */

void I2C_Stop(void)

{

 SCL_L;

 I2C_DELAY;

 SDA_L;

 I2C_DELAY;

 SCL_H;

 I2C_DELAY;

 SDA_H;

 I2C_DELAY;

}


/* I2C响应信号 */

void I2C_Ack(void)  

{     

 SCL_L;

 I2C_DELAY;  

 SDA_L;

 I2C_DELAY;  

 SCL_H;

 I2C_DELAY;  

 SCL_L;

 I2C_DELAY;  


/* I2C未响应信号 */

void I2C_NoAck(void)  

{     

 SCL_L;

 I2C_DELAY;  

 SDA_H;

 I2C_DELAY;  

 SCL_H;

 I2C_DELAY;  

 SCL_L;

 I2C_DELAY;  


/* 等待应答信号 */

bool I2C_WaitAck(void)     

{  

 SCL_L;

 I2C_DELAY;  

 SDA_H;

 I2C_DELAY;  

 SCL_H;

 I2C_DELAY;  

 if(SDA_READ)  

 {  

  SCL_L;

  return false;  

 }  

 SCL_L;

 

 return true;  


/* I2C发送一个字节 */

void I2C_SendByte(uint8_t SendByte)   

{  

 uint8_t i = 8;

 

 while(i--)  

 {  

  SCL_L;

  I2C_DELAY;

  if(SendByte & 0x80)

   SDA_H;

  else  

   SDA_L;

  SendByte <<= 1;  

  I2C_DELAY; 

  SCL_H;

  I2C_DELAY;  

 }  

 SCL_L;


/* I2C接收一个字节 */

uint8_t I2C_ReceiveByte(void)    

{   

 uint8_t i = 8;  

 uint8_t ReceiveByte = 0; 


 SDA_H;


 while(i--)  

 {  

  ReceiveByte<<=1;        

  SCL_L;

  I2C_DELAY;  

  SCL_H;

  I2C_DELAY;      

  if(SDA_READ)  

  {  

   ReceiveByte|=0x01;

  }  

 }


 SCL_L;


 return ReceiveByte;  

}


#define CTRL_CODE 0xA0


/* 写一个字节 */

bool EEPROM_Write_Byte(uint8_t block, uint8_t addr, uint8_t *data)

{

 uint8_t cnt = 10;

 

 /* 确认写周期结束,并写入控制字 */

 do

 {

  I2C_Start();

  I2C_SendByte((CTRL_CODE | (block & 0x0E)) & 0xFE);

 }while((I2C_WaitAck() == false) && (--cnt > 0));

 if(cnt == 0)

 {

  I2C_Stop();

  return false; 

 }

 

 /* 写入地址 */

 I2C_SendByte(addr);

 if(I2C_WaitAck() == false)

 {

  I2C_Stop();

  return false;

 }

 

 /* 写入数据 */

 I2C_SendByte(*data);

 if(I2C_WaitAck() == false)

 {

  I2C_Stop();

  return false;

 }


 I2C_Stop();

 

 return true;

}


/* 读一个字节 */

bool EEPROM_Read_Byte(uint8_t block, uint8_t addr, uint8_t *data)

{

 uint8_t cnt = 10;

 

 /* 确认写周期结束,并写入控制字 */

 do

 {

  I2C_Start();

  I2C_SendByte((CTRL_CODE | (block & 0x0E)) & 0xFE);

 }while((I2C_WaitAck() == false) && (--cnt > 0));

 if(cnt == 0)

 {

  I2C_Stop();

  return false; 

 }


 /* 写入地址 */

 I2C_SendByte(addr);

 if(I2C_WaitAck() == false)

 {

  I2C_Stop();

  return false;

 }

 

 /* 写入控制字 */

 I2C_Start();

 I2C_SendByte(CTRL_CODE | (block & 0x0E) | 0x01);

 if(I2C_WaitAck() == false)

 {

  I2C_Stop();

  return false;

 }

 

 /* 读出数据 */

 *data = I2C_ReceiveByte();

 I2C_NoAck();

 

 I2C_Stop();

 

 return true;

}


/* 主函数 */

int main(void)

{

 uint8_t data = 3;


 /* RCC时钟配置 */

 RCC_config();


 /* GPIO配置 */

 GPIO_config();

 

 EEPROM_Write_Byte(0, 0, &data);

 data = 6;

 EEPROM_Read_Byte(0, 0, &data);

 

 while(1)

 {

  delay_ms(1000);

 }

}

关键字:STM32  I2C例程  24C02 引用地址:STM32之I2C例程(24C02)

上一篇:STM32之BKP原理
下一篇:STM32之I2C原理

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

STM32学习笔记之RCC
时钟 三种不同的时钟源可被用来驱动系统时钟(SYSCLK): ● HSI振荡器时钟 ● HSE振荡器时钟 ● PLL时钟 这些设备有以下2种二级时钟源: ● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/待机模式下自动唤醒系统。 ● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。 当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。 1.当HSI被用于作为PLL时钟的输入时,系统时钟能得到的最大频率是64MHz。 2.对于内部和外部时钟源的特性,请参考相应产品数据手册中 电气特性 章节。 用户可通过多个预分频器配置AHB、高
[单片机]
STM32 SysTick滴答时钟分析
利用系统sysTick()时钟产生延时函数Delay_ms()的分析 SysTick 定时器, SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从 RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。 sysTick时钟来自系统时钟的8倍频。 一般作用于操作系统的节拍,此处我们可以依据此定时器作为延时函数。 /** * @brief Inserts a delay time. * @param nTime: specifies the delay time length, in milliseconds. * @retval
[单片机]
STM32开发笔记75: 使用STM32CubeMX点亮一个LED
今天调试在自己的程序框架下调试RTC始终不成功,只要初始化RTC就进入死机状态。现在重温一下STM32CubeMX的使用方法,看STM32CubeMX生成的程序是否有RTC初始化不成功的问题。本日志从工程的建立讲到点亮一个LED。 1、启动STM32CubeMX,我现在使用的版本是5.2.1。 2、File-New Project,选择相应的芯片类型。 3、双击相应的芯片类型后,进入配置界面。进行SYS配置,选中Debug Serial Wire,由于我习惯于使用FreeRTOS所以在我的项目中Timebase Source都选择定时器。 4、进行RCC设置。 5、时钟设置如下:
[单片机]
<font color='red'>STM32</font>开发笔记75: 使用STM32CubeMX点亮一个LED
关于STM32中管脚复用的使用方法
在STM32的数据手册的管脚分配图中可以看到:PC14与OSC32_IN公用一个引脚,PC15与OSC32_OUT公用一个引脚,管脚配置如图1、图2、图3所示。它们的使用方法如下: 当LSE(低速外部时钟信号)开启时,这两个公用管脚的功能是OSC32_IN和OSC32_OUT。 当LSE(低速外部时钟信号)关闭时这两个公用管脚的功能是PC14和PC15。 备用区域控制寄存器(RCC_BDCR)的LSEON用于控制LSE的开启或关闭。关于这个寄存器的用法请参看《STM3210x技术参考手册》。 图1 STM32 LQFP48封装引脚图 图2 STM32 LQFP64封装引脚图 图3 STM32 LQFP100封装
[单片机]
关于<font color='red'>STM32</font>中管脚复用的使用方法
STM32基础知识入门
一。 寄存器和固定库开发的区别和联系 STM32的寄存器很多,不容易记忆,调用固定库函数,设置好入口参数,从而操作相应的寄存器。 二。MDK下寄存器地址和名称映射关系 GPIO各端口的地址 GPIOA 的寄存器的地址=GPIOA 基地址+寄存器相对 GPIOA 基地址的偏移值 三。MDK下快速组织代码技巧 四。STM32中断优先级分组管理 STM32 的 68 个可屏蔽中断,在 STM32F103 系列上面,又只有 60 个(在 107 系列才有 68 个)。 STM32 的中断分组:STM32 将中断分为 5 个组,组 0~4。 抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。 需要注意两点
[单片机]
<font color='red'>STM32</font>基础知识入门
STM32学习之Flash 写入操作&看门狗喂狗
这两天调试的时候碰到这样一个问题,当我在向flash 中写入数据的时候,系统复位的概率高很多,而且获取复位标识,都是看门狗复位,然而我在做喂狗的定时器使用的中断优先级和抢占优先级都是最高的,应该是不会出现这样问题的。 百度得到的原因: 系统在写入flash 时,系统会对flash 总线进行锁定,导致中断即使发生了,也没有办法读取flash 中的指令,从而导致复位; 摘录大神的解释
[单片机]
stm32 nvic的理解
因为stm32有43个中断源,当同时用到多个中断时,就要指定其中断的优先级了。 nvic即是中断向量的控制!由SCB- AIRCR寄存器控制,SCB- AIRCR中目前只用到4位,也就是最高能有16级中断嵌套,如果全使用的话可以达到256级 (1);选用优先级分组(实际就是选几位用于主优先级几位用于辅优先级) group0:选0位用于主优先级,4位用于辅优先级。 group1:选1位用于主优先级,3位用于辅优先级。 group2:选2位用于主优先级,2位用于辅优先级。 group3:选3位用于主优先级,1位用于辅优先级。 group4:选4位用于主优先级,0位用于辅优先级。 (2)这样打个比方不恰当的比方吧,如
[单片机]
STM32开发者社区:从这里开启你的STM32之旅!小白和PRO都友好
当面对STM32Cube生态系统这样一个庞大而丰富的开发世界时,工程师难免会产生疑问,从哪里开始才好? ST的许多合作伙伴和客户都希望有更多的产品能够利用STM32Cube开发环境。开发人员很享受开发环境的图形用户界面和工具的易用性,如STM32CubeMX、免费的STM32CubeIDE以及许多软件包、驱动程序和中间件,这些都有助于更快地将产品推向市场。随着越来越多的企业选择ST的产品,越来越多的工程师在ST的生态系统中迈出了第一步。为了降低开发人员的进入门槛,ST推出了STM32开发者社区。开发者社区如何为开发团队提供帮助,ST如何将STM32生态系统整合在一起?让我们详细聊聊。 STM32开发者社区 为开
[单片机]
<font color='red'>STM32</font>开发者社区:从这里开启你的<font color='red'>STM32</font>之旅!小白和PRO都友好
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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