GD32 - IIC程序编写

一、初始化

理论知识链接:

IIC理论知识

二、代码实现

1、SDA和SCL设置成开漏输出模式

开漏输出的作用:

  • 因为IIC总线是一种双向的通信协议,需要使用开漏输出实现共享总线。
  • 开漏输出类似于一种线与的方式,即无论总线上哪个设备下拉了,所有设备都能知道。
  • IIC总线通常需要使用上拉电阻来保证总线上的高电平。

以GD32为例,使用普通GPIO模拟IIC,初始化如下:

c 复制代码
//PA1  --  SDA
//PA2  --  SCL

#define iic_addr         0x30      //根据从机地址进行修改
#define GPIO_PORT_I2C    GPIOA  //根据引脚进行修改
#define GPIO_RCC_I2C     RCU_GPIOA//根据引脚进行修改
#define GPIO_SCL_I2C     GPIO_PIN_2//根据引脚进行修改
#define GPIO_SDA_I2C     GPIO_PIN_1//根据引脚进行修改
#define delay_time       2    //2us

//将引脚设置成开漏输出
void iic_init()
{
	rcu_periph_clock_enable(GPIO_RCC_I2C);//启动时钟
	gpio_mode_set(GPIO_PORT_I2C, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SCL_I2C | GPIO_SDA_I2C);//默认上拉
	gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_SCL_I2C | GPIO_SDA_I2C);//设置开漏输出
	i2c_stop();//复位一下
}

2、写启动信号

启动信号表现形式为:

  • 静默状态:SCL、SDA为高电平。
  • 启动信号:SCL为高电平时,SDA由高电平变成低电平
c 复制代码
#define I2C_SCL_H    gpio_bit_set(GPIO_PORT_I2C,GPIO_SCL_I2C)//拉高
#define I2C_SCL_L    gpio_bit_reset(GPIO_PORT_I2C,GPIO_SCL_I2C)//拉低
#define I2C_SDA_H    gpio_bit_set(GPIO_PORT_I2C,GPIO_SDA_I2C)//拉高
#define I2C_SDA_L    gpio_bit_reset(GPIO_PORT_I2C,GPIO_SDA_I2C)//拉低


//启动信号
/*
SCL   ------------------------------------------------------------\
						   \___________
				
SDA   ------------------------------\
				 \____________________
*/
void i2c_start()
{
	I2C_SDA_H;
	I2C_SCL_H;
	delay_us(delay_time);
	I2C_SDA_L;
	delay_us(delay_time);
	I2C_SCL_L;
	delay_us(delay_time);
}

3、写终止信号

终止信号表现形式为:

  • 静默状态:SCL高电平、SDA为低电平。
  • 终止信号:SCL为高电平时,SDA由低电平变成高电平
c 复制代码
/*
SCL   ------------------------------------------------------------------------------------------------------------------------

				
SDA                      /------------------------------------------------------
      _________________/
*/
void i2c_stop()
{
	I2C_SDA_L;
	I2C_SCL_H;
	delay_us(delay_time);
	I2C_SDA_H;
}

4、发送一个字节数据

c 复制代码
void i2c_sendbyte(unsigned char data)
{
	unsigned char i;
	for(i = 0; i < 8; i++)//8bit = 1byte
	{
		if(data & 0x80)//取出最高位
		{
			I2C_SDA_H;
		}
		else
		{
			I2C_SDA_L;
		}
		delay_us(delay_time);
		I2C_SCL_H;
		delay_us(delay_time);
		I2C_SCL_L;
		if(i == 7)
		{
			I2C_SDA_H;//释放总线
		}
		data <<= 1;
		delay_us(delay_time);
	}
}

5、接收一个字节数据

c 复制代码
#define I2C_SDA_READ   gpio_input_bit_get(GPIO_PORT_I2C,GPIO_SDA_I2C)


unsigned char i2c_readbyte()
{
	unsigned char i;
	unsigned char data = 0x00;
	for(i = 0; i < 8; i++)
	{
		data <<= 1;
		I2C_SCL_H;
		delay_us(delay_time);
		if(I2C_SDA_READ)
		{
			data |= 0x01;//存入数据
		}
		I2C_SCL_L;
		delay_us(delay_time);
	}
	return data;
}

6、产生一个ACK信号

  • SCL为低电平时,SDA写入低电平
  • SCL为高电平时,SDA读取低电平
  • 读取完成后将SDA拉高
c 复制代码
/*
SCL	         /------------------------\
	_______/           \________________

SDA	                           /------------------------------------------------------------------------------------------------------------
 	__________________________/
*/
void i2c_ack()
{
	I2C_SDA_L;
	delay_us(delay_time);
	I2C_SCL_H;
	delay_us(delay_time);
	I2C_SCL_L;
	delay_us(delay_time);
	I2C_SDA_H;
}

7、产生一个NACK信号

c 复制代码
void i2c_nack()
{
	I2C_SDA_H;
	delay_us(delay_time);
	I2C_SCL_H;
	delay_us(delay_time);
	I2C_SCL_L;
	delay_us(delay_time);
}

8、检测是否从机是否返回ACK

c 复制代码
//0:表示ACK    1:表示NACK
unsigned char i2c_read_ack()
{
	unsigned char re;
	I2C_SDA_H;
	delay_us(delay_time);
	I2C_SCL_H;
	delay_us(delay_time);
	if(I2C_SDA_READ) re = 1;
	else             re = 0;
	I2C_SCL_L;
	delay_us(delay_time);
	return re;
}

9、发送地址和读操作,并读回一个字节数据

c 复制代码
unsigned char read_data()
{
	i2c_start();//启动信号
	i2c_sendbyte(iic_addr | 0x01);//发送地址和读位
	if(i2c_read_ack()) return 0;//如果没有读到ACK,终止执行。
	unsigned char data = i2c_readbyte();//读取数据
	i2c_stop();//发送终止信号
	return data;//返回接收的数据
}
相关推荐
FreakStudio44 分钟前
ESP32居然能当 DNS 服务器用?内含NCSI欺骗和DNS劫持实现
python·单片机·嵌入式·面向对象·并行计算·电子diy
LXY_BUAA1 小时前
《嵌入式操作系统》_使用GPIOLIB编写驱动_添加驱动到内核中_20260328
驱动开发·嵌入式硬件
liwulin05065 小时前
【ESP32-S3】通过ROS2使用YDLIDAR X2进行SLAM、自主导航方案选择
单片机·嵌入式硬件
是翔仔呐6 小时前
第11章 显示外设驱动:I2C协议OLED屏、SPI协议LCD屏字符/图片/中文显示
c语言·开发语言·stm32·单片机·嵌入式硬件·学习·gitee
-凌凌漆-8 小时前
【嵌入式】FreeRTOS串口等待vTaskDelay()
嵌入式硬件
小昭在路上……8 小时前
GPIO端口引脚(位域)打包技巧笔记
单片机·嵌入式硬件
是翔仔呐9 小时前
第13章 SPI通信协议全解:底层时序、4种工作模式与W25Qxx Flash芯片读写实战
c语言·开发语言·stm32·单片机·嵌入式硬件·学习·gitee
悠哉悠哉愿意9 小时前
【单片机复习笔记】第十六届省赛复盘
笔记·单片机·嵌入式硬件
IT方大同9 小时前
RT_thread(RTOS实时操作系统)线程的创建与切换
c语言·开发语言·嵌入式硬件
是翔仔呐9 小时前
第14章 CAN总线通信全解:底层原理、帧结构与双机CAN通信实战
c语言·开发语言·stm32·单片机·嵌入式硬件·学习·gitee