[嵌入式开发模块]环形缓冲区/循环队列C语言实现

李肖遥 2023-03-22 21:53
    关注、星标公众号,直达精彩内容

来源:https://blog.csdn.net/lin_strong/article/details/73604561



这里分享一个自己用纯C实现的环形缓冲区。

环形缓冲区有很多作用,比如嵌入式中的通信可以用环形缓冲区作为信道,一个线程往里放字节,一个线程取字节进行处理,只要保证取的速度大于读的速度,就可以保证通信顺畅进行,不丢一个字节。

简要介绍:

环形缓冲区其实就是一个队列,里头的元素是先入先出的,但是因为其(逻辑上)是环形的,所以不需要像很多队列的实现那样在内部元素变动的时候需要移动内部剩下的元素。这样就使元素出队入队的时间复杂度只有O(1)。具体实现一般有链表和数组两种方法,当不能确定需要的缓冲区大小时使用链表较好,能确定时使用数组可以节省很多动态分配内存的开销。

在嵌入式开发中,一般不动态分配内存,而是使用静态分配的数组。所以这里我使用数组实现了环形缓冲区,为了能够在不同的程序中复用代码,使用结构体模拟了面向对象编程,这样就可以用一套代码管理不同的缓冲区了。

废话不多说,直接上代码。以下是.h 文件:

/*
*********************************************************************************************************
*
*
*                                       RingQueueStruct
*                                         环形队列结构
*
* File : RingQueue.h
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date : 2018/02/23
* version: V1.2
* NOTE(s): 这段程序用来对一个给定的缓冲区进行模拟环形队列的管理
*                   程序本身不会自动分配缓冲区空间,用户需要自己负责分配空间,并且要保证不直接访问缓存区
*                   // 在某处分配内存空间
*                   RQTYPE buffer[BUFFER_SIZE];
*                   RING_QUEUE que,*ptr_que;
*                   unsigned char err;
*                   // 初始化
*                   ptr_que = RingQueueInit(&que,buffer,BUFFER_SIZE,&err);
*                   if(err == RQ_ERR_NONE  ){
*                     // 初始化成功,使用其他函数
*                   }
* History : 2017/04/25   the original version of RingQueueStruct.
*           2017/10/16   put functions used frequently,RingQueueIn and RingQueueOut, in non-banked address;
*                        modify single line function RingQueueIsEmpty and RingQueueIsFull to marco function;
*                        to get better efficiency.
*           2018/02/23   1.add the marco(RQ_ARGUMENT_CHECK_EN) to controll argument check so user can save 
*                          more code.
*                        2.add the ADDRESSING MODE so the buffer can be defined in banked addressing area.
*********************************************************************************************************
*/



#ifndef   RING_QUEUE_H
#define   RING_QUEUE_H

/*
********************************************************************************************
*                                   MISCELLANEOUS
********************************************************************************************
*/


#ifndef  FALSE
#define  FALSE    0
#endif

#ifndef  TRUE
#define  TRUE     1
#endif

/*
*********************************************************************************************************
*                                       ADDRESSING MODE 寻址模式
*********************************************************************************************************
*/


// uncomment the corresponding line to select the addressing mode to the buffer of RingQueue module.
// if you don't understand. Just use the extended addressing mode
// 取消对应行的注释以选择环形缓冲区模块访问缓冲区时使用的寻址方式
// 如果你不知道这是什么意思的话,那就用扩展寻址就行了,这是默认的方式

// extended addressing mode 扩展区寻址(默认)
#define RQ_ADDRESSING_MODE
// banked RAM addressing mode   RAM分页区寻址
//#define RQ_ADDRESSING_MODE __rptr
// global addressing mode   全局寻址
//#define RQ_ADDRESSING_MODE __far

/*
*********************************************************************************************************
*                                       CONFIGURATION  配置
*********************************************************************************************************
*/


#define RQ_ARGUMENT_CHECK_EN    TRUE     // TRUE: arguments will be checked, however,this will 
                                         //       cost a little code volume.

/*
*********************************************************************************************************
*                                        CONSTANTS     常量
*********************************************************************************************************
*/

#define   RQ_ERR_NONE                        0u

#define   RQ_ERR_POINTER_NULL                1u
#define   RQ_ERR_SIZE_ZERO                   2u

#define   RQ_ERR_BUFFER_FULL                 3u
#define   RQ_ERR_BUFFER_EMPTY                4u

#define   RQ_OPTION_WHEN_FULL_DISCARD_FIRST  0u       // discard the first element when ring buffer is full
#define   RQ_OPTION_WHEN_FULL_DONT_IN        1u       // discard new element when ring buffer is full
/*
*********************************************************************************************************
*                                    DATA TYPE    数据类型
*********************************************************************************************************
*/


