找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3030|回复: 0
收起左侧

IIC串口通信

[复制链接]
ID:112656 发表于 2016-4-7 09:59 | 显示全部楼层 |阅读模式
/******************************************************************************
IIC通信原理介绍
I2CInterIntegrated Circuit)总线是由PHILIPS公司开发的两线式(SCL
SDA)串行总线,用于连接微控制器及其外围设备。SDAserial data line)表示串行数据线,SCLserial clock line)为串行时钟线,SDA是双线数据线,既可以接收也可以发送数据。在使用时,SDASCL都必须利用外部上拉电阻连接到VCC(当总线空闲时可以保持高电平)。IIC总线快速模式下可以达到400kHZ的传输速率。每一个IIC器件都有一个唯一的可识别的地址。
STSTART):IIC数据传输开始于一个起始信号。起始信号定义为当SCL为高电平
HIGH)时SDA从高电平(HIGH)跳为低电平(LOW);
SADSlave Adress):起始信号传输后,下一个Byte7bit表示从机的地址,第8
位表示发送or接收数
据,若从机接收到前7bit,并与自己的地址比较,若匹配,则从机认为主机选中自己,需要
进行通信;
ACKAcknowledge):主从机接收到数据后会发送一个应答信号;
SPSTOP):停止信号定义为当SCL线为高电平时,SDA从低电平(LOW)跳变为高电平(HIGH)。
以上仅仅是针对IIC通信的简单的介绍,更加详细的介绍请参考IICdatesheet
*****************************************************************************/  
/******************************************************************************
  说明:
1、本文件主要功能是:用普通IO口模拟IIC实现通信功能
2、本文件版权属思飞工作室
3、使用方法:在需要使用IIC的工程中,包含IIC.hIIC.c文件
4、由于使用普通IO口模拟IIC,所以此处理论上可以用任意IO口来模拟
******************************************************************************/
#include "IIC.h"
#include "delay.h"
/**************************************************************************
函数名称:IIC_Initvoid
功能:初始化IIC使用的引脚。此处使用stm32PB10/PB11来模拟IIC通信
参数:无
返回值  :
说明:端口配置需要使用CNFx[1:0],MODEx[1:0]相关位含义列出如下:
MODEx[1:0]
00:输入模式(复位后的状态)
01:输出模式,最大速度10MHz
10:输出模式,最大速度2MHz
11:输出模式,最大速度50MHz
CNFx[1:0]
在输入模式(MODE[1:0]=00)
00:模拟输入模式
01:浮空输入模式(复位后的状态)
10:上拉/下拉输入模式
11:保留
在输出模式(MODE[1:0]>00)
00:通用推挽输出模式
01:通用开漏输出模式
10:复用功能推挽输出模式
11:复用功能开漏输出模式
***************************************************************************/
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3;
//先使能外设IO PORTB时钟
GPIOB->CRH&=0XFFFF00FF;
//PB10,11 推挽输出,
CNFx[1:0],MODEx[1:0],配置0011表示推挽输出
GPIOB->CRH|=0X00003300;
GPIOB->ODR|=3<<10;
//PB10 11输出高
}
/**************************************************************************
函数名称:IIC_Startvoid)
    :产生IIC起始信号(ST
数:无
返回值  :
说明:IIC起始信号定义为当SCL为高电平(HIGH)时,SDA线从高到低的跳变
***************************************************************************/
void IIC_Start(void)
{
SDA_OUT();     
//SDA线输出
IIC_SDA=1;
//SDA为高电平输出
delay_us(1);
IIC_SCL=1;
//SCL为高电平
delay_us(6);
IIC_SDA=0;
//START:when CLK is high,DATA
change form high to low
delay_us(6);
IIC_SCL=0;
//钳住I2C总线,准备发送或接收数
据,避免在SCL为高电平期间,再次发出起始信号或者停止信号
delay_us(2);
}
/**************************************************************************
函数名称: IIC_Stopvoid
: 产生IIC停止信号(SP
    数:None
返回值  : None
说明    :IIC停止信号定义为当SCL为高电平(HIGH)时,SDA线从低到高的跳变
***************************************************************************/
void IIC_Stop(void)
{
SDA_OUT();
//SDA线输出
IIC_SDA=0;
//SDA为低电平
delay_us(2);
IIC_SCL=1;
//SCL为高电平
delay_us(6);
IIC_SDA=1;
//STOP:when CLK is high DATA
change form low to high
delay_us(4);
}
/**************************************************************************
函数名称: IIC_Wait_Ackvoid
功能: 等待应答信号到来  
参数:无
返回值 :  [1,接收应答失败;0,接收应答成功]
说明:IIC通信时,接收到数据,从机(Slave)会发出ACK信号,一般是一个低电平
信号出现在SDA线上,若主机检测到,则认为此次通信成功
注意:应答信号是在SCL为高电平器件,SDA一直为低电平表示应答
***************************************************************************/   
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN();     
//SDA设置为输入  
IIC_SDA=1;delay_us(2);
IIC_SCL=1;delay_us(2);
while(READ_SDA)
//若超过250个时钟周期没有收到应
答信号,认为通信失败,返回1,并结束此次通信
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;
//时钟输出0
return 0;  
//若通信成功,则返回0
}
/**************************************************************************
函数名称: IIC_Ack()
    : 产生应答信号 ,主机从从机读取数据后,向从机发出应答信号
    数:None
返回值  : None
说明: 主机在接收到从机的数据后,向从机返回一个应答信号,继续通信,SCL
高电平器件,SDA一直保持低电平表示应答
***************************************************************************/
void IIC_Ack(void)
{
IIC_SCL=0;
//SCL初始为低
SDA_OUT();
IIC_SDA=0;
//SDA输出低
delay_us(2);
IIC_SCL=1;
//SCL输出高电平
delay_us(2);
IIC_SCL=0;
    //SCL再输出低电平,保证在SCL为高电平
期间,SDA始终保持高电平,表示应答信号
}
/**************************************************************************
函数名称: IIC_NAck()
功能: 不产生应答信号,主机接收到从机的数据后,不发出应答信号  
数:None
返回值  : None
说明:在IICSCL为高电平器件,SDA也保持高电平则表示不应答,NACK
***************************************************************************/
void IIC_NAck(void)
{
IIC_SCL=0;
//SCL输出低电平
SDA_OUT();
IIC_SDA=1;
//SDA输出高电平
delay_us(2);
IIC_SCL=1;
//SCL输出高电平
delay_us(2);
IIC_SCL=0;
    //SCL再次输出低电平,保证SCL为高时,
SDA一直为高
}
/**************************************************************************
函数名称: IIC_Send_Byte()
功能: 主机发送一个字节数据到从机
数:需要发送的数据
返回值  :
说明: IIC每次传输的数据位8bit
***************************************************************************/
void IIC_Send_Byte(u8 txd)
{   
u8 t;                     
SDA_OUT();
//SDA输出
IIC_SCL=0;
//拉低时钟开始数据传输
    for(t=0;t<8;t++)
//循环八次,把txd中的8bit数据通过SDA线输出,但同
SCL时钟也必须翻转
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;
delay_us(2);   
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
    }
}
/**************************************************************************
函数名称: IIC_Read_Byte()
功能: IIC接收一个字节的内容
参数:ack表示是否返回ACK信号,若ack=1,则发送ACK(),否则发送NACK()
返回值  : 返回读出的8bit的数据
***************************************************************************/   
u8 IIC_Read_Byte(unsigned char ack)
{
u8 i,receive=0;
SDA_IN();
//SDA设置为输入
    for(i=0;i<8;i++)
    //根据SDA电平的高低,决定receive8bit信息
{
4
IIC.txt
        IIC_SCL=0;
        delay_us(2);
IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
delay_us(2);
    }
IIC_SCL = 0;
    if (!ack)
        IIC_NAck();
//发送nACK
    else
        IIC_Ack();
//发送ACK   
    return receive;
    //返回读到的数据
}
/**************************************************************************
函数名称:IIC_ReadReg(u8 DeviceAddr,u8ReadAddr)
功能:在指定的器件地址中指定的寄存器地址中读出一个数据
数:DeviceAddr:从器件的地址   ReadAddr:寄存器的地址
返回值  : 读到的数据
说明:读取数据流程如下
master(主机):ST
SAD+W         SUB   
  SR   SAD+R
   NMAK   SP
slave(从机)
SAK
SAK   
   SAK   DATA
其中各符号含义如下:
ST :起始信号
SAD+W:从器件地址+Write
SAK:从机应答信号
SUB:寄存器地址
SR :重新启动
DATA :数据
NMAK :主机无应答
SP   :停止信号
**************************************************************************/
u8 IIC_ReadReg(u8 DeviceAddr,u8 ReadAddr)
{
u8 temp=0;
    IIC_Start();  
//起始信号
IIC_Send_Byte(DeviceAddr);
//发送器件地址
IIC_Wait_Ack();
    //等待应答
IIC_Send_Byte(ReadAddr);   
//发送寄存器地址
IIC_Wait_Ack();
    //等待应答
IIC_Start();
//重新启动IIC总线
IIC_Send_Byte(DeviceAddr+1);
//发送器件地址
IIC_Wait_Ack();
//再次等待应答
    temp=IIC_Read_Byte(0);
//只读取1byte的数据,无需主机应答
    IIC_Stop();
//产生一个停止条件
return temp;

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表