STM32标准库通用软件模拟IIC

STM32标准库通用软件模拟IIC

继上次通用可移植的矩阵键盘之后,便继续寻找着下一个能够拿来只需改改引脚就可以使用的通用方案。

恰好最近在研究PCA9685,这是一片能够产生最多十六路PWM信号的芯片,通过IIC总线接口控制,只需要SCL+SDA,外加一根GND,就可以控制多达16路舵机,这属实减少了开发难度。也正是因此,博主产生了写一下通用IIC总线的想法,以下是代码

具体IIC时序在网上一搜一大把,这里就不再多说了。

博主使用的是STM32F103ZET6开发板测试,测试有效,引脚输出速度可以根据你的板子再做修改。

#ifndef _IIC_H
#define _IIC_H

#include "stm32f10x.h"
#include "delay.h"
// 只需要修改下方需要使用的端口,以及时钟即可,注意一定要全部修改好,
#define SCLPort GPIOE		//SCL引脚端口
#define SCLPin GPIO_Pin_15			//SCL引脚
#define SCLPinCLK RCC_APB2Periph_GPIOE
#define SDAPort GPIOE   //SDA引脚端口
#define SDAPin GPIO_Pin_13			//SDA引脚
#define SDAPinCLK RCC_APB2Periph_GPIOE


void IIC_Init(void);	// IIC初始化
// 这里,因为SDA需要实现写和读的功能,因此写了两个,需要读的时候就调用in,需要写的时候调用out,默认out
void IIC_SDA_In(void);
void IIC_SDA_Out(void);

void IIC_Start(void);	// IIC起始
void IIC_Stop(void);	// IIC结束

uint8_t IIC_Wait_Ack(void);

void IIC_Ack(void);		//IICAck
void IIC_NAck(void);  //IICNAck

// 写一个字节
void IIC_Write_One_Byte(uint8_t byte);
// 读一个字节
uint8_t IIC_Read_One_Byte(uint8_t ack);

#endif
#include "stm32f10x.h"
#include "iic.h"

void IIC_Init(void)	// IIC初始化
{
	GPIO_InitTypeDef GPIO_InitStructure;
    // 这一句保留着,不要删掉,禁用掉JTAG
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 
	RCC_APB2PeriphClockCmd(SCLPinCLK,ENABLE);
	RCC_APB2PeriphClockCmd(SDAPinCLK,ENABLE);
	
	// 初始化SCL引脚
	GPIO_InitStructure.GPIO_Pin = SCLPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SCLPort, &GPIO_InitStructure);
	
	// 初始化SDA引脚
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
	
	GPIO_SetBits(SCLPort,SCLPin);
	GPIO_SetBits(SDAPort,SDAPin); 	

}
//
void IIC_SDA_In(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
}
void IIC_SDA_Out(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = SDAPin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SDAPort, &GPIO_InitStructure);
}

void IIC_Start(void)	// IIC起始
{
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(4);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(4);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}
void IIC_Stop(void)	// IIC结束
{
	IIC_SDA_Out();
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(4);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(4);
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)		//等待Ack
{
	u8 ucErrTime=0;
	IIC_SDA_In();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(1);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(1);
	while(GPIO_ReadInputDataBit(SDAPort,SDAPin))
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	return 0;
	
}

void IIC_Ack(void)	//IICAck
{
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}
void IIC_NAck(void)  //IICNAck
{
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	IIC_SDA_Out();
	GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
	delay_us(2);
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
}