// define the data type that stores in the RingQueue.       定义存在环形缓冲区内的数据的类型
typedef unsigned char RQTYPE;
typedef RQTYPE *RQ_ADDRESSING_MODE pRQTYPE;
typedef struct {
    unsigned short  RingBufCtr;              /* Number of characters in the ring buffer */
    unsigned short  RingBufSize;             /* Ring buffer Size */    
    pRQTYPE RingBufInPtr;                    /* Pointer to where next character will be inserted        */  
    pRQTYPE RingBufOutPtr;                   /* Pointer from where next character will be extracted     */  
    pRQTYPE RingBuf;                         /* Ring buffer array */  
    pRQTYPE RingBufEnd;                      /* Point to the end of the buffer */
} RING_QUEUE;

/*
*********************************************************************************************************
*                                  FUNCTION PROTOTYPES 函数原型
*********************************************************************************************************
*/


RING_QUEUE *RingQueueInit(RING_QUEUE *pQueue,pRQTYPE pbuf,unsigned short bufSize,unsigned char *perr);
#pragma CODE_SEG __NEAR_SEG NON_BANKED
unsigned short RingQueueIn(RING_QUEUE *pQueue,RQTYPE data,unsigned char option,unsigned char *perr);
RQTYPE RingQueueOut(RING_QUEUE *pQueue,unsigned char *perr);
#pragma CODE_SEG DEFAULT
short RingQueueMatch(RING_QUEUE *pQueue,pRQTYPE pbuf,unsigned short len);
void RingQueueClear(RING_QUEUE *pQueue);

/*
*********************************************************************************************************
*                                        RingQueueIsEmpty()
*
* Description :  whether the RingQueue is empty.   环形队列是否为空
*
* Arguments   :  pQueue  pointer to the ring queue control block;     指向环形队列控制块的指针
*
* Return      :  TRUE    the RingQueue is empty.
*                FALSE   the RingQueue is not empty.
* Note(s)     :
*********************************************************************************************************
*/


#define RingQueueIsEmpty(pQueue) ((pQueue)->RingBufCtr == 0)

/*
*********************************************************************************************************
*                                        RingQueueIsFull()
*
* Description : whether the RingQueue is full.    环形队列是否为空
*
* Arguments   : pQueue  pointer to the ring queue control block;   指向环形队列控制块的指针
*
* Return      : TRUE    the RingQueue is full.
*               FALSE   the RingQueue is not full.
* Note(s)     :
*********************************************************************************************************
*/


#define RingQueueIsFull(pQueue)  ((pQueue)->RingBufCtr >= (pQueue)->RingBufSize)

#endif

然后下面是.c文件。

/*
*********************************************************************************************************
*
*
*                                       RingQueueStruct
*                                         环形队列结构
*
* File : RingQueue.c
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date : 2018/02/23
* version: V1.2 
* NOTE(s): 
*
* History : 2017/04/25   the original version of RingQueueStruct.
*           2017/10/16   put functions used frequently,RingQueueIn and RingQueueOut, in non-banked address;
*                        modify single line function RingQueueIsEmpty and RingQueueIsFull to marco function;
*                        to get better efficiency.
*           2018/02/23   1.add the marco(RQ_ARGUMENT_CHECK_EN) to controll argument check so user can save 
*                          more code.
*                        2.add the ADDRESSING MODE so the buffer can be defined in banked addressing area.
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                     INCLUDES
*********************************************************************************************************
*/

#include "RingQueue.h"

/*
*********************************************************************************************************
*                                LOCAL FUNCTION DECLARATION
*********************************************************************************************************
*/


#if(RQ_ARGUMENT_CHECK_EN == TRUE)
  #define argCheck(cond,err,rVal)  if(cond) { *perr = (err); return (rVal); }
#else
  #define argCheck(cond,err,rVal)
#endif // of (SPI_ARGUMENT_CHECK_EN == TRUE)



/*
*********************************************************************************************************
*                                LOCAL FUNCTION DECLARE
*********************************************************************************************************
*/

