这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 物联网技术 » 【武汉芯源CW32】OTA升级系列之五软件模拟IIC驱动

共5条 1/1 1 跳转至

【武汉芯源CW32】OTA升级系列之五软件模拟IIC驱动

助工
2024-10-09 20:19:02     打赏

【前言】

这次准备驱动IIC,首先采取模拟IIC的驱动,这里跟大家分享如何书写IIC的start、stop、ack、sendbyte,readbyte的时序。

【IIC时序】

image.png

【实现步骤】

1、新建iic.c/h并添加进HW分组中。

2、找到原理图,确定IIC的SCL、SDA的IO。在原图中SCL为PC00,SDA为PC01。

image.png

3、首先书写IIC两个IO的GPIO的初始化,分为时钟使能,由于开发板上有4.7K上拉电阻,这里SCL定义为推挽输出,SDA为开漏输出。初始化代码如下:

void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	
	//开启GPIOA时钟
	__RCC_GPIOC_CLK_ENABLE();
	
			//GPIO配置
	GPIO_InitStructure.Pins = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_Init(CW_GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.Pins = GPIO_PIN_1;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
	GPIO_Init(CW_GPIOC, &GPIO_InitStructure);
	
	//初始化后,把空线设为空闲
	IIC_SCL_H;
	IIC_SDA_H;
}

4、为了方便阅读,在iic.h中宏义,高低电平的输出,以及GPIO电平的获取。

/* IIC IO高低电平的设置 */
#define IIC_SCL_H           CW_GPIOC->BSRR = GPIO_PIN_0
#define IIC_SCL_L           CW_GPIOC->BRR = GPIO_PIN_0

#define IIC_SDA_H           CW_GPIOC->BSRR = GPIO_PIN_1
#define IIC_SDA_L           CW_GPIOC->BRR = GPIO_PIN_1

/* SDA 电平获取 */
#define READ_SDA            GPIO_ReadPin(CW_GPIOC, GPIO_PIN_1)

5、IIC起始信号,SCL保持高电平期间,数据线SDA上的电平被拉低

void IIC_Start(void)
{
	IIC_SCL_H;
	IIC_SDA_H;
	Delay_US(2);
	IIC_SDA_L;
	Delay_US(2);
	IIC_SCL_L;
}

6、IIC停止信号:SCL保持高电平期间,数据线SDA被释放,返回高电平

void IIC_Stop(void)
{
	/*  SCL保持高电平期间,数据线SDA被释放,返回高电平 */ 
	IIC_SCL_H;
	IIC_SDA_L;
	Delay_US(2);
	IIC_SDA_H;
	Delay_US(2);
	IIC_SCL_L;
}

7、获取ACK应答

首选读取SDA的电平,如果读取到低电平,说明从机有应答,然后再读取一次,确保稳定的低电平。

uint8_t IIC_Wait_Ack(int16_t timeout)
{
	do{
		timeout --;
		Delay_US(2);
	}while((READ_SDA) && (timeout>=0));
	
	if(timeout<0)
		return 1;
	
	/* 判断SDA 稳定维持为低电平  */
	IIC_SCL_H;
	Delay_US(2);
	if(0 != READ_SDA)
		return 2;
	IIC_SCL_L;
	Delay_US(2);
	return 0;
}

8、发送一个字节

void IIC_Send_Byte(uint8_t txd)
{
	int i;
	for(i = 7; i >= 0; i--)
	{
		IIC_SCL_L;
		if(txd & BIT(i))
			IIC_SDA_H;
		else
			IIC_SDA_L;
		Delay_US(2);
		IIC_SCL_H;
		Delay_US(2);
	}
	IIC_SCL_L;
	Delay_US(2);
	IIC_SDA_H;
}

8、读取一个字节,发送完成产生应该信号

ACK信号:发送者在ACK时钟脉冲期间释放SDA线,接收者可以将SDA拉低并在时钟信号为高时保持低电平。

NACK信号:当在第9个时钟脉冲的时候SDA线保持高电平,就被定义为NACK信号。

uint8_t IIC_Read_Byte(uint8_t ack)
{
	int8_t i;
	uint8_t rxd;
	rxd = 0;
	for(i = 7; i >= 0; i--)
	{
		IIC_SCL_L;
		Delay_US(2);
		IIC_SCL_H;
		if(0 != READ_SDA)
			rxd |= BIT(i);
		Delay_US(2);
	}
	IIC_SCL_L;
	Delay_US(2);
	//开始应签
	if(ack)
	{
		IIC_SDA_L;
		IIC_SCL_H;
		Delay_US(2);
		IIC_SCL_L;
		IIC_SDA_H;
		Delay_US(2);
	}else{
		IIC_SDA_H;
		IIC_SCL_H;
		Delay_US(2);
		IIC_SCL_L;
		Delay_US(2);
	}
	return rxd;
}

到此IIC时序、写、读函数全部写完。保存好后,就可以供其他的驱动来使用。此例程也可以通过修改Init、宏定义进方便的进行移植。






关键词: IIC 模拟时序    

专家
2024-10-10 06:49:50     打赏
2楼

学习一下


院士
2024-10-10 18:13:52     打赏
3楼

学习了,谢谢分享。


专家
2024-10-11 11:25:39     打赏
4楼

感谢楼主分享


专家
2024-10-16 13:52:16     打赏
5楼

楼主的分享,对于理解ACK和NACK挺有帮助的。


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]