[单片机框架][os层] freertos 中间件 公共函数
重新封装freertos函数,以便适配RTX4 /RTX5 / FREERTOS_NRF_RTC。
FreeRTOS 是一类 RTOS,设计得足够小以在微控制器上运行——尽管它的使用不限于微控制器应用。
微控制器是一种小型且资源受限的处理器,它在单个芯片上集成了处理器本身、只读存储器(ROM 或闪存)以保存要执行的程序,以及程序所需的随机存取存储器 (RAM)执行。通常,程序直接从只读存储器中执行。
微控制器用于深度嵌入式应用程序(那些您从未真正看到处理器本身或其运行的软件的应用程序),这些应用程序通常有非常具体和专门的工作要做。大小限制和专用终端应用程序性质很少保证使用完整的 RTOS 实现 - 或者确实使使用完整的 RTOS 实现成为可能。因此,FreeRTOS 仅提供核心实时调度功能、任务间通信、计时和同步原语。这意味着它被更准确地描述为实时内核或实时执行程序。附加功能(例如命令控制台界面或网络堆栈)可以包含在附加组件中。
为什么选择 FreeRTOS?
可信内核
凭借久经考验的稳健性、微小的占用空间和广泛的设备支持,FreeRTOS 内核受到世界领先公司的信赖,成为微控制器和小型微处理器的事实上的标准。加快上市时间
通过详细的预配置演示和物联网 (IoT) 参考集成,无需确定如何设置项目。快速下载、编译并更快地进入市场。广泛的生态系统支持
我们的合作伙伴生态系统提供了广泛的选择,包括社区贡献、专业支持以及集成的 IDE 和生产力工具。长期支持的可预测性
FreeRTOS 通过长期支持 (LTS) 版本提供功能稳定性。FreeRTOS LTS 库提供两年的安全更新和关键错误修复。由 AWS 维护,以造福于 FreeRTOS 社区。
特征
小而省电的内核
大小可扩展,可用程序内存占用低至 9KB。一些架构包括无滴答的省电模式支持 40 多种架构
一个代码库,适用于 40 多种 MCU 架构和 15 多种工具链,包括最新的 RISC-V 和 ARMv8-M(Arm Cortex-M33)微控制器模块化库
越来越多的附加库用于所有行业部门,包括安全的本地或云连接AWS 参考集成
利用经过测试的示例,其中包括安全连接到云所必需的所有库MIT 许可,有选项
FreeRTOS 可在其MIT 许可下用于任何目的 。我们的战略合作伙伴还提供 商业许可证和 安全认证。
官网地址:https://www.freertos.org/
FreeRTOS 内核快速入门指南:https://www.freertos.org/FreeRTOS-quick-start-guide.html
/********************************************************************************
* @file os_api.c
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2021-04-03
* @brief
********************************************************************************/#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "cmsis_os2.h"
#include "os_api.h"#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
#define IS_IRQ_MODE() (__get_IPSR() != 0U)
#define IS_IRQ() (IS_IRQ_MODE() || (IS_IRQ_MASKED() && (KernelState == osKernelRunning)))
#define MAX_BITS_TASK_NOTIFY 31U
#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
/* Kernel initialization state */
static osKernelState_t KernelState = osKernelInactive;
/************************************OS_KERNEL************************************/
os_status os_kernel_initialize(void)
{return (os_status)osKernelInitialize();
}os_status os_kernel_start(void)
{return (os_status)osKernelStart();
}os_status os_kernel_lock(void)
{return (os_status)osKernelLock();
}os_status os_kernel_unlock(void)
{return (os_status)osKernelUnlock();
}os_status os_delay(uint32_t ms)
{return (os_status)osDelay(ms);
}uint32_t os_get_tick(void)
{return osKernelGetTickCount();
}/************************************OS_THREAD************************************/
os_thread_id os_thread_create(const os_thread_def_t *thread_def, void *arg)
{if (thread_def == NULL){return NULL;}osThreadAttr_t attr = {0};attr.name = arg;attr.priority = osPriorityLow;if (thread_def->tpriority == OS_PRIORITY_LOW){attr.priority = osPriorityLow;}else if (thread_def->tpriority == OS_PRIORITY_NORMAL){attr.priority = osPriorityNormal;}else if (thread_def->tpriority == OS_PRIORITY_ABOVENORMAL){attr.priority = osPriorityAboveNormal;}else if (thread_def->tpriority == OS_PRIORITY_HIGH){attr.priority = osPriorityHigh;}else if (thread_def->tpriority == OS_PRIORITY_REALTIME){attr.priority = osPriorityRealtime;}else{attr.priority = osPriorityLow;}attr.stack_size = thread_def->stacksize;attr.attr_bits = osThreadDetached;return (os_thread_id)osThreadNew((osThreadFunc_t)thread_def->pthread, arg, &attr);
}/************************************OS_TIMER************************************/
os_timer_id os_timer_create(const os_timer_def_t *timer_def, os_timer_t type, void *arg)
{return osTimerNew((osTimerFunc_t)timer_def->ptimer, (osTimerType_t)type, arg, NULL);
}os_status os_timer_start(os_timer_id timer_id, uint32_t millisec)
{return (os_status)osTimerStart(timer_id, millisec);
}os_status os_timer_stop(os_timer_id timer_id)
{return (os_status)osTimerStop(timer_id);
}/************************************OS_MAIL************************************/
os_mail_qid os_mail_create(const os_mailq_def_t *queue_def, os_thread_id thread_id)
{return (os_mail_qid)osMessageQueueNew(queue_def->queue_sz, queue_def->item_sz, NULL);
}void *os_mail_alloc(os_mail_qid queue_id, uint32_t millisec)
{return NULL;
}void *os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec)
{return os_mail_alloc(queue_id, millisec);
}os_status os_mail_put(os_mail_qid queue_id, void *mail)
{return (os_status)osMessageQueuePut((osMessageQueueId_t)queue_id, mail, NULL, NULL);
}os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void *arg)
{osStatus_t status;os_event event_t;status = osMessageQueueGet((osMessageQueueId_t)queue_id, arg, NULL, millisec);event_t.status = (os_status)status;event_t.def.message_id = (os_message_qid)queue_id;event_t.value.p = arg;return event_t;
}os_status os_mail_free(os_mail_qid queue_id, void *mail)
{return (os_status)0;
}/************************************OS_POOL************************************/
os_pool_id os_pool_create(const os_pool_def_t *pool_def)
{return (os_pool_id)osMemoryPoolNew(pool_def->pool_sz, pool_def->item_sz, NULL);
}void *os_pool_alloc(os_pool_id pool_id)
{return osMemoryPoolAlloc((osMemoryPoolId_t)pool_id, 0);
}void *os_pool_calloc(os_pool_id pool_id)
{return os_pool_alloc(pool_id);
}os_status os_pool_free(os_pool_id pool_id, void *block)
{return (os_status)osMemoryPoolFree((osMemoryPoolId_t)pool_id, block);
}
/************************************OS_MSG_QUEUE************************************/
os_message_qid os_message_create(const os_messageq_def_t *queue_def, os_thread_id thread_id)
{return (os_message_qid)osMessageQueueNew(queue_def->queue_sz, 4, &(queue_def->attr));
}os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec)
{return (os_status)osMessageQueuePut((osMessageQueueId_t)queue_id, (const void *)&info, 0, millisec); // Send Message
}os_event os_message_get(os_message_qid queue_id, uint32_t millisec)
{QueueHandle_t hQueue = (QueueHandle_t)queue_id;BaseType_t yield;uint32_t *msg_ptr;os_event event;event.status = OS_OK;if (IS_IRQ()){if ((hQueue == NULL) || (millisec != 0U)){event.status = OS_ERROR_PARAMETER;}else{yield = false;if (xQueueReceiveFromISR(hQueue, &msg_ptr, &yield) != true){event.status = OS_ERROR_RESOURCE;}else{event.status = OS_EVENT_MESSAGE;event.value.p = (void *)msg_ptr;portYIELD_FROM_ISR(yield);}}}else{if (hQueue == NULL){event.status = OS_ERROR_PARAMETER;}else{if (xQueueReceive(hQueue, &msg_ptr, (TickType_t)millisec) != true){if (millisec != 0U){event.status = OS_EVENT_TIMEOUT;}else{event.status = OS_ERROR_RESOURCE;}}else{event.status = OS_EVENT_MESSAGE;event.value.p = (void *)msg_ptr;//LOG_D("os_msg_get:0x%x|0x%x", queue_id, msg_ptr);}}}return event;
}uint8_t os_message_get_space(os_message_qid queue_id)
{return (uint8_t)osMessageQueueGetSpace(queue_id);
}uint8_t os_message_get_count(os_message_qid queue_id)
{return (uint8_t)osMessageQueueGetCount(queue_id);
}/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals)
{return osThreadFlagsSet((osThreadId_t)thread_id, signals);
}int32_t os_signal_set(os_thread_id thread_id, int32_t signals)
{return osThreadFlagsSet((osThreadId_t)thread_id, signals);
}int32_t os_signal_clear(os_thread_id thread_id, int32_t signals)
{return osThreadFlagsClear(signals);
}// signals = 0,则等待任意信号.
os_event os_signal_wait(int32_t signals, uint32_t millisec)
{BaseType_t rval;os_event event_t;if (IS_IRQ()){event_t.status = OS_ERROR_ISR;}else if ((signals & THREAD_FLAGS_INVALID_BITS) != 0U){event_t.status = OS_ERROR_PARAMETER;}else{rval = xTaskNotifyWait(signals, 0xFFFFFFFF, (uint32_t *)&(event_t.value.signals), millisec);if (rval == true){event_t.status = OS_EVENT_SIGNAL;}else{event_t.status = OS_EVENT_TIMEOUT;}}/* Return flags before clearing */return (event_t);
}
/********************************************************************************
* @file os_api.h
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-03
* @brief NULL
********************************************************************************/#include <stdint.h>
#include "cmsis_os.h"/// Timeout value.
#define OS_WAIT_FOREVER 0xFFFFFFFFU ///< wait forever timeout value/************************************OS_KERNEL************************************/
typedef enum {OS_OK = 0, ///< function completed; no error or event occurred.OS_EVENT_SIGNAL = 0x08, ///< function completed; signal event occurred.OS_EVENT_MESSAGE = 0x10, ///< function completed; message event occurred.OS_EVENT_MAIL = 0x20, ///< function completed; mail event occurred.OS_EVENT_TIMEOUT = 0x40, ///< function completed; timeout occurred.OS_ERROR_PARAMETER = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object.OS_ERROR_RESOURCE = 0x81, ///< resource not available: a specified resource was not available.OS_ERROR_TIMEOUTRESOURCE = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period.OS_ERROR_ISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines.OS_ERROR_ISRRECURSIVE = 0x83, ///< function called multiple times from ISR with same object.OS_ERROR_PRIORITY = 0x84, ///< system cannot determine priority or thread has illegal priority.OS_ERROR_NOMEMORY = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.OS_ERROR_VALUE = 0x86, ///< value of a parameter is out of range.OS_ERROR_OS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits.OS_STATUS_RESERVED = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} os_status;os_status os_kernel_initialize (void);
os_status os_kernel_start(void);
os_status os_kernel_lock(void);
os_status os_kernel_unlock(void);
os_status os_delay(uint32_t ms);
uint32_t os_get_tick(void);
/************************************OS_EVENT************************************/
typedef struct os_mailq_cb *os_mail_qid;
typedef struct os_messageq_cb *os_message_qid;typedef struct {os_status status; ///< status code: event or error informationunion {uint32_t v; ///< message as 32-bit valuevoid *p; ///< message or mail as void pointerint32_t signals; ///< signal flags} value; ///< event valueunion {os_mail_qid mail_id; ///< mail id obtained by \ref osMailCreateos_message_qid message_id; ///< message id obtained by \ref osMessageCreate} def; ///< event definition
} os_event;/************************************OS_THREAD************************************/
#ifndef FREERTOS
typedef enum {OS_PRIORITY_IDLE = -3, ///< priority: idle (lowest)OS_PRIORITY_LOW = -2, ///< priority: lowOS_PRIORITY_BELOWNORMAL = -1, ///< priority: below normalOS_PRIORITY_NORMAL = 0, ///< priority: normal (default)OS_PRIORITY_ABOVENORMAL = +1, ///< priority: above normalOS_PRIORITY_HIGH = +2, ///< priority: highOS_PRIORITY_REALTIME = +3, ///< priority: realtime (highest)OS_PRIORITY_ERROR = 0x84 ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#else
typedef enum {OS_PRIORITY_IDLE = 0, ///< priority: idle (lowest)OS_PRIORITY_LOW = 1, ///< priority: lowOS_PRIORITY_BELOWNORMAL = 2, ///< priority: below normalOS_PRIORITY_NORMAL = 3, ///< priority: normal (default)OS_PRIORITY_ABOVENORMAL = 4, ///< priority: above normalOS_PRIORITY_HIGH = 5, ///< priority: highOS_PRIORITY_REALTIME = 6, ///< priority: realtime (highest)OS_PRIORITY_ERROR = 0x84 ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#endiftypedef struct os_thread_cb *os_thread_id;
typedef void (*os_pthread) (void const *argument);typedef struct {os_pthread pthread; ///< start address of thread functionos_priority_t tpriority; ///< initial thread priorityuint32_t instances; ///< maximum number of instances of that thread functionuint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
} os_thread_def_t;#define os_thread(name) &os_thread_def_##name#define os_thread_def(name, priority, instances, stacksz) \
const os_thread_def_t os_thread_def_##name = {(name), (priority), (instances), (stacksz)}os_thread_id os_thread_create(const os_thread_def_t *thread_def, void *arg);/************************************OS_TIMER************************************/
typedef struct os_timer_cb *os_timer_id;
typedef void (*os_ptimer) (void const *argument);typedef struct
{os_ptimer ptimer; ///< start address of a timer functionvoid *timer; ///< pointer to internal data
} os_timer_def_t;typedef enum
{OS_TIMER_ONCE = 0, ///< one-shot timerOS_TIMER_PERIODIC = 1 ///< repeating timer
} os_timer_t;#define os_timer(name) &os_timer_def_##name#if (osCMSIS < 0x20000U)
#define os_timer_def(name, function) static uint8_t os_timer_cb_##name[40];\
static os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#else
#define os_timer_def(name, function) static const uint8_t os_timer_cb_##name[10];\
static const os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#endifos_timer_id os_timer_create(const os_timer_def_t *timer_def, os_timer_t type, void *arg);
os_status os_timer_start(os_timer_id timer_id, uint32_t millisec);
os_status os_timer_stop(os_timer_id timer_id);/************************************OS_MAIL************************************/
typedef struct os_mailq_cb *os_mail_qid;
#define os_mail_qdef(name, queue_sz, type) \static const uint8_t os_mailq_q_##name[4 + (queue_sz)] = {0}; \static const uint8_t os_mailq_m_##name[3 + ((sizeof(type) + 3) / 4) * (queue_sz)]; \static void *os_mailq_p_##name[2] = {(os_mailq_q_##name), os_mailq_m_##name}; \static const os_mailq_def_t os_mailq_def_##name = {(queue_sz), sizeof(type), (os_mailq_p_##name)} \
typedef struct os_mailq_def
{uint16_t queue_sz; ///< number of elements in the queueuint16_t item_sz; ///< size of an itemvoid *pool; ///< memory array for mail
} os_mailq_def_t;#define os_mailq(name) &os_mailq_def_##nameos_mail_qid os_mail_create(const os_mailq_def_t *queue_def, os_thread_id thread_id);
void *os_mail_alloc(os_mail_qid queue_id, uint32_t millisec);
void *os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec);
os_status os_mail_put(os_mail_qid queue_id, void *mail);
os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void *arg);
os_status os_mail_free(os_mail_qid queue_id, void *mail);/************************************OS_MSG_QUEUE************************************/
/// Message ID identifies the message queue (pointer to a message queue control block).
typedef struct os_messageq_cb *os_message_qid;
typedef struct os_messageq_def
{uint32_t queue_sz; ///< number of elements in the queue
#if (osCMSIS < 0x20000U)void *pool; ///< memory array for messages
#elseosMessageQueueAttr_t attr; ///< message queue attributes
#endif
} os_messageq_def_t;#if (osCMSIS < 0x20000U)
#define os_message_qdef(name, queue_sz, type) \static uint8_t os_messageq_q_##name[4 + (queue_sz)] = {0}; \static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), ((void *)os_messageq_q_##name)}
#else
#define os_message_qdef(name, queue_sz, type) \static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), { NULL, 0U, NULL, 0U, NULL, 0U }}
#endif/// \brief Access a Message Queue Definition.
/// \param name name of the queue
#define os_messageq(name) &os_messageq_def_##nameos_message_qid os_message_create(const os_messageq_def_t *queue_def, os_thread_id thread_id);
os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec);
os_event os_message_get(os_message_qid queue_id, uint32_t millisec);
uint8_t os_message_get_space(os_message_qid queue_id);
uint8_t os_message_get_count(os_message_qid queue_id);
/************************************OS_POOL************************************/
/// Pool ID identifies the memory pool (pointer to a memory pool control block).
typedef struct os_pool_cb *os_pool_id;
typedef struct os_pool_deft
{uint32_t pool_sz; ///< number of items (elements) in the pooluint32_t item_sz; ///< size of an itemvoid *pool; ///< pointer to memory for pool
} os_pool_def_t;#define os_pool_def(name, no, type) \static const uint8_t os_pool_m_##name[3 + ((sizeof(type) + 3) / 4) * (no)]; \static const os_pool_def_t os_pool_def_##name = {(no), sizeof(type), (void *)(os_pool_m_##name)}#define os_pool(name) &os_pool_def_##nameos_pool_id os_pool_create(const os_pool_def_t *pool_def);
void *os_pool_alloc(os_pool_id pool_id);
void *os_pool_calloc(os_pool_id pool_id);
os_status os_pool_free(os_pool_id pool_id, void *block);
uint8_t os_pool_get_space(os_pool_id pool_id);
/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_clear(os_thread_id thread_id, int32_t signals);
os_event os_signal_wait(int32_t signals, uint32_t millisec);#ifdef FREERTOS
void get_task_info(void);
#endif
[单片机框架][os层] freertos 中间件 公共函数相关推荐
- [单片机框架][drivers层][cw2015] fuelgauge 硬件电量计(二)
接上一篇:[单片机框架][device层] fuelgauge 电量计 [单片机框架][drivers层][cw2015] fuelgauge 硬件电量计(一) 本章是硬件电量计的使用方法,采用IIC ...
- [单片机框架][drivers层][cw2015/ADC] fuelgauge 硬件电量计和软件电量计(一)
接上一篇:[单片机框架][device层] fuelgauge 电量计 CW2015 是一款超紧凑.低成本.主机侧/电池组侧.无传感电阻器的电量计量系统 IC,适用于手持和便携式设备中的锂离子 (Li ...
- [单片机框架][bsp层][nrf52832][nrf52840][nrf52810][nrf52820][ESB(2.4G)] ESB(2.4G)使用说明
这个指南描述了什么是ESB(Enhanced ShockBurst)以及如何在nRF5系列中使用ESB. ESB支持双向数据包通信,包括数据包缓冲,数据包确认和丢失数据包的自动重传的基本协议.ESB提 ...
- [单片机框架][bsp层][cx32l003][bsp_adc] ADC配置和使用
ADC是模数转换器转换器 的供应商的英文简称,是一种能将模拟信号转变为数字信号的电子元件.通常是将信号采样并保持以后,再进行量化和编码,这两个过程是在转化的同时实现的. 分辨率-说明AD对输入信号的分 ...
- thinkphp框架配置验证是否登录公共函数的方法
一 .首先tp5\application\index\controller下创建Common.php文件 <?php namespace app\index\controller; use th ...
- [单片机框架][device层] fuelgauge 电量计
通过 DEVICE_INITCALL("dev-gauge", fuelgauge_dev_init); 注册驱动,自动在main初始化中运行. 优点:耦合少,可移植性强,适用大团 ...
- [单片机框架][bsp层][N32G4FR][bsp_uart] UART配置和使用
USART 简介 通用同步异步收发器(USART)是一种全双工或半双工,同步或异步的一个串行数据交换接口.USART 提 供了可编程的波特率发生器,能对系统时钟进行分频产生 USART 发送和接收所需 ...
- [单片机框架][drivers层][extend_16ch] 16位恒流驱动芯片 MBI5020 JXI5020GP
文章目录 一.简介 二.特性 三. 示例代码 一.简介 4pin控制16ping,IO扩展器件 二.特性 16 个等电流输出通道 等电流输出值不受输出端负载电压影响等电流范围值, 3-30mA@VDp ...
- php封装公共方法,TP框架下封装公共函数详解
本篇文章讲述了如何在TP框架下封装公共函数,大家对TP框架下封装公共函数不了解的话或者对TP框架下封装公共函数感兴趣的话那么我们就一起来看看本篇文章吧, 好了废话少说进入正题吧 当我们需要在控制层调用 ...
- [单片机框架] [app_led] [WS2812x] 利用软定时器实现WS2812x闪烁和呼吸等灯光模式
引脚编号 引脚名称 说明 1 DO 控制数据信号输出端 2 DI 控制数据信号输入端 3 VCC 控制电路电源正极 4 NC 空脚 5 VDD LED电源正极 6 VSS 电源负极 数据时序图 0,1 ...
最新文章
- 神器诞生!E3成首个3.50可降级国产电子狗
- 转发:为什么函数式编程至关重要
- 矫情这一次,感谢这几个人。
- 众神进入瓦尔哈拉_一时冲动:“通往瓦尔哈拉之路的冒险”
- udt java_Java DB中的Java用户定义类型(UDT)
- 过渡效果_剪映教程:剪映怎么添加视频之间的过渡转场效果?
- 用python内置函数算复杂度吗_Python减少代码量的两个内置函数
- Linux重启提示A stop job is running for ...
- 27款经典的 CSS 框架分享
- python小课账号转卖_Python小课笔记--Python报错处理
- 信号与系统2022春季学期:作业内容与参考答案-汇总
- 台达触摸屏和vfd-m变频器通讯控制监视程序
- Oracle创建用户后无法登录,报错ORA-01045: user lacks CREATE SESSION privilege
- JeecgBoot新增一个module
- ListView的增删改查(实战)
- 关于汇编语言中的立即寻址和直接寻址
- 淘宝图片怎么编辑处理?淘宝图片处理用什么软件?
- 如何搭建“业务化”的指标体系?
- 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解
- 基于PanoSim仿真开发平台BSD和RCTA的构思
热门文章
- 小程序 java在线考试系统python自动阅卷系统php自动组卷系统
- golang数据库的操作,更新删除增加单行查找与多行查找
- Qt配置OpenCV教程,亲测已试过(详细版)
- java图书馆抢座系统_java毕业设计_springboot框架的图书馆座位预约占座
- 清华大学计算机科学与技术专业设置,清华大学计算机科学与技术专业介绍
- IDEA自带的数据库连接工具连接(DM)达梦数据库
- 快收下这份照片模糊变清晰方法攻略
- PRML学习总结(1)——Introduction
- 经典合成器插件 – LennarDigital Sylenth1 v3.067 WiN
- 关于idea注释等颜色设置