自用模拟I2C的实现

发布时间:2026/9/9 17:32:30

自用模拟I2C的实现 1.头文件#define GPIO_PIN_X #define SDA_IN GPIO-PortC_OutputEN | GPIO_PIN_X;gpio_set_portpull(GPIO_C,GPIO_PIN_X,GPIO_NOPULL); #define SDA_OUT GPIO-PortC_OutputEN ~ GPIO_PIN_X; #define SDA_DATA() gpio_read_pin(GPIO_C, GPIO_PIN_X) #define SDA_H gpio_write_pin(GPIO_C, GPIO_PIN_X, GPIO_PIN_SET) #define SDA_L gpio_write_pin(GPIO_C, GPIO_PIN_X, GPIO_PIN_CLEAR) // IIC所有操作函数 void IIC_Start(void); void IIC_Stop(void); uint8_t IIC_Wait_Ack(void); void IIC_Put_Ack(uint8_t Ack); void IIC_Send_Byte(char Data); uint8_t IIC_Read_Byte(void); unsigned char I2C_WriteByte(uint8_t Master_addr, uint8_t Send_addr, uint8_t data); unsigned char I2C_ReadByte(uint8_t Master_addr, uint8_t Send_addr); unsigned char I2CWrite_Sequence(uint8_t Master_addr, uint8_t *wit_data, uint8_t sequence_length); unsigned char I2CRead_Sequence(uint8_t Master_addr, uint8_t *reg_value, uint8_t sequence_length);2.源码/************************************模拟I2C******************************************/ #define I2C_Delay_Time 5 // 10us // 产生IIC起始信号 void IIC_Start(void) { SDA_OUT; SCL_H; I2Cdelay(I2C_Delay_Time); SDA_H; I2Cdelay(I2C_Delay_Time); SDA_L; I2Cdelay(I2C_Delay_Time); SCL_L; I2Cdelay(I2C_Delay_Time); } // 产生IIC停止信号 void IIC_Stop(void) { SDA_OUT; SDA_L; I2Cdelay(I2C_Delay_Time); SCL_H; I2Cdelay(I2C_Delay_Time); SDA_H; I2Cdelay(I2C_Delay_Time); } // 等待数据接收方反馈ACK // 成功返回0 失败返回1 uint8_t IIC_Wait_Ack(void) { uint16_t wait_time 0; uint8_t ack_nack 0; SCL_L; I2Cdelay(I2C_Delay_Time); SDA_IN; // 释放总线 等待从机拉低 I2Cdelay(I2C_Delay_Time); SCL_H; I2Cdelay(I2C_Delay_Time); while (SDA_DATA()) { wait_time; if (wait_time 200) // 时间过长 退出等待 { ack_nack 1; break; } } SCL_L; SDA_OUT; I2Cdelay(I2C_Delay_Time); return ack_nack; } // 产生ACK应答 // 发送ACK就是在SDA0时 SCL由0变成1 // 发送NACK就是在SDA1时SCL由0变成1 void IIC_Put_Ack(uint8_t Ack) { SDA_OUT; I2Cdelay(I2C_Delay_Time); if (Ack 0) SDA_L; // 应答ACK else SDA_H; // 无应答NACK I2Cdelay(I2C_Delay_Time); SCL_H; I2Cdelay(I2C_Delay_Time); SCL_L; I2Cdelay(I2C_Delay_Time); } // 主设备发送一个字节 void IIC_Send_Byte(char Data) { char i; SDA_OUT; for (i 0; i 8; i) { SCL_L; if (Data 0x80) SDA_H; else SDA_L; Data Data 1; I2Cdelay(I2C_Delay_Time); SCL_H; I2Cdelay(I2C_Delay_Time); } SCL_L; I2Cdelay(I2C_Delay_Time); } // 主设备从从设备读一个字节 uint8_t IIC_Read_Byte(void) { uint8_t i, Data; SCL_L; SDA_IN; // 将SDA设置为输入 I2Cdelay(I2C_Delay_Time); for (i 0; i 8; i) { SCL_H; Data 1; if (SDA_DATA()) Data | 0x01; else Data 0xFE; I2Cdelay(I2C_Delay_Time); SCL_L; I2Cdelay(I2C_Delay_Time); } SDA_OUT; return Data; } // I2C主设备数据发送 // 有应答 0 失败 1 unsigned char I2C_WriteByte(uint8_t Master_addr, uint8_t Send_addr, uint8_t data) { IIC_Start(); IIC_Send_Byte(((Master_addr 1) 0xFE)); // I2C7位地址 if (IIC_Wait_Ack() 0) return 1; IIC_Send_Byte(Send_addr); if (IIC_Wait_Ack() 0) return 1; IIC_Send_Byte(data); if (IIC_Wait_Ack() 0) return 1; IIC_Stop(); return 0; } // I2C主设备数据读取 // 有应答data 失败 1 unsigned char I2C_ReadByte(uint8_t Master_addr, uint8_t Send_addr) // 读寄存器或读数据 { unsigned char reg_value; IIC_Start(); IIC_Send_Byte(((Master_addr 1) 0xFE)); // 主设备地址 if (IIC_Wait_Ack()) return 1; IIC_Send_Byte(Send_addr); if (IIC_Wait_Ack()) return 1; IIC_Start(); IIC_Send_Byte(((Master_addr 1) | 0x01)); // 读器件地址 if (IIC_Wait_Ack()) return 1; reg_value IIC_Read_Byte(); IIC_Stop(); return reg_value; } // I2C的连续写 unsigned char I2CWrite_Sequence(uint8_t slave_addr, uint8_t reg_addr, uint8_t *write_data, uint8_t data_len) { unsigned char i; IIC_Start(); // 发送写器件地址 IIC_Send_Byte(slave_addr 1); if (IIC_Wait_Ack()) { IIC_Stop(); return 1; } // 发送寄存器起始地址 IIC_Send_Byte(reg_addr); if (IIC_Wait_Ack()) { IIC_Stop(); return 2; } // 连续发送数据 for (i 0; i data_len; i) { IIC_Send_Byte(write_data[i]); if (IIC_Wait_Ack()) { IIC_Stop(); return 3; } } IIC_Stop(); return 0; } // I2C的连续读 unsigned char I2CRead_Sequence(uint8 slave_addr, uint8 reg_addr, uint8 *reg_value, uint8 sequence_length) { unsigned char i; IIC_Start(); // 写器件地址 IIC_Send_Byte(slave_addr 1); if (IIC_Wait_Ack()) { IIC_Stop(); return 1; } // 写寄存器地址 IIC_Send_Byte(reg_addr); if (IIC_Wait_Ack()) { IIC_Stop(); return 1; } // 重复起始条件 IIC_Start(); // 读器件地址 IIC_Send_Byte((slave_addr 1) | 0x01); if (IIC_Wait_Ack()) { IIC_Stop(); return 1; } // 读取数据 for (i 0; i sequence_length; i) { reg_value[i] IIC_Read_Byte(); if (i sequence_length - 1) IIC_Put_Ack(0); // ACK else IIC_Put_Ack(1); // NACK } IIC_Stop(); return 0; } void I2Cdelay(int time) { co_delay_10us(time); }
延伸阅读

