上一篇:STM32-(19):I2C通信(理论基础) | 下一篇:STM32-(21):NVIC中断 |
---|
硬件电路连接
底板上的 I2C 接口
A0、A1是用来确定器件的地址的。
排针上的引脚图:
核心板上的引脚图:
通过I2C总线实现对EEPROM的读写操作的准备工作:
1、掌握芯片(目标对象)特性,才能对其正确的读和写。
2、掌握 I2C 通信,读写过程需要用到。
3、Cortex的一些操作,编程方法。
实验内容:通过I2C总线实现对EEPROM的读写操作
main.c
#include"stm32f10x_lib.h"
#include"IIC.h"
/*------------函数的声明---------------*/
void Delay_MS(u16 dly);
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
/**********************************TEST*******************************/
int main(void)
{
#ifdef DEBUG
debug();
#endif
u8 Tab[]="hello";
u8 ReadTab[5];
RCC_Configuration();
I2C_Configuration();
NVIC_Configuration(); //中断配置
GPIO_Configuration();
GPIO_SetBits(GPIOA, GPIO_Pin_3);
//这里将 Tab的5个值写入 EEPROMZ中去,然后从EEPROM中读取出来存入ReadTab 中去,
//然后比较Tab 和 EEPROM ,若内容一致,则说明读写都成功。
while(1)
{
// I2C_PageWrite(&Tab[0],0xA0,5);
I2C_BufferWrite(&Tab[0],0xA0,5);
Delay_MS(20);
I2C_BufferRead(&ReadTab[0],0xA0,5);
Delay_MS(20);
}
}
/*******************************************************************************
* Function Name : Delay_Ms
* Description : delay 1 ms.
* Input : dly (ms)
* Output : None
* Return : None
*******************************************************************************/
void Delay_MS(u16 dly)
{
u16 i,j;
for(i=0;i<dly;i++)
for(j=1000;j>0;j--);
}
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : Configures the different system clocks.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void RCC_Configuration(void)
{
//----------使用外部RC晶振-----------
RCC_DeInit(); //初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON); //使能外部的高速时钟
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等待外部高速时钟使能就绪
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
FLASH_SetLatency(FLASH_Latency_2); //Flash 2 wait state
RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //PCLK2 = HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); //PCLK1 = HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE); //Enable PLLCLK
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock
while(RCC_GetSYSCLKSource()!=0x08); //Wait till PLL is used as system clock source
//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能APB2外设的GPIOA的时钟
}
/*******************************************************************************
* Function Name : GPIO_Configuration
* Description : 初始化GPIO外设
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //选择PA.3
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIOA寄存器
}
/*******************************************************************************
* Function Name : NVIC_Configuration
* Description : Configures the nested vectored interrupt controller.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void NVIC_Configuration(void)
{
// NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
IIC.c
/*******************************************************************
本实验使用CAT24WC16:
CAT24WC16是CATALSYT公司生产的串行电可擦除的可编程存储器。其内部共有128页,每一页
为16字节,每一个字节8位。CAT24WC16以一个字节为一个存储单元,共有2K个存储单元。因此任一
存储单位地址为11位(A0~A11),地址范围为0x00~0x7FF(2K地址范围)。
*******************************************************************/
#include"stm32f10x_lib.h"
#include"IIC.h"
#define EEPROM_ADDRESS 0xA0
#define I2C2_SLAVE_ADDRESS7 0xA0
#define I2C_Speed 200000
#define I2C_PageSize 16
void I2C_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
//1、开时钟 GPIOB,I2C2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
//2、PB10 PB11 复用开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//3、I2C 配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置I2C为I2C模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //I2C快速模式
I2C_InitStructure.I2C_OwnAddress1 = I2C2_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
//4、使能I2C模块
I2C_Cmd(I2C2,ENABLE);
I2C_Init(I2C2,&I2C_InitStructure);
}
void I2C2_Init(void)
{
I2C_Configuration();
}
//字节写
void I2C_ByteWrite(u8 *pBuffer,u8 WriteAddr)
{
I2C_WaitEepromStandbyState();
/* [1]Send Start Condition 发送起始信号*/
I2C_GenerateSTART(I2C2,ENABLE);
/* [2]Test On EV5 and clear it 起始信号已发送并清除该事件 */
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));
/* [3]Send EEPROM address for write 发送器件地址*/
I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);
/* [4]Test on Ev6 and clear it 地址发送结束 */
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* [5]Send EEPROM's internal address to write 发送器件内部写入地址 */
I2C_SendData(I2C2,WriteAddr);
/* [6]Test on EV8 _1 and clear it 移位寄存器空 */
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* [7]Send the byte to be writeen 发送数据*/
I2C_SendData(I2C2,*pBuffer);
/* [8]Test on EV8 and clear it 发送缓冲区空*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* [9]Send STOP condition 发送停止信号 */
I2C_GenerateSTOP(I2C2,ENABLE);
}
//页写
void I2C_PageWrite(u8 *pBuffer,u8 WriteAddr,u8 NumByteToWrite)
{
I2C_WaitEepromStandbyState();
/*[1]Send START condition 发送起始条件*/
I2C_GenerateSTART(I2C2,ENABLE);
/*[2]Test on EV5 and clear it 起始信号发送是否成功*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));
/*[3]Send EEPROM address for write 发送器件地址*/
//EEPROM_ADDRESS 表示 EEPROM器件的地址
I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);
/*[4]Test on EV6 and clear it 发送器件地址是否成功*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/*[5]Send EEPROM'S internal address to write to 发送数据的写入首地址*/
//WriteAddr 表示EEPROM器件内部的读写地址(器件内部的存储地址)
I2C_SendData(I2C2,WriteAddr);
/*[6]Test on EV8 and clear it 发送内部地址是否成功*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/*[7]Send data to Written 发送数据*/
while(NumByteToWrite--)
{
/*Send the current byte 发送当前一个字节*/
I2C_SendData(I2C2,*pBuffer);
/* Point to the next byte to be written 地址++*/
pBuffer++;
/*Test on EV8 and clear it 发送缓冲区是否为空*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
/*[8]Send STOP condition 发送停止信号*/ (发送完成之后发送停止信号)
I2C_GenerateSTOP(I2C2,ENABLE);
}
//写数据:参数1:即将被写入的源数据;参数2:写入的目的地址;参数3:写入数据的大小;
void I2C_BufferWrite(u8 *pBuffer,u8 WriteAddr,u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
Addr = WriteAddr % I2C_PageSize; //得到页地址 I2C_PageSize = 16,
count = I2C_PageSize - Addr;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
I2C_WaitEepromStandbyState(); //等待EEPROM处于空闲状态
/* If WriteAddr is I2C_PageSize aligned */
if(Addr == 0)
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage == 0)
{
I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
while(NumOfPage--)
{
I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle!=0)
{
I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
}
}
/* If WriteAddr is not I2C_PageSize aligned */
else
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage== 0)
{
I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(count != 0)
{
I2C_PageWrite(pBuffer, WriteAddr, count);
I2C_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
}
while(NumOfPage--)
{
I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_WaitEepromStandbyState();
}
}
}
}
void I2C_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
/* Send START condition */
I2C_GenerateSTART(I2C2, ENABLE);
/* Read I2C1 SR1 register */
SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));
//当 EEPROM 处于非空闲状态,则一直等待,这里需要注意 I2C_Register_SR1 的寄存器 的第1位
//为0时表示地址发送没有结束,则While的判断为真,则会一直等待。
/* Clear AF flag */
I2C_ClearFlag(I2C2, I2C_FLAG_AF); //清除应答错误标志位
}
//读数据:参数1:读完数据存放的位置;参数2:从哪里读取数据;参数3:读取数据的大小;
void I2C_BufferRead(u8 *pBuffer,u8 ReadAddr,u16 NumByteToRead)
{
I2C_WaitEepromStandbyState();
/*Send START Condition 发送起始信号*/
I2C_GenerateSTART(I2C2,ENABLE);
/*Test on EV5 and clear it 检测起始信号是否发送成功*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));
/* In the case of a singel data transfer disable ACK before readint the data*/
if(NumByteToRead==1)
{
I2C_AcknowledgeConfig(I2C2,DISABLE);//如果NumByteToRead则不需1字节一应答
}
/*Send EEPROM ADDRESS for write */
I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);
/* Test on EV6 and clear it*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Enable I2C*/
I2C_Cmd(I2C2,ENABLE);
/* Send EEPROM'S internal address to write to*/
I2C_SendData(I2C2,ReadAddr);
/*Test on EV8 and clear it*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
//在这之前都是告诉 EEPROM ,即将要从EERROM的某个位置读取数据
/*Send START condition again*/
I2C_GenerateSTART(I2C2,ENABLE);
/*Test on EV5 and clear it*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));
/*Send EEPROM address for read*/
I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Receiver);
/*Test on EV6 and clear it*/
while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/*Read Data*/
while(NumByteToRead)
{
/*Test on EV7 and clear it*/
if(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if(NumByteToRead == 2)
{
/*Disable Acknowledgement*/
I2C_AcknowledgeConfig(I2C2,DISABLE); //一般在最后一个字节关闭应答
}
if(NumByteToRead == 1)
{
/*Send STOP condition */ //最后一位要关闭应答,发送停止信号
I2C_GenerateSTOP(I2C2,ENABLE);
}
/*Read a byte from the EEPROM*/
*pBuffer = I2C_ReceiveData(I2C2);
/*Point to the next location where the byte read will be saved*/
pBuffer++;
/*Decrement the read bytes counter*/
NumByteToRead--;
}
}
/*Enable Acknowledgement to be ready for anotherreception*/
I2C_AcknowledgeConfig(I2C2,ENABLE); //允许再次应答
}
上一篇:STM32-(19):I2C通信(理论基础) | 下一篇:STM32-(21):NVIC中断 |
---|