学习日志2:针对于EXTI教程的扩展与优化

该教程详细介绍了如何使用STM32微控制器通过中断控制LED灯。首先在bsp_led.h和bsp_led.c中初始化LED的GPIO,然后配置中断线路,包括EXTI和NVIC设置,使得KEY1上沿触发蓝灯亮灭,KEY2下降沿触发绿灯亮灭。编程过程涉及GPIO_Init、EXTI_Init和NVIC_Init等函数。在stm32f10x_it.c中编写中断服务函数,实现中断响应。

教程是通过设定外设KYE1的上沿输入为中断申请,进而通过KEY1控制LED灯的亮暗。

根据老师的教学,以下为本人设计的通过KEY1的上沿输入触发亮灭蓝灯,KEY2的下降沿输入触发亮灭绿灯的编程演示。

一、初始化GPIO

1、首先创建bsp_led.h头函数,宏定义与LED相连的GPIO口。

2、创建bsp_led.c,通过结构体GPIO_InitTypeDef与GPIO_Init库函数进行GPIO的初始化

二、初始化对中段路线GPIO、EXTI、NVIC,完成中断信号从GPIO-->EXTI-->NVIC的路线连接

  1、先查开发板原理图,需要运用结构体NVIC_InitTypeDef、GPIO_InitTypeDef、EXTI_InitTypeDef以及库函数(GPIO_Init、EXTI_Init、NVIC_Init),其详细配置信息需查询头文件stm32f10x_exti.h。

 2、创建bsp_exti.h进行宏定义

3、创建 bsp_exti.c进行初始化编程

 三、在stm32f10x_it,c文件中编写中断函数

编程完成。