更多相关文章

2026/9/4 18:46:03

CANN坐标转换函数Crd2Idx

Crd2Idx 产品支持情况 产品 是否支持 Ascend 950PR/Ascend 950DT √ Atlas A3 训练系列产品/Atlas A3 推理系列产品√ Atlas A2 训练系列产品/Atlas A2 推理系列产品√ Atlas 200I/500 A2 推理产品x Atlas 推理系列产品AI Core x Atlas 推理系列产品Vector Core x Atlas 训练系…

2026/9/9 17:30:00

MySQL数据可视化实战:从环境搭建到Python图表全流程

说实话,最开始接触“MySQL数据可视化”这个项目时,我以为只是把数据库里的表格导出来画几张图而已。真正做起来才发现,这一路踩到的坑、优化的细节、还有最后看到数据变成讲故事工具时的成就感,都远超预期。本文就从实践角度把整套…

2026/9/9 17:30:00

用AI快速了解陌生行业:从零构建行业调研Skill实战指南

1. 为什么需要“用 AI 快速了解一个行业”1.1 从一次真实的“行业速览”需求说起先分享一个我最近遇到的场景。朋友准备转行做新能源方向的售前方案,面试前需要尽快搞懂整个充电桩产业链:上游做充电模块、中游做整桩和运营商、下游是物业和车队客户。他原…

2026/9/9 17:30:00

书匠策AI实测:从选题到定稿的本科论文全流程辅助指南

又是一年论文季。写本科毕业论文,说残酷点,它考察的压根不是你的学术天赋,而是你有没有一套“把脑子里的想法变成一篇合规文档”的流程化能力。这段时间我密集体验了一款专注学术写作场景的AI工具——书匠策AI,它的定位很有意思&a…

2026/9/9 17:30:00

基于UniApp+SpringBoot的高校校园微活动系统设计与实现

1. 项目概述与技术选型思路1.1 这个系统到底解决什么问题校园里的活动组织一直是个挺头疼的事。社团办个讲座,靠QQ群接龙报名,统计起来麻烦;学生会搞个晚会,签到靠纸质表格,事后对账对半天;班级组织个志愿活…

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/9 0:00:48

MHS模型硬件标准:让大模型像调用软件一样控制物理设备

让Claude真正看着显微镜说“这个细胞形态不太对”,或者让大模型自己调一版机械臂的运动轨迹,这事儿听上去已经很接近科幻片了。但你真上手试一次就会发现,模型不缺智商,缺的是一个能插进显微镜、机械臂、激光控制器里的“通用插座…

2026/9/9 0:00:48

AI五大核心方向详解:从机器学习到大模型,零基础转行选哪条?

会有人告诉我,他想转行学AI,但打开招聘网站一看直接傻眼:机器学习、深度学习、自然语言处理、计算机视觉、大模型应用……满屏都是这些词,好像每个都会一点,又好像每个都离自己很远。还有人上来就问“学Python还是学Ja…

2026/9/9 0:00:49

从50行最小循环到生产级AI引擎:工程化改造全解析

直接说干货。这一章我写的不是那种"hello world跑通某个模型"的教程,而是把AI引擎当做一个真正要上线、要被人调用、要扛流量的系统来聊。从最初只有50行的最小循环,到能够承载生产流量的AI引擎,中间差的不是代码量,而是…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码