如题,本人在使用STM32F103C8T6模拟IIC与24C02通信,例程是移植的原子哥战舰V3的程序(把ZE移植到了C8T6),引脚改为了PB0(SCL),PB1(SDA)。但是在使用时Check失败,用示波器抓了波形,发现CLK是正常的,也就是有模拟出来的时钟波形,但是SDA一直是高电平。单步调试下来看,IIC_start()里SDA可以拉高拉低,后面的第一个发送字节的函数里面的SDA也是可以拉高拉低的,但是再后边的SDA却“不受控制”了,也就是无论拉高拉低都是零,最终出现24C02的Check失败。有大佬能够解答一下嘛,谢谢您。萌新第一次发帖,有不足之处请见谅。注:用的板子是工厂打的样,排除了焊接问题。也尝试换过板子,已经是第二次了,之前也遇到过这种问题,只不过不是这个引脚。
注:之前用的引脚怀疑是使用了与USART有关的引脚,但是这次看来与USART关系不大。
C8T6的封装
选择的两个管脚 程序如下 //初始化IIC void EEPROM_IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;// |GPIO_Pin_0,1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ; //开漏输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1); //PB0,PB1 输出高 } ///////其他的什么Start,Stop,Wait_Ack等程序是例程那样的
//IO方向设置 #define EEPROM_SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<4;} #define EEPROM_SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<4;}
//IO操作函数 #define EEPROM_IIC_SCL PBout(0) //SCL #define EEPROM_IIC_SDA PBout(1) //SDA #define EEPROM_READ_SDA PBin(1) //输入SDA
//关于24C02的程序也是和例程是一样的 //所以下边参考就可以 //初始化IIC接口 void AT24CXX_Init(void) { EEPROM_IIC_Init(); } //在AT24CXX指定地址读出一个数据 //ReadAddr:开始读数的地址 //返回值 :读到的数据 u8 AT24CXX_ReadOneByte(u16 ReadAddr) { u8 temp=0; EEPROM_IIC_Start(); if(EE_TYPE>AT24C16) { EEPROM_IIC_Send_Byte(0XA0); //发送写命令 EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Send_Byte(ReadAddr>>8);//发送高地址 EEPROM_IIC_Wait_Ack(); }else EEPROM_IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据
EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Send_Byte(ReadAddr%256); //发送低地址 EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Start(); EEPROM_IIC_Send_Byte(0XA1); //进入接收模式 EEPROM_IIC_Wait_Ack(); temp=EEPROM_IIC_Read_Byte(0); EEPROM_IIC_Stop();//产生一个停止条件 return temp; } //在AT24CXX指定地址写入一个数据 //WriteAddr :写入数据的目的地址 //DataToWrite:要写入的数据 void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) { EEPROM_IIC_Start(); if(EE_TYPE>AT24C16) { EEPROM_IIC_Send_Byte(0XA0); //发送写命令 EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Send_Byte(WriteAddr>>8);//发送高地址 }else { EEPROM_IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据 } EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Send_Byte(WriteAddr%256); //发送低地址 EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Send_Byte(DataToWrite); //发送字节 EEPROM_IIC_Wait_Ack(); EEPROM_IIC_Stop();//产生一个停止条件 delay_ms(10); } //在AT24CXX里面的指定地址开始写入长度为Len的数据 //该函数用于写入16bit或者32bit的数据. //WriteAddr :开始写入的地址 //DataToWrite:数据数组首地址 //Len :要写入数据的长度2,4 void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len) { u8 t; for(t=0;t<Len;t++) { AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff); } }
//在AT24CXX里面的指定地址开始读出长度为Len的数据 //该函数用于读出16bit或者32bit的数据. //ReadAddr :开始读出的地址 //返回值 :数据 //Len :要读出数据的长度2,4 u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len) { u8 t; u32 temp=0; for(t=0;t<Len;t++) { temp<<=8; temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); } return temp; } //检查AT24CXX是否正常 //这里用了24XX的最后一个地址(255)来存储标志字. //如果用其他24C系列,这个地址要修改 //返回1:检测失败 //返回0:检测成功 u8 AT24CXX_Check(void) { u8 temp; temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX if(temp==0X55)return 0; else//排除第一次初始化的情况 { AT24CXX_WriteOneByte(255,0X55); temp=AT24CXX_ReadOneByte(255); if(temp==0X55)return 0; } return 1; }
//在AT24CXX里面的指定地址开始读出指定个数的数据 //ReadAddr :开始读出的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToRead:要读出数据的个数 void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) { while(NumToRead) { *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); NumToRead--; } } //在AT24CXX里面的指定地址开始写入指定个数的数据 //WriteAddr :开始写入的地址 对24c02为0~255 //pBuffer :数据数组首地址 //NumToWrite:要写入数据的个数 void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) { while(NumToWrite--) { AT24CXX_WriteOneByte(WriteAddr,*pBuffer); WriteAddr++; pBuffer++; } }
|