#pragma CODE_SEG __NEAR_SEG NON_BANKED
// 内部使用,给定将给定指针在环形缓冲区内向前移动一步(到尾了会移回头)
static void _forwardPointer(RING_QUEUE *pQueue,pRQTYPE* pPointer);
#pragma CODE_SEG DEFAULT
/*
*********************************************************************************************************
*                                        RingQueueInit()
*
* Description : To initialize the ring queue.    初始化环形队列
*
* Arguments   : pQueue   pointer to the ring queue control block;     指向环形队列控制块的指针
*               pbuf     pointer to the buffer(an array);             指向自定义的缓冲区(实际就是个数组)
*               bufSize  the Size of the buffer;                      缓冲区的大小;
*               perr     a pointer to a variable containing an error message which will be set by this
*                          function to either:
*
*                           RQ_ERR_NONE                                       
*                           RQ_ERR_SIZE_ZERO
*                           RQ_ERR_POINTER_NULL
*
* Return      : the pointer to the ring queue control block;        返回指向环形队列控制块的指针
*               0x00 if any error;                                  如果出错了则返回NULL
*
*Note(s):
*********************************************************************************************************
*/


RING_QUEUE* RingQueueInit(RING_QUEUE *pQueue,pRQTYPE pbuf,unsigned short bufSize,unsigned char *perr){
  argCheck(pQueue == 0x00 || pbuf == 0x00,RQ_ERR_POINTER_NULL,0x00);
  argCheck(bufSize == 0,RQ_ERR_SIZE_ZERO,0x00);
  pQueue->RingBufCtr = 0;
  pQueue->RingBuf = pbuf;
  pQueue->RingBufInPtr = pbuf;
  pQueue->RingBufOutPtr = pbuf;
  pQueue->RingBufSize = bufSize;
  pQueue->RingBufEnd = pbuf + bufSize;
  *perr = RQ_ERR_NONE;     
  return pQueue;
}

/*
*********************************************************************************************************
*                                        RingQueueIn()
*
* Description : Enqueue an element.    入队一个元素
*
* Arguments   : pQueue   pointer to the ring queue control block;    指向环形队列控制块的指针
*               data     the data to enqueue;                        要入队的数据
*               option   option when queue is full ,you can choose:  当队列满的时候的选项,你可以选择:
*                            RQ_OPTION_WHEN_FULL_DISCARD_FIRST          抛弃队头的元素来填进去新的元素
*                            RQ_OPTION_WHEN_FULL_DONT_IN                不入队新给的元素
*               perr     a pointer to a variable containing an error message which will be set by this
*                          function to either:
*
*                             RQ_ERR_NONE                            if no err happen
*                             RQ_ERR_POINTER_NULL                    if pointer is 0x00
*                             RQ_ERR_BUFFER_FULL                     if buffer is full
*
* Return       : the Elements Count after enqueue the element
*                    调用函数后队列中的元素个数
*Note(s)       :
*********************************************************************************************************
*/

#pragma CODE_SEG __NEAR_SEG NON_BANKED
unsigned short RingQueueIn(RING_QUEUE *pQueue,RQTYPE data,unsigned char option,unsigned char *perr){
  argCheck(pQueue == 0x00,RQ_ERR_POINTER_NULL,0x00);
  if(pQueue->RingBufCtr >= pQueue->RingBufSize){
    *perr = RQ_ERR_BUFFER_FULL;     
    if(option == RQ_OPTION_WHEN_FULL_DISCARD_FIRST){
      _forwardPointer(pQueue,&pQueue->RingBufOutPtr); /* Wrap OUT pointer                          */  
    }else{                                            // option == RQ_OPTION_WHEN_FULL_DONT_IN
      return pQueue->RingBufCtr;
    }
  }else{
    pQueue->RingBufCtr++;                             /* No, increment character count            */      
    *perr = RQ_ERR_NONE;
  }
  *pQueue->RingBufInPtr = data;                       /* Put character into buffer                */  
  _forwardPointer(pQueue,&pQueue->RingBufInPtr);      /* Wrap IN pointer                          */  
  return pQueue->RingBufCtr;
}
/*
*********************************************************************************************************
*                                        RingQueueOut()
*
* Description : Dequeue an element.       出队一个元素
*
* Arguments   : pQueue   pointer to the ring queue control block;     指向环形队列控制块的指针
*               perr     a pointer to a variable containing an error message which will be set by this
*                          function to either:
*
*                              RQ_ERR_NONE                            if no err happen
*                              RQ_ERR_POINTER_NULL                    if pointer is 0x00
*                              RQ_ERR_BUFFER_EMPTY                    if buffer is empty
*
* Return      : 0                 if any error or the data is 0;
*               others            the data 
*               
*Note(s):
*********************************************************************************************************
*/

