打印
[STM32F1]

stm32f103c硬件iic无法产生start信号

[复制链接]
2384|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
szkwong|  楼主 | 2016-5-25 16:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
望各位高手指点下: 我用 stm32f103c 硬件iic,用示波器看连start信号都无法产生。
main
{
  SystemInit(); /* 配置系统时钟为 72M */       
     IIC_Init();
   while(1)
   {
  
    I2C_GenerateSTART(I2C1, ENABLE);
     while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));   //在这里设置断点,用示波器看, pb.6和pb.7还是低(pb6和pb7都接了3k上拉电阻到vdd),连iic start信号都没有。
    Delay(0x000fffff);
     I2C_GenerateSTOP(I2C1, ENABLE);
     Delay(0x000fffff);
  }
}


void IIC_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  I2C_InitTypeDef I2C_InitStructure; //声明IIC初始化结构体
     
  
//   GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
//   GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
// conifgration of I2C
    // RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//IIC模式
     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //快速模式占空比
     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//反馈信号使能
     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//地址位设置
     I2C_InitStructure.I2C_ClockSpeed = 100000;//传输速度相关设置
     I2C_InitStructure.I2C_OwnAddress1 =0XD0;// 11010000B Write_Pcf8563; //PFC8563
     I2C_Init(I2C1, &I2C_InitStructure);
      I2C_Cmd(I2C1, ENABLE);
      
  /// xxxxx  RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  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);     
      
      
      
}
沙发
szkwong|  楼主 | 2016-5-25 16:54 | 只看该作者
pb6和pb7本来对于 iic的clk和data,平时是高,但发 I2C_GenerateSTART(I2C1, ENABLE);应该产生一个star信号,但用示波器看,另个io一直是低,请各位不吝赐教。谢谢

使用特权

评论回复
板凳
643757107| | 2016-5-25 20:03 | 只看该作者

使用特权

评论回复
地板
643757107| | 2016-5-25 20:06 | 只看该作者
不过还是要给你点例子
毕竟有人弄好了。
————————————————————————
先声明这里没有打开STM32的事件中断。本人菜鸟玩了两天I2C。
#include"stm32f10x_lib.h"
#include"stm32f10x_it.h"
#include"sys.h"


#define AT24C02_Addr_Write 0XA0;
#define AT24C02_Addr_Read (0XA0+1);


void IIC1_Init(u8 Addr);
void AT24C02_WriteByte(u8 ByteAddr,u8 Data);
int AT24C02_ReadByte(u8 ByteAddr);
int N;


int main(void)
{
Stm32_Clock_Init(9); //中断向量表映射到flash区,(SYSTEM=72MHZ AHB=72MHZ APB1=36MHZ APB2=72MHZ PLL=72MHZ PLL2=40MHZ)
delay_init(72);//延时初始化

RCC->APB2ENR |= 1<<3; //使能PORTB时钟;
GPIOB->CRL &= 0x00FFFFFF; //PB6 I2C1_SCL ,PB7 I2C1_SDL
GPIOB->CRL |= 0xFF000000; //复用开漏输出
IIC1_Init(0X30);//初始化IIC1接口地址为0X30
AT24C02_WriteByte(0X02,0XAA);//向AT24C02的0X02单元写入0XAA
delay_ms(3);//延时不可小于2ms
N=AT24C02_ReadByte(0X02); //从AT24C02的0X02单元读出数据
while(1)
{


}
}




//IIC1初始化,Addr为IIC1的自身地址
void IIC1_Init(u8 Addr)
{
RCC->APB1ENR |= 1<<21; //打开I2C1时钟
RCC->APB1RSTR |= 1<<21; //复位I2C1
RCC->APB1RSTR &= ~(1<<21); //复位结束I2C1

I2C1->CR1 |= 1<<15; //复位寄存器
I2C1->CR1 &= ~(1<<15); //复位结束
//I2C模块时钟频率,2~36MHz之间
I2C1->CR2 |= 36 ; //000000:禁用 000001:禁用

I2C1->CCR &= ~(1<<15); //I2C主模式 0:标准模式的I2C 1:快速模式的I2C
//I2C1->CCR &= ~(1<<14); //快速模式时的占空比 0:Tlow/Thigh=2 1:Tlow/Thigh=16/9 (标准模式时Tlow/Thigh=1/1)
//得到200KHZ频率
I2C1->CCR |= 90<<0; //标准模式时钟控制分频系数=PCLK1/2/f,f为想得到的频率

I2C1->TRISE |= 37; //最大允许SCL上升时间为1000ns,故TRISE[5:0]中必须写入(1us/(1/36)us = 36+1)。

//I2C1->CR1 |= 1<<10; //打开ACK应答,在接收到一个字节后返回一个应答
I2C1->CR1 |= 1<<6; //广播呼叫使能
I2C1->CR1 &= ~(1<<1); //0:I2C模式 1:SMBus模式


I2C1->OAR1 &= ~(1<<15);//寻址模式 1:响应10位地址 0:响应7位地址
I2C1->OAR1 |= 1<<14; //必须始终由软件保持为1
I2C1->OAR1 |= Addr<<1; //设置接口地址的7~1位

//I2C1->CR2 |= 1<<10; //缓冲器中断使能
//I2C1->CR2 |= 1<<9; //事件中断使能
I2C1->CR2 |= 1<<8; //出错中断使能


I2C1->CR1 |= 1<<0; //开启I2C1
}


