版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33194301/article/details/87907761
由于学习需要,我总结一下各种通讯协议,方便自己也方便各位朋友。
通讯协议概念:通讯协议又称通信规程,是指通信双方对数据传送控制的一种约定。约定中包括对数据格式,同步方式,传送速度,传送步骤,检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守,它也叫做链路控制规程。
一、IIC(Inter-Integrated Circuit)
IIC有两种实现方式:模拟IIC和硬件IIC
模拟IIC优点是可以任意选择SDA和SCL,不受管脚限制而比较灵活。它的缺点是不可用DMA,所以不用这功能的时候还是很方便的。
硬件IIC优点是可用DMA减轻CPU负担,速度也比模拟IIC快,但是实际调试时可能会出现BUG(死机)。
感兴趣的话可以看一下 血的经历告诉大家,慎用stm32的硬件iic
说明一下 SDA:双向数据线 SCL:时钟线 (IIC是所有总线协议里面用最少引脚的)
一般100K的通信速率,SCL,SDA都是加4.7K的上拉电阻。通信速率越大,电阻建议越小,这个也跟电路板的分布电容有关。
(一)模拟IIC
#define uchar unsigned char
#define uint unsigned int
#define SCL_H GPIO_SetBits(GPIOA, GPIO_Pin_6)
#define SCL_L GPIO_ResetBits(GPIOA, GPIO_Pin_6)
#define SDA_H GPIO_SetBits(GPIOA, GPIO_Pin_7)
#define SDA_L GPIO_ResetBits(GPIOA, GPIO_Pin_7)
#define SCL_read GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)
#define SDA_read GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)
/***************************************************************
* FunctionName: I2C_delay
* Function: DELAY
* Arguments: None
* Return: None
* Author seanOY
****************************************************************/
void I2C_delay(void)
{
uchar i=10; //可以通过修改i的值提升IIC运行速度
while(i)
i--;
}
void delayms(void)
{
int i=10000; //延时一定要够,不然会出BUG
while(i--);
}
/****************************************************************
* FunctionName: I2C_GPIO_Config
* Function: Configure IIC GPIO
* Arguments: None
* Return: None
* Author seanOY
*****************************************************************/
void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/***************************************************************
* FunctionName: I2C_Start
* Function: Start Simulate IIC Communication
* Arguments: None
* Return: bool flag
* Author: seanOY
****************************************************************/
bool I2C_Start(void)
{
SDA_H;
SCL_H;
I2C_delay();
if(!SDA_read)return false; //SDA线为低电平则总线忙,退出
SDA_L;
I2C_delay();
if(SDA_read) return false; //SDA线为高电平则总线出错,退出
SDA_L;
I2C_delay();
return true;
}
/******************************************************************
* FunctionName: I2C_Stop
* Function: Stop Simulate IIC Communication
* Arguments: None
* Return: None
* Author: seanOY
******************************************************************/
void I2C_Stop(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SDA_H;
I2C_delay();
}
/*******************************************************************
* FunctionName: I2C_Ack
* Function: Send Acknowledgement signal
* Arguments: None
* Return: None
* Author: seanOY
********************************************************************/
void I2C_Ack(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/********************************************************************
* FunctionName: I2C_NoAck
* Function: Send Not Acknowledgement signal
* Arguments: None
* Return: None
* Author: seanOY
********************************************************************/
void I2C_NoAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/**************************************************************************
* FunctionName: I2C_WaitAck
* Function: Wait for Acknowledgement signal from slave
* Arguments: None
* Return: bool flag
* Author: seanOY
***************************************************************************/
bool I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
SCL_L;
I2C_delay();
return false;
}
SCL_L;
I2C_delay();
return true;
}
/**************************************************************************
* FunctionName: I2C_SendByte
* Function: Send a Byte to Slave
* Arguments: None
* Return: None
* Author: seanOY
***************************************************************************/
void I2C_SendByte(u8 SendByte) //数据从高位到低位
{
u8 i=8;
while(i--)
{
SCL_L;
I2C_delay();
if(SendByte&0x80) //取最高位
SDA_H;
else
SDA_L;
SendByte<<=1;//下一位
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
}
/**************************************************************************
* FunctionName: I2C_RadeByte
* Function: Receive a Byte from Slave
* Arguments: None
* Return: unsigned char Data
* Author: seanOY
***************************************************************************/
unsigned char I2C_RadeByte(void) //数据从高位到低位//
{
u8 i=8;
u8 ReceiveByte=0;
SDA_H;
while(i--)
{
ReceiveByte<<=1;
SCL_L;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
ReceiveByte|=0x01;
}
}
SCL_L;
return ReceiveByte;
}
/**************************************************************************
* FunctionName: Single_Write
* Function: Write a Byte to an address
* Arguments: None
* Return: bool flag
* Author: seanOY
***************************************************************************/
bool Single_Write(unsigned char SlaveAddress,unsigned char REG_Address,unsigned char REG_data)
{
if(!I2C_Start())return false;
I2C_SendByte(SlaveAddress);
if(!I2C_WaitAck()){I2C_Stop(); return false;}
I2C_SendByte(REG_Address ); //设置低起始地址
I2C_WaitAck();
I2C_SendByte(REG_data);
I2C_WaitAck();
I2C_Stop();
delayms();
return true;
}
/**************************************************************************
* FunctionName: Single_Read
* Function: Read a Byte from an address
* Arguments: None
* Return: unsigned char Data
* Author: seanOY
***************************************************************************/
unsigned char Single_Read(unsigned char SlaveAddress,unsigned char REG_Address)
{ unsigned char REG_data;
if(!I2C_Start())return false;
I2C_SendByte(SlaveAddress);
if(!I2C_WaitAck()){I2C_Stop();test=1; return false;}
I2C_SendByte((u8) REG_Address); //设置低起始地址
I2C_WaitAck();
I2C_Start();
I2C_SendByte(SlaveAddress+1);
I2C_WaitAck();
REG_data= I2C_RadeByte();
I2C_NoAck();
I2C_Stop();
return REG_data;
}
/**************************************************************************
* FunctionName: WriteNByte
* Function: Write N Bytes to an address range
* Arguments: SlaveAddress: salve address
REG_Address: register address(write/read)
data[]: data that ready for write
NumOfByte: length of data[]
* Return: None
* Author: seanOY
***************************************************************************/
void WriteNByte(unsigned char SlaveAddress, unsigned char REG_Address, unsigned char data[], unsigned char NumOfByte)
{
uchar i ;
for(i=0;i<NumOfByte;i++)
{
Single_Write(SlaveAddress, REG_Address+i, data[i]);
// printf("%d ,",data[i]);
}
}
/**************************************************************************
* FunctionName: ReadNByte
* Function: Read N Bytes from an address range
* Arguments: SlaveAddress: salve address
REG_Address: register address(write/read)
data[]: data that ready for write
NumOfByte: length of data[]
* Return: None
* Author: seanOY
***************************************************************************/
void ReadNByte(unsigned char SlaveAddress, unsigned char REG_Address, unsigned char *data, unsigned char NumOfByte)
{
int i ;
for(i=0;i<NumOfByte;i++)
{
*(data+i)=Single_Read(SlaveAddress, REG_Address+i);
delayms(); //大概0.7ms,如果出错稍微加大应该可以
// printf("%d ,",*(data+i));
}
}
(二)硬件IIC
我根据上面ST的库来修改了一下,所以也可下载我修改过的程序(来支持我)哦!^0^(由于篇幅较长,我将它放到下载了)
硬件IIC可通过选择轮询(Polling),中断(Interrupt)或直接存储器存取(DMA)来进行操作,用的时候可以自行选择!
Polling | Interrupt | DMA | |
---|---|---|---|
优点 | 简易,可改变轮询顺序 | 省时(相对于polling) | 用于高速设备,省时(相对于polling) |
缺点 | 由于速度上CPU>>IO设备,不适合用于高速设备 | 需要有中断信号和中断服务进程 | 需要有DMA控制器 |