当前位置: 首页 > news >正文

ARM-I2C硬实现

硬件I2C-GD32F4系列的实现

===初始化操作===

在初始化函数里执行以下代码

uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
uint32_t i2cx_scl_port = GPIOB;
uint32_t i2cx_scl_pin = GPIO_PIN_6;
uint32_t i2cx_scl_af = GPIO_AF_4;uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
uint32_t i2cx_sda_port = GPIOB;
uint32_t i2cx_sda_pin = GPIO_PIN_7;
uint32_t i2cx_sda_af = GPIO_AF_4;uint32_t i2cx = I2C0;
uint32_t i2cx_rcu = RCU_I2C0;
uint32_t i2cx_speed = 400000;
/****************** GPIO config **********************/
// 时钟配置
rcu_periph_clock_enable(i2cx_scl_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
// 设置输出模式
gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);// 时钟配置
rcu_periph_clock_enable(i2cx_sda_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
// 设置输出模式
gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);/****************** I2C config  **********************/
i2c_deinit(i2cx);
// 时钟配置
rcu_periph_clock_enable(i2cx_rcu);
// I2C速率配置
i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);// 使能i2c
//i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(i2cx);// i2c ack enable
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
  • 哪个I2C
  • SCL是哪个引脚
  • SDA是哪个引脚
  • 速度是多快

准备两个wait函数

等待指定外设的flag状态变化的函数

#define	TIMEOUT	50000
static uint8_t I2C_wait(uint32_t flag) {uint16_t cnt = 0;while(!i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}static uint8_t I2C_waitn(uint32_t flag) {uint16_t cnt = 0;while(i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}

===写操作流程===

开始

/************* start ***********************/
// 等待I2C闲置
if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;
// start
i2c_start_on_bus(i2cx);
// 等待I2C主设备成功发送起始信号
if(I2C_wait(I2C_FLAG_SBSEND)) return 2;

发送设备地址

注意⚠️,这里是设备的写地址write_addr

/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, write_addr, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

发送寄存器地址

/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(I2C_FLAG_TBE)) return 4;// 发送数据
i2c_data_transmit(i2cx, reg);// 等待数据发送完成
if(I2C_wait(I2C_FLAG_BTC)) return 5;

数据发送

/***************** data ******************/
// 发送数据
uint32_t i;
for(i = 0; i < len; i++) {uint32_t d = data[i];// 等待发送数据缓冲区为空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 发送数据i2c_data_transmit(i2cx, d);// 等待数据发送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;
}

停止

/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 8;

===读操作流程===

开始

/************* start ***********************/
// 等待I2C空闲
if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;
// 发送启动信号
i2c_start_on_bus(i2cx);
// 等待I2C主设备成功发送起始信号
if(I2C_wait(I2C_FLAG_SBSEND)) return 2;

发送设备地址(写)

/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

发送寄存器地址

/********** register address **************/
// 等待发送缓冲区	
if(I2C_wait(I2C_FLAG_TBE)) return 4;// 发送寄存器地址
i2c_data_transmit(i2cx, reg);// 等待发送数据完成	
if(I2C_wait(I2C_FLAG_BTC)) return 5;

开始

/************* start ***********************/
// 发送再启动信号
i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 7;

发送设备地址(读)

/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_RECEIVER);
if(I2C_wait(I2C_FLAG_ADDSEND)) return 8;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);

数据读取

