GD32F407 GPIO模拟i2c

i2c.c

#include <stdio.h>

#include "dri_simulate_i2c.h"
#include "dri_timer.h"

/************************************************
函数名称 : I2C_Delay
功    能 : I2C时序延时
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
static void dri_i2c_delay(void)
{	
    dri_timer_delay_us(DRI_I2C_SPEED_DATA);
}

/************************************************
函数名称 : I2C_GPIO_Configuration
功    能 : I2C引脚配置(推挽输出)
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/


/************************************************
函数名称 : dri_i2c_simulate_init
功    能 : I2C初始化
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_simulate_init(void)
{
	gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, DRI_GPIOB_I2C2_SCL | DRI_GPIOB_I2C2_SDA);
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, DRI_GPIOB_I2C2_SCL | DRI_GPIOB_I2C2_SDA);
}

/************************************************
函数名称 : I2C_SDA_SetOutput
功    能 : I2C_SDA设置为输出
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_sda_out(void)
{
	gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, DRI_GPIOB_I2C2_SDA);
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, DRI_GPIOB_I2C2_SDA);
}

/************************************************
函数名称 : I2C_SDA_SetInput
功    能 : I2C_SDA设置为输入
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_sda_in(void)
{	
	gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, DRI_GPIOB_I2C2_SDA);
}

/************************************************
函数名称 : I2C_Start
功    能 : I2C开始
*           SCL: __________
*                          \__________
*           SDA: _____
*                     \_______________
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_start(void)
{	
	dri_i2c_sda_out();
	
	DRI_I2C_SCL_HIGH;                                  //SCL高
	dri_i2c_delay();
	
	DRI_I2C_SDA_HIGH;                                  //SDA高 -> 低
	dri_i2c_delay();
	DRI_I2C_SDA_LOW;                                   //SDA低
	dri_i2c_delay();

	DRI_I2C_SCL_LOW;                                   //SCL低(待写地址/数据)
	dri_i2c_delay();
}

/************************************************
函数名称 : dri_i2c_stop
功    能 : I2C停止
*			SCL: ____________________
*                          __________
*           SDA: _________/
参    数 : 无
返 回 值 : 无
作    者 : 
*************************************************/
void dri_dri_i2c_stop(void)
{	
	dri_i2c_sda_out();
	
	DRI_I2C_SDA_LOW;                                   //SDA低 -> 高
	dri_i2c_delay();

	DRI_I2C_SCL_HIGH;                                  //SCL高
	dri_i2c_delay();

	DRI_I2C_SDA_HIGH;                                  //SDA高
	dri_i2c_delay();
}

/************************************************
函数名称 : I2C_PutAck
功    能 : I2C主机产生应答(或非应答)位
参    数 : Ack: 
				I2C_ACK ----- 0: 应答
				I2C_NOACK --- 1:非应答
			注意从机的应答电平
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_put_ack(uint8_t Ack)
{
	dri_i2c_sda_out();
	
	DRI_I2C_SCL_LOW;                                   //SCL低
	dri_i2c_delay();

	if(DRI_I2C_ACK == Ack)
		DRI_I2C_SDA_LOW;                                //应答
	else
		DRI_I2C_SDA_HIGH;                                //非应答
	dri_i2c_delay();

	DRI_I2C_SCL_HIGH;                                  //SCL高 -> 低
	dri_i2c_delay();
	DRI_I2C_SCL_LOW;                                   //SCL低
	dri_i2c_delay();
}

/************************************************
函数名称 : I2C_GetAck
功    能 : I2C主机读取应答(或非应答)位
参    数 : 无
返 回 值 : ACK 
					0: 应答
					1: 非应答
			注意主机的应答电平
作    者 : 
*************************************************/
uint8_t dri_i2c_get_ack(void)
{
	uint8_t ack;
	  
	DRI_I2C_SCL_LOW;                                   //SCL低 -> 高
	dri_i2c_delay();
	
	dri_i2c_sda_in();                           	 	//SDA配置为输入模式(开漏模式可以不用切换方向)
	
	DRI_I2C_SCL_HIGH;                                  //SCL高(读取应答位)
	dri_i2c_delay();
	
	if(DRI_I2C_SDA_READ)
		ack = DRI_I2C_NOACK;                           	//应答
	else
		ack = DRI_I2C_ACK;                            //非应答
							
	DRI_I2C_SCL_LOW;                                   	//SCL低
	dri_i2c_delay();
	
	dri_i2c_sda_out();									//重新获取控制权
	return ack;                                    	//返回应答位
}

