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
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值