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__*/
纯属记录学习,如有助益,不胜欢喜;如有问题,欢迎指正!