##基于nordic的 GPIO IIC 模拟驱动
长夜漫漫无心睡眠,疫情影响还未解封, 发一个以前写的GPIO的IIC驱动,给有需要的同学.
环境
- 本文件 基于 nordic sdk 上层应用ccs811 芯片
- io_iic_config.h .文件用于移植其他芯片和配置
- 用过在stm32 , stc51, 国产ble IC …
io_iic_config.h
/***********************************************************
* @file io_iic_config.h
* @author jhe (156335168@qq.com)
* @brief
* @version 1.0
* @date 2021-01-18
*
* (C) COPYRIGHT 2015 - 2020,ALL TIGHTS RESERVED.
*
**/
#ifndef __IO_IIC_CONFIG_H__
#define __IO_IIC_CONFIG_H__
/***********************************************************
* @brief 用户设置选项
**/
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
// IO方向设置
#define SCL_OUT() nrf_gpio_cfg_output(CCS811_GPIO_SCL_PIN)
#define SDA_IN() nrf_gpio_cfg_input(CCS811_GPIO_SDA_PIN, NRF_GPIO_PIN_PULLUP)
#define SDA_OUT() nrf_gpio_cfg_output(CCS811_GPIO_SDA_PIN)
// IO操作函数
#define IIC_SCL(X) nrf_gpio_pin_write(CCS811_GPIO_SCL_PIN, X) // SCL
#define IIC_SDA(X) nrf_gpio_pin_write(CCS811_GPIO_SDA_PIN, X) // SDA
#define READ_SDA nrf_gpio_pin_read(CCS811_GPIO_SDA_PIN) //输入SDA
// 配置为输出方向的IO读取
#define SCL_READ nrf_gpio_pin_out_read(CCS811_GPIO_SCL_PIN)
#define SDA_READ nrf_gpio_pin_out_read(CCS811_GPIO_SDA_PIN)
// 延时函数
inline void delay_us(uint32_t us)
{
nrf_delay_us(us * 5);
}
// 调试定义 e.g #define log_d printf
#define log_d NRF_LOG_DEBUG // 调试输出
#endif
- note: 文件用于移植其他芯片和配置
io_iic.h
/**
* @file io_iic.h
* @author jhe (156335168@qq.com)
* @brief
* @version 0.1
* @date 2021-01-18
* (C) COPYRIGHT 2015 - 2020,ALL TIGHTS RESERVED.
*/
#ifndef __IO_IIC_H__
#define __IO_IIC_H__
#include <stdint.h>
#include <stdio.h>
#include "io_iic_config.h"
#define IIC_RESET 0
#define IIC_SET 1
// IIC所有操作函数
void io_iic_init(void); //初始化IIC的IO口
uint8_t io_iic_start(void); //发送IIC开始信号
void io_iic_stop(void); //发送IIC停止信号
void io_iic_send_byte(uint8_t txd); // IIC发送一个字节
uint8_t io_iic_read_byte(unsigned char ack); // IIC读取一个字节
uint8_t io_iic_wait_ack(void); // IIC等待ACK信号
void io_iic_send_ack(void); // IIC发送ACK信号
void io_iic_send_nack(void); // IIC不发送ACK信号
uint8_t io_iic_read_bytes(uint8_t slave_addr, uint8_t reg, uint8_t *data, uint8_t length); // 读取N字节长度
uint8_t io_iic_write_bytes(uint8_t slave_addr, uint8_t reg, uint8_t const *data, uint8_t length); //写入N字节长度
void delay_us(uint32_t us); // config里面的内联函数
#endif
- 不要更改里面内容
io_iic.c
/**
* @file io_iic.c
* @author jhe (156335168@qq.com)
* @brief
* @version 0.1
* @date 2021-01-18
*
* (C) COPYRIGHT 2015 - 2020,ALL TIGHTS RESERVED.
*
*/
#include "io_iic.h"
#include <stdint.h>
#include <string.h>
//初始化IIC
void io_iic_init(void)
{
SCL_OUT();
SDA_OUT();
IIC_SCL(1);
IIC_SDA(1);
}
//产生IIC起始信号
uint8_t io_iic_start(void)
{
// sda线输出
SDA_OUT();
IIC_SDA(1);
IIC_SCL(1);
if (!SDA_READ)
{
log_d("%s(%d):ERROR!!!", __func__, __LINE__);
return 0;
}
delay_us(5);
IIC_SDA(0);
if (SDA_READ)
{
log_d("%s(%d):ERROR!!!", __func__, __LINE__);
return 0;
}
delay_us(5);
//钳住IIC总线,准备发送或接收数据
IIC_SCL(0);
return 1;
}
//产生IIC停止信号
void io_iic_stop(void)
{
// sda线输出
SDA_OUT();
IIC_SCL(0);
IIC_SDA(0);
delay_us(5);
IIC_SCL(1);
//发送IIC总线结束信号
IIC_SDA(1);
delay_us(5);
}
//等待应答信号到来返回值:1,接收应答失败 0,接收应答成功
uint8_t io_iic_wait_ack(void)
{
uint32_t ucErrTime = 0;
// SDA设置为输入
SDA_IN();
IIC_SDA(1);
delay_us(1);
IIC_SCL(1);
delay_us(1);
while (READ_SDA)
{
ucErrTime++;
if (ucErrTime > 0xFFFF0)
{
io_iic_stop();
log_d("%s(%d):ERROR!!!", __func__, __LINE__);
return 1;
}
delay_us(1);
}
//时钟输出0
IIC_SCL(0);
return 0;
}
//产生ACK应答
void io_iic_send_ack(void)
{
IIC_SCL(0);
SDA_OUT();
IIC_SDA(0);
delay_us(5);
IIC_SCL(1);
delay_us(5);
IIC_SCL(0);
}
//不产生ACK应答
void io_iic_send_nack(void)
{
IIC_SCL(0);
SDA_OUT();
IIC_SDA(1);
delay_us(5);
IIC_SCL(1);
delay_us(5);
IIC_SCL(0);
}
// IIC发送一个字节,返回从机有无应答 1,有应答 0,无应答
void io_iic_send_byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
IIC_SCL(0); //拉低时钟开始数据传输
for (t = 0; t < 8; t++)
{
if ((txd & 0x80) >> 7)
IIC_SDA(1);
else
IIC_SDA(0);
txd <<= 1;
delay_us(50);
IIC_SCL(1);
delay_us(50);
IIC_SCL(0);
delay_us(50);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送NACK
uint8_t io_iic_read_byte(unsigned char ack)
{
unsigned char i, receive = 0;
// SDA设置为输入
SDA_IN();
for (i = 0; i < 8; i++)
{
IIC_SCL(0);
delay_us(50);
IIC_SCL(1);
receive <<= 1;
if (READ_SDA)
receive++;
delay_us(50);
}
//判断发送ACK
if (!ack)
io_iic_send_nack();
else
io_iic_send_ack();
return receive;
}
uint8_t io_iic_write_bytes(uint8_t slave_addr, uint8_t reg, uint8_t const *data, uint8_t length)
{
//起始信号
io_iic_start();
//发送设备地址+写信号
io_iic_send_byte(slave_addr);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
//内部寄存器地址
io_iic_send_byte(reg);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
//内部寄存器数据
while (length)
{
io_iic_send_byte(*data++);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
length--;
}
//发送停止信号
io_iic_stop();
return IIC_SET;
}
uint8_t io_iic_read_bytes(uint8_t slave_addr,
uint8_t reg,
uint8_t *data,
uint8_t length)
{
//起始信号
if (io_iic_start() == 0)
{
io_iic_stop();
return IIC_RESET;
}
//发送设备地址+写信号
io_iic_send_byte(slave_addr);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
//发送存储单元地址
io_iic_send_byte(reg);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
//起始信号
if (io_iic_start() == 0)
{
io_iic_stop();
return IIC_RESET;
}
//发送设备地址+读信号
io_iic_send_byte(slave_addr + 1);
if (io_iic_wait_ack())
{
io_iic_stop();
return IIC_RESET;
}
//读出寄存器数据
while (length - 1)
{
*data++ = io_iic_read_byte(1);
length--;
}
*data = io_iic_read_byte(0);
//停止信号
io_iic_stop();
return IIC_SET;
}
- 文件目录 ./sdk/components/drivers_ext/gpio_iic.