1、有四种模式
● 从发送器模式
● 从接收器模式
● 主发送器模式
● 主接收器模式
默认是在从模式,接口在生成起始条件后自动切换到主模式;当仲裁丢失或产生停止信号后,又回到从模式
从模式时,能识别自己的地址(7位或10位) 和广播呼叫地址。
数据和地址按8位传输,高位在前。SCL时钟为高电平期间数据要维持稳定, 否则会被认为是起始 或 停止条件
在第9个时钟脉冲,从机回复0 表示应答 ACK
这里主要介绍主模式
● 主模式
CR2设置I2C模块的时钟-----时钟控制寄存器CCR,配置快速还是慢速,时钟分频率----------上升时间寄存器TRISE,配置上升沿最大时间----配置CR2-----配置CR1的START位为1,用于产生开始条件。
起始:
对START位置1, SR1. SB位会自动置1表示已发出开始信号,然后读SR1。如果CR2.ITEVFEN位设置了允许中断,则会产生中断。程序在中断中把地址写入 DR寄存器等待发送。(读SR1,然后写DR,将会清除SB)
地址发送:
在地址发送完后,并收到从机应答时,SR1.ADDR会被置1,如果允许了中断,则会产生中断。然后读SR1,跟着读SR2则会清除ADDR。根据地址的最后一位,主设备将决定进入发送模式 还是 接收模式
发送模式
当发送完地址收到应答后,TxE 被置1,(如果设置为中断允许INEVFEN和ITBUFEN,则产生中断),将要发送的数据写入到DR,则清除该位。在TxE被置1表示发送寄存器空,并且在上一次发送结束之前没有写数据到DR,则SR1.BTF会被置1.
关闭发送
CR1.STOP置1,产生停止条件。
接收模式
当发送完地址收到应答后,进入接收模式,接收完一个字节后,发出一个应答(CR1.ACK置1才会发送应答),SR.RxNE置1表示收到数据,(如果INEVFEN和ITBUFEN置1,则表示允许中断,这里会产生中断)
关闭通信
在收到最后一个字节后发送一个NACK,从设置将释放总线。
为了在最后一个字节产生NACK,在读倒数第二个字节后必须清除ACK位;为了产生停止条件,在读倒数第二个字节后,设置STOP位。
hal库函数:
初始化:
HAL_I2C_Init(I2C_HandleTypeDef *hi2c),流程如下:
判断最小时钟是否达到,
/* Check the minimum allowed PCLK1 frequency */
if (I2C_MIN_PCLK_FREQ(pclk1, hi2c->Init.ClockSpeed) == 1U)
{
return HAL_ERROR;
}
#define I2C_MIN_PCLK_FREQ(__PCLK__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD) : ((__PCLK__) < I2C_MIN_PCLK_FREQ_FAST))
// 如如初始化的时钟小于100K, 则宏定义返回的是((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD)的比较结果,外设时钟小于2M吗,如果小于则返回1,返回1则上面的调用就会进入HAL_ERROR,表示模块时钟不够。
轮询模式,有4个函数:
HAL_I2C_Master_Transmit()
HAL_I2C_Master_Receive()
HAL_I2C_Slave_Transmit()
HAL_I2C_Slave_Receive()
HAL_I2C_Master_Transmit():
主发送式:限时等待BUSY=0-----确认PE位等于0----清除CR1的POS位-----------发送从机地址-----#产生START------#限时等待SB set---------#写从机地址DR,并把最后1位读写标志清0------#等待ADDR set-------##如果等待期间AF set-----##产生STOP----##清除AF------------------清除ADDR-----等待TXE set-----写数据入DR-----如果BTF is set-----再写数据到DR----等待BTF set----循环直到数据发送完----产生STOP
另外HAL_I2C_Mem_Write()函数与上面HAL_I2C_Master_Transmit()的区别是:
HAL_I2C_Mem_Write()发送从机地址是调用I2C_RequestMemoryWrite() 发送从机地址,同时发送寄存器地址。
发送从机地址-----#产生START------#限时等待SB set---------#写从机地址到DR,并把最后1位读写标志清0------#等待ADDR set-------#清除ADDR-----#等待TXE set-------#把寄存器地址写到DR ------写数据到DR
HAL_I2C_Master_Receive():
**主接收:**限时等待BUSY=0-----确认PE位等于0----清除CR1的POS位-----发送从机地址-----#设置应答ACK-----#产生START------#限时等待SB set-----#发送从机地址,并把最后1位读写标志置1------#等待ADDR set-------##如果等待期间AF set-----##产生STOP----##清除AF------如果接收数据为0,清除ADDR并生产STOP----如果接收数据为1字节,清除应答ACK,清除ADDR,并产生STOP------如果接收为2字节,置1 POS,并清除ADDR,清除ACK------否则清除ACK,清作ADDR------------------------------------接收数据分几种情况----如果还剩大于3字节-----等待RXNE set-----把数据从DR读走----如果BTF is set,说明还有1字节没读走,再从DR读走1字节-------如果还剩3字节,等待BTF is set, BTF set以后说明已经收到2字节了,只剩1字节,设置非应答,从DR读走一字节,等待BTF再次set,说明已经接收完,产生STOP,从DR读走1字节,再次从DR读走1字节------如果还剩2字节,等待BTF set,产生STOP信号,读两次DR,读走2字节。--------如果还剩1字节,等待RXNE set, 然后从DR读走1字节。
可见主接收时有点复杂,接收到1个字节时,RXNE会置1,如果数据没有读走,再接收到1个字节时,BTF会置1。这时表示已经有2个字节待读走。