因为博主之前是从stm32过来的,在mdk环境下进行gd32的开发。
一直听说stm32的iic有问题,所以从来也用的模拟iic,这次使用gd32,虽然有硬件iic的例程,但是在使用的过程中,永远卡在了iic的准备过程:
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C0);
/* wait until SBSEND bit is set */
while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND))
这个SBSEND按理说应该由硬件置位,但是这里并不行……所以博主决定还是使用模拟iic……
代码如下:
#ifndef __MYIIC_H
#define __MYIIC_H
#include "gd32f30x.h"
//IIC所有操作函数
int iic_init(void); //初始化IIC的IO口
void iic_start(void); //发送IIC开始信号
void iic_stop(void); //发送IIC停止信号
void iic_write_byte(uint8_t txd); //IIC发送一个字节
uint8_t iic_read_byte(uint8_t ack); //IIC读取一个字节
uint8_t iic_wait_ack(void); //IIC等待ACK信号
#endif
因为博主使用了rt-thread,所以这里的延时函数直接使用了rt-thread接口的rt_hw_us_delay
函数进行实现,因为IO口配置为开漏模式,所以实际也不需要进行输入输出模式的转换。
#include "myiic.h"
#include "rtthread.h"
#include "rthw.h"
#define IIC_SCL_PIN GPIO_PIN_6
#define IIC_SCL_GPIO_PORT GPIOB
#define IIC_SCL_GPIO_CLK RCU_GPIOB
#define IIC_SDA_PIN GPIO_PIN_7
#define IIC_SDA_GPIO_PORT GPIOB
#define IIC_SDA_GPIO_CLK RCU_GPIOB
#define iic_printf rt_kprintf
//配置成OD模式不需要进行输入输出模式切换
#define SDA_IN() {;}
#define SDA_OUT() {;}
//#define SDA_IN() {GPIO_CTL0(GPIOB)&=0X0FFFFFFF;GPIO_CTL0(GPIOB)|=(uint32_t)8<<28;}
//#define SDA_OUT() {GPIO_CTL0(GPIOB)&=0X0FFFFFFF;GPIO_CTL0(GPIOB)|=(uint32_t)3<<28;}
static void iic_delay_us(int us)
{
rt_hw_us_delay(10);
}
static void iic_scl_h(void)
{
GPIO_BOP(IIC_SCL_GPIO_PORT) = IIC_SCL_PIN;
}
static void iic_scl_l(void)
{
GPIO_BC(IIC_SCL_GPIO_PORT) = IIC_SCL_PIN;
}
static void iic_sda_write(unsigned char bit)
{
if (bit == 0)
GPIO_BC(IIC_SDA_GPIO_PORT) = IIC_SDA_PIN;
else
GPIO_BOP(IIC_SDA_GPIO_PORT) = IIC_SDA_PIN;
}
static unsigned char iic_sda_read(void)
{
if (RESET == gpio_input_bit_get(IIC_SDA_GPIO_PORT, IIC_SDA_PIN))
return 0x00;
else
return 0x01;
}
void iic_start(void)
{
SDA_OUT();
iic_sda_write(1);
iic_delay_us(1);
iic_scl_h();
iic_delay_us(4);
iic_sda_write(0);
iic_delay_us(4);
iic_scl_l();
iic_delay_us(1);
}
void iic_stop(void)
{
SDA_OUT();
iic_scl_l();
iic_delay_us(1);
iic_sda_write(0);
iic_delay_us(4);
iic_scl_h();
iic_delay_us(1);
iic_sda_write(1);
iic_delay_us(4);
}
uint8_t iic_wait_ack(void)
{
uint32_t retry = 0;
SDA_IN();
iic_sda_write(0x01);
iic_delay_us(1);
iic_scl_h();
iic_delay_us(1);
while (iic_sda_read() == 0x01)
{
retry++;
//iic_delay_us(1);
if (retry > 500) break;
}
if (iic_sda_read() == 0)
{
iic_scl_l();
iic_delay_us(1);
return 0;
}
else
{
iic_printf("stop \r\n");
iic_stop();
return 1;
}
}
static void iic_ack(uint8_t ack_nack)
{
iic_scl_l();
SDA_OUT();
iic_sda_write(ack_nack);
iic_delay_us(1);
iic_scl_h();
iic_delay_us(1);
iic_scl_l();
iic_delay_us(1);
}
uint8_t iic_read_byte(uint8_t ack)
{
uint8_t i, data;
SDA_IN();
for (i = 0, data = 0; i < 8; i++)
{
data <<= 1;
iic_scl_h();
iic_delay_us(1);
data |= iic_sda_read();
iic_scl_l();
iic_delay_us(1);
}
iic_ack(ack);
return data;
}
void iic_write_byte(uint8_t data)
{
int i;
SDA_OUT();
iic_scl_l();
for (i = 0; i < 8; i++)
{
iic_sda_write((data & 0x80) >> 7);
iic_delay_us(1);
iic_scl_h();
iic_delay_us(1);
iic_scl_l();
iic_delay_us(1);
data <<= 1;
}
}
int iic_init(void)
{
rcu_periph_clock_enable(IIC_SCL_GPIO_CLK);
rcu_periph_clock_enable(IIC_SDA_GPIO_CLK);
gpio_init(IIC_SCL_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, IIC_SCL_PIN);
gpio_init(IIC_SDA_GPIO_PORT, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, IIC_SDA_PIN);
GPIO_BOP(IIC_SCL_GPIO_PORT) = IIC_SCL_PIN;
GPIO_BOP(IIC_SDA_GPIO_PORT) = IIC_SDA_PIN;
return 0;
}
INIT_BOARD_EXPORT(iic_init);