历史上的今天
今天是:2025年08月09日(星期六)
2019年08月09日 | STM32 I2C从机发送数据
2019-08-09 来源:eefocus
stm32 I2C主机发送功能在网上有很多例程,调试也很容易,从机发送数据的介绍很少,鉴于本人刚开始调试单片机程序不久,花了一整天也没调试通,最后在部门领导的帮助下,通过示波器及单步调试程序,查看寄存器状态值,终于实现了。下面主要介绍下从机发送数据注意事项。(附带例程)
1、相信使用I2C的都知道,从机是不能主动发送数据的,开始条件都是由主机生成。
2、根据参考文档,I2C默认是从机模式,只有在生成起始条件后,才会从从机模式自动切换到主机模式。所以作为从机模式使用时不能生成起始条件。
3、附图1,为从机发送器的传送时序图,截图于参考手册,图中说明部分讲述了怎样能清除事件,这点很重要,每次事件是都要去清除才可以去检测下一个事件,否则很可能检测不到其他事件,我当初就是死在这上面的。
4、需要的数据发送完成了,根据附图1和2可知,主机需要发送一个NACK,从机有NACK应答,当你以为这样可以的时候就大错特错了。文档中有句话,要在读倒数第二个字节之后发送,而非所有字节发送完成再发送。仔细看附图1中说明部分[EV3:TxE=1,写DR将清除该事件;移位寄存器非空。],如果不清除该事件的话,那对不起,你根本就检测不到EV3-2事件。所以在需要传输的数据传输完时,再向DR寄存器中写入一个数据后发送NACK就行了,这个数据是我们不需要的,写什么不重要,目的是为了清除事件(EV3)罢了(也可以在最后一个数据之前发送NACK,就不需要写入无用数据了,这里没有测试其他办法就不赘述了)
附图1:从发送器的传送序列图

附图2: 主接收器传送序列图