/************************************************
函数名称 : I2C_WriteByte
功    能 : I2C写一字节
参    数 : Data -------- 数据
返 回 值 : I2C_ACK ----- 应答
            I2C_NOACK --- 非应答
作    者 : 
*************************************************/
uint8_t dri_i2c_write_byte(uint8_t Data)//0xA0
{
	uint8_t cnt;
	
	dri_i2c_sda_out();
	
	for(cnt = 0; cnt < 8; cnt++)
	{	
		DRI_I2C_SCL_LOW; 
		dri_i2c_delay();		//SCL低(SCL为低电平时变化SDA有效)
		
		if(Data & 0x80)
			DRI_I2C_SDA_HIGH;                              //SDA高
		else
			DRI_I2C_SDA_LOW;  							//SDA低
		Data <<= 1;
		dri_i2c_delay();
	
		DRI_I2C_SCL_HIGH;                                //SCL高(发送数据)
		dri_i2c_delay();		
	}		                        
	DRI_I2C_SCL_LOW; 
	dri_i2c_delay();
	
	return dri_i2c_get_ack();  //返回应答位
}

/************************************************
函数名称 : I2C_ReadByte
功    能 : I2C读一字节
参    数 : ack --------- 产生应答(或者非应答)位
返 回 值 : data -------- 读取的一字节数据
作    者 : 
*************************************************/
uint8_t dri_i2c_read_byte(uint8_t ack)
{
	uint8_t cnt;
	uint8_t data; 

	DRI_I2C_SCL_LOW;                                   //SCL低
	dri_i2c_delay();

	dri_i2c_sda_in();                            //SDA配置为输入模式
	
	for(cnt=0; cnt<8; cnt++)
	{
		DRI_I2C_SCL_HIGH;                                //SCL高(读取数据)
		dri_i2c_delay();

		data <<= 1;
		if(DRI_I2C_SDA_READ)
			data |= 0x01;                              //SDA为高(数据有效)

		DRI_I2C_SCL_LOW;                                 //SCL低
		dri_i2c_delay();
	}

	dri_i2c_put_ack(ack);                               //产生应答(或者非应答)位

	return data;                                   //返回数据
}

/************************************************
函数名称 : I2C_REG_WriteNByte
功    能 : EEPROM写N字节
参    数 : slaveAddr ----- IIC地址
            regAddr ---- 数据(寄存器)地址
			pData ---- 数据
            dataLength --- 长度
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_write_nbyte(uint8_t slaveAddr, uint16_t regAddr, uint8_t *pData, uint16_t dataLength)
{
	uint8_t  ack;
	uint8_t i;

	/* 开始 */
	dri_i2c_start();

	/* 设备地址/写 */
	ack = dri_i2c_write_byte(slaveAddr | DRI_I2C_EEPROM_WD);
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		printf("I2C_WriteByte_IIC_ADDR %d\r\n",ack);
		return;
	}

	/* 数据地址 */
	#if (8 == DRI_I2C_EEPROM_WORD_ADDR_SIZE)
	ack = dri_i2c_write_byte((uint8_t)(regAddr & 0x00FF));   //数据地址(8位)
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		return;
	}
	#else
	ack = dri_i2c_write_byte((uint8_t)(regAddr>>8));       //数据地址(16位)
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		return;
	}
	ack = dri_i2c_write_byte((uint8_t)(regAddr&0x00FF));
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		return;
	}
	#endif

	/* 写数据 */
	for (i = 0; i < dataLength; i++)
	{
		ack = dri_i2c_write_byte(pData[i]);
		if(DRI_I2C_NOACK == ack)
		{
			dri_dri_i2c_stop();
			return;
		}
	}
	
	/* 停止 */
	dri_dri_i2c_stop();
//	printf("W_dri_i2c_stop\r\n");
}