//向AT24C02写一个字节,ByteAddr字节地址(0~255),Data所要写入的数据
void AT24C02_WriteByte(u8 ByteAddr,u8 Data)
{
int clear;
clear=clear;
while(I2C1->SR2&=1<<1); //等待SR2.Busy=0(总线空闲)
I2C1->CR1 |= 1<<8; //I2C1产生起始条件


while(!(I2C1->SR1&=1<<0));//等待SR1.SB=1开始位已经发送
I2C1->SR1 &= ~(1<<10);//SR1.AF清零
I2C1->DR = AT24C02_Addr_Write;//写入AT24C02的地址Addr,写指令,SR1.SB清零


while(!(I2C1->SR1&=1<<1));//等待SR1.ADDR=1,从设备应答
clear=I2C1->SR1;
clear=I2C1->SR2;//SR1.ADDR清零
I2C1->DR = ByteAddr;//写入字节地址


while(!(I2C1->SR1&=1<<2));//等待SR1.BTF=1,字节地址发送完毕
clear=I2C1->SR1;//SR1.BTF清零
I2C1->DR = Data;//发送要写入的数据


while(!(I2C1->SR1&=1<<2));//数据发送完成


I2C1->CR1 |= 1<<9; //I2C1产生停止条件
}


//从AT24C02读出一个字节,ByteAddr字节地址(0~255)
int AT24C02_ReadByte(u8 ByteAddr)
{
int clear;
clear=clear;
while(I2C1->SR2&=1<<1); //等待SR2.Busy=0(总线空闲)
I2C1->CR1 |= 1<<8; //I2C1产生起始条件


while(!(I2C1->SR1&=1<<0));//等待SR1.SB=1开始位已经发送
I2C1->SR1 &= ~(1<<10);//SR1.AF清零
I2C1->DR = AT24C02_Addr_Write;//写入AT24C02的地址Addr,写指令,SR1.SB清零


while(!(I2C1->SR1&=1<<1));//等待SR1.ADDR=1,从设备应答
clear=I2C1->SR1;
clear=I2C1->SR2;//SR1.ADDR清零
I2C1->DR = ByteAddr;//写入字节地址


I2C1->CR1 |= 1<<8; //I2C1产生起始条件


while(!(I2C1->SR1&=1<<0));//等待SR1.SB=1开始位已经发送
I2C1->SR1 &= ~(1<<10);//SR1.AF清零
I2C1->DR = AT24C02_Addr_Read;//写入AT24C02的地址Addr,读指令,SR1.SB清零


while(!(I2C1->SR1&=1<<1));//等待SR1.ADDR=1,从设备应答
clear=I2C1->SR1;
clear=I2C1->SR2;//SR1.ADDR清零


while(!(I2C1->SR1&=1<<6));//等待SR1.RxNE=1,接收到数据
I2C1->CR1 |= 1<<9; //I2C1产生停止条件
return I2C1->DR;
}


