158 lines
4.2 KiB
C
158 lines
4.2 KiB
C
#include "systick.h"
|
||
#include "bitband.h"
|
||
#include "gpio_iic.h"
|
||
|
||
static GPIO_InitTypeDef GPIO_InitStructSDAOut;
|
||
static GPIO_InitTypeDef GPIO_InitStructSDAIn;
|
||
// 位段定义
|
||
#define IIC_SCL_OUT PBOut(6)
|
||
#define IIC_SDA_OUT PBOut(7)
|
||
#define IIC_SDA_IN PBIn(7)
|
||
|
||
// 初始化 IIC 的IO 端口:SDA:PB7,SCL:PB6
|
||
void iic_init(void)
|
||
{
|
||
GPIO_InitTypeDef GPIO_InitStructSCL;
|
||
// 使能时钟
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||
|
||
// 初始化 PB6 为开漏输出
|
||
GPIO_InitStructSCL.GPIO_Mode = GPIO_Mode_Out_OD;
|
||
GPIO_InitStructSCL.GPIO_Pin = GPIO_Pin_6;
|
||
GPIO_InitStructSCL.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_Init(GPIOB, &GPIO_InitStructSCL);
|
||
|
||
// 初始化 PB7 为开漏输出
|
||
GPIO_InitStructSDAOut.GPIO_Mode = GPIO_Mode_Out_OD;
|
||
GPIO_InitStructSDAOut.GPIO_Pin = GPIO_Pin_7;
|
||
GPIO_InitStructSDAOut.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_Init(GPIOB, &GPIO_InitStructSDAOut);
|
||
// 设置 SCL和SDA 都为高电平
|
||
IIC_SCL_OUT = 1;
|
||
IIC_SDA_OUT = 1;
|
||
// 填充 PB7 为上拉输入状态的结构体(后续备用)
|
||
GPIO_InitStructSDAIn.GPIO_Mode = GPIO_Mode_IPU;
|
||
GPIO_InitStructSDAIn.GPIO_Pin = GPIO_Pin_7;
|
||
}
|
||
|
||
// 设置 SDA 为输入模式
|
||
static void iic_set_sda_in(void)
|
||
{
|
||
GPIO_Init(GPIOB, &GPIO_InitStructSDAIn);
|
||
}
|
||
// 设置 SDA 为输出模式
|
||
static void iic_set_sda_out(void)
|
||
{
|
||
GPIO_Init(GPIOB, &GPIO_InitStructSDAOut);
|
||
}
|
||
|
||
// 主机发送起始信号
|
||
void iic_start(void)
|
||
{
|
||
iic_set_sda_out();
|
||
IIC_SDA_OUT = 1;
|
||
IIC_SCL_OUT = 1;
|
||
delay_us(2);
|
||
IIC_SDA_OUT = 0;
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 0;
|
||
delay_us(1);
|
||
}
|
||
//主机发送停止信号
|
||
void iic_stop(void)
|
||
{
|
||
iic_set_sda_out();
|
||
IIC_SCL_OUT = 0;
|
||
IIC_SDA_OUT = 0;
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 1;
|
||
delay_us(1);
|
||
IIC_SDA_OUT = 1;
|
||
delay_us(2);
|
||
}
|
||
// 主机发送一个字节
|
||
void iic_send_byte(u8 txd)
|
||
{
|
||
int bit;
|
||
|
||
iic_set_sda_out();
|
||
for (bit = 7; bit >= 0; bit--) {
|
||
// 拉低时钟线
|
||
IIC_SCL_OUT = 0;
|
||
delay_us(1);
|
||
// 变化数据线的数据
|
||
IIC_SDA_OUT = (txd >> bit) & 0x01;
|
||
delay_us(1);
|
||
IIC_SCL_OUT = 1;
|
||
delay_us(2);
|
||
}
|
||
IIC_SCL_OUT = 0; // 发送完毕拉低时钟线。
|
||
}
|
||
// 主机接收一个字节并回复ack,参数ack:1表示应答,0表示非应答。
|
||
u8 iic_recv_byte(u8 ack)
|
||
{
|
||
int bit;
|
||
u8 value = 0; // 用于保存最终的返回值
|
||
|
||
iic_set_sda_in(); // 设置为输入模式
|
||
for (bit = 7; bit >= 0; bit--) {
|
||
IIC_SCL_OUT = 0; // 拉低时钟线
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 1;
|
||
delay_us(2);
|
||
if (IIC_SDA_IN) {
|
||
value |= (0x01 << bit);
|
||
}
|
||
}
|
||
IIC_SCL_OUT = 0;
|
||
// 接收8为数据,根据参数ack 回复应答或非应答。
|
||
if (ack)
|
||
iic_send_ack();
|
||
else
|
||
iic_send_nack();
|
||
|
||
return value;
|
||
}
|
||
// 主机等待从机,如果从机未响应(收到NACK),则发送停止
|
||
// 信号结束本次通信,非应答返回1(NACK),应答返回0,ACK);
|
||
u8 iic_wait_ack(void)
|
||
{
|
||
u8 error_timeout = 0;
|
||
IIC_SCL_OUT = 0; // 拉低时钟线
|
||
iic_set_sda_in(); // 设置为输入模式
|
||
delay_us(1);
|
||
IIC_SCL_OUT = 1; // 拉高时钟线。
|
||
// 等待从机拉低的引号
|
||
while (IIC_SDA_IN) {
|
||
error_timeout++;
|
||
if (error_timeout > 250) {
|
||
iic_stop(); // 发送停止信号,然后返回1
|
||
return 1;
|
||
}
|
||
}
|
||
IIC_SCL_OUT = 0; // 拉低时钟线
|
||
return 0;
|
||
}
|
||
// 主机发送 ACK
|
||
void iic_send_ack(void)
|
||
{
|
||
IIC_SCL_OUT = 0; // 拉低时钟线
|
||
iic_set_sda_out(); // 变为输出模式
|
||
IIC_SDA_OUT = 0; // 低电平为应答ACK
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 1; // 拉高时钟线
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 0;
|
||
}
|
||
// 主机发送 NACK
|
||
void iic_send_nack(void)
|
||
{
|
||
IIC_SCL_OUT = 0; // 拉低时钟线
|
||
iic_set_sda_out(); // 变为输出模式
|
||
IIC_SDA_OUT = 1; // 高电平为非应答NACK
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 1; // 拉高时钟线
|
||
delay_us(2);
|
||
IIC_SCL_OUT = 0;
|
||
}
|