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__*/
純屬記錄學習,如有助益,不勝歡喜;如有問題,歡迎指正!

浙公網安備 33010602011771號