保证counter_cache在更新时也有效

#ifndef __SOFT_I2C_H #define __SOFT_I2C_H #include "stm32g0xx_hal.h" // I2C引脚定义 #define I2C_SCL_PIN GPIO_PIN_6 #define I2C_SDA_PIN GPIO_PIN_7 #define I2C_GPIO_PORT GPIOB // I2C地址 #define I2C_SLAVE_ADDR 0x48 // 通信缓冲区配置 #define DATA_OFFSET 3 // 数据起始位置 #define I2C_TIMEOUT 10000 // 超计数(基于系统频率调整) #define FRAME_LENGTH 20 // 帧长度定义 // 外部变量声明 extern uint8_t i2c_rx_buf[FRAME_LENGTH]; extern uint8_t i2c_tx_buf[FRAME_LENGTH]; extern uint8_t i2c_receive_complete; // 函数声明 void I2C_Init(void); void I2C_Send_ACK(void); void I2C_Send_NACK(void); uint8_t I2C_Read_SCL(void); uint8_t I2C_Read_SDA(void); void I2C_Write_SDA(uint8_t state); uint8_t Calculate_XOR_Checksum(uint8_t *data, uint8_t length); void Prepare_TX_Frame(uint8_t data_type); void I2C_Reset_Communication(void); #endif #include "soft_i2c.h" #include "delay.h" #include <stdio.h> // 全局变量定义 uint8_t i2c_rx_buf[FRAME_LENGTH] = {0}; uint8_t i2c_tx_buf[FRAME_LENGTH] = {0}; uint8_t i2c_rx_index = 0; uint8_t i2c_tx_index = 0; uint8_t i2c_receive_complete = 0; uint8_t current_function_code = 0x00; // 传感器数据缓存结构 typedef struct { uint16_t reg_11; // 寄存器11的数据 uint8_t updated; // 数据更新标志(1:新数据,0:未更新) uint32_t timestamp; // 数据间戳 uint8_t valid; // 数据有效标志 } 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; // I2C状态机枚举 typedef enum { I2C_STATE_IDLE, // 空闲状态 I2C_STATE_ADDR_RECEIVING, // 接收地址状态 I2C_STATE_RX_DATA, // 接收数据状态 I2C_STATE_TX_DATA, // 发送数据状态 I2C_STATE_ERROR // 错误状态 } I2C_State; // 全局状态变量 static volatile I2C_State i2c_state = I2C_STATE_IDLE; static volatile uint8_t i2c_addr_match = 0; // 地址匹配标志 static volatile uint8_t i2c_read_mode = 0; // 读模式标志(1:读,0:写) static volatile uint8_t last_sda_level = 1; // 上一次SDA电平 static volatile uint8_t last_scl_level = 0; // 上一次SCL电平 static volatile uint8_t bit_counter = 0; // 位计数器 static volatile uint8_t current_byte = 0; // 当前字节缓存 static volatile uint32_t comm_timeout = 0; // 通信超计数器 static const uint32_t COMM_TIMEOUT_THRESHOLD = 50000; // 通信超阈值 // 读取SCL引脚电平 uint8_t I2C_Read_SCL(void) { return HAL_GPIO_ReadPin(I2C_GPIO_PORT, I2C_SCL_PIN); } // 读取SDA引脚电平 uint8_t I2C_Read_SDA(void) { return HAL_GPIO_ReadPin(I2C_GPIO_PORT, I2C_SDA_PIN); } // 设置SDA引脚电平 static void I2C_Write_SDA(uint8_t state) { HAL_GPIO_WritePin(I2C_GPIO_PORT, I2C_SDA_PIN, state ? GPIO_PIN_SET : GPIO_PIN_RESET); } // 设置SDA引脚为输入模式 static void I2C_Set_SDA_Input(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = I2C_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct); } // 设置SDA引脚为开漏输出模式 static void I2C_Set_SDA_Output(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = I2C_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct); } // 发送ACK信号 void I2C_Send_ACK(void) { I2C_Set_SDA_Output(); I2C_Write_SDA(0); // 拉低SDA表示ACK } // 发送NACK信号 void I2C_Send_NACK(void) { I2C_Set_SDA_Output(); I2C_Write_SDA(1); // 保持SDA高表示NACK } // 计算异或校验和 uint8_t Calculate_XOR_Checksum(uint8_t *data, uint8_t length) { uint8_t checksum = 0; for(uint8_t i = 0; i < length; i++) { checksum ^= data[i]; } return checksum; } // 发送帧准备函数 void Prepare_TX_Frame(uint8_t data_type) { // 帧头 i2c_tx_buf[0] = 0x01; i2c_tx_buf[1] = 0xBB; i2c_tx_buf[2] = data_type; // 根据功能码准备不同数据 switch(data_type) { case 0x01: // ADC数据 i2c_tx_buf[3] = (adc_ch4_avg >> 8) & 0xFF; i2c_tx_buf[4] = adc_ch4_avg & 0xFF; i2c_tx_buf[5] = (adc_ch5_avg >> 8) & 0xFF; i2c_tx_buf[6] = adc_ch5_avg & 0xFF; i2c_tx_buf[7] = (adc_ch6_avg >> 8) & 0xFF; i2c_tx_buf[8] = adc_ch6_avg & 0xFF; i2c_tx_buf[9] = (adc_ch7_avg >> 8) & 0xFF; i2c_tx_buf[10] = adc_ch7_avg & 0xFF; break; case 0x02: // 传感器数据 // 传感器2数据 - 从缓存读取 if (sensor2_cache.valid) { i2c_tx_buf[3] = (sensor2_cache.reg_11 >> 8) & 0xFF; i2c_tx_buf[4] = sensor2_cache.reg_11 & 0xFF; } else { i2c_tx_buf[3] = 0xFF; // 无效数据标志 i2c_tx_buf[4] = 0xFF; } // 传感器3数据 - 从缓存读取 if (sensor3_cache.valid) { i2c_tx_buf[5] = (sensor3_cache.reg_11 >> 8) & 0xFF; i2c_tx_buf[6] = sensor3_cache.reg_11 & 0xFF; } else { i2c_tx_buf[5] = 0xFF; i2c_tx_buf[6] = 0xFF; } // 传感器4数据 - 从缓存读取 if (sensor4_cache.valid) { i2c_tx_buf[7] = (sensor4_cache.reg_11 >> 8) & 0xFF; i2c_tx_buf[8] = sensor4_cache.reg_11 & 0xFF; } else { i2c_tx_buf[7] = 0xFF; i2c_tx_buf[8] = 0xFF; } i2c_tx_buf[9] = 0x00; // 预留 i2c_tx_buf[10] = 0x00; // 预留 break; default: // 未知功能码 i2c_tx_buf[2] = 0xFF; // 错误标识 break; } // 填充剩余字节并计算校验和 for(uint8_t i = 11; i < 19; i++) { i2c_tx_buf[i] = 0x00; } i2c_tx_buf[FRAME_LENGTH-1] = Calculate_XOR_Checksum(i2c_tx_buf, FRAME_LENGTH-1); } // 重置通信状态 void I2C_Reset_Communication(void) { i2c_state = I2C_STATE_IDLE; i2c_rx_index = 0; i2c_tx_index = 0; i2c_addr_match = 0; i2c_read_mode = 0; bit_counter = 0; current_byte = 0; i2c_receive_complete = 0; I2C_Set_SDA_Input(); } // 处理接收位 static void I2C_Process_Receive_Bit(uint8_t scl_rising) { if (scl_rising) { // 在SCL上升沿采样数据 current_byte = (current_byte << 1) | I2C_Read_SDA(); bit_counter++; // 完成一个字节接收 if (bit_counter >= 8) { if (i2c_state == I2C_STATE_ADDR_RECEIVING) { // 处理地址字节 uint8_t addr = current_byte; i2c_read_mode = addr & 0x01; uint8_t slave_addr = (addr >> 1) & 0x7F; if (slave_addr == I2C_SLAVE_ADDR) { i2c_addr_match = 1; I2C_Send_ACK(); // 发送ACK if (i2c_read_mode) { Prepare_TX_Frame(current_function_code); i2c_state = I2C_STATE_TX_DATA; bit_counter = 0; current_byte = i2c_tx_buf[i2c_tx_index]; I2C_Set_SDA_Output(); } else { i2c_state = I2C_STATE_RX_DATA; } } else { i2c_addr_match = 0; I2C_Send_NACK(); // 发送NACK i2c_state = I2C_STATE_IDLE; } } else if (i2c_state == I2C_STATE_RX_DATA && i2c_addr_match) { // 处理数据字节 if (i2c_rx_index < FRAME_LENGTH) { i2c_rx_buf[i2c_rx_index] = current_byte; // 验证帧头 if (i2c_rx_index == 1) { if (i2c_rx_buf[0] != 0x01 || i2c_rx_buf[1] != 0xAA) { I2C_Send_NACK(); I2C_Reset_Communication(); return; } } i2c_rx_index++; I2C_Send_ACK(); // 发送ACK // 检查是否接收完成 if (i2c_rx_index == FRAME_LENGTH) { if (i2c_rx_buf[FRAME_LENGTH-1] == Calculate_XOR_Checksum(i2c_rx_buf, FRAME_LENGTH-1)) { current_function_code = i2c_rx_buf[2]; Prepare_TX_Frame(current_function_code); i2c_receive_complete = 1; } I2C_Reset_Communication(); return; } } else { I2C_Send_NACK(); I2C_Reset_Communication(); return; } } // 准备接收下一个字节 bit_counter = 0; current_byte = 0; } } } // 处理发送位 static void I2C_Process_Transmit_Bit(uint8_t scl_falling, uint8_t scl_rising) { if (i2c_state == I2C_STATE_TX_DATA && i2c_addr_match) { if (scl_falling) { // SCL下降沿,设置下一位数据 if (bit_counter < 8) { // 发送数据位 I2C_Write_SDA((current_byte & 0x80) ? 1 : 0); current_byte <<= 1; bit_counter++; } else if (bit_counter == 8) { // 释放SDA线,准备接收ACK I2C_Set_SDA_Input(); bit_counter++; } } else if (scl_rising) { if (bit_counter == 9) { // 读取ACK位 uint8_t ack = !I2C_Read_SDA(); bit_counter = 0; i2c_tx_index++; // 如果主机发送NACK或数据发送完成,结束传输 if (!ack || i2c_tx_index >= FRAME_LENGTH) { I2C_Reset_Communication(); return; } // 准备发送下一个字节 I2C_Set_SDA_Output(); current_byte = i2c_tx_buf[i2c_tx_index]; } } } } // 中断处理核心函数:处理起始/停止位并驱动状态机 static void I2C_Process_Edge(void) { uint8_t current_scl = I2C_Read_SCL(); uint8_t current_sda = I2C_Read_SDA(); uint8_t scl_rising = (current_scl && !last_scl_level); // SCL上升沿 uint8_t scl_falling = (!current_scl && last_scl_level); // SCL下降沿 uint8_t sda_changed = (current_sda != last_sda_level); // SDA电平变化 // 检测起始信号:SCL高电平,SDA出现下降沿 if (last_scl_level && current_scl && sda_changed && !current_sda) { if (last_sda_level) { // 确保是从高到低变化 // 检测到起始信号 I2C_Reset_Communication(); i2c_state = I2C_STATE_ADDR_RECEIVING; } } // 检测停止信号:SCL高电平,SDA出现上升沿 else if (last_scl_level && current_scl && sda_changed && current_sda) { if (!last_sda_level) { // 确保是从低到高变化 // 检测到停止信号 I2C_Reset_Communication(); } } // 处理当前状态 else { switch(i2c_state) { case I2C_STATE_ADDR_RECEIVING: case I2C_STATE_RX_DATA: I2C_Process_Receive_Bit(scl_rising); break; case I2C_STATE_TX_DATA: I2C_Process_Transmit_Bit(scl_falling, scl_rising); break; default: break; } } // 更新历史电平 last_scl_level = current_scl; last_sda_level = current_sda; // 重置超计数器 comm_timeout = 0; } // I2C初始化函数 void I2C_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 配置SCL引脚为输入,双边沿中断 GPIO_InitStruct.Pin = I2C_SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct); // 配置SDA引脚为输入,双边沿中断 GPIO_InitStruct.Pin = I2C_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct); // 使能并设置中断优先级 HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); // 初始化状态 I2C_Reset_Communication(); } // 超处理函数,应在定器中断中周期性调用 void I2C_Timeout_Handler(void) { if (i2c_state != I2C_STATE_IDLE) { comm_timeout++; if (comm_timeout >= COMM_TIMEOUT_THRESHOLD) { I2C_Reset_Communication(); } } } // 添加中断锁防止重入 static volatile uint8_t in_interrupt = 0; // 中断回调函数(处理SCL和SDA引脚中断) void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (in_interrupt) return; in_interrupt = 1; if (GPIO_Pin == I2C_SCL_PIN || GPIO_Pin == I2C_SDA_PIN) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); I2C_Process_Edge(); // 在中断中处理边沿和状态机 } in_interrupt = 0; } 目前需要更改功能,主机会发送01 AA 功能码01或者02 16个00 校验位。从机需要根据功能码将01或者02的数据传给主机。
09-19
#include "spi_slave_server.h" // SPI 库 #include <SPI.h> #include <ESP32SPISlave.h> #include "helper.h" #include <main.h> ESP32SPISlave slave; // 自定义引脚 #define MY_CS 12 #define MY_SCK 13 #define MY_MOSI 14 #define MY_MISO 11 // 启用 SPI Slave 功能 #define SPI_SLAVE_ENABLE 1 // 超设置(微秒) #define SPI_READ_TIMEOUT 999999 #define SPI_TX_CACHE_BUF_LEN 1024 static volatile uint8_t spi_tx_cache_buf[SPI_TX_CACHE_BUF_LEN]; static volatile int spi_tx_cache_buf_cnt = 0; // 实现缺失的函数 int spi_slave_data_cache_add(uint8_t *data, uint16_t len) { if (len > SPI_TX_CACHE_BUF_LEN) len = SPI_TX_CACHE_BUF_LEN; for (int i = 0; i < len; ++i) spi_tx_cache_buf[i] = data[i]; spi_tx_cache_buf_cnt = len; return 0; } // 扩展缓冲区至 64 字节以容纳 33 字节的有效响应 static constexpr size_t SPI_BUFFER_SIZE = 64; static constexpr size_t QUEUE_SIZE = 1; // SPI 发送/接收缓冲区 static uint8_t spi_tx_buf[SPI_BUFFER_SIZE] = {0}; static uint8_t spi_rx_buf[SPI_BUFFER_SIZE] = {0}; // 用户命令定义 #define SPI_USER_CMD_NULL 0 #define SPI_USER_CMD_READ 1 #define SPI_USER_CMD_WRITE 2 // 当前命令状态 static volatile int spi_current_cmd = SPI_USER_CMD_NULL; static volatile int spi_current_cmd_len = 0; // 包序号或控制标志 // 发送忙标志(预留扩展) static uint8_t spi_send_busy = 0; static uint8_t spi_send_mode = 1; /** * 生成 16 个随机 16 位数据,并写入 buffer(32 字节) */ void generate_random_16bit_data(uint8_t *buffer, int count) { for (int i = 0; i < count; i++) { uint16_t val = random(0xFFFF); // 随机 16 位值 buffer[i * 2 + 0] = (val >> 8) & 0xFF; // 高字节 buffer[i * 2 + 1] = val & 0xFF; // 低字节 } } /** * SPI 事务完成后的回调函数(放在 IRAM 中保证中断快速响应) */ void IRAM_ATTR my_post_setup_cb(spi_slave_transaction_t *trans) { // 如果当前处于读取模式且尚未响应,则构造 0xAA + 32字节数据 if (spi_current_cmd == SPI_USER_CMD_READ && spi_current_cmd_len == 0) { memset(spi_tx_buf, 0, SPI_BUFFER_SIZE); // 清空缓冲区 spi_tx_buf[0] = 0xAA; // 回复标识 generate_random_16bit_data(spi_tx_buf + 1, 16); // 写入 16 个 16 位随机数(32字节) // 标记已响应,防止重复发送 spi_current_cmd_len = 1; } else { // 默认响应(可用于调试) memset(spi_tx_buf, 0, SPI_BUFFER_SIZE); spi_tx_buf[0] = 0xAB; spi_tx_buf[1] = spi_current_cmd_len; spi_tx_buf[2] = millis() >> 8; spi_tx_buf[3] = millis(); } } /** * SPI Slave 任务(FreeRTOS 任务) */ static void spi_slave_task(void *pvParameters) { size_t received_bytes; while (1) { int cs = digitalRead(MY_CS); #if SPI_SLAVE_ENABLE if (cs == 0) { // 片选拉低,表示主设备开始通信 memset(spi_rx_buf, 0, SPI_BUFFER_SIZE); // 执行一次 SPI 传输(阻塞直到完成或超) received_bytes = slave.transfer(spi_tx_buf, spi_rx_buf, SPI_BUFFER_SIZE, SPI_READ_TIMEOUT); if (received_bytes > 0) { printf_log_hex("SPI RX", spi_rx_buf, received_bytes); // 检查是否收到 0xAA 命令(假设命令在第一个字节) if (spi_rx_buf[0] == 0xAA) { spi_current_cmd = SPI_USER_CMD_READ; spi_current_cmd_len = 0; // 准备下次回复 printf("SPI Slave: Received 0xAA command, will respond in next transaction.\n"); } // 调用回调函数准备下一次的响应数据 my_post_setup_cb(NULL); } } #endif vTaskDelay(5 / portTICK_PERIOD_MS); // 小延避免 CPU 占满 } } /** * 初始化 SPI Slave */ void spi_slave_server_init(void) { #if SPI_SLAVE_ENABLE // 设置 SPI 模式(MODE3 示例) slave.setDataMode(SPI_MODE3); slave.setQueueSize(QUEUE_SIZE); // 初始化 SPI Slave(使用 HSPI,自定义引脚) slave.begin(HSPI, MY_SCK, MY_MISO, MY_MOSI, MY_CS); // 初始化随机种子(用于生成随机数) randomSeed(micros()); // 创建 SPI 从机任务 xTaskCreate(spi_slave_task, "spi_slave_task", 8192, NULL, 2, NULL); printf("SPI Slave initialized in MODE3, Buffer Size: %d\n", SPI_BUFFER_SIZE); #endif } 将发送的数据改为有规律的数
09-27
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值