#ifndef _SOFT_I2C_H #define _SOFT_I2C_H #ifdef __cplusplus extern "C" { #endif #include "stm32g0xx_hal.h" #define SW_SLAVE_ADDR 0x48 #define SW_SLAVE_SCL_CLK_EN() __HAL_RCC_GPIOB_CLK_ENABLE() #define SW_SLAVE_SDA_CLK_EN() __HAL_RCC_GPIOB_CLK_ENABLE() #define SW_SLAVE_SCL_PRT GPIOB #define SW_SLAVE_SCL_PIN GPIO_PIN_6 #define SW_SLAVE_SDA_PRT GPIOB #define SW_SLAVE_SDA_PIN GPIO_PIN_7 #define GPIO_MODE_MSK 0x00000003U #define I2C_STA_IDLE 0 #define I2C_STA_START 1 #define I2C_STA_DATA 2 #define I2C_STA_ACK 3 #define I2C_STA_NACK 4 #define I2C_STA_STOP 5 #define I2C_READ 1 #define I2C_WRITE 0 #define FRAME_HEADER1 0x01 #define FRAME_HEADER2 0xAA #define HOST_FRAME_LEN 5 // 主机发送帧长度:地址+01+AA+功能码+校验和(地址单独处理,不参校验) #define SLAVE_FRAME_LEN 12 // 从机响应帧长度:01+AA+功能码+8字节数据+校验和 #define I2C_SDA_Pinx 7 #define BUFFER_SIZE 256 // 缓冲区大小定义 #define MAX_RX_INDEX 255 // 最大接收索引(BUFFER_SIZE - 1) #define I2C_TIMEOUT_MS 500 // I2C超时时间 typedef struct _SwSlaveI2C_t { uint8_t State; // I2C通信状态 uint8_t Rw; // I2C读写标:0-写,1-读 uint8_t SclFallCnt; // SCL下降沿计数 uint8_t Flag; // I2C状态标,BIT0:0-地址无效,1-地址匹配 uint32_t StartMs; // I2C通信起始时间,单位ms,用于判断通信是否超时 uint8_t* RxBuf; // 指向接收缓冲区的指针 uint8_t* TxBuf; // 指向发送缓冲区的指针 uint8_t RxIdx; // 接收缓冲区数据写入索引 uint8_t TxIdx; // 发送缓冲区数据读取索引 uint8_t HostFuncCode; // 存储主机发送的功能码 uint8_t FrameReceived; // 主机帧接收完成标 uint8_t IgnoreData; // 忽略后续数据标 }SwSlaveI2C_t; extern SwSlaveI2C_t SwSlaveI2C; void InitSwSlaveI2C(void); void I2cGpioIsr(void); void CheckSwSlaveI2cTimeout(void); void I2C_Slave_Set_SDA_IT(void); void I2C_Slave_Set_SDA_Out(void); void CheckSwSlaveI2cTimeout(void); /* 使用HAL函数操作GPIO */ #define SET_SCL_PIN() HAL_GPIO_WritePin(SW_SLAVE_SCL_PRT, SW_SLAVE_SCL_PIN, GPIO_PIN_SET) #define CLR_SDA_PIN() HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, GPIO_PIN_RESET) #define SET_SDA_PIN() HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, GPIO_PIN_SET) #define READ_SDA_PIN() HAL_GPIO_ReadPin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN) #define READ_SCL_PIN() HAL_GPIO_ReadPin(SW_SLAVE_SCL_PRT, SW_SLAVE_SCL_PIN) // 函数原型声明 void InitSwSlaveI2C(void); void EXTI4_15_IRQHandler(void); void CheckSwSlaveI2cTimeout(void); uint8_t ParseHostFrame(void); void Prepare_TX_Frame(void); // 接收索引,防止缓冲区溢出 inline void IncrementRxIndex(void) { // 如果已接收完整帧,则忽略后续数据 if (SwSlaveI2C.IgnoreData) return; if (SwSlaveI2C.RxIdx < MAX_RX_INDEX) { SwSlaveI2C.RxIdx++; // 检查是否达到帧长度,超过则忽略 if (SwSlaveI2C.RxIdx >= HOST_FRAME_LEN) { SwSlaveI2C.IgnoreData = 1; } } else { SwSlaveI2C.RxIdx = 0; // 可添加缓冲区溢出错误处理 } } #define DEBUG_BUF_SIZE 256 typedef struct { uint8_t data[DEBUG_BUF_SIZE]; uint16_t head; uint16_t tail; uint16_t count; } DebugRingBuffer; void DebugRingBuffer_Write(DebugRingBuffer *buf, uint8_t byte); int DebugRingBuffer_Read(DebugRingBuffer *buf, uint8_t *byte); void DebugRingBuffer_Init(DebugRingBuffer *buf); extern DebugRingBuffer rx_debug_buf; extern DebugRingBuffer tx_debug_buf; extern uint8_t last_prepared_tx_frame[SLAVE_FRAME_LEN]; #ifdef __cplusplus } #endif #endif #include "soft_i2c.h" #include "delay.h" #include <stdio.h> DebugRingBuffer rx_debug_buf; DebugRingBuffer tx_debug_buf; uint8_t last_prepared_tx_frame[SLAVE_FRAME_LEN]; // 初始化环形缓冲区 void DebugRingBuffer_Init(DebugRingBuffer *buf) { buf->head = 0; buf->tail = 0; buf->count = 0; } // 向环形缓冲区写入一个字节,如果满了则覆盖最旧的数据 void DebugRingBuffer_Write(DebugRingBuffer *buf, uint8_t byte) { if (buf->count < DEBUG_BUF_SIZE) { buf->data[buf->head] = byte; buf->head = (buf->head + 1) % DEBUG_BUF_SIZE; buf->count++; } else { // 缓冲区满,覆盖尾部数据 buf->data[buf->head] = byte; buf->head = (buf->head + 1) % DEBUG_BUF_SIZE; buf->tail = (buf->tail + 1) % DEBUG_BUF_SIZE; } } // 从环形缓冲区读取一个字节,返回0表示成功,-1表示缓冲区空 int DebugRingBuffer_Read(DebugRingBuffer *buf, uint8_t *byte) { if (buf->count == 0) { return -1; } *byte = buf->data[buf->tail]; buf->tail = (buf->tail + 1) % DEBUG_BUF_SIZE; buf->count--; return 0; } // 传感器数据缓存结构 typedef struct { uint16_t reg_11; // 寄存器11的数据 uint8_t updated; // 数据更新标(1:新数据,0:未更新) uint32_t timestamp; // 数据时间戳 uint8_t valid; // 数据有效标 uint8_t error_count; // 连续错误计数 } SensorDataCache; // 外部变量声明 extern uint16_t adc_ch4_avg; extern uint16_t adc_ch5_avg; extern uint16_t adc_ch6_avg; extern uint16_t adc_ch7_avg; extern SensorDataCache sensor2_cache; extern SensorDataCache sensor3_cache; extern SensorDataCache sensor4_cache; uint8_t RxDataBuf[BUFFER_SIZE]; uint8_t TxDataBuf[BUFFER_SIZE]; SwSlaveI2C_t SwSlaveI2C = { I2C_STA_IDLE, // State I2C_WRITE, // Rw 0, // SclFallCnt 0, // Flag 0, // StartMs RxDataBuf, // RxBuf TxDataBuf, // TxBuf 0, // RxIdx 0, // TxIdx 0x00, // HostFuncCode - 默认为0x00 0, // FrameReceived 0 // IgnoreData }; // 配置SDA为中断模式(输入) void I2C_Slave_Set_SDA_IT(void) { // 清除当前模式 SW_SLAVE_SDA_PRT->MODER &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); // 设置为输入模式 SW_SLAVE_SDA_PRT->MODER |= (0 << I2C_SDA_Pinx * 2); // 确保为上拉输入 SW_SLAVE_SDA_PRT->PUPDR &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); SW_SLAVE_SDA_PRT->PUPDR |= (1 << I2C_SDA_Pinx * 2); } // 配置SDA为开漏输出 void I2C_Slave_Set_SDA_Out(void) { // 清除当前模式 SW_SLAVE_SDA_PRT->MODER &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); // 设置为输出模式 SW_SLAVE_SDA_PRT->MODER |= (1 << I2C_SDA_Pinx * 2); // 配置为开漏输出 SW_SLAVE_SDA_PRT->OTYPER |= (1 << I2C_SDA_Pinx); } // 异或校验 uint8_t Calculate_XOR_Checksum(uint8_t *buf, uint8_t len) { uint8_t checksum = 0; for (uint8_t i = 0; i < len; i++) { checksum ^= buf[i]; } return checksum; } // 解析主机发送的帧 uint8_t ParseHostFrame(void) { // 检查帧长度(地址+4字节数据) if (SwSlaveI2C.RxIdx != HOST_FRAME_LEN) return 0; // 验证帧头(01 AA) if (SwSlaveI2C.RxBuf[1] != FRAME_HEADER1 || SwSlaveI2C.RxBuf[2] != FRAME_HEADER2) return 0; // 计算校验和:仅包含数据部分(01、AA、功能码),共3字节,第4字节(校验和)比较 // 不包含地址字节(RxBuf[0]) uint8_t calc_checksum = Calculate_XOR_Checksum(&SwSlaveI2C.RxBuf[1], 3); if (calc_checksum != SwSlaveI2C.RxBuf[4]) return 0; // 存储主机功能码(第3字节) SwSlaveI2C.HostFuncCode = SwSlaveI2C.RxBuf[3]; // 收到功能码后立即准备数据 Prepare_TX_Frame(); return 1; } // 发送帧格式: 01 AA 主机功能码 8字节数据 异或校验 void Prepare_TX_Frame(void) { //关中断保护全局变量访问 __disable_irq(); // 填充帧头 SwSlaveI2C.TxBuf[0] = FRAME_HEADER1; SwSlaveI2C.TxBuf[1] = FRAME_HEADER2; SwSlaveI2C.TxBuf[2] = SwSlaveI2C.HostFuncCode; // 使用主机功能码 // 清空数据区域 for (uint8_t i = 3; i < 11; i++) { SwSlaveI2C.TxBuf[i] = 0x00; } // 根据主机功能码填充8字节数据 switch (SwSlaveI2C.HostFuncCode) { case 0x01: // ADC数据(4个16位ADC值拆分为8字节) SwSlaveI2C.TxBuf[3] = (adc_ch4_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[4] = adc_ch4_avg & 0xFF; SwSlaveI2C.TxBuf[5] = (adc_ch5_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[6] = adc_ch5_avg & 0xFF; SwSlaveI2C.TxBuf[7] = (adc_ch6_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[8] = adc_ch6_avg & 0xFF; SwSlaveI2C.TxBuf[9] = (adc_ch7_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[10] = adc_ch7_avg & 0xFF; break; case 0x02: // 传感器数据 // 传感器2数据 if (sensor2_cache.valid) { SwSlaveI2C.TxBuf[3] = (sensor2_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[4] = sensor2_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[3] = 0xFF; SwSlaveI2C.TxBuf[4] = 0xFF; } // 传感器3数据 if (sensor3_cache.valid) { SwSlaveI2C.TxBuf[5] = (sensor3_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[6] = sensor3_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[5] = 0xFF; SwSlaveI2C.TxBuf[6] = 0xFF; } // 传感器4数据 if (sensor4_cache.valid) { SwSlaveI2C.TxBuf[7] = (sensor4_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[8] = sensor4_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[7] = 0xFF; SwSlaveI2C.TxBuf[8] = 0xFF; } // 预留2字节 SwSlaveI2C.TxBuf[9] = 0x00; SwSlaveI2C.TxBuf[10] = 0x00; break; default: // 未知功能码 SwSlaveI2C.TxBuf[2] = 0xFF; // 错误标识 break; } // 计算校验和(前11字节) SwSlaveI2C.TxBuf[11] = Calculate_XOR_Checksum(SwSlaveI2C.TxBuf, 11); // 恢复中断 __enable_irq(); for (int i = 0; i < SLAVE_FRAME_LEN; i++) { last_prepared_tx_frame[i] = SwSlaveI2C.TxBuf[i]; } } void CheckSwSlaveI2cTimeout(void) { uint32_t TimeMs, TimeCurMs; if(SwSlaveI2C.State != I2C_STA_IDLE) { TimeCurMs = HAL_GetTick(); if(TimeCurMs >= SwSlaveI2C.StartMs) { TimeMs = TimeCurMs - SwSlaveI2C.StartMs; } else { TimeMs = ~(SwSlaveI2C.StartMs - TimeCurMs) + 1; } if(I2C_TIMEOUT_MS <= TimeMs) { // 超时重置,释放总线 SwSlaveI2C.State = I2C_STA_IDLE; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.FrameReceived = 0; // 重置功能码 SwSlaveI2C.HostFuncCode = 0x00; // 重置为默认值 // 释放SDA和SCL线,将其设置为高电平 SET_SDA_PIN(); // 释放SDA SET_SCL_PIN(); // 释放SCL // 超时后设置回输入模式以检测新的起始条件 I2C_Slave_Set_SDA_IT(); } } } // 初始化软件I2C从机 void InitSwSlaveI2C(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 使能GPIO时钟 SW_SLAVE_SCL_CLK_EN(); SW_SLAVE_SDA_CLK_EN(); // 配置SCL引脚为输入上拉 GPIO_InitStruct.Pin = SW_SLAVE_SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SW_SLAVE_SCL_PRT, &GPIO_InitStruct); // 配置SDA引脚为输入上拉,带中断 GPIO_InitStruct.Pin = SW_SLAVE_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SW_SLAVE_SDA_PRT, &GPIO_InitStruct); // 使能并设置中断优先级 HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); // 初始状态设置为输入模式以检测起始条件 I2C_Slave_Set_SDA_IT(); // 初始化时准备默认功能码的数据 Prepare_TX_Frame(); } void EXTI4_15_IRQHandler(void) { /* USER CODE BEGIN EXTI4_15_IRQn 0 */ /* USER CODE END EXTI4_15_IRQn 0 */ // HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6); // HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7); /* USER CODE BEGIN EXTI4_15_IRQn 1 */ // 保存中断状态 uint32_t scl_it_flag = __HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SCL_PIN); uint32_t sda_it_flag = __HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SDA_PIN); // 清除中断标 if (scl_it_flag) __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SCL_PIN); if (sda_it_flag) __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SDA_PIN); SwSlaveI2C.StartMs = HAL_GetTick(); // 先处理SDA中断(起始/停止条件优先) if (sda_it_flag) { if(READ_SDA_PIN() == GPIO_PIN_RESET) { // SDA下降沿且SCL为高电平,检测到起始条件 if(READ_SCL_PIN() == GPIO_PIN_SET) { SwSlaveI2C.State = I2C_STA_START; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.IgnoreData = 0; // 重置忽略标 // 起始条件后,准备接收地址,设置为输入模式 I2C_Slave_Set_SDA_IT(); } } else { // SDA上升沿且SCL为高电平,检测到停止条件 if(READ_SCL_PIN() == GPIO_PIN_SET) { SwSlaveI2C.State = I2C_STA_IDLE; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.IgnoreData = 0; // 重置忽略标 // 停止条件不重置FrameReceived和HostFuncCode,以便支持连续读操作 // 切换回输入模式以检测新的起始条件 I2C_Slave_Set_SDA_IT(); } } } // 处理SCL中断 if (scl_it_flag) { // SCL下降沿处理 if(READ_SCL_PIN() == GPIO_PIN_RESET) { switch(SwSlaveI2C.State) { case I2C_STA_START: SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0; SwSlaveI2C.Rw = I2C_WRITE; SwSlaveI2C.State = I2C_STA_DATA; // 接收地址阶段保持输入模式 I2C_Slave_Set_SDA_IT(); break; case I2C_STA_DATA: SwSlaveI2C.SclFallCnt++; if(SwSlaveI2C.Rw == I2C_READ) { // 发送数据时设置为输出模式 I2C_Slave_Set_SDA_Out(); // 发送数据位(只发送SLAVE_FRAME_LEN字节) if (SwSlaveI2C.TxIdx < SLAVE_FRAME_LEN) { uint8_t bit_val = (SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx] >> (7 - SwSlaveI2C.SclFallCnt)) & 0x01; HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, bit_val ? GPIO_PIN_SET : GPIO_PIN_RESET); } else { SET_SDA_PIN(); // 数据发送完成,释放总线 } } // 接收模式保持输入 else { I2C_Slave_Set_SDA_IT(); } // 8位数据发送/接收完成,准备ACK if(SwSlaveI2C.SclFallCnt == 8) { if(SwSlaveI2C.Rw == I2C_WRITE) { // 地址匹配检查 - 修复了地址比较逻辑 if(SwSlaveI2C.RxIdx == 0) { // 正确的比较方式:将接收的地址左移后的从机地址比较 if((SwSlaveI2C.RxBuf[0] & 0xFE) == (SW_SLAVE_ADDR << 1)) { SwSlaveI2C.Flag = 1; SwSlaveI2C.Rw = SwSlaveI2C.RxBuf[0] & 0x01; // 对于读操作,确保数据已准备好 if (SwSlaveI2C.Rw == I2C_READ) { // 即使没有新的帧,也使用上次的功能码准备数据 Prepare_TX_Frame(); } } } // 发送ACK,需要输出模式 I2C_Slave_Set_SDA_Out(); if(SwSlaveI2C.Flag) { CLR_SDA_PIN(); // 发送ACK } else { SET_SDA_PIN(); // 发送NACK } } else { // 读操作时释放SDA总线,等待主机的ACK/NACK I2C_Slave_Set_SDA_IT(); } // 添加的调试日记录代码开始 // 记录接收到的字节(对于写操作) if (SwSlaveI2C.Rw == I2C_WRITE && SwSlaveI2C.Flag) { // 注意:这里记录的是刚刚接收到的完整字节(存储在RxBuf[RxIdx]中) DebugRingBuffer_Write(&rx_debug_buf, SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx]); } // 记录发送的字节(对于读操作) if (SwSlaveI2C.Rw == I2C_READ) { // 注意:我们发送的字节是TxBuf[TxIdx](已经发送完的字节) DebugRingBuffer_Write(&tx_debug_buf, SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx]); } // 添加的调试日记录代码结束 SwSlaveI2C.State = I2C_STA_ACK; } break; case I2C_STA_ACK: // ACK状态下的SCL下降沿处理 // 只有在确认主机已检测到ACK后才继续处理 if(SwSlaveI2C.Rw == I2C_WRITE) { // 切换回输入模式接收下一个字节 I2C_Slave_Set_SDA_IT(); SET_SDA_PIN(); // 释放SDA总线 IncrementRxIndex(); // 检查主机帧是否接收完成 if (SwSlaveI2C.RxIdx == HOST_FRAME_LEN) { // 解析主机帧 if (ParseHostFrame()) { SwSlaveI2C.FrameReceived = 1; } SwSlaveI2C.RxIdx = 0; // 重置接收索引 } if (!SwSlaveI2C.IgnoreData && SwSlaveI2C.RxIdx < MAX_RX_INDEX) { SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0; } // 重置SclFallCnt为0 SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.State = I2C_STA_DATA; } else { // 读操作,根据NACK状态决定下一步 if (SwSlaveI2C.State == I2C_STA_NACK) { // 已收到NACK,结束传输 SET_SDA_PIN(); SwSlaveI2C.State = I2C_STA_IDLE; I2C_Slave_Set_SDA_IT(); // 切换回输入模式 } else if (SwSlaveI2C.TxIdx < SLAVE_FRAME_LEN - 1) { // 还有数据要发送,继续 SwSlaveI2C.TxIdx++; SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.State = I2C_STA_DATA; } else { // 最后一个字节已发送,等待NACK确认 SwSlaveI2C.SclFallCnt = 0; // 保持在ACK状态,等待主机的NACK } } break; case I2C_STA_NACK: SwSlaveI2C.SclFallCnt = 0; SET_SDA_PIN(); // 释放SDA总线 I2C_Slave_Set_SDA_IT(); // 切换回输入模式 SwSlaveI2C.State = I2C_STA_IDLE; // 收到NACK后结束通信 break; } } // SCL上升沿处理 else { switch(SwSlaveI2C.State) { case I2C_STA_DATA: if((SwSlaveI2C.Rw == I2C_WRITE) && (SwSlaveI2C.SclFallCnt < 8) && !SwSlaveI2C.IgnoreData) { // 读取数据位(保持输入模式) if(READ_SDA_PIN() == GPIO_PIN_SET) { SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] |= (1 << (7 - SwSlaveI2C.SclFallCnt)); } } break; case I2C_STA_ACK: // 对于写操作,从机已发送ACK,等待SCL上升沿确认主机已接收 if(SwSlaveI2C.Rw == I2C_WRITE) { // ACK信号已被主机检测到,保持状态直到SCL下降沿 } // 对于读操作,检测主机发送的ACK/NACK else { if(READ_SDA_PIN() == GPIO_PIN_SET) { // 主机发送NACK,标记为NACK状态 SwSlaveI2C.State = I2C_STA_NACK; I2C_Slave_Set_SDA_IT(); // 切换回输入模式 } else { // 主机发送ACK但已无更多数据,仍需等待NACK if (SwSlaveI2C.TxIdx >= SLAVE_FRAME_LEN - 1) { SwSlaveI2C.State = I2C_STA_NACK; I2C_Slave_Set_SDA_IT(); } } } break; } } } /* USER CODE END EXTI4_15_IRQn 1 */ } frame_updated是不是有问题,并没其他地方调用它
最新发布
10-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值