资讯动态

一份基于GPIO和宏定义实现的IIC队列发送和队列接收程序

发布时间:2026/10/28 1:16:22 来源:尧图企业网站定制
提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档目录前言一、IIC是什么二、程序构成1.GPIO_IIC.c2.GPIO_IIC.h3.GPIO_IIC_CONFIG.h4.其它总结更新情况其实我现在的工作已经和这篇文章的内容没啥关联了写码更像是一点赛博猫抓板一样的爱好。前阵子想拿这个轮子去缝合一下手里找得到的电子零件测一下我的车丢在单位停车场上暴晒究竟会升温到多少度又在各种机缘巧合之下找到了个逻辑分析仪就顺手正了正这些代码的时序并且把测试环境STM32F1的GPIO输入输出模式切换宏定义从 GPIO_IIC.c 抽离至专门的 GPIO_IIC_config.c进一步去做解耦合其余的主要设计思想和队列收发函数及相关入口、出口没有做出改变。有关更新我放在了github上详见链接RosaCentifolia/IIC_based_on_GPIOhttps://github.com/RosaCentifolia/IIC_based_on_GPIO当然原贴里面的代码也是能跑的这一点我实测过。以上内容于2026年10月27日更新以下为原文。前言在不知不觉中已经想不起来究竟是什么时候开始接触硬件和嵌入式了。在此期间搓了很多虽然不太一样但是本质上都是重重复复的东西。学习编程的时候任何一本书、任何一位讲师、任何一份教程都会强调代码的可读性和可复用性但是却又总是因为各种稀奇古怪的原因亦或者是单纯的菜和懒把本应奉为金科玉律的教条抛到九霄云外然后向无尽的虚空中滑行。写下这篇文章一来是想多保存几份自己封装好的代码方便自己二来也是一篇检讨反思过去的几年里自己都写了些什么东西三来也算是晾晒一下自己捂的“臭袜子”请大伙儿看看还有哪些场景下会出现不适用、不适配、运行不良的情况。希望抛砖引玉也欢迎大伙儿拿去使用也顺便吐槽一下为什么硬件IIC遍地都是但又总是绕不过软件方式实现呢恼事先声明文章中的代码遵循MIT协议允许自由使用但是转发文章请注明出处。相关代码同步上传GITHUB。一、IIC是什么I2C或称IIC是一种由飞利浦公司开发的两线式串行总线具有一主多从 一个主设备Master多个从设备Slave的结构特征总线上的设备依据设备地址实现区分同一I2C总线上的不同设备。该总线具有一根时钟线通常简写作SCL和一根数据线通常简写作SDA时钟线上的时钟信号由主设备产生而数据线则用于在主设备和从设备之间传输数据。由此决定了通过GPIO方式实现I2C时SCL管脚将长期工作在输出模式上而SDA管脚则需要在输出模式和输入模式之间切换。由于I2C通讯的发起由主设备完成开始时机和接收长度均由主设备指定因此在本例中SDA管脚在Init阶段将和SCL管脚一样配置为开漏输出模式。I2C通讯的过程具有比较复杂的时序但是鉴于网上资料较多本篇将不再赘述。二、程序构成本例中程序包含三个文件分别是GPIO_IIC.c、GPIO_IIC.h、GPIO_IIC_CONFIG.h。按照我的设计目的预期的结果是仅需配置GPIO_IIC_CONFIG.h中注明的头文件和宏定义即可实现GPIO_IIC.c中描述的IIC方法的使用。顺便鉴于不知道什么原因导致的、但是事实上单片机源程序中广泛存在的GB2312编码和UTF-8编码格式“混为一谈”的现状写下这些程序并初步debug的时候我采用了UTF-8编码中文英文冗余的方式编写注释发布的时候我懒得删了请以中文注释为主顺便请忽略自然语言的语法错误。1.GPIO_IIC.c主要的功能函数有1、GPIO_I2C_Puts( ) 。用于向指定地址的从机连续发送一串 uint8_t 的指令。通常首字节是寄存器指针后续为指令。返回值ACK_REPORT表示发送结果若全部发送成功返回ACK_repeat若任意字节含从机地址发送失败则立刻退出并返回NACK_repeat 。2、GPIO_I2C_Gets( )。用于在指定地址的从机连续接收一串 uint8_t 的报文。必须由主机指定接收长度。返回值ACK_REPORT表示发送从机地址结果若发送成功返回ACK_repeat若发送失败则立刻退出并返回NACK_repeat 。3、GPIO_I2C_ReadSlavReg( )。用于读取指定地址的从机中指定寄存器的连续报文。必须由主机指定接收长度。返回值ACK_REPORT表示发送结果若全部发送成功返回ACK_repeat若发送写地址、写报文任意字节失败则立刻退出并返回NACK_repeat发送读地址失败则立刻退出并返回NACK_repeatType2 。4、GPIO_I2C_RESET( )。作为在未知情况下总线宕机重新复位I2C通讯的接口设计上考虑了利用SMBUS模式的超时机制但鉴于本例中采用软件延迟虽然声明了弱函数允许覆写的方式只作为接口考虑。5、DEBUG模式。需要使能宏定义 GPIO_IIC_DEBUG_MODE 在GPIO_IIC_CONFIG.h中提供Oscilloscope_IO_Speed_Test( ) 方法供示波器测试SCL、SDA管脚高低电平的切换速度建议使用上升沿触发模式。并设计全局变量countNACK_repeat、countACK_repeat、countWaitACK、countACKsend、countNACKsend监控I2C通讯的应答情况。代码如下/*DOC Encode Type: UTF-8*/ /* *FileName:GPIO_IIC.c *Description: use GPIO accomplish IIC *Author: RosaCentifolia *Version: V1.0 *Fixed record: */ /* *正常情况下不需要修改此文件 *Normally, you do not need to modify this file. *使用前应配置GPIO_IIC_CONFIG.h中的宏定义 *Before use, the macro definition in GPIO_IIC_CONFIG.h should be configured */ #include GPIO_IIC.h uint8_t g_GPIOI2C_recvBuf[stack_length_GPIOI2C_Recv_buf]; /*IIC Recv buff*/ uint8_t g_GPIOI2C_recvBufLength0; uint8_t g_GPIOI2C_sendBuf[stack_length_GPIOI2C_Send_buf];/*IIC Send buff*/ uint8_t g_GPIOI2C_send_bufLength0; /*debug test variable*/ #ifdef GPIO_IIC_DEBUG_MODE volatile uint16_t countNACK_repeat0, countACK_repeat0, countWaitACK0, countACKsend0, countNACKsend0; #endif /* *Function: I2C_Puts(uint8_t SlaveAddr, uint8_t * sendQueue, uint8_t sendLength ) *Value: SlaveAddr: slave chip address, sendQueue: message queue sendlength:message length *Description: Using in send a queue which length is sendlegth to SlaveAddr device by GPIO IIC *Return: ACKstatus: ACK_repeat: sending successful NACK_repeat:sended had error *Error: *Author: RosaCentifolia */ ACK_REPORT GPIO_I2C_Puts(uint8_t SlaveAddr, uint8_t * sendQueue, uint8_t sendLength ) { uint8_t cursor; ACK_REPORT ACKstatus; /*prepare slave address and writing symbol */ uint8_t DeviceSelect ( SlaveAddr1 )0xFE; GPIO_IIC_Start(); /*Send slave address and writing symbol */ GPIO_IIC_Send_Byte(DeviceSelect); ACKstatusGPIO_IIC_Wait_ACK(); /*Waitting ACK*/ if( ACKstatusACK_repeat ){/*if ACK, start transmit*/ for(cursor0; cursorsendLength; cursor){ GPIO_IIC_Send_Byte( sendQueue[cursor] ); ACKstatusGPIO_IIC_Wait_ACK(); /*ACK check*/ if( ACKstatus!ACK_repeat ){ break; /*if NACK, abroad transmit*/ } } } GPIO_IIC_Stop(); return ACKstatus; } /* *Function: I2C_Gets(uint8_t SlaveAddr, uint8_t * recvQueue, uint8_t recvLength ) *Value: SlaveAddr: slave chip address, recvQueue: message queue recvLength:recv message length *Description: Using in receive a queue which length is recvlength from SlaveAddr device by GPIO IIC *Return: ACKstatus: ACK_repeat: initiate receiving successful NACK_repeat:initiated received had error *Error: *Author: RosaCentifolia */ ACK_REPORT GPIO_I2C_Gets(uint8_t SlaveAddr, uint8_t * recvQueue, uint8_t recvLength ) { uint8_t cursor; ACK_REPORT ACKstatus; /*prepare slave address and reading symbol */ uint8_t DeviceSelect ( SlaveAddr1 )|0x01; GPIO_IIC_Start(); /*Send slave address and reading symbol */ GPIO_IIC_Send_Byte( DeviceSelect ); ACKstatusGPIO_IIC_Wait_ACK(); /*Waiting ACK*/ if( ACKstatusACK_repeat ){ /*if ACK, start receive*/ for(cursor0; cursorrecvLength; cursor){ if( recvLengthcursor1 ){ /*Last recv byte NACK, ready to stop*/ recvQueue[cursor]GPIO_IIC_Read_Byte(NACK_repeat); }else{ recvQueue[cursor]GPIO_IIC_Read_Byte(ACK_repeat); } } } GPIO_IIC_Stop(); return ACKstatus; } /* *Function: I2C_ReadSlavReg(uint8_t SlaveAddr, uint8_t *sendQueue, uint8_t sendLength, uint8_t * recvQueue, uint8_t recvLength ) *Value: SlaveAddr: slave chip address, *sendQueue: message queue, such as regsitercommand sendLength: message length *recvQueue: message queue, recvLength:recv message length *Description: reading register value from SlaveAddr device by GPIO IIC *Return: ACKstatus: ACK_repeat: read slave register successful NACK_repeat: sended register and command had error NACK_repeatType2:writing register and command successful, but sended reading symbol error. *Error: *Author: RosaCentifolia */ ACK_REPORT GPIO_I2C_ReadSlavReg(uint8_t SlaveAddr, uint8_t *sendQueue, uint8_t sendLength, uint8_t *recvQueue, uint8_t recvLength ){ uint8_t cursor; ACK_REPORT ACKstatus; /*prepare slave address and writing symbol */ uint8_t DeviceSelect ( SlaveAddr1 )0xFE; GPIO_IIC_Start(); /*Send slave address and writing symbol */ GPIO_IIC_Send_Byte( DeviceSelect ); /*Send register and commands*/ ACKstatusGPIO_IIC_Wait_ACK(); /*Waiting ACK*/ if( ACKstatusACK_repeat ){/*if ACK, start transmit*/ for(cursor0;cursorsendLength;cursor){ GPIO_IIC_Send_Byte( sendQueue[cursor] ); ACKstatusGPIO_IIC_Wait_ACK(); /*ACK check*/ if( ACKstatus!ACK_repeat ){ GPIO_IIC_Stop(); /*if NACK, abroad transmit*/ return ACKstatus; /*runing here,should be return NACK_repeat*/ } } /*prepare slave address and reading symbol */ DeviceSelect ( SlaveAddr1 )|0x01; GPIO_IIC_Start(); /*Send slave address and reading symbol */ GPIO_IIC_Send_Byte( DeviceSelect ); ACKstatusGPIO_IIC_Wait_ACK(); /*Waiting ACK*/ if( ACKstatusACK_repeat ){ /*if ACK, start receive*/ for(cursor0; cursorrecvLength; cursor){ if( recvLengthcursor1 ){ /*Last recv byte NACK, ready to stop*/ recvQueue[cursor]GPIO_IIC_Read_Byte(NACK_repeat); }else{ recvQueue[cursor]GPIO_IIC_Read_Byte(ACK_repeat); } } }else{ GPIO_IIC_Stop(); ACKstatusNACK_repeatType2; return ACKstatus; /*runing here,should be return NACK_repeatType2*/ } } GPIO_IIC_Stop(); return ACKstatus; } /* *Function: GPIO_I2C_RESET( void ) *Value: *Description: reset GPIO SDA pin to output mode, pull up SDASCL *Return: *Error: *Author: RosaCentifolia */ void GPIO_I2C_RESET( void ){ GPIO_IIC_SDA_OUTPUT_MODE; GPIO_IIC_SCL_PIN_Set_to_Low; GPIO_IIC_SDA_PIN_Set_to_Low; /*Waiting for SMBUS mode timeout*/ CPUdelay_10us(20); GPIO_IIC_SDA_PIN_Set_to_High; CPUdelay_10us(20); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(20); } /* *Function: IIC_Start(void) *Value: *Description: GPIO IIC running *Return: *Error: *Author: RosaCentifolia */ void GPIO_IIC_Start( void ) { /*step of restart:*/ CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; /*step of start:*/ CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_Low; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_Low; } /* *Function: IIC_Stop(void) *Value: *Description: GPIO IIC Stop *Return: *Error: *Author: RosaCentifolia */ void GPIO_IIC_Stop(void) { /*STOP:when SCL to high, SDA set to high*/ GPIO_IIC_SDA_OUTPUT_MODE; GPIO_IIC_SCL_PIN_Set_to_Low; GPIO_IIC_SDA_PIN_Set_to_Low; /*Preliminary work to ensure shutdown finished*/ CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_High; CPUdelay_10us(1); } /* *Function: IIC_Send_Byte(uint8_t txDataByte ) *Value: *Description: GPIO IIC Send one byte *Return: *Error: *Author: RosaCentifolia */ void GPIO_IIC_Send_Byte(uint8_t txDataByte ) { uint8_t cursor,sendBit; for(cursor0;cursor8;cursor){ sendBit txDataByte0x80; CPUdelay_10us(1); if( sendBit0x80 ){ GPIO_IIC_SDA_PIN_Set_to_High; }else{ GPIO_IIC_SDA_PIN_Set_to_Low; } txDataByte1; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_Low; } } /* *Function: IIC_Read_Byte( uint8_t ackEn ) *Value: ACK_repeat:making an ACK by master NACK_repeat:don,t making an ACK by master *Description: GPIO IIC Read one byte *Return: recvByte *Error: *Author: RosaCentifolia */ uint8_t GPIO_IIC_Read_Byte( ACK_REPORT ACK_status ) { uint8_t cursor, recvByte0; GPIO_IIC_SDA_INPUT_MODE; /*switch SDA to input mode*/ for( cursor0; cursor8; cursor ){ CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); recvByte1; if( GPIO_IIC_SDA_PIN_Input_High ){ recvByte|0x01; }else{ recvByte0xFE; } GPIO_IIC_SCL_PIN_Set_to_Low; } GPIO_IIC_SDA_OUTPUT_MODE; /*switch SDA to output mode*/ CPUdelay_10us(1); /*making ACK or NACK*/ if ( ACK_statusACK_repeat ){ GPIO_IIC_SDA_PIN_Set_to_Low; #ifdef GPIO_IIC_DEBUG_MODE countACKsend1; #endif }else{ GPIO_IIC_SDA_PIN_Set_to_High; #ifdef GPIO_IIC_DEBUG_MODE countNACKsend1; #endif } CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_Low; return recvByte; } /* *Function: IIC_Wait_Ack(void) *Value: *Description: waitting ACK when get slave device massage *Return: NACK_repeat: IIC slave device errror ACK_repeat: IIC slave device ready to send *Error: *Author: RosaCentifolia */ ACK_REPORT GPIO_IIC_Wait_ACK(void) { uint16_t countErrTime0; #ifdef GPIO_IIC_DEBUG_MODE countWaitACK1; #endif GPIO_IIC_SDA_INPUT_MODE; /*switch SDA to input mode*/ CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); for(countErrTime0; countErrTimeMAXMUIN_ACK_Error; countErrTime){ /*wating ACK*/ if( GPIO_IIC_SDA_PIN_Input_Low ){ /*if recv ACK*/ GPIO_IIC_SCL_PIN_Set_to_Low; GPIO_IIC_SDA_OUTPUT_MODE; /*switch SDA to output mode*/ #ifdef GPIO_IIC_DEBUG_MODE countACK_repeat1; #endif return ACK_repeat; } } /*if recvnt ACK*/ GPIO_IIC_SCL_PIN_Set_to_Low; GPIO_IIC_SDA_OUTPUT_MODE; /*switch SDA to output mode*/ GPIO_IIC_Stop(); #ifdef GPIO_IIC_DEBUG_MODE countNACK_repeat1; #endif return NACK_repeat; } /* *Function: void CPUdelay_us( uint16_t ) *Value: delay_Countdown: number of software delays *Description: software delay *Return: *Error: *Author: RosaCentifolia */ #if ( DLY_SYSTEM_CLOCK_MHz*10 8 ) #warning CPUdelay_10us maybent be use #endif __WEAK void CPUdelay_10us( uint16_t delay_Countdown ){ uint16_t Count_10us ( DLY_SYSTEM_CLOCK_MHz*10 )/8; Count_10us * delay_Countdown; for(;Count_10us;Count_10us--) ; } #ifdef GPIO_IIC_DEBUG_MODE /* *Function: Oscilloscope_IO_Speed_Test(void) *Value: *Description: Used for oscilloscope testing the switching speed of SCL and SDA pins * Suggestion: Use rising edge trigger * Special notes: Hardware debugging method, no other intention *Return: *Error: *Author: RosaCentifolia */ void Oscilloscope_IO_Speed_Test(void){ /*Shutdown communication*/ GPIO_IIC_Stop(); /*Function main body, start*/ /*make a ready sign*/ GPIO_IIC_SCL_PIN_Set_to_Low; GPIO_IIC_SDA_PIN_Set_to_Low; CPUdelay_10us(100); /*runing SDA pin check*/ GPIO_IIC_SDA_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_Low; CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SDA_PIN_Set_to_Low; /*runing SCL pin check*/ GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_Low; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_High; CPUdelay_10us(1); GPIO_IIC_SCL_PIN_Set_to_Low; /*make a finished sign*/ CPUdelay_10us(100); /*Function main body, over*/ /*restore communication*/ GPIO_IIC_Stop(); } #endif2.GPIO_IIC.h配套头文件都是一些声明没有什么特殊作用。/*DOC Encode Type: UTF-8*/ /* *FileName:GPIO_IIC.h *Description: use GPIO accomplish IIC *Author: RosaCentifolia *Version: V1.0 *Fixed record: */ /* *正常情况下不需要修改此文件 *Normally, you do not need to modify this file. *使用前应配置GPIO_IIC_CONFIG.h中的宏定义 *Before use, the macro definition in GPIO_IIC_CONFIG.h should be configured */ #ifndef __GPIO_IIC_H #define __GPIO_IIC_H #include stdint.h #include GPIO_IIC_CONFIG.h /*Gobal variable declaration*/ extern uint8_t g_GPIOI2C_recvBuf[]; /*IIC Recv buff*/ extern uint8_t g_GPIOI2C_recvBufLength; extern uint8_t g_GPIOI2C_sendBuf[];/*IIC Sending buff*/ extern uint8_t g_GPIOI2C_send_bufLength; /*Debug test variable*/ #ifdef GPIO_IIC_DEBUG_MODE extern volatile uint16_t countNACK_repeat, countACK_repeat, countWaitACK, countACKsend, countNACKsend; #endif /*Typedef declaration*/ typedef enum{ Restart 0u, Start }START_STATUS; typedef enum{ ACK_repeat 0u, NACK_repeat, NACK_repeatType2 }ACK_REPORT; /*Function declaration */ void GPIO_I2C_RESET(void); ACK_REPORT GPIO_I2C_Puts(uint8_t SlaveAddr, uint8_t * sendQueue, uint8_t sendLength ); ACK_REPORT GPIO_I2C_Gets(uint8_t SlaveAddr, uint8_t * recvQueue, uint8_t recvLength ); ACK_REPORT GPIO_I2C_ReadSlavReg(uint8_t SlaveAddr, uint8_t * sendQueue, uint8_t sendLength, uint8_t * recvQueue, uint8_t recvLength ); void GPIO_IIC_Start(void); void GPIO_IIC_Stop(void); void GPIO_IIC_Send_Byte( uint8_t txDataByte ); uint8_t GPIO_IIC_Read_Byte( ACK_REPORT ACK_status ); ACK_REPORT GPIO_IIC_Wait_ACK(void); __WEAK void CPUdelay_10us( uint16_t delay_Countdown ); #ifdef GPIO_IIC_DEBUG_MODE void Oscilloscope_IO_Speed_Test(void); #endif #endif3.GPIO_IIC_CONFIG.h用于配置各种必须参数的头文件使用前应结合具体的硬件和开发库进行配置包含GPIO控制、DEBUG模式等参数。/*DOC Encode Type: UTF-8*/ /* *FileName:GPIO_IIC_CONFIG.h *Description: Initialization settings for configuring GPIO accomplish IIC *用途配置GPIO模拟IIC通讯的初始化设置 *Author: RosaCentifolia *Version: V1.0 *Fixed record: */ #ifndef __GPIO_IIC_CONFIG_H #define __GPIO_IIC_CONFIG_H /*Configuration start **配置开始 **Preset 13 #define, 1 required #include and 1 optional #include **预先设置13个#define、1个必须的#include和一个可选的#include */ /*Include GPIO Pin IO control headfile **包含GPIO pin控制的的头文件*/ //#include empty.h /*Includes an optional header to override the software delay mode **包含一个可选的覆写软件延迟方式的头文件 **Default state used: **缺省状态下将使用 * __WEAK void CPUdelay_10us( uint16_t delay_Countdown ) ***/ //#include empty.h /*Include the optional header file above *在上方包含可选的头文件 */ /*Configure the system clock of __WEAK void CPUdelay_10us( uint16_t delay_Countdown ) *配置__WEAK void CPUdelay_10us( uint16_t delay_Countdown ) 的系统时钟 *Override can be default *覆写时可以缺省 ****#define DLY_SYSTEM_CLOCK_MHz */ #define DLY_SYSTEM_CLOCK_MHz 72 /* *If dont need debug mode based on statistical ACK and NACK, *and function Oscilloscope_IO_Speed_Test(void) *如果不需要基于ACK和NACK统计的debug模式和函数 Oscilloscope_IO_Speed_Test(void) *Please comment this define *请注释这条宏定义 ****#define GPIO_IIC_DEBUG_MODE */ #define GPIO_IIC_DEBUG_MODE /*Config Macro*/ /*配置宏定义*/ /*sendrecv stack size, word sizeuint8_t *#define stack_length_GPIOI2C_Recv_buf *#define stack_length_GPIOI2C_Send_buf *发送和接收堆栈长度字长uint8_t*/ #define stack_length_GPIOI2C_Recv_buf 3 /*Define it yourself*/ #define stack_length_GPIOI2C_Send_buf 3 /*Define it yourself*/ /*ACK waitting limited period *#define MAXMUIN_ACK_Error *等待ACK应答的最大周期*/ #define MAXMUIN_ACK_Error 255 /*GPIO Pin ctrl *#define GPIO_IIC_SDA_OUTPUT_MODE *#define GPIO_IIC_SDA_INPUT_MODE *#define GPIO_IIC_SDA_PIN_Input_High *#define GPIO_IIC_SDA_PIN_Input_Low *#define GPIO_IIC_SDA_PIN_Set_to_High *#define GPIO_IIC_SDA_PIN_Set_to_Low *#define GPIO_IIC_SCL_PIN_Set_to_High *#define GPIO_IIC_SCL_PIN_Set_to_Low *GPIO Pin 控制*/ #define GPIO_IIC_SDA_OUTPUT_MODE #define GPIO_IIC_SDA_INPUT_MODE #define GPIO_IIC_SDA_PIN_Input_High #define GPIO_IIC_SDA_PIN_Input_Low #define GPIO_IIC_SDA_PIN_Set_to_High #define GPIO_IIC_SDA_PIN_Set_to_Low #define GPIO_IIC_SCL_PIN_Set_to_High #define GPIO_IIC_SCL_PIN_Set_to_Low /*Configuration completed **配置结束 **A total of 13 #define, 1 required #include and one optional #include **总计13个#define、1个必须的#include和一个可选的#include */ #endif4.其它本例中g_GPIOI2C_recvBuf[ ]、g_GPIOI2C_recvBufLength、g_GPIOI2C_sendBuf[ ]、g_GPIOI2C_send_bufLength等参数其实可以不要把它写上去是考虑哪天要在中断里调用这些东西的时候可以拿起来就用。事实上我反对写一堆全局变量的编程风格。顺便上传一份在STM32F103ZET6上的演示用例也是我初步debug时用的版本。我觉得大伙儿这么聪明看不看应该都一样的吧。总结封库是好文明重复工作是坏文明。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