STM32 IIC协议 HAL库

IIC是多主、多从、单工IIC的串行总线,传输仅需两根线,SDA(数据线)、SCL(时钟线)

IIC空闲时SDA和SCL都处于高电平状态(两根线一般情况均接上拉电阻)

IIC传输数据的模式为每传输8位后,要通过一个ACK位进行相互确认。

个人认为SCL产生上升沿后,设备开始检测SDA的电平,当SDA下降,SCL为高,表示开始工作,以此作为当前传输的数据,SCL的下降沿是作为SDA信息可调整的信号,在之后就能进行SDA的电平调整。

IIC有三种速率选择:

普通模式(100kbps)

快速模式(400kbps)

高速模式(3.4Mbps)

具体选用哪种速率要看对应IIC设备数据手册能支持的最大速率是多少,并通过更改时序中的延时时间进行切换。 IIC驱动代码基本上通用于任何IIC设备上。实现包括IIC 的初始化(IO 口)、 IIC 开始、 IIC 结束、 ACK、 IIC读写等功能 IIC 的初始化(IO 口)、 IIC 开始、 IIC 结束、 ACK、 IIC读写等功能 。

扫描二维码关注公众号,回复: 11139484 查看本文章

IIC初始化代码:

#define IIC_SCL_H   HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET) //SCL H
#define IIC_SCL_L   HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_RESET) //SCL H
#define IIC_SDA_H    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET) //SDA_H
#define IIC_SDA_L      HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_RESET) //SDA_L
#define READ_SDA      HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_11)  //输入SDA
View Code

上面为.h中的SDA、SCL的宏定义

void IIC_Init(void)
    {
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC时钟
    
    //PC11,12初始化设置
    GPIO_Initure.Pin=GPIO_PIN_11|GPIO_PIN_12;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;     //高速
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);
    
        GPIO_Initure.Pin = GPIO_PIN_10;
        GPIO_Initure.Mode=GPIO_MODE_INPUT;  
    GPIO_Initure.Pull=GPIO_NOPULL;          
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;     //高速
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);
        
    IIC_SDA_H;
    IIC_SCL_H;  
        delay_nms(5);
}
View Code

记得初始化时把SDA和SCL拉高

IIC开始:

void IIC_Start(void)
{
    IIC_SDA_H;            
    IIC_SCL_H;
    delay_nns(5);
     IIC_SDA_L;//START:when CLK is high,DATA change form high to low 
    delay_nns(5);
    IIC_SCL_L;//钳住I2C总线,准备发送或接收数据 
    delay_nns(5);
}    

IIC结束:

void IIC_Stop(void)
{
    IIC_SDA_L;//STOP:when CLK is high DATA change form low to high
     delay_nns(5);
    IIC_SCL_H; 
        delay_nns(5);
    IIC_SDA_H;//发送I2C总线结束信号
    delay_nns(5);                                   
}

发送ACK:

void IIC_Ack(void)
{
    IIC_SDA_L;
    delay_nns(5);
    IIC_SCL_H;
    delay_nns(5);
    IIC_SCL_L;
    delay_nns(5);
    IIC_SDA_H;
}

不发送NACK:

void IIC_NAck(void)
{
    IIC_SDA_H;
    delay_nns(5);
    IIC_SCL_H;
delay_nns(5);
    IIC_SCL_L;
    delay_nns(5);
    IIC_SDA_L;
}        

等待ACK:

uint8_t IIC_Wait_Ack(void)
{
    uint8_t ucErrTime=0;
    //SDA_IN();      //SDA设置为输入  
    IIC_SDA_H;
    delay_nns(5);       
    IIC_SCL_H;
    delay_nns(5);          
    
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL_L;//时钟输出0        
    return 0;  
}

发送字节:

void IIC_Send_Byte(uint8_t txd)
{                              
   IIC_SCL_L;//拉低时钟开始数据传输
   for(uint8_t i = 0;i < 8;i++)
    {              
        if(txd&0x80)
                    IIC_SDA_H;
                else
                    IIC_SDA_L;                
        txd<<=1;       
                
        IIC_SCL_H;
        delay_nns(5);
        IIC_SCL_L;
        delay_nns(5);
    }            
    //    IIC_SDA_H;
    //    IIC_SCL_H;            //当去掉wait_ack时的时候添加
    //    delay_nns(5);
        //IIC_SCL_L;
} 

读取字节:

uint8_t IIC_Read_Byte(unsigned char ack)
{
      uint8_t TData=0,i;
    for(i=0;i<8;i++)
    {
        IIC_SCL_H;
        delay_nns(5);
        TData=TData<<1;
        //if(GPIOB->IDR& GPIO_IDR_IDR7)        //判断SDA是否为高
            if(SDA_READ)
        {
            TData|=0x01;
        }
        IIC_SCL_L;
        delay_nns(5);
    }
        if(!ack)
            IIC_NAck();
        else
            IIC_Ack();
//    IIC_SCL_L;
//    delay_nns(5);
//    IIC_SDA_L;
//    delay_nns(5);                //ACK
//    IIC_SCL_H;
//    delay_nns(5);
//    IIC_SCL_L;
//    delay_nns(5);
//    IIC_SDA_H;
    return TData;
}

以上为IIC通用代码,但是注意每次发完数据之后需要 wait_ACK检测是否发送成功!

猜你喜欢

转载自www.cnblogs.com/zjx123/p/12785182.html