RQTYPE RingQueueOut(RING_QUEUE *pQueue,unsigned char *perr){
  RQTYPE data;
  argCheck(pQueue == 0x00,RQ_ERR_POINTER_NULL,0x00);
  if(pQueue->RingBufCtr == 0){
    *perr = RQ_ERR_BUFFER_EMPTY;        
    return 0;
  }
  pQueue->RingBufCtr--;                                      /*  decrement character count           */  
  data = *pQueue->RingBufOutPtr;                      /* Get character from buffer                */  
  _forwardPointer(pQueue,&pQueue->RingBufOutPtr);        /* Wrap OUT pointer                          */  
  *perr = RQ_ERR_NONE;
  return data;
}
#pragma CODE_SEG DEFAULT
/*
*********************************************************************************************************
*                                        RingQueueMatch()
*
* Description : Match the given buffer in RingQueue          在环形队列中匹配给定缓冲区
*
* Arguments   : pQueue   pointer to the ring queue control block;     指向环形队列控制块的指针
*               pbuf     pointer to the chars need to match;
*               len      the length of the chars
* Return      :  -1       Don't match            -1    则没有匹配到
*                >= 0     match                  >= 0  则匹配到了
*
*Note(s):
*********************************************************************************************************
*/


short RingQueueMatch(RING_QUEUE *pQueue,pRQTYPE pbuf,unsigned short len){
  pRQTYPE pPosQ,pCurQ,pCurB,pEndB;
  unsigned short rLen,Cnt;
  if(len > pQueue->RingBufCtr)
    return -1;
  pPosQ = pQueue->RingBufOutPtr;
  pEndB = pbuf + len;
  Cnt = 0;
  rLen = pQueue ->RingBufCtr;
  while(rLen-- >= len){          // if remian length of queue bigger than buffer. continue
    pCurQ = pPosQ;
    pCurB = pbuf;
    while(pCurB != pEndB && *pCurQ == *pCurB) {    // compare one by one,until match all(pCurB==pEndB) or some one don't match
      _forwardPointer(pQueue,&pCurQ);
      pCurB++;
    }
    if(pCurB == pEndB)                                                 // if match all
       return Cnt;
     Cnt++;
     _forwardPointer(pQueue,&pPosQ);
  }
  return -1;
}

/*
*********************************************************************************************************
*                                        RingQueueClear()
*
* Description:  Clear the RingQueue.        清空环形队列
*
* Arguments  :  pQueue    pointer to the ring queue control block;     指向环形队列控制块的指针
*
* Return:             
*
* Note(s):
*********************************************************************************************************
*/


void RingQueueClear(RING_QUEUE *pQueue){
#if(RQ_ARGUMENT_CHECK_EN == TRUE)
  if(pQueue == 0x00)
    return;
#endif
  pQueue->RingBufCtr = 0;
  pQueue->RingBufInPtr = pQueue -> RingBufOutPtr;
}

/*
*********************************************************************************************************
*                                       LOCAL FUNCTION 
*********************************************************************************************************
*/


#pragma CODE_SEG __NEAR_SEG NON_BANKED
static void _forwardPointer(RING_QUEUE *pQueue,pRQTYPE* pPointer){
  if (++*pPointer == pQueue->RingBufEnd)   
    *pPointer = pQueue->RingBuf;        /* Wrap OUT pointer                          */  
}
#pragma CODE_SEG DEFAULT

简单解释下。

在.h文件中定义了一个环形缓冲区的控制块,当然也可以当其为一个环形缓冲区对象,用户需要为每个环形缓冲区分配一个控制块和其缓冲区(也就是一个数组)。理想情况下,虽然用户知道控制块的结构,但也不应该直接访问内部字段,而应该通过提供的函数来访问。

队列中默认的元素是无符号字符,如果要改成缓存其他类型的话改下.h文件中的typedef unsigned char RQTYPE;这行就行了。

使用示例:

#include "RingQueue.h"
#define RX_BUF_MAX_SIZE     200        // 定义缓冲区的最大大小为200
static unsigned char RxBuffer[RX_BUF_MAX_SIZE];   // 定义缓冲区
static RING_QUEUE RxRingQ;             // 定义环形缓冲区的控制块
void main(){
   unsigned char err;
   // 初始化缓冲区
   RingQueueInit(&RxRingQ,RxBuffer,RX_BUF_MAX_SIZE,&err);
   if(err != RQ_ERR_NONE){
       //初始化缓冲区失败的处理
   }
   ……
}

然后调用所有方法都需要传递环形缓冲区控制块的指针。如入队就像:

// 往RxRingQ缓冲区内入队一个元素c,如果满的话丢弃第一个元素
RingQueueIn(&RxRingQ,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&err); 

出队就像:

// 从RxRingQ缓冲区内提取一个字符
c = RingQueueOut(&RxRingQ,&err);

