假设搞过51的I2C的同志,再来看看STM32的I2C驱动,一定有相见恨晚的感觉。STM32自带I2C硬件模块,再合作ST的官方库函数,I2C在STM32这儿能够玩得如火的境地。这儿的这个I2C驱动算是很完整了的,能够直接拿来用到项目开发中去。好,不废话,上图:
工程结构图:
1、main.c
#include”stm32f10x.h”
#include”usart1.h”
#include”led.h”
#include”i2c_at24c02.h”
#include
struct Contact{
u8 Name[15]; //名字
u8 Phone[11];//电话
u8 BirthDay[10];//生日
}WgchnlnContact[3],NewContact;
struct Contact WgchnlnContact[3]={
{
“wgchnln”,
“18682101373”,
“1987-02-19”,
},
{
“hezepan”,
“18528473728”,
“1987-10-28”,
},
{
“lixiaowei”,
“13527492729”,
“1988-12-02”,
}};
#ifdef Test
void I2C_Test(void)
{
u16 i;
u8 I2c_Buf[256];
printf(“写入的数据”);
//填充缓冲
for(i=0;i<=255;i++)
{
I2c_Buf[i]=i;
printf(“0x%x “,I2c_Buf[i]);
if(i == 9)
{
printf(“”);
}
}
printf(“”);
I2C_AT24Cx_Writes(0,I2c_Buf,256);//将I2C_Buf中次序递加的数据写入EERPOM中
//清缓冲
for(i=0;i<=255;i++)
{
I2c_Buf[i]=0;
}
printf(“读出的数据”);
I2C_AT24Cx_Reads(0,I2c_Buf,256);//将EEPROM读出数据次序坚持到I2C_Buf中
//将I2C_Buf中的数据经过串口打印
for(i=0;i<256;i++)
{
if(I2c_Buf[i]!=i)
{
printf(“过错:I2C EEPROM写入与读出的数据不一致”);
while(1);
}
printf(“0x%X “, I2c_Buf[i]);
if(i == 9)
{
printf(“”);
}
}
}
#endif
int main(void)
{
u8 ReadBuffer[36];
u8 i=0;
u8 j=0;
USART_Config(); //串口1初始化
printf(“这是一个I2C-EEPROM-AT24C02演示试验”);
//Led_Init(); //LED初始化
I2C_AT24Cx_Init(); //I2C初始化
#ifdef Test
I2C_Test();
#endif
printf(“写入联系人”);
for(j=0;j<3;j++)
{
I2C_AT24Cx_Writes(0+j*36,WgchnlnContact[j].Name,15);
I2C_AT24Cx_Writes(15+j*36,WgchnlnContact[j].Phone,11);
I2C_AT24Cx_Writes(26+j*36,WgchnlnContact[j].BirthDay,10);
}
j=0;
printf(“读出联系人”);
for(j=0;j<3;j++)
{
I2C_AT24Cx_Reads(j*36,ReadBuffer,36);
for(i=0;i<15;i++)
{
NewContact.Name[i]=ReadBuffer[i];
}
i=0;
printf(“名字:%s”,NewContact.Name);
for(i=0;i<11;i++)
{
NewContact.Phone[i]=ReadBuffer[i+15];
}
i=0;
printf(“电话:%s”,NewContact.Phone);//为什么打印第二个联系人的号码电话会把第一个联系人的生日一起打印出来
for(i=0;i<10;i++)
{
NewContact.BirthDay[i]=ReadBuffer[i+26];
}
i=0;
printf(“生日:%s”,NewContact.BirthDay);
}
while(1);
}
2、今日的主角:i2c_at24c02.c
#include”stm32f10x.h”
#include”i2c_at24c02.h”
#define AT24Cx_Address 0xa0 //I2C芯片地址 EEPROM
#define AT24Cx_PageSize 8 //芯片内部一页容量
static void I2C_ATC24x_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(I2C_SCL_GPIO_RCC,ENABLE); //没有外部中止,没有重映射,所以不需求敞开复用功用
GPIO_InitStructure.GPIO_Pin =I2C_SCL_Pin|I2C_SDA_Pin;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_OD; //设置管脚为复用功用开漏输出 SDA是输入输出引脚
GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);
}
static void I2C_Config(void)
{
I2C_InitTypeDef I2C_InitStructure;
RCC_APB1PeriphClockCmd(I2C_RCC,ENABLE);
I2C_DeInit(I2C);
I2C_InitStructure.I2C_ClockSpeed =100000; //100KHz I2C时钟频率
I2C_InitStructure.I2C_Mode =I2C_Mode_I2C; //I2C形式
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; //时钟占空比
I2C_InitStructure.I2C_OwnAddress1 =0x30; //主机地址 能够恣意的
I2C_InitStructure.I2C_Ack =I2C_Ack_Enable; //敞开ACK应对呼应
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit;//7位地址形式 非10为地址形式
I2C_Init(I2C,&I2C_InitStructure);
I2C_Cmd(I2C,ENABLE);
I2C_AcknowledgeConfig(I2C,ENABLE);
}
void I2C_AT24Cx_Init(void)
{
I2C_ATC24x_GPIO_Config();
I2C_Config();
}
void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber)
{
if(ReadNumber==0) //没有需求读取的数据
return;
while(I2C_GetFlagStatus(I2C,I2C_FLAG_BUSY));
I2C_AcknowledgeConfig(I2C, ENABLE);
I2C_GenerateSTART(I2C,ENABLE);
while(!I2C_CheckEvent(I2C,I2C_EVENT_MASTER_MODE_SELECT)); //查看是不是主形式与开始位现已发送 补白:这样做的意图便是为了清空该事情
I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//查看数据是不是现已发送地址完结
I2C_SendData(I2C, Address);
while (!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //查看数据是不是现已发送完结
//需求读取数据,这个时分需求改换数据传输方向,就要主机从头发送开始位
I2C_GenerateSTART(I2C, ENABLE);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Receiver); //再一次发送EEPROM地址
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
while(ReadNumber)
{
if(ReadNumber==1)
{
I2C_AcknowledgeConfig(I2C, DISABLE);//封闭应对
I2C_GenerateSTOP(I2C,ENABLE);//使能中止功用
}
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)); //查看是不是承受到了数据
*ReadBuffer=I2C_ReceiveData(I2C);
ReadBuffer++;
ReadNumber–;
}
I2C_AcknowledgeConfig(I2C, ENABLE);//答应应对形式
}
static void I2C_AT24Cx_WaitForComplete(void)
{
vu16 SR1_Tmp;
do
{
I2C_GenerateSTART(I2C1, ENABLE); //一旦发送开始位,主机等候读取SR1,然后发送地址
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1); //也是为了铲除该事情
I2C_Send7bitAddress(I2C1,AT24Cx_Address, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002)); //直到地址发送完结
I2C_ClearFlag(I2C, I2C_FLAG_AF); //前面假设呈现过繁忙 就会呈现应对过错现象
I2C_GenerateSTOP(I2C, ENABLE);
}
void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData)
{
I2C_GenerateSTART(I2C, ENABLE);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //实践便是等候收到EEPROM的ACK应对信号(收到ACK后,硬件会做相应的置位)
I2C_SendData(I2C, Address);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C, WriteData);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C, ENABLE); //这儿的设置中止为与接纳时不同 这儿是写入最终一个数据之后设置中止位
I2C_AT24Cx_WaitForComplete();
}
void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber)
{
while(I2C_GetFlagStatus(I2C, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C, ENABLE);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C,AT24Cx_Address, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C,Address);
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
while(WriteNumber–)
{
I2C_SendData(I2C,*WriteData);
WriteData++;
while(!I2C_CheckEvent(I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
I2C_GenerateSTOP(I2C, ENABLE);
}
void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber)
{
u8 Temp;
Temp=Address%AT24Cx_PageSize;
if(Temp)//存在页不对齐的现象
{
Temp=AT24Cx_PageSize-Temp;//求出页不对齐的数量
I2C_AT24Cx_WritePage(Address,WriteData,Temp);
Address+=Temp;
WriteData+=Temp;
WriteNumber-=Temp;
I2C_AT24Cx_WaitForComplete();
}
while(WriteNumber)
{
if(WriteNumber>=AT24Cx_PageSize)
{
I2C_AT24Cx_WritePage(Address,WriteData,AT24Cx_PageSize);
Address+=AT24Cx_PageSize;
WriteData+=AT24Cx_PageSize;
WriteNumber-=AT24Cx_PageSize;
I2C_AT24Cx_WaitForComplete();
}
else
{
I2C_AT24Cx_WritePage(Address,WriteData,WriteNumber);
WriteNumber=0;
I2C_AT24Cx_WaitForComplete();
}
}
}
i2c_at24c02.h
#ifndef _I2C_AT24C02_H
#define _I2C_AT24C02_H
#include”stm32f10x.h”
#define I2C I2C1
#define I2C_RCC RCC_APB1Periph_I2C1
#define I2C_SCL_GPIO_RCC RCC_APB2Periph_GPIOB
#define I2C_SCL_GPIO GPIOB
#define I2C_SCL_Pin GPIO_Pin_6
#define I2C_SDA_GPIO_RCC RCC_APB2Periph_GPIOB
#define I2C_SDA_GPIO GPIOB
#define I2C_SDA_Pin GPIO_Pin_7
void I2C_AT24Cx_Init(void); //I2C外设与AT24C02初始化
void I2C_AT24Cx_Reads(u8 Address,u8 *ReadBuffer,u16 ReadNumber); //从AT24C02中读取数据 EEPROM
void I2C_AT24Cx_WriteByte(u8 Address,u8 WriteData); //写入一字节数据
void I2C_AT24Cx_WritePage(u8 Address,u8 *WriteData,u16 WriteNumber); //写入一页之内数据
void I2C_AT24Cx_Writes(u8 Address,u8 *WriteData,u16 WriteNumber); //写入恣意数量的数据 流程:写入也不对齐部分–写入整页部分(假设需求)–写入最终缺乏一页的
#endif
剩余的串口驱动与LED驱动别离见:《STM32 串口例程之查询收发》、《STM32 根据库函数操控按键 蜂鸣器 LED显现》彻底相同的。这儿就不在重复上代码了。
以上,完毕。
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/fpga/259157.html