IO模拟,IIC,SPI,PWM

20220402

Kshine

  • 单片机中的各种外设功能,反应在引脚上,实际就是引脚的变化。
  • 在使用单片机设计负责功能时,经常会遇到外设引脚对应不上,或者不够用的情况。

1. 模拟IIC

1.1 IIC简介

  • I2C (inter-integrated circuit) bus 。IIC总线官网
  • 标准模式(Sm,最高 100 kHz)和 快速模式(Fm,最高 400 kHz)。
  • 可用于多种用途,包括 CRC 生成和验证、SMBus(系统管理总线)和 PMBus(电源管理总线)。
    在这里插入图片描述
1.1.1 通讯流
  • Master 主模式。I2C 接口启动数据传输并生成时钟信号。串行数据传输总是以开始条件开始并以停止条件结束。启动和停止条件均由软件在主模式下生成。
  • Slave 从模式。接口能够识别自己的地址(7 位或 10 位)和广播呼叫地址。通用呼叫地址检测可以通过软件启用或禁用。
  • 数据和地址以 8 位字节传输,MSB 在前。
  • 起始条件后的第一个字节包含地址(一个在 7 位模式下,两个在 10 位模式下)。地址总是在主模式下传输。
  • 第 9 个时钟脉冲跟随字节传输的 8 个时钟周期,在此期间接收器必须向发送器发送一个确认位。
    在这里插入图片描述

1.2 进行IO适配,模拟IIC

  • 参考链接:https://zhuanlan.zhihu.com/p/161710767
  • 参考链接:https://www.cnblogs.com/-wenli/p/10907967.html
  • 参考链接:https://blog.csdn.net/Kshine2017/article/details/124683260?spm=1001.2014.3001.5501
  • 在设计电路时,搞反了SCL和SDA,可以通过模拟IIC的方式,弥补这一问题。
  • 下面为模拟IO的适配操作。
1.2.1 STM32
#define GPIO_PORT_I2C	GPIOB	
#define I2C_SCL_PIN		GPIO_PIN_7
#define I2C_SDA_PIN		GPIO_PIN_8
//---------------------------------------------------------------------------------------//
//输出控制
#define I2C_SCL_1()  GPIO_PORT_I2C->BSRR = I2C_SCL_PIN							// SCL = 1 
#define I2C_SCL_0()  GPIO_PORT_I2C->BSRR = (uint32_t)I2C_SCL_PIN << 16U  		// SCL = 0 
#define I2C_SDA_1()  GPIO_PORT_I2C->BSRR = I2C_SDA_PIN   						// SDA = 1 
#define I2C_SDA_0()  GPIO_PORT_I2C->BSRR = (uint32_t)I2C_SDA_PIN << 16U  		// SDA = 0 
//输入检测
#define I2C_SDA_READ()  (GPIO_PORT_I2C->IDR & I2C_SDA_PIN)						// 读取SDA电平 
#define I2C_SCL_READ()  (GPIO_PORT_I2C->IDR & I2C_SCL_PIN)	                    // 读取SCL电平 (一般用不到)
//切换SDA的输入输出方向
#define I2C_SDA_DIR_OUT   GPIOB->CRH &= 0xFFFFFFF0;GPIOB->CRH|=3<<0; //输出
#define I2C_SDA_DIR_IN   GPIOB->CRH &= 0xFFFFFFF0;GPIOB->CRH|=8<<0;  //输入
1.2.2 HHD32
  • 海威华芯。
#define GPIO_PORT_I2C	GPIOB	
#define I2C_SCL_PIN		PIN7
#define I2C_SDA_PIN		PIN8

//port->SET.all |= pin;
//port->CLR.all |= pin;
#define I2C_SCL_1()  GPIO_PORT_I2C->SET.all |= I2C_SCL_PIN											// SCL = 1 
#define I2C_SCL_0()  GPIO_PORT_I2C->CLR.all |= I2C_SCL_PIN  		                // SCL = 0 
 
#define I2C_SDA_1()  GPIO_PORT_I2C->SET.all |= I2C_SDA_PIN   										// SDA = 1 
#define I2C_SDA_0()  GPIO_PORT_I2C->CLR.all |= I2C_SDA_PIN                  		// SDA = 0 
 
//port->PIN.all & pin
#define I2C_SDA_READ()  (GPIO_PORT_I2C->PIN.all & I2C_SDA_PIN)										// 读取SDA电平 
#define I2C_SCL_READ()  (GPIO_PORT_I2C->PIN.all & I2C_SCL_PIN)	                  // 读取SCL电平 