/*******************************************************************************
* Function Name : I2C1_ER_IRQHandler
* Description : This function handles I2C1 Error interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void I2C1_ER_IRQHandler(void)
{
if(I2C1->SR1 & 1<<10) //应答失败
{
I2C1->SR1 &=~(1<<10); //清除中断
}

if(I2C1->SR1 & 1<<14) //超时
{
I2C1->SR1 &=~(1<<14); //清除中断
}

if(I2C1->SR1 & 1<<11) //过载/欠载
{
I2C1->SR1 &=~(1<<11); //清除中断
}

if(I2C1->SR1 & 1<<9) //仲裁丢失
{
I2C1->SR1 &=~(1<<9); //清除中断
}

if(I2C1->SR1 & 1<<8) //总线出错
{
I2C1->SR1 &=~(1<<8); //清除中断
}
}


使用特权

评论回复
5
643757107| | 2016-5-25 20:08 | 只看该作者
再来一个
————————————————————————————
34STM32-IIC 配置解说
STM32 - I2C简介:
I2C总线接口连接微控制器和串行I2C总线。它提供多主机功能,控制所有I2C总线特定的时序、协议、仲裁和定时。支持标准和快速两种模式,另外STM32的I2C可以使用DMA方式操作。

本文主要以一个实例来介绍STM32-I2C的配置方式和具体在工程中通过调用哪些库函数来实现I2C器件的通信。
实例:写入数据到器件AT24C02并将存入的数据读出
好,我们先来讲讲STM32 I2C模块的端口基本配置,由STM32中文参考手册可以查到在使用I2C时对应的引脚要配置成哪种模式。SCL和SDA引脚都配置成开漏复用输出

本人用的是STM32F103VET6,它有2个I2C接口。I/O口定义为PB6-I2C_SCL,PCB7-I2C1_SDA;PB10-I2C_SCL,PB11-I2C_SDA,由手册可以查出对应的端口。 图文如下:

调用库函数将I2C端口配置好(本文使用的是PB6、PB7端口):
程序代码如下:
/*I2C-IO口配置*/
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef  GPIO_InitStructure; //GPIO结构体定义
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能I2C的IO口
/* PB6-I2C1_SCL、PB7-I2C1_SDA*/
GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;        // 开漏输出   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化结构体配置
}

/* I2C 工作模式配置 */
void I2C_Mode_config(void)
{
/* 使能与 I2C1 有关的时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/*定义I2C结构体*/
I2C_InitTypeDef  I2C_InitStructure;
/*配置为I2C模式*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
/*该参数只有在I2C 工作在快速模式(时钟工作频率高于 100KHz)下才有意义。*/
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
/*设置第一个设备自身地址*/
I2C_InitStructure.I2C_OwnAddress1 =0x0A;
/*使能应答*/
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
/*AT24C02地址为7位所以设置7位就行了*/
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /*时钟速率,以HZ为单位的,最高为400khz*/
I2C_InitStructure.I2C_ClockSpeed = 400000;
/* 使能 I2C1 */
I2C_Cmd(I2C1, ENABLE);

/* I2C1 初始化 */
I2C_Init(I2C1, &I2C_InitStructure);
}

好了,STM32 内部的 I2C模块工作模式就这样被设好了,接下来需要完成与外部器件AT24C02(EEPROM)进行通信。将分两部分进行代码解析,第一部分是:对AT24C02进行写操作,第二部分:对AT24C02进行读操作。

第一部分(写):
备注:I2C_PageSize  为宏定义 #define I2C_PageSize  8 ;
/*
* 函数名:I2C_EE_BufferWrite
* 描述  :将缓冲区中的数据写到I2C EEPROM中
* 输入  :-pBuffer 缓冲区指针
*         -WriteAddr 接收数据的EEPROM的地址
*         -NumByteToWrite 要写入EEPROM的字节数
* 输出  :无
* 返回  :无
* 调用  :外部调用
*/
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

Addr = WriteAddr % I2C_PageSize;//查看输入的地址是不是8的整数倍
count = I2C_PageSize - Addr;//表示距离下一页页首地址的距离(步伐数)
NumOfPage =  NumByteToWrite / I2C_PageSize;//算出一共有多少页
NumOfSingle = NumByteToWrite % I2C_PageSize;//算出不够一页的数据的余数
if(Addr == 0) //如果输入的地址是首页地址
{
if(NumOfPage == 0) //如果不足一页数据
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//调用写函数,NumOfSingle不              够一页的余数作为实参
I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作
}
/* If NumByteToWrite > I2C_PageSize */
else  //如果数据有一页以上
{
while(NumOfPage--)//用一个while循环,执行页写循环操作,有多少页就写多少次       {
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize); //调用写函数,将
I2C_PageSize变量作为实              参执行页写
I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作
WriteAddr +=  I2C_PageSize;//每执行完一次页写对应的地址也需要移8个位         pBuffer += I2C_PageSize;//数据指针移8个位
}

if(NumOfSingle!=0)//如果有不足一页的数据余数则执行
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//调用写函数,NumOfSingle              不够一页的余数作为实参
I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作

}
}
}

else //输入的地址不是首页地址
{
if(NumOfPage== 0) //如果不足一页
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//调用写函数,NumOfSingle不              够一页的余数作为实参       I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作
}