/************* data **************/
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
// 接收一个数据后,自动发送ACK
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
// 确认ACK已启用
if(I2C_wait(I2C_CTL0(i2cx) & I2C_CTL0_ACKEN)) return 11;// 读取数据
uint32_t i;
for (i = 0; i < len; i++) {if (i == len - 1) {// 在读取最后一个字节之前,禁用ACK,配置为自动NACKi2c_ack_config(i2cx, I2C_ACK_DISABLE);}// 等待接收缓冲区不为空if(I2C_wait(I2C_FLAG_RBNE)) return 10;data[i] = i2c_data_receive(i2cx);
}

停止

/***************** stop ********************/
i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 12;

GD32F4寄存器

流程

功能

标记

描述

START

I2C_FLAG_I2CBSY

busy标记。I2C是否占用,没有占用才可以使用。

I2C_FLAG_SBSEND

起始信号发送状态标记。START成功或失败。

数据

设备地址

I2C_FLAG_ADDSEND

地址发送状态标记。成功或失败。

发送

I2C_FLAG_TBE

发送数据寄存器是否为空的标记。为空才可以继续发送。

I2C_FLAG_BTC

发送数据寄存器中数据是否发送完成。

接收

I2C_FLAG_RBNE

接收缓冲区寄存器是否为空的标记。为空才可以继续接收。

STOP

I2C_CTL0_STOP

停止标记位。

完整代码

//I2C0.h
#ifndef __I2C0_H__
#define __I2C0_H__#include "systick.h"
#include "gd32f4xx.h"void I2C0_init();uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);void I2C0_deinit();#endif

 

//I2C0.c
#include "I2C0.h"#define i2cx	I2C0void I2C0_init() {uint32_t i2cx_scl_port_rcu = RCU_GPIOB;uint32_t i2cx_scl_port = GPIOB;uint32_t i2cx_scl_pin = GPIO_PIN_6;uint32_t i2cx_scl_af = GPIO_AF_4;uint32_t i2cx_sda_port_rcu = RCU_GPIOB;uint32_t i2cx_sda_port = GPIOB;uint32_t i2cx_sda_pin = GPIO_PIN_7;uint32_t i2cx_sda_af = GPIO_AF_4;uint32_t i2cx = I2C0;uint32_t i2cx_rcu = RCU_I2C0;uint32_t i2cx_speed = 400000;/****************** GPIO config **********************/// 时钟配置rcu_periph_clock_enable(i2cx_scl_port_rcu);// 设置复用功能gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);// 设置输出模式gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);// 时钟配置rcu_periph_clock_enable(i2cx_sda_port_rcu);// 设置复用功能gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);// 设置输出模式gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);/****************** I2C config  **********************/i2c_deinit(i2cx);// 时钟配置rcu_periph_clock_enable(i2cx_rcu);// I2C速率配置i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);// 使能i2ci2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);i2c_enable(i2cx);// i2c ack enablei2c_ack_config(i2cx, I2C_ACK_ENABLE);//i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);}static uint8_t I2C_wait(uint32_t flag) {uint16_t TIMEOUT = 50000;uint16_t cnt = 0;while(!i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}static uint8_t I2C_waitn(uint32_t flag) {uint16_t TIMEOUT = 50000;uint16_t cnt = 0;while(i2c_flag_get(i2cx, flag)) {cnt++;if(cnt > TIMEOUT) return 1;}return 0;
}uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {uint8_t address = addr << 1;/************* start ***********************/// 等待I2C闲置if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// starti2c_start_on_bus(i2cx);// 等待I2C主设备成功发送起始信号if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 发送设备地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);// 等待地址发送完成if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/************ register address ************/// 寄存器地址// 等待发送数据缓冲区为空if(I2C_wait(I2C_FLAG_TBE)) return 4;// 发送数据i2c_data_transmit(i2cx, reg);// 等待数据发送完成if(I2C_wait(I2C_FLAG_BTC)) return 5;/***************** data ******************/// 发送数据uint32_t i;for(i = 0; i < data_len; i++) {uint32_t d = data[i];// 等待发送数据缓冲区为空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 发送数据i2c_data_transmit(i2cx, d);// 等待数据发送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;}/***************** stop ********************/// stopi2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 8;return 0;
}uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {uint8_t address = addr << 1;/************* start ***********************/// 等待I2C闲置if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// starti2c_start_on_bus(i2cx);// 等待I2C主设备成功发送起始信号if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 发送设备地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);// 等待地址发送完成if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/************ register address ************/// 寄存器地址// 等待发送数据缓冲区为空if(I2C_wait(I2C_FLAG_TBE)) return 4;// 发送数据i2c_data_transmit(i2cx, reg);// 等待数据发送完成if(I2C_wait(I2C_FLAG_BTC)) return 5;/***************** data ******************/// 发送数据do {// 等待发送数据缓冲区为空if(I2C_wait(I2C_FLAG_TBE)) return 6;// 发送数据i2c_data_transmit(i2cx, *data);data += offset;// 等待数据发送完成if(I2C_wait(I2C_FLAG_BTC)) return 7;} while(--len);/***************** stop ********************/// stopi2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;return 0;
}void I2C0_deinit() {}uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {uint32_t i2cx = I2C0;uint8_t address = addr << 1;/************* start ***********************/// 等待I2C空闲if(I2C_waitn(I2C_FLAG_I2CBSY)) return 1;// 发送启动信号i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 2;/************* device address **************/// 发送从设备写地址i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 3;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/********** register address **************/// 等待发送缓冲区	if(I2C_wait(I2C_FLAG_TBE)) return 4;// 发送寄存器地址i2c_data_transmit(i2cx, reg);// 等待发送数据完成	if(I2C_wait(I2C_FLAG_BTC)) return 5;	/************* start ***********************/// 发送再启动信号i2c_start_on_bus(i2cx);if(I2C_wait(I2C_FLAG_SBSEND)) return 7;/************* device address **************/// 发送从设备读地址i2c_master_addressing(i2cx, address + 1, I2C_RECEIVER);if(I2C_wait(I2C_FLAG_ADDSEND)) return 8;i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);/**************** 接收数据data *************///acki2c_ack_config(i2cx, I2C_ACK_ENABLE);// 接收一个数据后,自动发送ACKi2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);// 确认ACK已启用if(I2C_wait(I2C_CTL0(i2cx) & I2C_CTL0_ACKEN)) return 11;// 读取数据uint32_t i;for (i = 0; i < len; i++) {if (i == len - 1) {// 在读取最后一个字节之前,禁用ACK,配置为自动NACKi2c_ack_config(i2cx, I2C_ACK_DISABLE);}// 等待接收缓冲区不为空if(I2C_wait(I2C_FLAG_RBNE)) return 10;data[i] = i2c_data_receive(i2cx);}/***************************************//***************** stop ********************/i2c_stop_on_bus(i2cx);if(I2C_waitn(I2C_CTL0(i2cx)&I2C_CTL0_STOP)) return 12;return 0;
}

