(原创)sem_wait实现毫秒级延时

由于未提供博客具体内容,无法给出包含关键信息的摘要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

static int gettimeofday(struct timeval *tp, void *t)
{
    timeb tv;
    
    ftime(&tv);
    tp->tv_sec = tv.time;
    tp->tv_usec = tv.millitm*1000;
    
    return 1;
}


int sem_timedwait_ms(sem_t *sem, int milliseconds)
{
    struct timespec abstime;
    struct timeval now;
    uint64_t tv_nsec;
    
    gettimeofday(&now, NULL);
    
    tv_nsec = now.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
    abstime.tv_sec = now.tv_sec + milliseconds / 1000;
    if(tv_nsec>=1000000000)
    {
        tv_nsec -= 1000000000;
        abstime.tv_sec += 1;
    }
    abstime.tv_nsec = tv_nsec;
    
    return sem_timedwait(sem, &abstime);
}
#pragma once #include <zephyr/kernel.h> // 批量发送配置 #define UART_BUF_SIZE 255 extern uint8_t rs485_rx_buf[UART_BUF_SIZE][8]; #define BATCH_SIZE 32 #define MAX_BATCH_TIMEOUT 10 // 秒 typedef struct { int32_t timestamp; // 时间(ms) int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } sensor_data_point_t; typedef struct { sensor_data_point_t data[BATCH_SIZE]; uint16_t count; int64_t start_timestamp; // 批次起始时间 (ms) bool ready; // 批次就绪标志 } sensor_batch_t; typedef struct { float a0; // 常数项系数 float a1; // 一次项系数 float a2; // 二次项系数 float b; // 压力项系数 int32_t ref_temp; // 参考温度 (centi-°C) } temp_comp_coeff_t; extern sensor_batch_t sensor_batch; extern struct k_mutex data_mutex; extern struct k_sem batch_ready_sem; extern sensor_data_point_t sensor_data_rs485;#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/uart.h> #include <string.h> #include "GVL.h" #define LOG_MODULE_NAME rs485_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); #define RS485_DIR_PIN_DELAY_US 100 #define UART_RX_TIMEOUT_MS 100 #define MAX_RETRIES 3 #define COMMAND_TIMEOUT_MS 500 // 获取设备树节点 #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // 声明设备 static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // 双缓冲结构 static sensor_batch_t tx_buffers[2]; static sensor_batch_t *current_tx_buffer = &tx_buffers[0]; static sensor_batch_t *pending_tx_buffer = &tx_buffers[1]; static bool buffer_ready = false; // RS485发送函数 // static int rs485_send_batch(const sensor_batch_t *batch) // { // if (batch->count == 0) { // return 0; // } // // 切换到发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // // 计算实际数据长度 // size_t data_size = sizeof(sensor_data_point_t) * batch->count; // LOG_INF("Sending batch of %d points (%u bytes)", batch->count, data_size); // // 发送数据 // int retry_count = 0; // int err = -EAGAIN; // while (retry_count < MAX_RETRIES && err != 0) { // err = uart_tx(rs485_uart, (const uint8_t *)batch->data, data_size, SYS_FOREVER_MS); // if (err) { // LOG_ERR("UART TX error (attempt %d): %d", retry_count + 1, err); // retry_count++; // k_msleep(10); // } // } // if (err) { // LOG_ERR("Failed to send after %d attempts", MAX_RETRIES); // } // return err; // } static int rs485_send_batch(const sensor_data_point_t *sensor_data) { // if (batch->count == 0) { // return 0; // } // 切换到发送模式 gpio_pin_set_dt(&direct_pin, 1); k_busy_wait(RS485_DIR_PIN_DELAY_US); // 计算实际数据长度 size_t data_size = sizeof(sensor_data_point_t); LOG_INF("rs485 Sending (%u bytes)", data_size); // 发送数据 int retry_count = 0; int err = -EAGAIN; while (retry_count < MAX_RETRIES && err != 0) { err = uart_tx(rs485_uart, sensor_data, data_size, SYS_FOREVER_MS); if (err) { LOG_ERR("UART TX error (attempt %d): %d", retry_count + 1, err); retry_count++; k_msleep(10); } } if (err) { LOG_ERR("Failed to send after %d attempts", MAX_RETRIES); } return err; } // 处理接收到的命令 static void process_command(const uint8_t *data, size_t len) { if (len < 1) return; // 空命令 switch (data[0]) { case 0x01: // 请求传感器数据 LOG_DBG("Received data request command"); k_sem_give(&batch_ready_sem); break; case 0x02: // 设置采样率 if (len >= 2) { uint16_t new_rate = data[1] << 8 | data[2]; LOG_INF("Setting new sample rate: %d ms", new_rate); // 这里可以添加设置采样率的逻辑 } break; case 0x03: // 设备状态查询 LOG_DBG("Received status query"); // 这里可以添加状态响应逻辑 break; default: LOG_WRN("Unknown command: 0x%02X", data[0]); break; } } // UART接收回调 static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { static uint8_t rx_buffer[128]; static size_t rx_index = 0; static int64_t last_rx_time = 0; switch (evt->type) { case UART_RX_RDY: // 检查是否新数据包 int64_t now = k_uptime_get(); if ((now - last_rx_time) > COMMAND_TIMEOUT_MS || (rx_index + evt->data.rx.len) > sizeof(rx_buffer)) { rx_index = 0; // 重置缓冲区 } // 复制数据到缓冲区 size_t to_copy = MIN(evt->data.rx.len, sizeof(rx_buffer) - rx_index); memcpy(&rx_buffer[rx_index], evt->data.rx.buf, to_copy); rx_index += to_copy; last_rx_time = now; break; case UART_RX_DISABLED: // 处理缓冲区中的数据 if (rx_index > 0) { process_command(rx_buffer, rx_index); rx_index = 0; } // 重新启用接收 uart_rx_enable(rs485_uart, rs485_rx_buf, sizeof(rs485_rx_buf), UART_RX_TIMEOUT_MS); break; case UART_RX_BUF_RELEASED: // 可以在这里释放缓冲区 break; case UART_TX_DONE: LOG_DBG("TX complete"); //发送完成后切换回接收模式 gpio_pin_set_dt(&direct_pin, 0); break; case UART_TX_ABORTED: LOG_WRN("TX aborted"); break; default: break; } } // 初始化RS485模块 static int rs485_init(void) { int ret; // 检查设备是否就绪 if (!device_is_ready(rs485_uart)) { LOG_ERR("UART device not ready"); return -ENODEV; } if (!device_is_ready(direct_pin.port)) { LOG_ERR("GPIO device not ready"); return -ENODEV; } // 配置方向控制引脚 ret = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); if (ret) { LOG_ERR("GPIO config error: %d", ret); return ret; } // 配置UART回调 ret = uart_callback_set(rs485_uart, uart_cb, NULL); if (ret) { LOG_ERR("UART callback set error: %d", ret); return ret; } // 初始化双缓冲 memset(tx_buffers, 0, sizeof(tx_buffers)); // 启用接收 ret = uart_rx_enable(rs485_uart, rs485_rx_buf, sizeof(rs485_rx_buf), UART_RX_TIMEOUT_MS); if (ret) { LOG_ERR("UART RX enable error: %d", ret); return ret; } LOG_INF("RS485 initialized"); return 0; } void rs485_thread(void) { if (rs485_init() != 0) { LOG_ERR("RS485 initialization failed"); return; } LOG_INF("RS485 thread started"); while (1) { // // 等待批次数据就绪信号 // if (k_sem_take(&batch_ready_sem, K_FOREVER) == 0) { // // 安全地获取批次数据 // k_mutex_lock(&data_mutex, K_FOREVER); // // 检查是否有待处理数据 // if (buffer_ready) { // LOG_WRN("Previous buffer not sent, overwriting"); // } // // 复制数据到待发送缓冲区 // *pending_tx_buffer = sensor_batch; // // 重置主批次 // sensor_batch.count = 0; // sensor_batch.start_timestamp = 0; // sensor_batch.ready = false; // // 标记缓冲区就绪 // buffer_ready = true; // k_mutex_unlock(&data_mutex); // } // // 检查是否有数据需要发送 // if (buffer_ready) { // // 交换缓冲区指针 // sensor_batch_t *send_buffer = pending_tx_buffer; // pending_tx_buffer = current_tx_buffer; // current_tx_buffer = send_buffer; // // 发送数据 // rs485_send_batch(send_buffer); // // 重置缓冲区 // send_buffer->count = 0; // buffer_ready = false; // } sensor_data_point_t *send_buffer = &sensor_data_rs485; rs485_send_batch(send_buffer); // 处理超时命令 k_sleep(K_MSEC(1000)); } } K_THREAD_DEFINE(rs485_thread_id, 4096, rs485_thread, NULL, NULL, NULL, 5, 0, 0); rs485发送数据// GVL.h #pragma once #include <zephyr/kernel.h> // 批量发送配置 #define BATCH_SIZE 32 #define MAX_BATCH_TIMEOUT_MS 10000 #define UART_BUF_SIZE 256 #define MEM_POOL_SIZE 8 #define RS485_DIR_PIN_DELAY_US 100 #define UART_RX_TIMEOUT_MS 100 #define MAX_RETRIES 3 #define COMMAND_TIMEOUT_MS 500 #define UART_WAIT_FOR_RX 50000 #define DATA_POINT_SIZE 37 // unified_data_point_t大小(字节) #define MAX_POINTS_PER_PACKET 6 // 每个包最大数据点数(根据MTU计算) typedef struct { int32_t timestamp; // 时间(ms) int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } sensor_data_point_t; // 批处理包头(用于蓝牙传输) typedef struct __attribute__((packed)) { uint16_t item_count; // 批处理中数据点数量 int64_t batch_timestamp; // 批处理开始时间戳 uint32_t data_size; // 数据部分总大小(字节) } batch_header_t; // 统一的数据点结构 typedef struct { int32_t timestamp; // 时间(ms) // 传感器数据 int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) // IMU数据 (来自RS485) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) // 数据来源标识 uint8_t data_source; // 1:本地传感器, 2:RS485设备 } unified_data_point_t; // 蓝牙数据包结构 - 确保每个包包含完整数据点 typedef struct __attribute__((packed)) { uint16_t packet_index; // 包序号 uint16_t total_packets; // 总包数 uint16_t points_in_packet; // 本包数据点数 unified_data_point_t data_points[MAX_POINTS_PER_PACKET]; // 数据点数组 } ble_packet_t; extern struct k_mem_slab uart_tx_pool; extern struct k_mem_slab batch_pool; // 批处理容器 typedef struct { unified_data_point_t data[BATCH_SIZE]; uint16_t count; int64_t start_timestamp; bool ready; } batch_container_t; typedef struct __attribute__((packed)) { int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } rs485_raw_data_t; // 双缓冲批处理 extern batch_container_t data_batches[2]; extern uint8_t active_batch_index; // 同步信号量 extern struct k_sem ble_data_ready_sem; // 自旋锁保护批处理缓冲区 extern struct k_spinlock batch_lock; static double atmospheric_pressure; // #include <zephyr/kernel.h> // #include <zephyr/device.h> // #include <zephyr/devicetree.h> // #include <zephyr/drivers/gpio.h> // #include <zephyr/logging/log.h> // #include <zephyr/drivers/uart.h> // #include "GVL.h" // #define LOG_MODULE_NAME rs485_thread // LOG_MODULE_REGISTER(LOG_MODULE_NAME); // // 获取设备树节点 // #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // // 声明设备 // static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); // static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // // 延时工作 // static struct k_work_delayable uart_work; // struct uart_data_t { // void *fifo_reserved; // uint8_t data[UART_BUF_SIZE]; // uint16_t len; // }; // static K_FIFO_DEFINE(fifo_uart_tx_data); // // RS485接收状态机 // enum rx_state { // STATE_IDLE, // STATE_GOT_AA, // STATE_RECEIVING // }; // static struct { // enum rx_state state; // uint8_t buffer[sizeof(rs485_raw_data_t) + 3]; // AA + BB + payload + CRC // size_t index; // } rx_state_machine; // // CRC校验函数 // static uint8_t calculate_crc(const uint8_t *data, size_t len) // { // uint8_t crc = 0; // for (size_t i = 0; i < len; i++) { // crc ^= data[i]; // } // return crc; // } // static void process_rs485_packet(uint8_t *packet, size_t len) // { // // CRC校验 (最后1字节是CRC) // if (calculate_crc(packet, len - 1) != packet[len - 1]) { // LOG_WRN("Invalid RS485 packet CRC"); // return; // } // // 解析RS485原始数据(跳过包头AA BB) // rs485_raw_data_t raw_data; // memcpy(&raw_data, packet + 2, sizeof(raw_data)); // // 转换为统一数据结构 // unified_data_point_t data_point = { // .timestamp = k_uptime_get_32(), // .pressure = raw_data.pressure, // .temp = raw_data.temp, // .acc_x = raw_data.acc_x, // .acc_y = raw_data.acc_y, // .acc_z = raw_data.acc_z, // .gyro_x = raw_data.gyro_x, // .gyro_y = raw_data.gyro_y, // .gyro_z = raw_data.gyro_z, // .data_source = 2 // 标记为RS485设备数据 // }; // LOG_INF("sensor module : pressure %.4f,temp %.2f",data_point.pressure,data_point.temp); // // k_spinlock_key_t key = k_spin_lock(&batch_lock); // // batch_container_t *batch = &data_batches[active_batch_index]; // // if (batch->count == 0) { // // batch->start_timestamp = k_uptime_get(); // // } // // if (batch->count < BATCH_SIZE) { // // batch->data[batch->count++] = data_point; // // bool batch_ready = false; // // if (batch->count >= BATCH_SIZE) { // // batch_ready = true; // // } else if (batch->count > 0 && // // (k_uptime_get() - batch->start_timestamp) >= MAX_BATCH_TIMEOUT_MS) { // // batch_ready = true; // // } // // if (batch_ready) { // // batch->ready = true; // 只设置就绪标志 // // active_batch_index = (active_batch_index + 1) % 2; // 切换到另一个缓冲区 // // k_sem_give(&ble_data_ready_sem); // 通知BLE线程 // // } // // } else { // // LOG_WRN("Batch buffer overflow"); // // } // // k_spin_unlock(&batch_lock, key); // } // static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) // { // static size_t aborted_len; // struct uart_data_t *buf; // static uint8_t *aborted_buf; // static bool disable_req; // switch (evt->type) { // case UART_TX_DONE: // LOG_DBG("UART_TX_DONE"); // // 设置方向为接收模式 // gpio_pin_set_dt(&direct_pin, 0); // if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) { // return; // } // if (aborted_buf) { // buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data[0]); // aborted_buf = NULL; // aborted_len = 0; // k_free(buf); // } else { // buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data[0]); // k_free(buf); // } // // 发送下一个数据包 // buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); // if (buf) { // // 设置方向为发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // if (uart_tx(rs485_uart, buf->data, buf->len, SYS_FOREVER_MS)) { // LOG_WRN("Failed to send data over UART"); // gpio_pin_set_dt(&direct_pin, 0); // 确保切换回接收模式 // k_free(buf); // } // } // break; // case UART_RX_RDY: // const uint8_t *data = evt->data.rx.buf; // size_t len = evt->data.rx.len; // for (size_t i = 0; i < len; i++) { // uint8_t byte = data[i]; // switch (rx_state_machine.state) { // case STATE_IDLE: // if (byte == 0xAA) { // rx_state_machine.state = STATE_GOT_AA; // } // break; // case STATE_GOT_AA: // if (byte == 0xBB) { // rx_state_machine.state = STATE_RECEIVING; // rx_state_machine.index = 0; // rx_state_machine.buffer[rx_state_machine.index++] = 0xAA; // rx_state_machine.buffer[rx_state_machine.index++] = 0xBB; // } else { // rx_state_machine.state = (byte == 0xAA) ? STATE_GOT_AA : STATE_IDLE; // } // break; // case STATE_RECEIVING: // rx_state_machine.buffer[rx_state_machine.index++] = byte; // // 检查完整数据包 (AA + BB + payload + CRC) // if (rx_state_machine.index >= sizeof(rx_state_machine.buffer)) { // process_rs485_packet(rx_state_machine.buffer, rx_state_machine.index); // rx_state_machine.state = STATE_IDLE; // } // break; // } // } // break; // case UART_RX_DISABLED: // LOG_DBG("UART_RX_DISABLED"); // disable_req = false; // buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); // } // break; // case UART_RX_BUF_REQUEST: // LOG_DBG("UART_RX_BUF_REQUEST"); // buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_buf_rsp(rs485_uart, buf->data, sizeof(buf->data)); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // } // break; // case UART_RX_BUF_RELEASED: // LOG_DBG("UART_RX_BUF_RELEASED"); // buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data[0]); // k_free(buf); // break; // case UART_TX_ABORTED: // LOG_DBG("UART_TX_ABORTED"); // gpio_pin_set_dt(&direct_pin, 0); // 确保切换回接收模式 // if (!aborted_buf) { // aborted_buf = (uint8_t *)evt->data.tx.buf; // aborted_len = evt->data.tx.len; // } // struct uart_data_t *tx_buf = (struct uart_data_t *)aborted_buf; // size_t remaining = tx_buf->len - aborted_len; // if (remaining > 0) { // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // uart_tx(rs485_uart, &tx_buf->data[aborted_len], remaining, SYS_FOREVER_MS); // } // break; // default: // break; // } // } // static void uart_work_handler(struct k_work *item) // { // struct uart_data_t *buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); // } // } // static int rs485_init(void) // { // int err; // if (!device_is_ready(rs485_uart)) { // LOG_ERR("UART device not ready"); // return -ENODEV; // } // // 初始化方向控制引脚 // if (!device_is_ready(direct_pin.port)) { // LOG_ERR("GPIO device not ready"); // return -ENODEV; // } // err = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); // if (err) { // LOG_ERR("GPIO config error: %d", err); // return err; // } // // 初始化引脚为接收 // gpio_pin_set_dt(&direct_pin, 0); // // 初始化接收状态机 // rx_state_machine.state = STATE_IDLE; // rx_state_machine.index = 0; // // 初始化UART // k_work_init_delayable(&uart_work, uart_work_handler); // err = uart_callback_set(rs485_uart, uart_cb, NULL); // if (err) { // LOG_ERR("Cannot set UART callback: %d", err); // return err; // } // // 启动接收 // k_work_schedule(&uart_work, K_NO_WAIT); // return 0; // } // void rs485_send(const uint8_t *data, size_t len) // { // struct uart_data_t *tx = k_malloc(sizeof(*tx) + len); // if (!tx) { // LOG_ERR("Not enough memory for UART send"); // return; // } // memcpy(tx->data, data, len); // tx->len = len; // // 如果发送队列为空,直接发送,否则加入队列 // if (k_fifo_is_empty(&fifo_uart_tx_data)) { // // 设置方向为发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // if (uart_tx(rs485_uart, tx->data, tx->len, SYS_FOREVER_MS)) { // LOG_WRN("Failed to start UART send"); // gpio_pin_set_dt(&direct_pin, 0); // 切换回接收模式 // k_free(tx); // } // } else { // k_fifo_put(&fifo_uart_tx_data, tx); // } // } // void rs485_thread(void) // { // if (rs485_init() != 0) { // LOG_ERR("RS485 initialization failed"); // return; // } // LOG_INF("RS485 thread started"); // // 线程主循环 // while (1) { // LOG_INF("rs485 thread"); // k_sleep(K_FOREVER); // } // } // K_THREAD_DEFINE(rs485_thread_id, 2048, rs485_thread, NULL, NULL, NULL, 5, 0, 0); #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/uart.h> #include "GVL.h" #define LOG_MODULE_NAME rs485_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME); // 获取设备树节点 #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // 声明设备 static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // 延时工作 static struct k_work_delayable uart_work; struct uart_data_t { void *fifo_reserved; uint8_t data[UART_BUF_SIZE]; uint16_t len; }; static K_FIFO_DEFINE(fifo_uart_tx_data); // 定义RS485数据包结构 typedef struct { uint8_t header[2]; // 0xAA, 0xBB rs485_raw_data_t payload; uint8_t crc; } rs485_packet_t; #define RS485_PACKET_SIZE sizeof(rs485_packet_t) // CRC校验函数 static uint8_t calculate_crc(const uint8_t *data, size_t len) { uint8_t crc = 0; for (size_t i = 0; i < len; i++) { crc ^= data[i]; } return crc; } static void process_rs485_packet(const uint8_t *packet) { const rs485_packet_t *pkt = (const rs485_packet_t *)packet; // 检查包头 if (pkt->header[0] != 0xAA || pkt->header[1] != 0xBB) { LOG_WRN("Invalid packet header: 0x%02X%02X", pkt->header[0], pkt->header[1]); return; } // 计算并验证CRC (不包括CRC自身) uint8_t crc = calculate_crc(packet, RS485_PACKET_SIZE - 1); if (crc != pkt->crc) { LOG_WRN("Invalid CRC: expected 0x%02X, got 0x%02X", crc, pkt->crc); return; } // 转换为统一数据结构 unified_data_point_t data_point = { .timestamp = k_uptime_get_32(), .pressure = pkt->payload.pressure, .temp = pkt->payload.temp, .acc_x = pkt->payload.acc_x, .acc_y = pkt->payload.acc_y, .acc_z = pkt->payload.acc_z, .gyro_x = pkt->payload.gyro_x, .gyro_y = pkt->payload.gyro_y, .gyro_z = pkt->payload.gyro_z, .data_source = 2 // 标记为RS485设备数据 }; LOG_INF("RS485 sensor: pressure %.4f, temp %.2f", data_point.pressure, data_point.temp); // // 添加数据到批处理 // k_spinlock_key_t key = k_spin_lock(&batch_lock); // batch_container_t *batch = &data_batches[active_batch_index]; // if (batch->count == 0) { // batch->start_timestamp = k_uptime_get(); // } // if (batch->count < BATCH_SIZE) { // batch->data[batch->count++] = data_point; // bool batch_ready = false; // if (batch->count >= BATCH_SIZE) { // batch_ready = true; // } else if (batch->count > 0 && // (k_uptime_get() - batch->start_timestamp) >= MAX_BATCH_TIMEOUT_MS) { // batch_ready = true; // } // if (batch_ready) { // batch->ready = true; // active_batch_index = (active_batch_index + 1) % 2; // k_sem_give(&ble_data_ready_sem); // } // } else { // LOG_WRN("Batch buffer overflow"); // } // k_spin_unlock(&batch_lock, key); } static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { static size_t aborted_len; struct uart_data_t *buf; static uint8_t *aborted_buf; static bool disable_req; switch (evt->type) { case UART_TX_DONE: LOG_DBG("UART_TX_DONE"); gpio_pin_set_dt(&direct_pin, 0); // 切换回接收模式 if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) { return; } if (aborted_buf) { buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data[0]); aborted_buf = NULL; aborted_len = 0; k_free(buf); } else { buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data[0]); k_free(buf); } // 发送下一个数据包 buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); if (buf) { gpio_pin_set_dt(&direct_pin, 1); // 切换到发送模式 k_busy_wait(RS485_DIR_PIN_DELAY_US); if (uart_tx(rs485_uart, buf->data, buf->len, SYS_FOREVER_MS)) { LOG_WRN("Failed to send data over UART"); gpio_pin_set_dt(&direct_pin, 0); k_free(buf); } } break; case UART_RX_RDY: // 直接处理接收到的数据 if (evt->data.rx.len == RS485_PACKET_SIZE) { // 检查包头 if (evt->data.rx.buf[0] == 0xAA && evt->data.rx.buf[1] == 0xBB) { process_rs485_packet(evt->data.rx.buf); } else { LOG_WRN("Invalid packet header"); } } else if (evt->data.rx.len > 0) { LOG_WRN("Received unexpected length: %d (expected %d)", evt->data.rx.len, RS485_PACKET_SIZE); } break; case UART_RX_DISABLED: LOG_DBG("UART_RX_DISABLED"); disable_req = false; buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); } break; case UART_RX_BUF_REQUEST: LOG_DBG("UART_RX_BUF_REQUEST"); buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_buf_rsp(rs485_uart, buf->data, sizeof(buf->data)); } else { LOG_WRN("Not able to allocate UART receive buffer"); } break; case UART_RX_BUF_RELEASED: LOG_DBG("UART_RX_BUF_RELEASED"); buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data[0]); k_free(buf); break; case UART_TX_ABORTED: LOG_DBG("UART_TX_ABORTED"); gpio_pin_set_dt(&direct_pin, 0); if (!aborted_buf) { aborted_buf = (uint8_t *)evt->data.tx.buf; aborted_len = evt->data.tx.len; } struct uart_data_t *tx_buf = (struct uart_data_t *)aborted_buf; size_t remaining = tx_buf->len - aborted_len; if (remaining > 0) { gpio_pin_set_dt(&direct_pin, 1); k_busy_wait(RS485_DIR_PIN_DELAY_US); uart_tx(rs485_uart, &tx_buf->data[aborted_len], remaining, SYS_FOREVER_MS); } break; default: break; } } static void uart_work_handler(struct k_work *item) { struct uart_data_t *buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); } } static int rs485_init(void) { int err; if (!device_is_ready(rs485_uart)) { LOG_ERR("UART device not ready"); return -ENODEV; } // 初始化方向控制引脚 if (!device_is_ready(direct_pin.port)) { LOG_ERR("GPIO device not ready"); return -ENODEV; } err = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); if (err) { LOG_ERR("GPIO config error: %d", err); return err; } // 初始化引脚为接收模式 gpio_pin_set_dt(&direct_pin, 0); // 初始化UART k_work_init_delayable(&uart_work, uart_work_handler); err = uart_callback_set(rs485_uart, uart_cb, NULL); if (err) { LOG_ERR("Cannot set UART callback: %d", err); return err; } // 启动接收 k_work_schedule(&uart_work, K_NO_WAIT); return 0; } void rs485_send(const uint8_t *data, size_t len) { struct uart_data_t *tx = k_malloc(sizeof(*tx) + len); if (!tx) { LOG_ERR("Not enough memory for UART send"); return; } memcpy(tx->data, data, len); tx->len = len; if (k_fifo_is_empty(&fifo_uart_tx_data)) { gpio_pin_set_dt(&direct_pin, 1); // 切换到发送模式 k_busy_wait(RS485_DIR_PIN_DELAY_US); if (uart_tx(rs485_uart, tx->data, tx->len, SYS_FOREVER_MS)) { LOG_WRN("Failed to start UART send"); gpio_pin_set_dt(&direct_pin, 0); k_free(tx); } } else { k_fifo_put(&fifo_uart_tx_data, tx); } } void rs485_thread(void) { if (rs485_init() != 0) { LOG_ERR("RS485 initialization failed"); return; } LOG_INF("RS485 thread started"); while (1) { k_sleep(K_FOREVER); } } K_THREAD_DEFINE(rs485_thread_id, 2048, rs485_thread, NULL, NULL, NULL, 5, 0, 0);rs485接收数据[00:49:12.400,446] <wrn> rs485_thread: Received unexpected length: 3 (expected 35) [00:49:12.401,129] <wrn> rs485_thread: Received unexpected length: 2 (expected 35) [00:49:12.402,071] <wrn> rs485_thread: Received unexpected length: 3 (expected 35)接收数据时报错,不使用状态机
最新发布
07-12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值