STM32软件IIC

发布于 2024-06-27  124 次阅读


MCU:STM32L475RGT6(SYSCLK:80Mhz)

iic.c

#include "iic.h"
#include "main.h"
#include "gpio.h"

void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();//使能 GPIOB 时钟
	
	GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
}

void SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();//使能 GPIOB 时钟

	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


void SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();//使能 GPIOB 时钟

	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	five_us_delay();
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET);//START:when CLK is high,DATA change form high to low
	six_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);//钳住I2C总线,准备发送或接收数据
}	

void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET);//STOP:when CLK is high DATA change form low to high
 	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	six_us_delay();
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);//发送I2C总线结束信号
	six_us_delay();
}

uint8_t IIC_Wait_Ack(void)
{
	uint8_t tempTime=0;
	SDA_IN();      //SDA设置为输入
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
	one_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	one_us_delay();
	while(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin))
	{
		tempTime++;
		if(tempTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);//时钟输出0
	return 0;  
} 

void IIC_Ack(void)
{
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
	SDA_OUT();
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET);
	two_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	five_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
}
		    
void IIC_NAck(void)
{
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
	SDA_OUT();
	HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
	two_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
	five_us_delay();
	HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
}	
		  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;
	SDA_OUT(); 	    
    HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        if((txd&0x80)>0) //0x80  1000 0000
			HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET);
		else
			HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET);
        txd<<=1; 	  
		two_us_delay();   //对TEA5767这三个延时都是必须的
		HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
		two_us_delay();
		HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
		two_us_delay();
    }	 
} 
 
uint8_t IIC_Read_Byte(uint8_t ack)
{
	uint8_t i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET);
        two_us_delay();
		HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET);
        receive<<=1;
        if(HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin))receive++;
		one_us_delay();
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK
    return receive;
}


void us_delay(uint32_t us)
{
    // 每个循环迭代大约需要50纳秒
    uint32_t iterations = (us * 1000) / 50;

    for(uint32_t i = 0; i < iterations; i++) {
        __asm("NOP");
    }
}

void one_us_delay(void)
{
    for(uint32_t i = 0; i < 6; i++) {
        __asm("NOP");
    }
}

void two_us_delay(void)
{
    for(uint32_t i = 0; i < 13; i++) {
        __asm("NOP");
    }
}

void five_us_delay(void)
{
    for(uint32_t i = 0; i < 37; i++) {
        __asm("NOP");
    }
}

void six_us_delay(void)
{
    for(uint32_t i = 0; i < 45; i++) {
        __asm("NOP");
    }
}

iic.h

#ifndef _IIC_H
#define _IIC_H

#include "stdint.h"

//IO口配置
#define SCL_Pin GPIO_PIN_6
#define SCL_GPIO_Port GPIOB
#define SDA_Pin GPIO_PIN_7
#define SDA_GPIO_Port GPIOB

//IIC所有操作函数
void IIC_Init(void);                   //初始化IIC的IO口
void IIC_Start(void);                  //发送IIC开始信号
void IIC_Stop(void);                   //发送IIC停止信号
void IIC_Send_Byte(uint8_t txd);       //IIC发送一个字节
uint8_t IIC_Read_Byte(uint8_t ack);    //IIC读取一个字节
uint8_t IIC_Wait_Ack(void);            //IIC等待ACK信号
void IIC_Ack(void);                    //IIC发送ACK信号
void IIC_NAck(void);                   //IIC不发送ACK信号
void us_delay(uint32_t us);
void one_us_delay(void);
void two_us_delay(void);
void five_us_delay(void);
void six_us_delay(void);

#endif

应用

#include "iic.h"

#define ADS1115_WRITE_ADDRESS        0x90
#define ADS1115_READ_ADDRESS         0x91

  IIC_Init();

  IIC_Start();
  IIC_Send_Byte(ADS1115_WRITE_ADDRESS);
  IIC_Wait_Ack();
  IIC_Send_Byte(0b00000001);
  IIC_Wait_Ack();
  IIC_Send_Byte(0b10000100);
  IIC_Wait_Ack();
  IIC_Send_Byte(0b11100011);
  IIC_Wait_Ack();
  IIC_Stop();
  HAL_Delay(10);

  IIC_Start();
  IIC_Send_Byte(ADS1115_WRITE_ADDRESS);
  IIC_Wait_Ack();
  IIC_Send_Byte(0b00000000);
  IIC_Wait_Ack();
  IIC_Stop();
  HAL_Delay(10);

  while(1)
  {
	  IIC_Start();
	  IIC_Send_Byte(ADS1115_READ_ADDRESS);
	  IIC_Wait_Ack();
	  ads_data[0] = IIC_Read_Byte(1);
	  ads_data[1] = IIC_Read_Byte(0);
	  IIC_Stop();
	  HAL_Delay(10);
	  printf("Data: %x %x\n", ads_data[0], ads_data[1]);
  }


基于普中科技标准库软件IIC代码进行改写

最后更新于 2024-06-27