//port->DIR.all |= pins;
//port->DIR.all &= ~pins;
#define I2C_SDA_DIR_OUT  GPIO_PORT_I2C->DIR.all |= I2C_SCL_PIN; //输出
#define I2C_SDA_DIR_IN   GPIO_PORT_I2C->DIR.all &= ~I2C_SCL_PIN; //输入

1.3 其他准备工作

  • 类型的定义,延时函数。
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
typedef const int32_t sc32;  /*!< Read Only */
typedef const int16_t sc16;  /*!< Read Only */
typedef const int8_t sc8;   /*!< Read Only */
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */
//短暂延时
static void delaysoft(int DelayData)
{ 	
	int i = 0;
	while(i <= DelayData)
	{
		i++;
	}
}

1.4 模拟IIC的实现

1.4.1 起始和结束条件
  • SDA和SCL同时为高时,为IIC总线的空闲状态。
  • 起始:时钟线SCL为高时,数据线SDA由高到低。
  • 停止:时钟线SCL为高时,数据线SDA由低到高。
    在这里插入图片描述
void IIC_Start()
{
    //配置SDA引脚,为输出
    //-----------------//
    I2C_SDA_1(); //sda=1
    I2C_SCL_1(); //scl=1 
    delaysoft(40);
    I2C_SDA_0(); //SDA 由高变低  ,产生下降沿
    delaysoft(40);
    //--------------------------------------------------------//
    I2C_SCL_0(); //时钟线拉低,钳住IIC总线,准备发送数据 
}

void IIC_Stop()
{
    I2C_SCL_0(); //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号
	//-----------------//
	//配置SDA引脚,为输出
    I2C_SDA_0(); //sda=0
    I2C_SCL_1(); //scl=1  
    delaysoft(40);
    I2C_SDA_1();//SDA 由低变成高,产生上升沿
    delaysoft(40);
}
1.4.2 等待ACK
  • 用于发送模式下,发送8位后,等待器件应答第9位。
  • SDA引脚配置为输入,由从设备拉低,表示ACK。
    在这里插入图片描述
uint8_t IIC_Wait_Ack()
{
    u8 ucErrTime=0;
    //配置SDA引脚,为输入
    I2C_SDA_DIR_IN //
    //-----------------//
    I2C_SDA_1();//拉高,等待从机拉低。
    //delaysoft(1);	 
    I2C_SCL_1();//scl=1,产生脉冲,第9位
    while(I2C_SDA_READ()) //等待SDA被拉低
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    I2C_SCL_0();//scl=0	 
     //配置SDA引脚,为输出
    I2C_SDA_DIR_OUT  
	return 0;
} 
1.4.3 发出ACK
  • 用于读取模式(SDA为in)读了8位器件数据后,在第9位给出一个应答,我还要继续读。
    发送ACK
//产生ACK应答
void IIC_Ack()
{
    I2C_SCL_0(); //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号
	//-----------------//
	//配置SDA引脚,为输出
	I2C_SDA_0();//sda=0
	delaysoft(20);
	I2C_SCL_1();//scl=1
	delaysoft(20);
	I2C_SCL_0();//scl=0
}
1.4.4 发送NACK
  • 用于读取模式(SDA为in)读了8位器件数据后,在第9位给出一个应答,我不想读了。
  • 拉高SDA,表示不应答NACK。
    NACK
void IIC_NAck()
{
	I2C_SCL_0(); //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号
	//-----------------//
	//配置SDA引脚,为输出
	I2C_SDA_1();//sda=1
	delaysoft(20);
	I2C_SCL_1();//scl=1
	delaysoft(20);
	I2C_SCL_0(); //scl=0
}	
1.4.5 发送8位

发送一个字节

void IIC_Send_Byte(uint8_t txd)
{                        
   uint8_t i;
	I2C_SCL_0();
	for (i = 0; i < 8; i++)
	{
		if (txd & 0x80)
		{
			I2C_SDA_1();
		}
		else
		{
			I2C_SDA_0();
		}
    txd<<=1; 	  
		delaysoft(20);   
		I2C_SCL_1();//scl=1
		delaysoft(20); 
		I2C_SCL_0();//scl=0	
	}
} 	
1.4.6 接收8位,并回复
  • 读取一个字节时,SDA配置为输入;发出ACK或者NACK时,SDA配置为输出。
    读取一个字节