else//如果有一页或一页以上
{
NumByteToWrite -= count;//将地址后续的缺省位置补上数据,数据的多少就是count         的值,NumByteToWrite变量的值就是补上数据之后          还剩下未发送的数量
NumOfPage =  NumByteToWrite / I2C_PageSize;//剩余的页数
NumOfSingle = NumByteToWrite % I2C_PageSize;//不足一页的数据数量

if(count != 0)//将地址后续的缺省位置补上数据
{
I2C_EE_PageWrite(pBuffer, WriteAddr, count);//调用写函数,以count为实参,将地            址缺省下来的部分地址给填充             上数据
I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作
WriteAddr += count;//加上count后,地址就移位到下一页的首地址
pBuffer += count;//数据指针移count个位
}

while(NumOfPage--)//将剩余的页数数据写入EEPROM
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);//调用写函数,将
I2C_PageSize变量作为实
参执行页写
I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作         WriteAddr +=  I2C_PageSize;//将地址移8个位
pBuffer += I2C_PageSize;  //将数据指针移8个位
}
if(NumOfSingle != 0)//将不足一页的数据写入EEPROM
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//调用写函数,NumOfSingle              不够一页的余数作为实参          I2C_EE_WaitEepromStandbyState();//等待EEPROM器件完成内部操作       }
}
}
}
/*END OF FUNCTION*/

在以上写操作里面我们拿经常被调用的I2C_EE_PageWrite函数还有
I2C_EE_WaitEepromStandbyState函数并结合STM32中文参考手册图文进行对照分析

请读者在读I2C_EE_PageWrite函数时请结合上述时序图和下述代码联系一起看! 注:EEPROM_ADDRESS 为器件的地址,大家按照自己具体器件地址写入即可, 例:#define EEPROM_ADDRESS 0xA0
/*
* 函数名:I2C_EE_PageWrite
* 描述  :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数  *         不能超过EEPROM页的大小。AT24C02每页有8个字节。

*输入:-pBuffer缓冲区指针;*-WriteAddr接收数据的EEPROM的地;*-NumByteToWrite要写入EEPRO;*输出:无;*返回:无;*调用:外部调用;*/;voidI2C_EE_PageWrite(u8*;I2C_GenerateSTART(I2C1,E;while(!I2C_CheckEvent(I2;I2C_Send7bitA




* 输入 :-pBuffer 缓冲区指针

* -WriteAddr 接收数据的EEPROM的地址

* -NumByteToWrite 要写入EEPROM的字节数

* 输出 :无

* 返回 :无

* 调用 :外部调用

*/

void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)

{

I2C_GenerateSTART(I2C1, ENABLE);//产生起始位



while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //清除EV5

I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//发送器件地 址

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //ADDR=1,清除EV6



I2C_SendData(I2C1, WriteAddr); //EEPROM的具体存储地址位置



while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//移位寄存器非空,数据寄存器已经空,产生EV8,发送数据到DR既可清除该事件



while(NumByteToWrite--) //利用while循环 发送数据

{

I2C_SendData(I2C1, *pBuffer); //发送数据



pBuffer++; //数据指针移位



while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//清除 EV8 }



I2C_GenerateSTOP(I2C1, ENABLE);//产生停止信号

}

/*END OF FUNCTION*/



I2C_EE_WaitEepromStandbyState这个函数,在每调用完写操作函数后都调用这个函数,这个函数是用来检测EEPROM器件是否已经完成内部写的操作,判断器件完成操作后在进行下一步的操作!代码如下:

/*

* 函数名:I2C_EE_WaitEepromStandbyState

* 描述 :Wait for EEPROM Standby state

* 输入 :无

* 输出 :无

* 返回 :无

* 调用 :

*/

void I2C_EE_WaitEepromStandbyState(void)

{

vu16 SR1_Tmp = 0;



do

{

I2C_GenerateSTART(I2C1, ENABLE);//产生起始信号

SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);//读SR1寄存器

I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//发送器件 地址清除事 件

}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));//如果接收不到从机的应答(NACK)则说明EEPROM器件还在工作,直到完成操作跳出循环体!



I2C_ClearFlag(I2C1, I2C_FLAG_AF);//清除AF标志位

I2C_GenerateSTOP(I2C1, ENABLE); //产生停止信号

}





第二部分(读):



由以上AT24C02读时序图可以知道:读部分需要产生两次起始信号



另外:主设备在从从设备接收到最后一个字节后发送一个NACK 。接收到NACK 后,从设备释放对SCL和SDA线的控制;主设备就可以发送一个停止/ 重起始条件。

● 为了在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后(在倒数第二个RxNE事件之后)必须清除ACK位。

● 为了产生一个停止/ 重起始条件,软件必须在读倒数第二个数据字节之后(在倒数第二个RxNE事件之后)设置STOP/START位。

● 只接收一个字节时,刚好在EV6 之后(EV6_1时,清除ADDR 之后)要关闭应答和停止条件的产生位。



请读者将代码和图结合在一起看!





/*

* 函数名:I2C_EE_BufferRead

* 描述 :从EEPROM里面读取一块数据。

* 输入 :-pBuffer 存放从EEPROM读取的数据的缓冲区指针。

* -WriteAddr 接收数据的EEPROM的地址。

* -NumByteToWrite 要从EEPROM读取的字节数。

* 输出 :无

* 返回 :无

* 调用 :外部调用

*/

void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//需要两个起始信号

{

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //调用库函数检测I2C器件是否处 于BUSY状态

I2C_GenerateSTART(I2C1, ENABLE);//开启信号

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));//清除EV5