// 写一个字节
void IIC_Write_One_Byte(uint8_t byte)
{
	uint8_t t;
	IIC_SDA_Out();
	GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
	for(t=0;t<8;t++)
  {              
		if((byte&0x80)>>7)
			GPIO_WriteBit(SDAPort,SDAPin,Bit_SET);
		else
			GPIO_WriteBit(SDAPort,SDAPin,Bit_RESET);
		byte<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
		delay_us(2); 
		GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
		delay_us(2);
  }
}
// 读一个字节
uint8_t IIC_Read_One_Byte(uint8_t ack)
{
	unsigned char i,receive=0;
	IIC_SDA_In();//SDA设置为输入
   for(i=0;i<8;i++ )
	{
		GPIO_WriteBit(SCLPort,SCLPin,Bit_RESET);
		delay_us(2);
		GPIO_WriteBit(SCLPort,SCLPin,Bit_SET);
		receive<<=1;
        if(GPIO_ReadInputDataBit(SDAPort,SDAPin))receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

代码中使用的延时函数取自正点原子官方例程提供的delay.c,delay.h,这里也一并放到了压缩包里。

网盘链接
提取码:1111
博主个人网站,欢迎访问,发现更多有趣的东西,欢迎交流。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用STM32F103标准库进行软件模拟I2C读写一个字节的示例代码: ```c #include "stm32f10x.h" #define SDA_PIN GPIO_Pin_7 #define SCL_PIN GPIO_Pin_6 #define I2C_GPIO GPIOB void I2C_Delay(void) { volatile int i = 7; while(i--); } void I2C_Start(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_SetBits(I2C_GPIO, SDA_PIN); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); GPIO_ResetBits(I2C_GPIO, SDA_PIN); I2C_Delay(); GPIO_ResetBits(I2C_GPIO, SCL_PIN); } void I2C_Stop(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_ResetBits(I2C_GPIO, SDA_PIN); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); GPIO_SetBits(I2C_GPIO, SDA_PIN); I2C_Delay(); } void I2C_Ack(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_ResetBits(I2C_GPIO, SDA_PIN); I2C_Delay(); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); GPIO_ResetBits(I2C_GPIO, SCL_PIN); } void I2C_Nack(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_SetBits(I2C_GPIO, SDA_PIN); I2C_Delay(); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); GPIO_ResetBits(I2C_GPIO, SCL_PIN); } int I2C_WaitAck(void) { GPIO_InitTypeDef GPIO_InitStructure; uint8_t ack = 0; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_SetBits(I2C_GPIO, SDA_PIN); I2C_Delay(); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); if(GPIO_ReadInputDataBit(I2C_GPIO, SDA_PIN) == RESET) { ack = 1; } GPIO_ResetBits(I2C_GPIO, SCL_PIN); return ack; } void I2C_SendByte(uint8_t byte) { uint8_t i = 8; GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SCL_PIN; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); while(i--) { if(byte & 0x80) { GPIO_SetBits(I2C_GPIO, SDA_PIN); } else { GPIO_ResetBits(I2C_GPIO, SDA_PIN); } I2C_Delay(); GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); GPIO_ResetBits(I2C_GPIO, SCL_PIN); byte <<= 1; } } uint8_t I2C_ReadByte(void) { uint8_t i = 8; uint8_t byte = 0; GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO, &GPIO_InitStructure); while(i--) { byte <<= 1; GPIO_SetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); if(GPIO_ReadInputDataBit(I2C_GPIO, SDA_PIN) == SET) { byte |= 0x01; } GPIO_ResetBits(I2C_GPIO, SCL_PIN); I2C_Delay(); } return byte; } void I2C_WriteByte(uint8_t device_addr, uint8_t reg_addr, uint8_t data) { I2C_Start(); I2C_SendByte(device_addr << 1); if(!I2C_WaitAck()) { I2C_Stop(); return; } I2C_SendByte(reg_addr); if(!I2C_WaitAck()) { I2C_Stop(); return; } I2C_SendByte(data); if(!I2C_WaitAck()) { I2C_Stop(); return; } I2C_Stop(); } uint8_t I2C_ReadByte(uint8_t device_addr, uint8_t reg_addr) { uint8_t data = 0; I2C_Start(); I2C_SendByte(device_addr << 1); if(!I2C_WaitAck()) { I2C_Stop(); return 0; } I2C_SendByte(reg_addr); if(!I2C_WaitAck()) { I2C_Stop(); return 0; } I2C_Start(); I2C_SendByte((device_addr << 1) | 0x01); if(!I2C_WaitAck()) { I2C_Stop(); return 0; } data = I2C_ReadByte(); I2C_Nack(); I2C_Stop(); return data; } ``` 这段代码将I2C总线的SDA和SCL引脚分别定义为GPIOB的第7和第6个引脚。I2C_Start()函数用于在总线上发送起始信号,I2C_Stop()函数用于发送停止信号。I2C_Ack()和I2C_Nack()函数分别用于发送应答或非应答信号。I2C_WaitAck()函数用于等待从设备发送的应答信号。I2C_SendByte()函数用于向从设备发送一个字节的数据,I2C_ReadByte()函数用于从从设备读取一个字节的数据。I2C_WriteByte()函数用于向从设备写入一个字节的数据,I2C_ReadByte()函数用于从从设备读取一个字节的数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值