http://www.lryc.cn/news/599814.html

相关文章:

  • linux-开机启动流程
  • 编程语言Java——核心技术篇(三)异常处理详解
  • 将本地项目推送到远程github仓库
  • 学习游戏制作记录(克隆技能)7.25
  • C语言|指针的应用
  • Python 之 keyboard
  • 详解软件需求中的外部接口需求
  • 网络安全入门第一课:信息收集实战手册(3)
  • 芯显15寸工控液晶屏RV150X0M-N10产品资料详情
  • 高德地图 loca 实现点线的显示和点击
  • Ping32:企业数据安全的智能护盾
  • C++中使用Essentia实现STFT/ISTFT
  • C++中new和delete的多重面孔:operator new、new operator与placement new解析
  • 机器学习-SVM支持向量机
  • Zookeeper学习专栏(十):核心流程剖析之服务启动、请求处理与选举协议
  • 【Linux】进程切换与优先级
  • Metaspace耗尽导致OOM问题
  • 【运维自动化-标准运维】各类全局变量使用说明(下)
  • 伯俊科技× OB Cloud:零售业落地AI的“三步走”渐进式发展实践
  • 企业微信H5应用OAuth2登录,企业微信授权登录
  • 国产DevOps平台Gitee:如何重塑中国企业研发效能新格局
  • 如何在 Ubuntu 24.04 或 22.04 上安装和使用 GDebi
  • Qt 反射机制与动态属性系统
  • UserWarning: Workbook contains no default style, apply openpyxl‘s default warn
  • ReAct Agent(LangGraph实现)
  • 04-netty基础-Reactor三种模型
  • 无需 Root 关闭联网验证 随意修改手机名称(适用于OPPO、一加、真我)
  • 【笔记】Handy Multi-Agent Tutorial 第四章: CAMEL框架下的RAG应用 (简介)
  • RocketMQ 5.3.0 ARM64 架构安装部署指南
  • 详解FreeRTOS开发过程(八)-- 时间标志