附bsp_i2c.c源码:
/** ******************************************************************************
* @file bsp_i2c.c
* @author Eason
* @version V1.0
* @date 2014-09-15
* @brief I2C应用函数接口
******************************************************************************
* @attention
*
* 实验平台:野火 iSO-MINISTM32 开发板
* 固件库版本V3.5
*****************************************************************************
*/
#include"bsp_i2c.h"
/* Private typedef-----------------------------------------------------------*/
typedef enum{FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define------------------------------------------------------------*/
#defineI2C1_SLAVE_ADDRESS7 0x30
#defineI2C2_SLAVE_ADDRESS7 0x24
#defineBufferSize 4
#defineClockSpeed 300000
/* Privatevariables ---------------------------------------------------------*/
u8I2C1_Buffer_Tx[BufferSize] = {1,20,50,100};
u8I2C2_Buffer_Rx[BufferSize] = {0};
u8 TxIdx = 0,RxIdx = 0;
volatileTestStatus TransferStatus = FAILED;
/******************************************************************************
* FunctionName : I2C_GPIO_Config
* Description : Configuresthe different GPIO ports.
* Input : None
* Output : None
* Return : None
******************************************************************************/
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
/* Enable peripheral clocks--------------------------------------------------*/
/*GPIOB Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
/*I2C1 and I2C2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1| RCC_APB1Periph_I2C2, ENABLE);
/*Configure I2C1 pins: SCL and SDA ----------------------------------------*/
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_6 | GPIO_Pin_7; //选择待设置的GPIO管脚
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz; //管脚速率50MHz
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_OD; //复用开漏输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
/*Configure I2C2 pins: SCL and SDA ----------------------------------------*/
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_10 | GPIO_Pin_11;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/******************************************************************************
* FunctionName : I2C_Master_Init
* Description : I2C Master initialize.
* Input : None
* Output : None
* Return : None
******************************************************************************/
voidI2C_Master_Init(void)
{
I2C_InitTypeDef I2C_InitStructure;
/* I2C1 configuration------------------------------------------------------*/
I2C_InitStructure.I2C_Mode= I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle= I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1= I2C1_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack= I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed= ClockSpeed;
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
/******************************************************************************
* FunctionName : I2C_Slave_Init
* Description :I2C Slave initialize.
* Input : None
* Output :None
* Return : None
******************************************************************************/
voidI2C_Slave_Init(void)
{
I2C_InitTypeDef I2C_InitStructure;
/*I2C2 configuration ------------------------------------------------------*/
I2C_InitStructure.I2C_Mode =I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle= I2C_DutyCycle_2;
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= ClockSpeed;
I2C_Init(I2C2,&I2C_InitStructure);
I2C_Cmd(I2C2, ENABLE);
}
voidI2C_Mode_Init(void)
{
I2C_GPIO_Config();
I2C_Master_Init();
I2C_Slave_Init();
}
/******************************************************************************
* FunctionName : Buffercmp
* Description : Compares two buffers.
* Input : - pBuffer1, pBuffer2: buffers to becompared.
* : - BufferLength: buffer'slength
* Output : None
* Return : PASSED: pBuffer1 identical topBuffer2
* FAILED: pBuffer1 differs frompBuffer2
******************************************************************************/
TestStatusBuffercmp(u8* pBuffer1, u8* pBuffer2, u16 BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
/*******************************************************************************
* FunctionName : I2C_Transmission
* Description : Data Transmission.
* Input : None
* Output : None
* Return : None
******************************************************************************/
voidI2C_Transmission(void)
{
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
/* Send I2C2 slave Address for read*/
I2C_Send7bitAddress(I2C1,I2C2_SLAVE_ADDRESS7, I2C_Direction_Receiver);
/* Test on I2C2 EV1 and clear it */
while(!I2C_CheckEvent(I2C2,I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED));
/* Test on I2C1 EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* Send data */
while (RxIdx < BufferSize)
{
/* Send I2C2 data */
I2C_SendData(I2C2,I2C1_Buffer_Tx[TxIdx++]);
/* Test on I2C1 EV7 and clear it */
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));
while(!I2C_CheckEvent(I2C2,I2C_EVENT_SLAVE_BYTE_TRANSMITTED));
/* Store received data on I2C1 */
I2C2_Buffer_Rx[RxIdx++] =I2C_ReceiveData(I2C1);
}
I2C_SendData(I2C2, 0); //此处写DR寄存器目的是为了清除EV3事件
RxIdx = 0;
TxIdx = 0;
I2C_AcknowledgeConfig(I2C1,DISABLE); //主机发送NACK
while(!I2C_CheckEvent(I2C2,I2C_EVENT_SLAVE_ACK_FAILURE));
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));
/*Clear I2C2 AF flag */
I2C_ClearFlag(I2C2, I2C_FLAG_AF);
/* Send I2C1 STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
/* Check the corectness of written data */
TransferStatus = Buffercmp(I2C1_Buffer_Tx,I2C2_Buffer_Rx,BufferSize);
}
史海拾趣
|
遇到大麻烦了,PB6.0在编译wince系统的时候 在NETCFV2_MODULES= dotnetv2处失败了。 一下子就没了头绪,网上只有问的却没有解答的。google了快一天了,没有答案。 编译日志如下 配置sysgen参数 User selected the following SYSGEN variables sysgen_as_base=1 sysgen_as_file=1 sysgen_audio=1 sysgen_auth=1 ............. ...… 查看全部问答> |
|
在文件过滤驱动中,如何禁止系统创建新的系统服务? 原来是想将注册表HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services设为只读, 但是发现系统有时会自己修改这个位置,比如说插入一个U盘, 设为只读会导致蓝屏。 所以问问大家,如何 ...… 查看全部问答> |
|
100件未来式设计方案,是否反映出想象力和现实的矛盾呢?作出你自己的判断吧http://www.webdesignerdepot.com/2009/04/100-amazing-futuristic-design-concepts-w-wish-were-real/… 查看全部问答> |
|
因公司业务发展,急需招聘兼职人员,要求: 1、具有DSP/FPGA/ARM/CPLD方面的研发经验,熟悉数字电路、模拟电路设计; 2、熟悉嵌入式系统设计,熟练掌握C语言; 3、有4层以上PCB板设计经验,熟悉PCB板的设计规范; 4、对电磁兼容设计有了解; 5 ...… 查看全部问答> |
|
因为只做过一个DIY 只好炒冷饭了。 这个是我觉得DIY完成后该做的一个文档的一个大致内容。 它的目的只有一个 以简洁的方式,让读者了解整个设计的目标,优缺点,以及无需太多个人创造性工作即可原样复制该DIY; 曾经的那个收官资料,只是资 ...… 查看全部问答> |
|
这里介绍一个纽扣电池供电的LED灯电路 主要控制芯片是比较常用NE555,纽扣电池供电,其他器件图上标的相当的清楚了,,就是连接电路是有点麻烦,可以自己腐蚀一块电路板,, … 查看全部问答> |