uint8_t IIC_Read_Byte(unsigned char ack)
{
	uint8_t i;
	uint8_t receive=0;
	I2C_SDA_DIR_IN  //配置SDA为输入模式
	for (i = 0; i < 8; i++)
	{
		delaysoft(20);
		I2C_SCL_0();
		delaysoft(20);
		I2C_SCL_1();
		receive <<= 1;
		
		if (I2C_SDA_READ())
		{
			receive++;
		}
	}
	
	I2C_SDA_DIR_OUT
	
	if (!ack)
        IIC_NAck();
  else
        IIC_Ack();
  return receive;
}

1.5 写入字节与读取字节

1.5.1 写入
  • 需要查看从器件的IIC通信时序。严格按照数据手册组合时序。
    LTC2990
  • 向从设备的某一个寄存器,写入数值。
    发送一个字节
void IIC_WriteByteSoft(uint8_t DcvaddrWrite, uint8_t Regaddr, uint8_t data)
{
	IIC_Start();
	IIC_Send_Byte(DcvaddrWrite);
	IIC_Wait_Ack();
	IIC_Send_Byte(Regaddr);
	IIC_Wait_Ack();
	IIC_Send_Byte(data);
	IIC_Wait_Ack();
	IIC_Stop();
}
1.5.1 读取
  • 需要查看从器件的IIC通信时序。严格按照数据手册组合时序。
    在这里插入图片描述
u8 IIC_ReadByteSoft(uint8_t DcvaddrWrite, uint8_t Regaddr,uint8_t DcvaddrRead, unsigned char ack)
{
	u8 temp;
	IIC_Start();
	IIC_Send_Byte(DcvaddrWrite);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(Regaddr); //Read 命令
	IIC_Wait_Ack();
	
	IIC_Start();
	IIC_Send_Byte(DcvaddrRead);
	IIC_Wait_Ack();
	
	temp=IIC_Read_Byte(ack);
	IIC_Stop();
	return temp;
}

2. 模拟SPI

  • SPI外设引脚不够用的时候,或者引脚分配错误的时候,可以使用模拟SPI。
  • 缺点是,占用CPU的处理时间。
  • 参考链接:https://blog.csdn.net/zwj695535100/article/details/107303648/
  • CPOL与CPHA的定义,有些芯片DATASHEET中描述与通用的规则是相反的,所以选型时候一定要以DATASHEET中的时序图为准。
  • 以W25Q128JV为例。
    W25Q128JV

2.1 引脚定义

  • MISO,主设备输入,从设备输出。
  • MOSI,主设备输出,从设备输入。
  • SCLK,时钟信号(由主设备产生)。
  • CS, 片选信息(由主设备控制)。
2.1.1 STM32
/**SPI GPIO Configuration    
		PC14 CS
		PC15 CLK
		PB15 DIN   -- MOSI (5)  MCU -> OUT
		PB14 Dout  -- MISO (2)  MCU -> IN
*/
#define SPI_SCK_PIN                     MCU_CLK_Pin
#define SPI_SCK_GPIO_PORT               MCU_CLK_GPIO_Port
#define SPI_MOSI_PIN                    MCU_DIN_Pin
#define SPI_MOSI_GPIO_PORT              MCU_DIN_GPIO_Port
#define SPI_MISO_PIN                    MCU_DOUT_Pin
#define SPI_MISO_GPIO_PORT              MCU_DOUT_GPIO_Port
#define SPI_NSS_PIN                     MCU_CS_Pin
#define SPI_NSS_GPIO_PORT               MCU_CS_GPIO_Port
 
#define SPI_SCK_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOC_CLK_ENABLE()
#define SPI_MISO_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPI_MOSI_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPI_NSS_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOC_CLK_ENABLE()
 
#define MOSI_H  HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_SET)  
#define MOSI_L  HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_RESET)  
#define SCK_H   HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_SET)  
#define SCK_L   HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_RESET)  
#define MISO    HAL_GPIO_ReadPin(SPI_MISO_GPIO_PORT, SPI_MISO_PIN) 
#define NSS_H   HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET)  
#define NSS_L   HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_RESET) 

2.2 相关函数

2.2.1 引脚初始化
  • 必须对引脚进行初始化,且使得输出引脚处于某种电平状态。
  • 输出引脚 :SCLK = 0;MOSI = 0;CS = 1;