其他就不一 一举例了。要特别说明下的是RingQueueMatch()这个方法并不是队列应该有的方法,这是为了比如我需要在缓冲区中匹配到某一串字符后做某些事情而特别加上的,不需要的话删掉即可。比如我需要一旦出现“abc”就做某些事情,那我代码可以类似这么写:

static const unsigned char* StringsWait = "abc";
……
while(true){
    //比如从某处获得了下一个字符c
    ……
    // 将字符c入队
    RingQueueIn(&RxRingQ,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&err); 
    if(RingQueueMatch(&RxRingQ,StringsWait,3) >= 0){  // 如果在缓冲区内找到"abc"
         // RingQueueClear(&RxRingQ);     // 可能需要清空缓冲区
         // 做想要做的事
         ……
    }
}

有什么建议或意见请留言,谢谢!

版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论 (0)
  • 基于JAVA的RSA文件加密软件的设计与实现(源代码+论文)
    基于JAVA的RSA文件加密软件的设计与实现(源代码+论文)
  • C++微服务架构及安全云盘项目实训
    学完《C++微服务架构及安全云盘项目实训》课,您将学到:从实践中理解软件工程,学习需求分析、架构设计、详细设计文档的编写,学习编程规范,了解多人协作开发策略,理解并引用软件的版本管理,熟悉git工具和软件发布管理流程, bug管理提交问题。

    课程大纲:
    第一阶段环境准备
    开发工具安装、系统和虚拟机安装、sdk库编译安装
    代码规范说明(参考google代码规范)
    版本管理讲解,使用git

    第二阶段原型开发
    不做设计、不用框架、直接基于qt+ libevent开发出云盘的后端和前端上传下载和目录功能
    教会同学碰到需求如何思考开发出原型

    第三阶段0.1版本微服务框架
    编写需求分析、架构设计、详细设计文档
    完成版本管理策略
    完成主体框架开发,基于libevent

    第四阶段1.0版本微服务框架
    完成微服务架构
    完成基于protobuf的通信RPC模块
    完成公共服务(认证、日志、监控)

    第五阶段1.1版本微服务框架
    添加加密和压缩通信,完成后端服务注册和管理,完成服务的自动启动和停止管理
    优化负载均衡,完成运维管理

    第六阶段基于框架安全云盘的业务功能
    支持高并发的文件上传下载,支持秒传和文件完整性校验,支持文件加密存储和传输,支持图片
    视频生成缩略图,支持视频生成gif预览动画,支持文件共享和分发

    第七阶段学员独立微服务开发辅导
    安全云盘扩展功能,可以是前端或者是后端服务
    直播评审学员代码

  • EMC电磁兼容案例
    EMC电磁兼容的一些典型案例解析 ,NO2是医疗行业的解析
  • Linux云计算运维工程师路线图(集群、虚拟化、K8S、Docker、智能化、Python大数据)
    Linux云计算运维工程师路线图(集群、虚拟化、K8S、Docker、智能化、Python大数据)课程分享

    从目前市场发展情况以及应用率来说,Linux云计算的就业前景是非常不错的,至少在未来十年都是非常不错的职业,市场上对于Linux人才需求量很大,就业薪资待遇也是非常不错,有百分之八十的公司都在使用Linux;学习Linux之后可以从业的岗位也是非常多的,比如说:
    Linux运维工程师
    Linux运维平台研究工程师
    运维开发工程师
    运维总监
    大数据运维工程师
    系统运维架构师

    随着互联网的高速发展、网站规模越来越大、架构越来越复杂,对网络运维工程师的需求也会越来越急迫,特别是对有经验的人才需求量大,而且职业发展前景非常好。

    Linux云计算运维工程师路线图(集群、虚拟化、K8S、Docker、智能化、Python大数据)持续更新
    第一阶段Linux基础环境搭建篇
    第二阶段Linux磁盘管理
    第三阶段Linux网络篇
    第四阶段Docker篇  
    第五阶段Kubernetes(K8S)篇 
    第六阶段Shell基础+实战 
    地七阶段搜索引擎运维篇+logstash日志收集
    第八阶段自动化运维
    第九阶日志监控系统Promethus
    第十阶段K8S监控方案
    第十一阶段大型在线教育运维项目

  • 电路板设计 针对各种噪音的降噪方法2
    要将电阻摆放在运算放大器的输入引脚附近,线圈下方不可以布置 GND 覆铜。
  • 2023 年更新,Vue3 + TS 仿知乎专栏企业级项目(升级版14章)
    为了更好的适应 vue3 的最新的发展,让大家更好的掌握最新的动态以及知识点,以及更加丰富课程的功能点,在 2023 年 6 月 8 日完成一次新的常规迭代。时长 3 个小时。
     更新内容如下:
     1、学习新的状态管理工具 Pinia 并且重构整个应用
     2、Pinia 简介
     3、Pinia 基本概念 - State/Getter/Actions
     4、Pinia 和 Vuex 的对比
     5、Pinia 中大型 Store 设计思路
     6、使用 Pinia 重构整个应用

    Vue3 +TS ,使用新版Vuex 和 Vue-Router 全家桶让你学会一个基本的组件库的开发思路和技巧。接入真实后端API,提供抓住前后端分离开发痛点 - 权限管理,路由控制,全局Store 结构设计,前端缓存实现等。

    深度剖析 Vue3 特性
    Composition API 全解析
    Script Setup 语法大揭秘
    结合 Typescript 完美输出
    手把手开发企业级项目
    <teleport> 瞬移组件的位置
    <suspense>异步加载的新福音
    全局 API 修改和优化

    热门技术+经典项目
    Vue3 配合 Typescript
    结合新版 Vue3 全家桶
    以及十几个流行的第三方库
    全流程开发并且部署经典项目

    接入真实后端API
    前后端分离,重点难点全程解析
    含身份鉴权、路由守护、上传文件、
    前端数据缓存、部署等
    全程提供后端API
    让你告别虚假数据,拥抱真实项目
    后端在线调试

    从易到难完成组件库开发
    手把手由浅入深实现常用组件库
    了解原理远比使用更重要
    从下拉菜单到上传组件
    经典复刻六个常用组件
    了解六种原理

    完全拥抱 TypeScript
    全程 TypeScript 编码
    杜绝 any
    让你真正理解TS的优势
    学会使用 typescript
    为你未来的编码如虎添翼

    Vue3 + Vue 全家桶+ TypeScript 组件化开发,技术全面,落地扎实
    项目全部采用新版Composition API 编写,汇聚当前市场热门的技术栈

    从需求分析到上线部署 带你用 Vue3 造轮子
    本项目的原理/架构/思路/实现方式/解决方案,可以应对全行业的绝大部分项目
  • 道路车辆 电气及电子设备的环境条件和试验

    道路车辆 电气及电子设备的环境条件和试验

    第1~3部分

  • 基于JAVA的班主任管理系统设计与实现(包含源代码及论文)
    基于JAVA的班主任管理系统设计与实现(包含源代码及论文)
  • 跟我一起写DApp(转型区块链开发推荐课程)
    分享课程——《跟我一起写DApp(转型区块链开发推荐课程)》,课程内容上主要分为3部分:项目背景以及项目级智能合约实战;以太坊SDK使用以及后端服务开发;fisco-bcos简介及区块链应用实战。

    本课程属于讲师个人原创课程,并非照搬国外技术开发课程,课程中可以学习Go-web开发,gin框架的使用,提升智能合约开发能力,授课风格以代码驱动为主,希望学习者能够积极动手实践,并在评论区交流互动,分享自己的学习心得和体会。课程源码可以供学习者下载。

    第一章:课程简介与环境准备
    第二章:项目需求与智能合约实战
    第三章:以太坊go-sdk使用
    第四章:后端应用开发实战
    第五章:联盟链fisco-bcos使用介绍
    第六章:基于fisco-bcos应用实战

  • RA-Eco-RA6E2-64PIN-V1.0开发板开发板资料

    瑞萨 RA6E2 功能板,免费申请

    https://mbb.eet-china.com/evaluating/product-127.html

  • 基于JAVA的SNMP网络设备MIB信息采集(论文+源代码)
    基于JAVA的SNMP网络设备MIB信息采集(论文+源代码)
  • 基于JAVA的SMART系统-系统框架设计与开发(源代码+论文)
    基于JAVA的SMART系统-系统框架设计与开发(源代码+论文)
  • 基于JAVA的某店POS积分管理系统设计(包含源代码及论文)
    基于JAVA的某店POS积分管理系统设计(包含源代码及论文)
  • 基于JAVA的物业管理系统设计与实现(包含论文及源代码)
    基于JAVA的物业管理系统设计与实现(包含论文及源代码)
  • 近期有点全身心投入到了嵌入式驱动的开发意思了,起早贪黑的学习。不过也是,人生的路都是在不断地学习中度过的。对于干了几年的硬件工程师而言,不说硬件是不是很牛了,就是想换换脑子,整天三极管、电阻、电容的,确实让人乏味。思来想去,硬件是软件的基座,驱动是软件沟通硬件的桥梁。倒不如自己整点知识,也方便自己以后调试硬件不是,再说了从软件角度去理解硬件思维,会有很多不同的收获不是。 奋战了一个月,倒是把驱动的基本框架了解七七八八了,兴致使然,图像采集感觉还不错,公司有产品当开发板,也是省下了大部分的学
    二月半 2023-06-08 12:09 701浏览
  • 半导体制冷片是电子器件中重要的辅助元件,用于控制器件的温度,从而保证器件的稳定性和可靠性。在半导体制冷片的制造过程中,半导体制冷片的基板材料选择是非常关键的,因为基板材料的性能会直接影响到制冷片的性能。同时作为精密制冷片新型技术,对陶瓷基板的要求也高于普通基板。1.外观要求:严格的铜面平整度,粗糙度要求控制在0.5um以内,铜面上不允许有凹坑、铜颗粒、氧化、任何形式的外观划伤等。2.尺寸要求:完成板厚控制公差在10-20um以内,而陶瓷板材的来料公差就有±30un公差,这就意味着需要挑选公差范围
    斯利通陶瓷电路板 2023-06-08 11:50 199浏览
  • 最近在使用串口读一些数据,但是总会出现些发、送之间的冲突问题,为了弄清楚问题的所在,于是产生了想法,做了一个日志保存。[code]void Widget::SaveLogTxt(QString dat ){ QDateTime currenttime = QDateTime::currentDateTime(); QString strDate = currenttime.toString("yyyy/MM/dd"); QString strTime = currenttime
    E_ARM 2023-06-09 10:31 176浏览
  • 增加电池寿命的秘诀 1.新买的电车要先充满几次吗?把电车电池完全充满这个操作,在专业上叫锂电池化成,是电车在出厂之前激活电池的一道工序,车主完全没必要这样做。《汽车大数据应用研究报告》里明确指出充放电深度是表征电池健康度的重要参数,充放电深度增加,释放电量变大,使电池的健康度衰减非常明显。所以在日常用车的时候我们尽量把电池的电量维持在20%~80%之间,这样能显著提升电池的使用寿命。1. 电池寿命会受温度影响吗?锂电池的理想工作温度为25摄氏度,工作温度过高或者过低都会引发电
    四川英特丽科技有限公司 2023-06-08 10:42 186浏览
  • CS5466支持dsc1.1/12a压缩视频传输,是一款Type-C转HDMI8K30HZ或者4K144HZ方案芯片,Type-C/DP1.4转HDMI2.1的显示协议转换芯片, 内部集成了PD3.0及DSC decoder.CS5466电路原理图参考:CS5466芯片产品参数特性:1. Type-C/DP(2lanes)to HDMI2.1 8K30或者4K144产品。2. 支持HDMI2.1 FRL。3. 集成DSC1.2a decoder。4. DSC支持RGB, YCbCr4:4:4,
    QQ1540182856 2023-06-09 09:52 178浏览
  • MSDS中干电池、铅酸蓄电池、锂电池正负极材料介绍191-0751-6775一、干电池干电池也叫锰锌电池,所谓干电池是相对于伏打电池而言,所谓锰锌是指其原材料。针对其它材料的干电池如氧化银电池,镍镉电池而言。锰锌电池的电压是15V。干电池是消耗化学原料产生电能的。它的电压不高,所能产生的持续电流不能超过1安培。锌锰干电池:正极材料:锰、石墨棒负极材料:锌镁锰干电池:正极材料:二氧化锰粉、氯化铵及碳黑组成的一个混合糊状物负极材料:镁筒锌空气电池:正极材料:用活性炭吸附空气中的氧或纯氧作为正极活性物
    陈丽莎 2023-06-09 16:43 153浏览
  • 是日高考,祝各位考生如愿。据前瞻产业研究统计数据显示,2022年中国共有相关传感器产业链企业50664家,中国智能传感器行业企业共有16875家。其中,直接从事传感器生产制造研发的企业仅有不到2000家,这里面大部分都是小微企业。据传感器专家网统计,目前,整个中国股市,仅有约64家国产传感器概念企业上市,总市值超1万亿元。其中,仅2022年以来,就有14家传感器企业上市,中国传感产业风起云涌。传感器专家网https://www.sensorexpert.com.cn专注于传感器技术领域,致力于对
    传感器专家网 2023-06-07 20:00 220浏览
  • 近年来,伴随着智慧化港口的大潮流,经纬恒润L4高级别智能驾驶业务产品也陆续扎根港口自动驾驶多个项目中,帮助港口实现无人水平运输自动化,达到降本增效的效果,助力客户实现智慧化绿色港口。   在整个港口水平运输场景中,经纬恒润提供了端到端的车、路、网、云、图全栈式自研解决方案,包含自动驾驶系统、路侧车路协同、基于5G网络的远程遥控驾驶、车队调度管理平台、数字孪生、仿真系统、高精地图等专业模块,组成了一套完整的智慧港口解决方案。本篇专门介绍其中的自动驾驶系统。  
    hirain 2023-06-09 11:29 189浏览
  • 电源适配器CE认证标准测试项目,电子产品现在用的是相当的广,常见的产品就一大堆,比如说手机电脑等都会使用到电源适配器。电源适配器适用范围很广,不仅在移动设备端,在其它领域也会应用到。电源适配器CE认证,一般会做CE认证中的低电压指令LVD和电磁兼容指令EMC,欧洲能效认证ERP,RoHS等。下面具体来看看认证这么做吧。电源适配器为什么要做CE认证?CE认证制度下的LVD低电压指令涵盖了交流50V-1000V,直流75V-1500V的所有带电产品,EMC指令涵盖了所有有电路板产生电磁辐射的带电产品
    陈丽莎 2023-06-08 14:09 246浏览
  • 苹果如何重新定义AR?在如今以智能手机为主的消费电子市场下行阶段,市场急需开辟一个新的领域带来新的增长点,以往被寄予厚望的VR/AR等头显设备在经历了数年发展后,依旧难堪大任,业界都把希望寄托在苹果身上。简单来说,Vision Pro本质上其实还是VR设备,不过所有操作界面可以结合头显摄像头捕捉的外界环境,在头显内部显示出来,即一款数字内容无缝融入真实世界的VR显示设备。同时Vision Pro的操作方式无需手柄,完全通过眼睛、双手和语音,通过苹果为Vision Pro打造的空间操作系统Visi
    华秋商城 2023-06-08 10:32 150浏览
  • 在过去的20年,传感器厂商不断研究创新的测量原理和敏感材料,这些成果能让我们用到高集成、低成本的传感器,其中,最成功也是最具颠覆性的,无疑是MEMS技术在传感器制造中的应用。MEMS技术在传感器的大规模应用,让传感器的小型化、低功耗、智能化成为可能,从而推动了传感器在物联网、消费电子、汽车电子等领域的广泛应用,促进了数字经济的发展和智能时代的到来。可以说,在过去20年,MEMS颠覆和扩展了传感器。传感器专家网https://www.sensorexpert.com.cn专注于传感器技术领域,致力
    传感器专家网 2023-06-08 19:28 206浏览
  • 低温型产品概述:霍尔效应测试仪由电磁铁、电磁铁电源、高精度恒流源、高精度电压表、霍尔效应样品支架、标准样品、高低温杜瓦,控温仪,系统软件组成。为本仪器系统专门研制的JH10效应仪将恒流源,六位半微伏表及霍尔测量复杂的切换继电器——开关组装成一体,大大减化了实验的连线与操作。JH10可单独做恒流源、微伏表使用。用途:用于测量半导体材料的载流子浓度、迁移率、电阻率、霍尔系数等重要参数,而这些参数是了解半导体材料电学特性必须预先掌控的,因此霍尔效应测试系统是理解和研究半导体器件和半导体材料电学特性必*
    锦正茂科技 2023-06-09 13:16 138浏览
  • 近日,一则长城汽车举报比亚迪的消息,瞬间刷爆了整个汽车圈,行业外对于这个事情多少有点懵,但业内对此却并不感到意外。如果说去年前年国内新能源汽车的“较量”,还是争夺入选资格的话,如今这种级别的“较量”,则进入了深层次的“叫阵厮杀”阶段。尤其是今年以来,伴随着各大头部新能源车企纷纷宣布降价售车,之前就已经熬不住的合资汽车,先行顶不住而宣布大力度降价,随后降价的浪潮开始席卷全行业,这给其他新能源车企也带来了巨大的压力。而在这种压力背后,行业共识也逐渐显现。油电同价背后的行业共识5月25日,比亚迪宋Pr
    刘旷 2023-06-08 10:04 256浏览
  • 前段时间出了接近一个月的差,没来得及及更新试用报告,有点不好意思,今天抽空过来写一下自己的看书的心得以及对于整个书籍的一些认知和看法,希望对大家能够有一定的帮助,也希望可以和大家一起探讨进步。以前自己都是使用的Altium Designer做开发设计的,大学的时候就开始接触,作为个人爱好延续至今,对于PADS也是有所耳闻,只是一直没有机会来了解,根据我个人的经验来看,按照以前使用Altium 的经验来说,PADS设计指南 无论说是从流程步骤上以及类容的细致程度上都还是很不错的,从设计流程、原理图
    君莫笑啊 2023-06-08 11:21 216浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