先说明一下遇到的问题:
1、在进行单字节数据循环读写的时候,循环写的数据少了(如<=100)可以,但是多了就会挂(目前随即选了发送120个就挂了)。
2、在多字节读取的函数中,读写的数据量在20(随即选的)以内时木有问题,但是如果一次写的字节数多了(>100),在多字节读的函数中执行到读最后一个字节数据时,就会挂在while();等待EV5处。
3、有时什么都不做,直接初始化完了,进行发送第一个字节的时候,也会莫名其妙的挂在等待总线空闲处。(间歇性的,时好时坏)。
补充一下(FM24CL04:4K的内存,分两页,(从机地址的倒数第二位区分操作的是哪个页),一页2Kbit也就是256个字节:2Kbit=256*8bit).
以下是我的代码,请指正啊:
#include "config.h"
//PB5/I2C_WP 写保护
#define DIS_WP() GPIO_ResetBits(GPIOB,GPIO_Pin_5); // PB5/I2C_WP 低电平可写
#define EN_WP() GPIO_SetBits(GPIOB,GPIO_Pin_5); // PB5/I2C_WP 高电平写保护
/********************************************************
*函数名称:void I2C1_Init(uint32 fi2c)
*函数功能: STM32 硬件I2C初始化,主程序要配置好I2C总线接口(I2C引脚功能,并已使能I2C主模式)
*未开中断,之前的函数I2C收发都是在中断中完成的。
********************************************************/ void I2C1_Init(uint32 fi2c)
{
/*PB6 I2C1_SCL PB7 I2C1_SDA */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD; //复用开漏输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//PB5/I2C1_Wp
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;; //开漏输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/********************
配置I2C1为I2C主模式,置I2C 的占空比/快速模式Tlow / Thigh = 2,
置第一个设备自身地址 7位模式,使能应答(ACK),应答 7 位地址,时钟频率200KHz
**********************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//配置I2C2为主模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//快速模式Tlow / Thigh = 2
I2C_InitStructure.I2C_OwnAddress1 = 0x30;//第一个设备自身地址0x30; 7位模式
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//使能应答(ACK)
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = fi2c;//时钟频率200KHz
I2C_Init(I2C1, &I2C_InitStructure);//初始化I2C1
// I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT, ENABLE);//使能缓存和事件中断
I2C_Cmd(I2C1, ENABLE);//使能I2C1
DS_WP(); //禁止写保护
}
/*******************************************************
** 函数名称:ISendByte() 从机地址内包含页地址1位,读写1位
** 函数功能:向无子地址器件发送1字节数据。
** 入口参数:sla 要写入数据的地址 器件地址
** dat 要写入的数据 要发送的数据
***************************************************/
uint8 ISendByte(uint8 sla, uint8 dat)
{
I2C_GenerateSTART(I2C1,ENABLE);//发送一个开始讯号
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)){;}//等待EV5 已发送起始条件
I2C_Send7bitAddress(I2C1, 0xA2, I2C_Direction_Transmitter);//发送从机地址 写
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){;}//等待EV6 已发送从机地址
I2C_SendData(I2C1, sla);//发送要写的寄存器地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;}//等待EV8 第一个数据已发送
I2C_SendData(I2C1, dat);//发送要写入到从机寄存器地址中的数据
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;}//等待EV8
I2C_GenerateSTOP(I2C1,ENABLE); //停止位
return 1;//无实意,防止系统警告 13 12 4
}
/******************************************************
** 函数名称:IRcvByte() 从机地址内包含页地址1位,读写1位
** 入口参数:sla 器件地址
** dat 接收数据的变量指针
** 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
** 说明:使用前要初始化好I2C引脚功能,并已使能I2C主模式
***************************************************/
uint8 IRcvByte(uint8 sla, uint8 *dat)
{
I2C_AcknowledgeConfig(I2C1, ENABLE); //使能应答位
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //等待I2C
I2C_GenerateSTART(I2C1, ENABLE); //产生起始信号
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //等待EV5
I2C_Send7bitAddress(I2C1,0xA2, I2C_Direction_Transmitter); //发送从机地址 写
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6
I2C_SendData(I2C1, sla); //发送读地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8
I2C_GenerateSTART(I2C1, ENABLE); //重新启动
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,0xA2, I2C_Direction_Receiver);//发送从机地址 读
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6
I2C_AcknowledgeConfig(I2C1, DISABLE); //关闭应答和停止条件产生
I2C_GenerateSTOP(I2C1, ENABLE); //停止条件产生
while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))); //EV7
*(dat++)=I2C_ReceiveData(I2C1);
return 1;
}
/************************************************
** 函数名称 :I2C_ReadNByte() 从机地址内包含页地址1位,读写1位
** 函数功能 :从有子地址器件任意地址开始读取N字节数据
** 入口参数 : sla 器件从地址
** suba 器件子地址
** s 数据接收缓冲区指针
** num 读取的个数
********************************************************/
uint8 I2C_ReadNByte (uint8 sla, uint32 suba_type, uint32 suba, uint8 *s, uint32 num)
{
suba_type=suba_type;//防止系统报错
I2C_AcknowledgeConfig(I2C1,ENABLE);//使能应答位
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); //等待I2C空闲
I2C_GenerateSTART(I2C1,ENABLE);//产生起始信号
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//等待EV5
///////////////////发送从机地址 写
I2C_Send7bitAddress(I2C1,sla, I2C_Direction_Transmitter); //发送从机地址 写
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6
//////////发送要读取的数据的地址
I2C_SendData(I2C1, suba);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//EV8
I2C_GenerateSTART(I2C1, ENABLE);//重新发送
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//EV5
////////////////////////////发送从机地址 读
I2C_Send7bitAddress(I2C1, sla, I2C_Direction_Receiver);//发送从机地址 读
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6
while(num)
{
if(num==1) //写255的时候,执行完if后会挂在while(),写20个时没事啊
{
I2C_AcknowledgeConfig(I2C1, DISABLE);//关闭应答
I2C_GenerateSTOP(I2C1, ENABLE);//关闭应答和停止条件产生 OK
}
while(!(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)));//等待EV7
*(s++)=I2C_ReceiveData(I2C1);
num--;
}
I2C_AcknowledgeConfig(I2C1, ENABLE);//使能i2C 指定的应答功能
return 1;//无实意,防止警告
}
/************************************************
** 函数名称 :I2C_WriteNByte() 从机地址内包含页地址1位,读写1位
** 函数功能 :向有子地址器件写入N字节数据
** 入口参数 : sla 器件从地址(区别两个页0XA0对应1页,0XA2对应0页)
** suba_type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** suba 器件内部物理地址
** *s 将要写入的数据的指针
** num 将要写入的数据的个数
****************************************************/
uint8 I2C_WriteNByte(uint8 sla, uint8 suba_type, uint32 suba, uint8 *s, uint32 num)
{
//此处有两个问题1、 写超过一页。2、写的内存地址(uint32)
suba_type=suba_type; //防止报错 子地址结构
suba=(uint8)(suba); //要写入的数据的地址 char型
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); //等待I2C空闲
I2C_GenerateSTART(I2C1,ENABLE); //产生I2C1传输START条件
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)){;}//等待EV5
I2C_Send7bitAddress(I2C1, sla, I2C_Direction_Transmitter);//发送从机地址 写
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){;}//等待EV6
I2C_SendData(I2C1, suba);//发送要写的寄存器地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;}//等待EV8
while(num)
{
I2C_SendData(I2C1, *s++);//发送要写入到从机寄存器地址中的数据
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;}//等待EV8
num--;
}
I2C_GenerateSTOP(I2C1,ENABLE);
return 1;//无实意,防止系统警告
}
/////////测试任务 I2C FM24CL04
static void I2CFlash_task(void *p_arg)
{
p_arg=p_arg;
I2C1_Init(200000); //FM24cl04的I2C总线初始化 速率200K
SysDOInit(); //测试任务切换用 开关量输出管脚初始化
unsigned int i=0;
uint8 AddrI2C[256],add; //建立数组用来存储要读、写的数据的地址
uint8 Readdata_AddrI2C[256]={0};//存储读取来的数据
uint8 onedata[256]={0};
//////初始化要读取的数据的地址数组
for(i=0;i<=255;i++)
{
AddrI2C[i]=i++; //初始化要读取的数据的地址数组
}
while(1)
{
CtrlDOData(0x80); //测试任务切换用点灯
///////////////////测试写单个字节 Begin 向24CL04发送256个数据0~~255
//目前数据发多了(目前测试120)就会进入硬件故障,不知道哪里出了问题?超限了?
for(i=0;i<=110;i++)
{
ISendByte(AddrI2C[i],i); //向24CL04发送256个数据0~~255
IRcvByte(AddrI2C[i],&onedata[i]); //从24CL04读取256个数据0~~255存入onedata[]中
}
///////////////////测试写单个字节 end
/////////////////////////测试写多个字节 begin
add=0x00; //重新赋0地址
uint8 AddrI2C1[256]= {0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA};
I2C_WriteNByte(0xA2, 1, add, AddrI2C1, 20); //写多个字节数据到FM24CL04
I2C_ReadNByte(0xA2,1, add,Readdata_AddrI2C,20);//从FM24CL04读多个字节数据
/////////////////////////测试写多个字节 end
OSTimeDlyHMSM(0,0,0,50);
}
}
我要赚赏金