void SPI_Init(void)
{  
  /*##-1- Enable peripherals and GPIO Clocks #########################*/
  /* Enable GPIO TX/RX clock */
  SPI_SCK_GPIO_CLK_ENABLE();
  SPI_MISO_GPIO_CLK_ENABLE();
  SPI_MOSI_GPIO_CLK_ENABLE();
  SPI_NSS_GPIO_CLK_ENABLE();
  
  /*##-2- Configure peripheral GPIO #######################*/
  /* SPI SCK GPIO pin configuration  */
  GPIO_InitTypeDef GPIO_InitStruct;
  
  GPIO_InitStruct.Pin       = SPI_SCK_PIN;
  GPIO_InitStruct.Mode      = GPIO_MODE_OUTPUT_PP;
  //GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(SPI_SCK_GPIO_PORT, &GPIO_InitStruct);
  HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_RESET);
 
  /* SPI MISO GPIO pin configuration  */
  GPIO_InitStruct.Pin = SPI_MISO_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  HAL_GPIO_Init(SPI_MISO_GPIO_PORT, &GPIO_InitStruct);
 
  /* SPI MOSI GPIO pin configuration  */
  GPIO_InitStruct.Pin = SPI_MOSI_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  HAL_GPIO_Init(SPI_MOSI_GPIO_PORT, &GPIO_InitStruct);
  HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_RESET);
 
  GPIO_InitStruct.Pin = SPI_NSS_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  HAL_GPIO_Init(SPI_NSS_GPIO_PORT, &GPIO_InitStruct);
  HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET);
}

2.2.2 延时函数

void delay_us(uint32_t nus)
{		
   uint16_t i;
	for(i=0;i<nus;i++)
	{
	} 
}

2.2.3 不同模式的时序函数

2.2.3.1 mode0

(1) 下降沿之后(低电平),MOSI输出。
(2) 上升沿之后(高电平),读取MISO输入。
在这里插入图片描述

/* CPOL = 0, CPHA = 0, MSB first */
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat )
{
    uint8_t i, read_dat;
    for( i = 0; i < 8; i++ )
    {
        if( write_dat & 0x80 )
            MOSI_H;  
        else                    
            MOSI_L;  
        write_dat <<= 1;
        delay_us(1);	
        SCK_H; 
        read_dat <<= 1;  
        if( MISO ) 
            read_dat++; 
		delay_us(1);
        SCK_L; 
        __nop();
    }
	
    return read_dat;
}
 
2.2.3.2 mode1

(1) 上升沿之后(高电平),MOSI输出。
(2) 下降沿之后(低电平),读取MISO输入。
在这里插入图片描述

/* CPOL=0,CPHA=1, MSB first */
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) 
{
    uint8_t i,Temp=0;
 
	for(i=0;i<8;i++)
	{
		SCK_H;
		if(byte&0x80)
        {
			MOSI_H;
        }
		else      
		{
			MOSI_L;
		}
		byte <<= 1;
		delay_us(1);
		SCK_L;
		Temp <<= 1;
 
		if(MISO)
			Temp++; 
		delay_us(1);
 
	}
	return (Temp);
}

2.2.3.3 mode2

(1) 上升沿之后(高电平),MOSI输出。
(2) 下降沿之后(低电平),读取MISO输入。
在这里插入图片描述

/* CPOL=1,CPHA=0, MSB first */
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) 
{
    uint8_t i,Temp=0;
 
	for(i=0;i<8;i++)
	{
		if(byte&0x80)
        {
			MOSI_H; 
        }
		else      
		{
			MOSI_L; 
		}
		byte <<= 1; 
		delay_us(1);
		SCK_L;  
		Temp <<= 1; 
 
		if(MISO)
			Temp++;
		delay_us(1);
		SCK_H; 
		
	}
	return (Temp); 
}
2.2.3.4 mode3

(1) 下降沿之后(低电平),MOSI输出。
(2) 上升沿之后(高电平),读取MISO输入。
在这里插入图片描述

/* CPOL = 1, CPHA = 1, MSB first */
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat )
{
    uint8_t i, read_dat;
    for( i = 0; i < 8; i++ )
    {
		SCK_L; 
        if( write_dat & 0x80 )
            MOSI_H;  
        else                    
            MOSI_L;  
        write_dat <<= 1;
        delay_us(1);	
        SCK_H; 
        read_dat <<= 1;  
        if( MISO ) 
            read_dat++; 
		delay_us(1);
        __nop();
    }
    return read_dat;
}

2.2.4 用户封装使用SPI

//HAL_SPI_Receive(&_W25QXX_SPI, pBuffer, sizeof(pBuffer), 100);
void Kshine_SPI_Receive(uint8_t* buff,uint16_t len)
{
	  uint16_t i = 0;
	 for(i=0;i<len;i++)
	 {
	    buff[i] =  SOFT_SPI_RW_MODE0(0xA5);
	 }
}

//HAL_SPI_Transmit(&_W25QXX_SPI, pBuffer, NumByteToWrite_up_to_PageSize, 100);
void Kshine_SPI_Transmit(uint8_t* buff,uint16_t len)
{
	  uint16_t i = 0;
	 for(i=0;i<len;i++)
	 {
	     SOFT_SPI_RW_MODE0(buff[i]);
	 }
}