/************************************************
函数名称 : I2C_REG_ReadNByte
功    能 : EEPROM读N字节
参    数 : slaveAddr ----- IIC地址
            regAddr ---- 数据(寄存器)地址
			pData ---- 数据
            dataLength --- 长度
返 回 值 : 无
作    者 : 
*************************************************/
void dri_i2c_read_nbyte(uint8_t slaveAddr, uint16_t regAddr, uint8_t *pData, uint16_t dataLength)
{
	uint8_t  ack;
	uint8_t i;

	/* 开始 */
	dri_i2c_start();
	
	/* 设备地址/写 */
	ack = dri_i2c_write_byte(slaveAddr | DRI_I2C_EEPROM_WD);
	if(DRI_I2C_NOACK == ack)
	{
//		printf("I2C_READ_ADDR\r\n");
		dri_dri_i2c_stop();
		return;
	}

	/* 数据地址 */
	#if (8 == DRI_I2C_EEPROM_WORD_ADDR_SIZE)
	ack = dri_i2c_write_byte((uint8_t)(regAddr & 0x00FF));   //数据地址(8位)
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		return;
	}
	#else
	ack = dri_i2c_write_byte((uint8_t)(regAddr>>8));       //数据地址(16位)
	if(DRI_I2C_NOACK == ack)
	{
		dri_i2c_stop();
		return;
	}
	ack = dri_i2c_write_byte((uint8_t)(regAddr&0x00FF));
	if(DRI_I2C_NOACK == ack)
	{
		dri_i2c_stop();
		return;
	}
	#endif

	/* 重新开始 */
	dri_i2c_start();

	/* 设备地址/读 */
	ack = dri_i2c_write_byte(slaveAddr | DRI_I2C_EEPROM_RD);
	if(DRI_I2C_NOACK == ack)
	{
		dri_dri_i2c_stop();
		return;
	}

	/* 读数据 */
	for (i = 0; i < dataLength - 1; i++)
	{
		*(pData + i) = dri_i2c_read_byte(DRI_I2C_ACK);		//读取字节(产生应答)
	}
	*(pData + dataLength - 1) = dri_i2c_read_byte(DRI_I2C_NOACK);     		//读取最后一个字节(产生非应答)

	/* 停止 */
	dri_dri_i2c_stop();
	
//	printf("dri_i2c_stop\r\n");
}

/**** END OF FILE ****/

i2c.h

#ifndef __DRI_SIMULATE_I2C_H__
#define __DRI_SIMULATE_I2C_H__

#include "dri_gpio_map.h"

/* 宏定义 --------------------------------------------------------------------*/

#define DRI_I2C_MASTER_ADDRESS		    0x28
#define DRI_I2C_SLAVE_DEV_ADDR          0xA0                     //地址(设备地址:与A2、A1、A0有关)

#define DRI_I2C2_SCL_PIN                   	DRI_GPIOB_I2C2_SCL
#define DRI_I2C2_SCL_PORT                   GPIOB
#define DRI_I2C2_SDA_PIN                   	DRI_GPIOB_I2C2_SDA
#define DRI_I2C2_SDA_PORT                   GPIOB

#define DRI_I2C_SCL_LOW                 	(GPIO_BC(DRI_I2C2_SCL_PORT) |= DRI_GPIOB_I2C2_SCL)									
#define DRI_I2C_SCL_HIGH                	(GPIO_BOP(DRI_I2C2_SCL_PORT) |= DRI_GPIOB_I2C2_SCL)

#define DRI_I2C_SDA_LOW                 	(GPIO_BC(DRI_I2C2_SDA_PORT) |= DRI_GPIOB_I2C2_SDA)
#define DRI_I2C_SDA_HIGH                	(GPIO_BOP(DRI_I2C2_SDA_PORT) |= DRI_GPIOB_I2C2_SDA)
#define DRI_I2C_SDA_READ                	(GPIO_ISTAT(DRI_I2C2_SDA_PORT) & DRI_GPIOB_I2C2_SDA)

#define DRI_I2C_ACK						0		//应答  /*注意从机的应答电平*/
#define DRI_I2C_NOACK					1   	//非应答

#define DRI_I2C_SPEED_DATA 				4	 	 //5us 100kbps

/*EEPROM*************************************************************************/

#define DRI_I2C_EEPROM_WD               0x00                     //写
#define DRI_I2C_EEPROM_RD               0x01                    //读

#define DRI_I2C_EEPROM_WORD_ADDR_SIZE   8
#define DRI_I2C_EEPROM_WORD_PAGE_SIZE   128

/* 函数申明 ------------------------------------------------------------------*/
void  dri_i2c_simulate_init  (void);
void  dri_i2c_write_nbyte    (uint8_t slaveAddr, uint16_t regAddr, uint8_t *pData, uint16_t dataLength);
void  dri_i2c_read_nbyte     (uint8_t slaveAddr, uint16_t regAddr, uint8_t *pData, uint16_t dataLength);
#endif /*__DRI_SIMULATE_I2C_H__*/

纯属记录学习,如有助益,不胜欢喜;如有问题,欢迎指正!

posted @ 2023-03-06 16:56  xMofang  阅读(602)  评论(0编辑  收藏  举报