I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//写入器件地址



while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//清除EV6



I2C_SendData(I2C1, ReadAddr); //发送读的地址



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, EEPROM_ADDRESS, I2C_Direction_Receiver);//将器件地址传出,主机为读



while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//清除EV6



while(NumByteToRead)

{

if(NumByteToRead == 1)//只剩下最后一个数据时进入if语句

{

I2C_AcknowledgeConfig(I2C1, DISABLE);//最后有一个数据时关闭应答位

I2C_GenerateSTOP(I2C1, ENABLE);//最后一个数据时使能停止位

}



if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) //读取数据 {



*pBuffer = I2C_ReceiveData(I2C1);//调用库函数将数据取出到pBuffer

pBuffer++; //指针移位



NumByteToRead--;//字节数减1

}

}



I2C_AcknowledgeConfig(I2C1, ENABLE);//将应答位使能回去,等待下次通信 }

STM32-IIC 配置解说到此告一段落!


使用特权

评论回复
6
fan321| | 2016-5-26 14:08 | 只看该作者
szkwong 发表于 2016-5-25 16:54
pb6和pb7本来对于 iic的clk和data,平时是高,但发 I2C_GenerateSTART(I2C1, ENABLE);应该产生一个star信号 ...

你引脚加上拉没?

使用特权

评论回复
7
szkwong|  楼主 | 2016-5-26 14:57 | 只看该作者
回楼上,两个io都接了上拉电阻, 现在   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); 改为        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);  可以看到 clk和data 变高,但是start 还是没出来,求指点

使用特权

评论回复
8
Thethree| | 2016-5-26 20:51 | 只看该作者
643757107 发表于 2016-5-25 20:06
不过还是要给你点例子
毕竟有人弄好了。
————————————————————————

我知道stm32的i2c有bug,好像是时钟的速率上不去

使用特权

评论回复
9
lefeng| | 2016-5-26 21:44 | 只看该作者
用ST的硬件IIC时,不要用中断和DMA

使用特权

评论回复
10
fan321| | 2016-5-27 10:26 | 只看该作者
szkwong 发表于 2016-5-26 14:57
回楼上,两个io都接了上拉电阻, 现在   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); 改为        RCC_ ...

我也是新手,前段时间也是没有Start产生,我没有加上拉。。。。。。  下面的你参考一下,我使用的是简单的I2C,没有触及到大神们用到的那些
        GPIO_InitTypeDef GPIO_InitStructure;
        I2C_InitTypeDef I2C_InitStructure;
        RCC_APB2PeriphClockCmd  (RCC_APB2Periph_GPIOB,ENABLE );
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  

         /* PB6-I2C1_SCL  PB7-I2C1_SDA*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
       /* I2C配置*/
        I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ;
        I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9;
        //I2C_InitStructure.I2C_OwnAddress1 = SlaveAddress;
        I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
        I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
        I2C_InitStructure.I2C_ClockSpeed = 400000;



        I2C_Init(I2C1, &I2C_InitStructure);          
       

        I2C_Cmd  (I2C1,ENABLE); //I2C使能

        I2C_AcknowledgeConfig(I2C1, ENABLE);

使用特权

评论回复
11
szkwong|  楼主 | 2016-5-30 10:33 | 只看该作者
回复楼上,是不是硬件哪里要注意什么呀。搞了几天都搞不定,都不敢去找工作了。

使用特权

评论回复
12
szkwong|  楼主 | 2016-5-30 11:35 | 只看该作者
我用的是keil 4.72, 不知道是不是编译软件哪里没有设置好呀? 恳请指点。

使用特权

评论回复
13
xmshao| | 2016-5-31 16:36 | 只看该作者
szkwong 发表于 2016-5-30 11:35
我用的是keil 4.72, 不知道是不是编译软件哪里没有设置好呀? 恳请指点。

你代码配置有问题吧。
找个官方例程试试。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

21

帖子

0

粉丝