3. 模拟PWM

未完待续。。。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于STM32的IO模拟IIC的完整例程: 首先,需要在STM32的CubeMX中配置GPIO口,使其能够模拟IIC的时钟和数据线。具体方法如下: 1. 打开CubeMX软件,选择相应的芯片型号。 2. 在Pinout选项卡中,选择需要使用的GPIO引脚,右键单击进入Pinout Configuration。 3. 在Pinout Configuration中,将引脚的Mode设置为GPIO_Output,并将Type设置为Open-Drain。 4. 在Configuration选项卡中,选择I2C模块,将I2C的Mode设置为I2C GPIO模拟,并将SCL和SDA引脚分别设置为上一步中配置的GPIO引脚。 接下来,可以使用以下代码实现IO模拟IIC的读写操作: ``` #include "iic.h" #define IIC_SCL_PIN GPIO_PIN_8 #define IIC_SDA_PIN GPIO_PIN_9 #define IIC_SCL_LOW() HAL_GPIO_WritePin(GPIOB, IIC_SCL_PIN, GPIO_PIN_RESET) #define IIC_SCL_HIGH() HAL_GPIO_WritePin(GPIOB, IIC_SCL_PIN, GPIO_PIN_SET) #define IIC_SDA_LOW() HAL_GPIO_WritePin(GPIOB, IIC_SDA_PIN, GPIO_PIN_RESET) #define IIC_SDA_HIGH() HAL_GPIO_WritePin(GPIOB, IIC_SDA_PIN, GPIO_PIN_SET) #define IIC_SDA_READ() HAL_GPIO_ReadPin(GPIOB, IIC_SDA_PIN) void delay_us(uint32_t nus) { uint32_t ticks = nus * (SystemCoreClock / 1000000) / 5; while (ticks--) { __NOP(); } } void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin = IIC_SCL_PIN | IIC_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); IIC_SCL_HIGH(); IIC_SDA_HIGH(); } void IIC_Start(void) { IIC_SDA_HIGH(); IIC_SCL_HIGH(); delay_us(5); IIC_SDA_LOW(); delay_us(5); IIC_SCL_LOW(); } void IIC_Stop(void) { IIC_SDA_LOW(); IIC_SCL_HIGH(); delay_us(5); IIC_SDA_HIGH(); delay_us(5); } uint8_t IIC_WriteByte(uint8_t data) { uint8_t i, res; for (i = 0; i < 8; i++) { if (data & 0x80) { IIC_SDA_HIGH(); } else { IIC_SDA_LOW(); } delay_us(5); IIC_SCL_HIGH(); delay_us(5); IIC_SCL_LOW(); data <<= 1; } IIC_SDA_HIGH(); delay_us(5); IIC_SCL_HIGH(); delay_us(5); res = IIC_SDA_READ(); IIC_SCL_LOW(); return res; } uint8_t IIC_ReadByte(uint8_t ack) { uint8_t i, res = 0; IIC_SDA_HIGH(); for (i = 0; i < 8; i++) { delay_us(5); IIC_SCL_HIGH(); res <<= 1; if (IIC_SDA_READ()) { res |= 0x01; } IIC_SCL_LOW(); } if (ack) { IIC_SDA_LOW(); } else { IIC_SDA_HIGH(); } delay_us(5); IIC_SCL_HIGH(); delay_us(5); IIC_SCL_LOW(); IIC_SDA_HIGH(); return res; } ``` 在以上代码中: - `IIC_Init()`函数用于初始化GPIO引脚。 - `IIC_Start()`函数用于发送起始信号。 - `IIC_Stop()`函数用于发送停止信号。 - `IIC_WriteByte()`函数用于向IIC总线写入一个字节的数据。 - `IIC_ReadByte()`函数用于从IIC总线读取一个字节的数据。 使用以上代码时,只需要在需要读写数据的地方调用相应的函数即可。例如: ``` IIC_Start(); // 发送起始信号 IIC_WriteByte(0x50); // 向IIC总线写入设备地址 IIC_WriteByte(0x00); // 向IIC总线写入寄存器地址 IIC_Start(); // 发送重复起始信号 IIC_WriteByte(0x51); // 向IIC总线写入设备地址(读模式) data = IIC_ReadByte(1); // 从IIC总线读取数据,并发送ACK IIC_Stop(); // 发送停止信号 ``` 以上代码实现了IO模拟IIC的读写操作。在实际使用时,还需要根据实际情况进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值