嵌入式C语言(入门必看)

2023-05-16

     

目录

STM32的数据类型

const关键字

static 关键字

volatile关键字

extern关键字

 struct结构体

enum

 typedef

#define

回调函数

#ifdef 、#ifndef、#else  、#if    


嵌入式开发中既有底层硬件的开发又涉及上层应用的开发,即涉及系统的硬件和软件,C语言既具有汇编语言操作底层的优势,又具有高级语言功能性强的特点,当之无愧地成为嵌入式开发的主流语言。在 STM32开发过程中,不论是基于寄存器开发还是基于库开发,深入理解和掌握嵌入式C语言的函数、指针、结构体是学习STM32的关键。
嵌入式C语言的结构特点如下。
(1)程序总是从main函数开始执行,语句以分号“;”结束,采用/*…*/或//做注释。

(2)函数是C语言的基本结构,每个C语言程序均由一个或多个功能函数组成。

(3) 函数由两部分组成:说明部分和函数体。
 

  函数名(参数)
  {
      [说明部分];
      函数体;
  }

(4)一个C语言程序包含若干个源程序文件(.c文件)和头文件(.h文件),其中.h头文件主要由预处理命令(包括文件、宏定义、条件编译等)和数据声明(全局变量、函数等声明)组成;c源文件主要是功能函数的实现文件。
(5)采用外设功能模块化设计方法,一个外设功能模块包括一个源文件(.c文件)和一个头文件(.h文件),.c文件用于具体外设功能模块函数的实现,.h头文件用于对该外设功能模块参数及功能函数的声明。
      嵌入式系统开发多采用模块化、层次化的设计思想,系统层次架构清晰,便于协同开发。图1为嵌入式系统的软件基本结构框图。

                            图1 嵌入式系统的软件基本结构框架图

STM32的数据类型


数据是嵌入式C语言的基本操作对象,数据类型是指数据在计算机内存中的存储方式,如基本数据类型中的整型(存放整数)、浮点型(存放实数)、字符型(存放字符)、指针(存放地址)以及派生出的复合数据类型(如数组、结构体、共用体、枚举类型)。嵌入式C语言的数据类型如图2所示。

                                                     图二 嵌入式C语言的数据类型

      由于不同CPU定义的数据类型的长度不同,因此ARM公司联合其他半导体厂商制定了统一的CMSIS 软件标准,这个标准中预先定义了相关的数据类型,ST公司也为开发人员提供了基于C语言的标准外设库,其定义的数据类型如表1所示,相关源代码请参考STM32标准外设库v3.5.0的stdint.h头文件。
      stm32f10x.h头文件还对标准外设库之前版本所使用的数据类型进行了说明,v3.5.0版本已不再使用这些旧的数据类型,为了兼容以前的版本,新版本对其进行了兼容说明,如图3所示。

                                                  表1   STM32定义的数据类型
 

                                 图3  STM32标准外设库数据类型兼容说明

图3中的_I、_O以及_IO为IO类型限定词,内核头文件 core_cm3.h定义了标准外设库所使用的IO类型限定词,如表2所示。注意,IO类型限定词加下画线是为了避免命名冲突。
表1的数据类型与表2中的IO类型限定词相结合,在标准外设库中常用来定义寄存器和结构体变量,图4为stm32f10x.h头文件中相关外设的寄存器定义。

                                                表2   STM32的IO类型限定词

                                              图4 stm32f10x.h头文件中相关外设的寄存器定义

       结合表2和图3,可以看出同一数据类型有多种表示方式,如无符号8位整型数据有unsigned char、uint8_t、u8三种表示方式,在不同的ST标准外设库版本中这三种表示方式都可以表示无符号8位整型数据,初学者应了解这三种表达方式,最新的v3.5.0版本采用 CMSIS软件标准的C99标准,即 uint8_t方式。

const关键字

      const关键字用于定义只读的变量,其值在编译时不能被改变,注意,const关键字定义的是变量而不是常量。
      使用 const关键字是为了在编译时防止变量的值被误修改,同时提高程序的安全性和可靠性,一般放在头文件中或者文件的开始部分。
      在C99标准中,const关键字定义的变量是全局变量。const 关键字与#definc关键字存在区别,#define关键字只是简单的文本替换,而const关键字定义的变量是存储在静态存储器中的。使用#define关键字定义常量的形式为

#define PI3.14159


      使用该方式定义后,无论在何处使用PI,都会被预处理器以3.14159替代,编译器不对PI进行类型检查,若使用不慎,则很可能由预处理引入错误,且这类错误很难发现。用const声明变量的方式虽然增加了分配空间,但可以很好地消除预处理引入的错误,并提供了良好的类型检查形式,保证安全性。
利用 const关键字进行编程时需要注意以下三点。
(1)使用const关键字声明的变量,只能读取,不能被赋值。如:

const uint8t sum = 3.14;
uint8_t abs=0;

...
sum= abs;//非法,将导致编译错误,因为sum 只能被读取,不能赋值
abs- sum: //合法


(2) const关键词修饰的变量在声明时必须初始化,上述语句表示 sum值是3.14,且sum值在编译时不能修改,若在编译过程中直接修改sum值,则编译器会提示出错。
(3)函数的形参声明为const,则意味着所传递的指针指向的内容只能读,不能被修改。如C语言的标准函数库中用于统计字符串长度的函数 int strlen(const char*str)。


static 关键字

      在嵌入式C语言中,static关键字可以用来修饰变量,使用static关键字修饰的变量,称为静态变量。
      静态变量的存储方式与全局变量一样,都是静态存储方式。全局变量的作用范围是整个源程序,当一个源程序由多个源文件组成时,全局变量在各个源文件中都是有效的,即一个全局变量定义在某个源文件中,若想在另一个源文件中使用该全局变量,则只需要在该源文件中通过 extern关键字声明该全局变量就可以使用了。若在该全局变量前加上关键字static,则该全局变量被定义成一个静态全局变量,其作用范围只在定义该变量的源文件内有效,其他源文件不能引用该全局变量,这样就避免了在其他源文件中因引用相同名字的变量而引发的错误,有利于模块化程序设计。
      利用static关键字进行编程时需要注意以下要点。
      (1)static关键字不仅可以用来修饰变量,而且可以用来修饰函数。模块化程序设计中,若用static声明一个函数,则该函数只能被该模块内的其他函数调用,例如:
 

      #include "stm32f1xx_hal .h”
      static void DMA_SetConfig (DMA_HandleTypeDef *hdma,uint32_t SrcAddress,uint32_t DstAddress, uint32_t DataLength);
...
      HAL_statusTypeDef HAL_DMA_start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
      HAL_StatusTypeDef status- HAL_OK;”
.... ...
      if(HAL_DMA_STATE_REA.DY m- hdma->state)
  {
        DMA_Setconfig(hdma, SrcAddress, DstAddress, DataLength);
       ... ...
  }
      ... ...
}

 上述代码为DMA模块的源文件stm32f1xx_hal_dma.c,若利用static将DMA_SetConfig()函数声明为一个静态函数,则 DMA_SetConfig)函数只能被stm32flxx_hal_dma.c中的其他函数调用,而不能被其他模块的文件使用,即定义了一个本地函数,有效避免了因其他模块的文件定义了同名函数而引发的错误,充分体现了程序的模块化设计思想。
(2) static除了用于定义静态全局变量,还用于定义静态局部变量,保证静态局部变量在调用过程中不被重新初始化。典型应用案例有实现计数统计功能。

void fun_count()
{
      static count_num=0;
      //声明一个静态局部变量,count_num用作计数器,初值为0
      count_num++;
      printf("%d\n",count_num) :
}
int main(void)
(
     int i=0;
     for( i=0;i<=5;i++)
  {
     fun_count();
  }
     return 0;
}

在main函数中每调用一次 fun_count()函数,静态局部变量count_num加1,而不是每次都被初始化为初值0。


volatile关键字


      嵌入式开发中,常用到volatile关键字,它是一个类型修饰符,含义为“易变的”。使用方式如下:

volatile char i;


      这里使用volatile关键字定义了一个字符型的变量i,指出i是随时可能发生变化的,每次使用该变量时都必须从i的地址中读取。
      由于内存的读/写速度远不及CPU中寄存器的读/写速度,为了提高数据信息的存取速度,一方面在硬件上引入高速缓存Cache,另一方面在软件上使用编译器对程序进行优化,将变量的值提前从内存读取到CPU的寄存器中,以后用到该变量时,直接从速度较快的寄存器中读取,这样有利于提高运算速度,但同时也可能存在风险,如该变量在内存中的值有可能被程序的其他部分(如其他线程)修改或覆盖,而寄存器中存放的仍是之前的值,这就导致应用程序读取的值和实际变量值不一致;也有可能是寄存器中的值发生了改变,而内存中该变量的值没有被修改,同样也会导致不一致的情况发生。因此,为防止由于编译器对程序进行优化导致读取错误数据,使用 volatile关键词进行定义。
      简单地说,使用volatile关键字就是不让编译器进行优化,即每次读取或者修改值时,都必须重新从内存中读取或者修改,而不是使用保存在寄存器的备份。
      举个简单的例子:大学里的奖/助学金的发放一般都是直接转给学校,学校再发给每名学生,学校财务处都登记了每名学生的银行卡号,但不可避免地会有一些学生因各种原因丢失银行卡或不再使用这张银行卡,而没来得及去财务处重新登记,从而影响奖/助学金的发放,这里,学生就是变量的原始地址,而财务处的银行卡号就是变量在寄存器中的备份,使用 volatile关键字来定义学生这个变量,这样每次发放奖/助学金时都去找学生这个变量的原始地址,而不是直接转到财务处保存的银行卡上,进而避免错误的发生。
       const关键字的含义为“只读”,volatile关键字的含义为“易变的”,但volatile关键字解释为“直接存取原始内存地址”更为合适,使用 volatile关键字定义变量后,该变量就不会因外因而发生变化了。一般来说,volatile 关键字常用在以下场合。
     (1)中断服务程序中修改的、供其他程序检测的变量需要使用volatile关键字。

     (2)多任务环境下各任务间共享的标志应添加 volatile关键字。

  (3)外设寄存器地址映射的硬件寄存器通常要用volatile关键字进行声明。


extern关键字


       extern关键字用于指明此函数或变量定义在其他文件中,提示编译器遇到此函数或变量时到其他模块中寻找其定义。这样,extern关键字声明的函数或变量就可以在本模块或其他模块中使用,因此,使用extern关键字是一个声明而不是重新定义。使用方法如下:

extern int a;
extern int  funA( ):


      解析:第一条语句仅仅是变量a的声明,而不是定义变量a,并未为a分配内存空间,变量a作为全局变量只能被定义一次。第二条语句声明函数funA(),此函数已在其他文件中定义。
       STM32中,extern关键字还有一个重要作用,即与"C一起连用,即 extern "c",进行链接指定。例如,stm32f10x.h头文件中有如下代码。

#ifndef _STM32F10× H
#define _STM32F10x_H
#ifdef .epluspius
extern "C"{
#endif
...
#ifdef _eplusplus
}
"endif

       这段代码的含义是,若没有定义_STM32F10x_H,则定义_STM32F10x H,若已经定义_cplusplus,则执行 extern "C"中语句,extern "C"是告诉C++编译器括号中的程序代码是按照C语言的文件格式进行编译的,_cplusplus是C++编译器中自定义的宏,plus是“+”的意思。
C+H+支持函数重载,即在编译时会将函数名与参数联合起来生成一个新的中间函数名称,而C语言不支持函数重载,这就导致在C++环境下使用C函数会出现链接时找不到对应函数的情况,这时就需要使用extern "C"进行链接指定,告知编译器此时采用的是C语言定义的函数,需要使用C语言 的命名规则来处理函数,不要生成用于链接的中间函数名。
       一般将函数声明存放在头文件中,当函数有可能被C语言或C+使用时,将函数声明存放在 extern "C"中以免出现编译错误,完整的使用方法如下:
 

#ifdef__cplusplus
   extern "C"{
    #endif
   //函数声明
    #ifdef_Cplusplus
     }
#endif

       STM32中很多头文件都采用这样的用法,如标准外设库中的 stm32f1 0x_adc.h ,stm32f10x can.h、 stm32f1Ox_gpio.h 等。
      利用extern 关键字进行编程时需要注意以下要点。
      嵌入式开发一般采用模块化设计思想,因此,为保证全局变量和功能函数的使用,extern关键字一般用在.h头文件中对某个模块提供给其他模块调用的外部函数及变量进行声明,实际编程中只需要将该.h头文件包含进该模块对应的.c文件中,即在该模块的.c文件中加入代码#include "xxx.h”。实例如下:

 struct结构体

      struct用于定义结构体类型,其作用是将不同数据类型的数据组合在一起,构造出一个新的数据类型。struct一般用法如下:

 struct  结构体名
	{
	 数据类型   成员名1;
	 数据类型   成员名2;
	 数据类型   成员名n;
	 };
struct Student{         //声明结构体
    char name[20];      //姓名
    int num;            //学号
    float score;        //成绩
};

enum

       有时一个变量会有几种可能的取值,如一个星期有7天、每学期开设的课程、12种不同的颜色(红、橙、黄、绿、青、蓝、紫、灰、粉、黑、白、棕)等,C语言提供了一种enum枚举类型,用来将变量或对象的所有可能的值一一列出,变量取值只限于列举出来的值。enum枚举类型的用法如下:
 

enum枚举名
{
枚举成员1,
枚举成员2,
...
枚举成员n;
}枚举变量;

      enum枚举类型是一个集合,将所有可能的取值用花括号括住,花括号中的各枚举成员之间用逗号隔开,最后一个枚举成员后省略逗号。enum枚举类型以分号结束,这里的枚举变量可以省略,在后面需要时再根据枚举名进行定义。
例如,利用enum枚举类型列举几种常见的颜色。
 

enum Color
{
RED,
GREEN,
BLACK,
YELLOw
};

      上述名为 Color的枚举类型只有4个成员:RED、GREEN、BLACK、YELLOW,即意味着Color类型变量的取值只能取这4种颜色中的某一种颜色。
      例如,利用enum定义一个 Weekdays枚举类型名,包括7个枚举成员:从星期一到星期日,并定义枚举变量 Mydays 与 Olddays.

enumweekdays
{
Monday=1,
Tuesday,
wednesday,
Thursday,
Friday,
Saturday,
sunday
}Mydays.olddays;

      注意:enum枚举类型具有自动编号功能,第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员值上自动加1,也可以自定义枚举成员的值,若把第一个枚举成员的值定义为1,则第二枚举成员的值就为2,依此类推,如上述例子中 Friday 的值为5。因此,enum枚举类型中的枚举成员的值是常量而不是变量,不能在程序中用赋值语句再对它赋值,但可以将枚举值赋给枚举变量。
例如,以下两条语句是正确的。

Mydays=Thursday;
olddays=Friday;


      但以下两条语句是错误的。

Tuesday=o;
Mydays=1;

 typedef

      typedef用于为复杂的声明定义一个简单的别名,它不是一个真正意义上的新类型。在编程中使用 typedef的目的一般有两个:①为变量起一个容易记忆且意义明确的新名称;②简化一些比较复杂的类型声明。其基本格式如下:
typedef类型名自定义的别名;
例如:

typedef signed char int8_t;//为数据类型signed char起别名int8_t
typedef signed int int32_t;//为数据类型signed int起别名int32_t


      STM32开发中,typedef主要有以下三种用法。
      1. typedef的基本应用
      为已知的数据类型起一个简单的别名,如上例。
      2. typedef 与结构体struct结合使用
      该用法用于自定义数据类型。如 stm32f10x_gpio.h头文件中的GPIO初始化结构体GPIO_InitTypeDef。

typedef struct
{
   uint16_t GPIO_ Pin;
   GPIOSpeed_TypeDef GPIO_Speed;
   GPIOMode TypeDef GPIO_Mode;
}IGPIo_InitTypeDef;


       上述语句利用 struct创建了一个新的结构体,这个新结构体有三个成员 GPIO_Pin、GPIO_Speed和 GPIO_Mode,同时又使用 typedef为这个新建的结构体定义一个新的名称GPIO_InitTypeDef,在应用时就可以直接使用GPIO_InitTypeDef 来定义变量。例如:

GPIO_InitTypeDef GPIO_ InitStrueture;


       上述语句利用 GPIO_InitTypeDef结构体定义了一个变量GPIO_InitStructure,引用三个成员的方法如下:

GPIO InitStructure.GPIO_Pin;
GPIO_InitStructure.GPIO_Speed;
GPIO InitStructure.GPIO Mode;

3. typedef 与 enum结合使用
      利用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明,STM32标准外设库v3.5.0版本中有很多enum和 typedef结合使用的应用。stm32f10x_gpio.h头文件中的代码如下。

Typedef enum
{
GPIO Speed_1OMHz=1,
GPIo_Speed_2MHz,
GPIOSpeed_50MHz;
}GPIOSpeed_TypeDef;


       该例中enum枚举类型共有三个成员:GPIO Speed_10MHz、GPIO Speed_2MHz和GPIO_Speed_50MHz,并将第一个枚举成员GPIO_Speed_10MHz赋值为1,enum枚举类型会将枚举成员的赋值在第一个枚举成员赋值的基础上加1,因此GPIO_Speed_2MHz 默认值为2,GPIO_Speed_50MHz默认值为3。同时,利用typedef关键字将此枚举类型定义一个别名GPIOSpeed TypeDef,这里省略了枚举类型的枚举名,只用 typedef为枚举类型定义一个别名。


#define

      #define是C语言的预处理命令,它用于宏定义,用来将一个标识符定义为一个字符串,该标识符称为宏名,被定义的字符串称为替换文本,采用宏定义的目的主要是方便程序编写,一般放在源文件的前面,称为预处理部分。
      所谓预处理是指在编译前所做的工作。预处理是C语言的一个重要功能,由预处理程序负责完成,程序编译时,系统将自动引用预处理程序对源程序中的预处理部分进行处理,处理完毕后自动进入对源程序的编译。
      STM32标准外设库中,#define的使用方式主要有以下两种。
1.无参数宏定义
无参数宏定义的一般形式如下:

#define<宏名>字符串>


其中,字符串可以是常数、字符串和表达式等。
       例如:#define UINT8_MAX 255
       该语句表示定义了宏名UINT8_MAX,它代表255,例如:#define_IO volatile;
       该语句表示定义宏名_IO,代表 volatile,若以后程序中再需要用到 volatile,则可以使用IO。
       例如:#define RCC AHBPeriph_DMA1 ((uint32_t)0x00000001)
       该语句表示定义RCC_AHBPeriph_DMA1宏名,代表32位的无符号数据0x00000001.

       STM32中有很多此类用法,如标准外设库 v3.5.0的 stm32f1 0x_rcc.h文件中APB2_peripheral外设基地址的定义,如图5所示。

                          图5  APB2_peripheral各外设基地址的定义

2.带参数的宏定义
宏定义格式如下:

#define<宏名>(参数1,参数2,…,参数n)<替换列表>

例如:

define SUM(x,y) (x+y)
…
a=SUM(2,2):


其中,a的结果是4,将 SUM(X,y)定义为x+y,预编译时会将SUM(x,y)替换为xty。
例如:

#define IsGPIO_SPEED(SPEED)(((SPEED) = GP1o_Speed_10MHz)||((SPEED)==GPIO_Speed_ 2MHz)||((SPEED)==GP10_Speed_50MHz))


使用宏定义#define 将 IS_GPIO_SPEED(SPEED)替换为 GPIO_Speed_10MHz、GPIO_Speed_2MHz或者GPIO_Speed_50MHz。
      注意:带参数的宏定义同样也只是进行简单的字符替换,替换是在编译前进行的,展开并不分配内存单元,不进行值的传递处理,因此替换不会占用运行时间,只占用编译时间,因此该方式可以提高运行效率。
       #define与 typedef的区别为:typedef是在编译阶段处理的,具有类型检查的功能,而#define是在预处理阶段处理的,即在编译前,只进行简单的字符串替换,而不进行任何检查。


回调函数

       回调函数是一个通过函数指针调用的函数。操作系统中的某些函数常需要调用用户定义的函数来实现其功能,由于与常用的用户程序调用系统函数的调用方向相反,因此将这种调用称为回调(Callback),而被系统函数调用的函数就称为回调函数。
      STM32的HAL库在stm32flxx_hal_xxx.c文件中定义了相应的回调函数,并由中断触发,其实质是中断处理程序。如 stm32flxx_hal_gpio.c代码中通过GPIO中断处理函数voidHAL _GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)调用相应的回调函数HAL_GPIO_EXTICallback(GPIO_Pin),开发人员只需要在回调函数中编写应用程序就能实现中断服务功能。

#ifdef 、#ifndef、#else  #if    


#define            定义一个预处理宏
#undef            取消宏的义
 #if                  编译预处理中的条件命令,相当于C语法中的if语句
#ifdef              判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef            与#ifdef相反,判断某个宏是否未被定义
#elif                若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
#else              与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
#endif             #if, #ifdef, #ifndef这些条件命令的结束标志.
defined          与#if, #elif配合使用,判断某个宏是否被定义

指针相关内容我这里就不在赘述了网上有很多丰富的资料。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式C语言(入门必看) 的相关文章

  • python 类变量详解

    强烈建议先看我之前的面向对象基本了解 python中 xff0c 类变量又叫做类属性 然而类属性有分为3个不同的类型 类属性 xff0c 实例属性 xff0c 局部变量 class a 类属性 hobby 61 39 play sport
  • Python运行环境Ngrok内网穿透

    这次就教大家怎么在手机或机顶盒上运行Ngrok内网穿透 首先下载安卓上的Python运行环QPython apk 官网 http www qpython com 下载完后开始安装 xff0c 怎么安装安卓软件不用我怎么教了吧 复制pytho
  • 记一次PWN机(Vmware和Docker+VNC)的搭建

    基于Vmware搭建虚拟机 学长已经提供了镜像 xff0c 在Vmware界面打开那个镜像 xff0c 开机即可 Vmware和镜像下载地址 xff1a 链接 xff1a https pan quark cn s 057a23e631f5
  • vue.runtime.esm.js?2b0e:619 [Vue warn]: Invalid prop: type check failed for prop “index“. Expected S

    vue runtime esm js 2b0e 619 Vue warn Invalid prop type check failed for prop 34 index 34 Expected String with value 34 1
  • 解决vscode上边菜单栏不显示的问题

    由于我们不小心点击了哪个键 xff0c 导致上边的菜单栏不显示 两种解决方案 方法一 xff1a 点击下面的这个按钮 xff0c 会弹出一个弹框 点击一下菜单栏的可见性 xff0c 即可出来 方式二 xff1a 使用快捷键Ctrl 43 S
  • node+vue搜索和分页功能实现

    前端代码 lt template gt lt div class 61 34 main box 34 gt lt 卡片区 gt lt el card gt lt 搜索 gt lt el input placeholder 61 34 请输入
  • React面试题最全

    1 什么是虚拟DOM xff1f 虚拟DOM是真实DOM在内存中的表示 xff0c ul的表示形式保存在内存中 xff0c 并且与实际的DOM同步 xff0c 这是一个发生在渲染函数被调用和元素在屏幕上显示的步骤 xff0c 整个过程被称为
  • vue项目页面空白但不报错产生的原因分析

    vue项目中我们请求一个路由 xff0c 打开页面发现页面是空白的 xff0c 产生的主要原因有四种 xff1a 1 路由重复 如果配置了两个路由是重复的 xff0c 比如配置了两个 path xff0c 那么访问就会看到空白页面 xff0
  • react--电商商品列表使用

    目录 整体页面效果 项目技术点 拦截器的配置 主页面 添加商品 分页 xff0c 搜索 修改商品 删除商品 完整代码 整体页面效果 项目技术点 antd组件库 xff0c 64 ant design icons antd的图标库axios
  • 服务器端升级或者切换node版本

    1 查看版本 nvm list 2 选择你需要的版本 nvm use v18 15 0
  • lodash防抖节流

    应用场景 xff1a 当用户高频率的触发事件 xff0c 事件较短 xff0c 内部出现卡顿现象 解决方法 xff1a 防抖节流 防抖节流功作用 xff1a 主要目的是为了降低高频事件触发 xff0c 减少dom操作或请求次数 xff0c
  • 使用webpack(4版本)搭建vue2项目

    在学习webpack之前 xff0c 也从网上搜过一些用webpack搭建vue项目的博客 xff0c 但是在自己使用的时候会报各种的问题 xff0c 报错的根本原因其实就是版本的问题 xff0c 以下代码是经过解决了许多报错问题研究出来最
  • VUE调用摄像头PC

    页面效果 实现代码 lt template gt lt div id 61 34 app 34 gt lt router view gt lt 开启摄像头 gt lt Button type 61 34 primary 34 64 clic
  • koa2的脚手架koa-generator使用

    我们在搭建项目的时候 xff0c 会使用一些脚手架 xff0c 今天我们使用koa2的脚手架koa generator 使用非常简单 首先 xff0c 我们需要全局安装 npm install g koa generator 创建项目 ko
  • css行内元素、块元素、行内块元素的区别

    行内元素的特点 xff1a 1 和其他元素在一行显示 2 元素的宽度 高度 行高及底部边距不可编辑 3 元素的宽度就是它包含的文字或图片的宽度 xff0c 不可改变 4 行内元素只能容纳纯文本或者是其他的行内元素 xff08 a标签除外 x
  • STM32CubeMX安装

    一 STM32CubeMX下载 官网地址 xff1a STM32CubeMX STM32Cube初始化代码生成器 意法半导体STMicroelectronics 官网下载需要注册账号 网盘链接 xff08 6 8 xff09 xff1a 链
  • 关于汇编指令sar右移32位的情况,记录一下

    网上 对sar指令右移超过31位的情况 比如右移32位 右移33位 很少有详细的说明 为了防止下一次还有像我这样傻x的人不会 我就记录一下 我不会过多说基础 基础了解就行 xff0c 能懒就懒 1字节 sar 我们以一字节为例子 00412
  • vs2022 汇编环境配置,xxx.inc头文件找不到,出现报错,不影响正常代码生成的解决方案

    解决方案前提 1 你的include和lib路径已经配置好了 然后代码可以正常的生成一个exe 2 安装了的AsmDube 其实inc文件找不到 是AsmDub找不到 不是vs2022找不到 所以你就去AsmDube修改一下 所以你只需要告
  • 关于8皇后解决方法的浅析

    关于8皇后解决方法的浅析 众所周知 xff0c 解决8皇后最普遍的方法是回溯法 那具体是怎么样的呢 xff1f 大概思路 xff1a 定义一个int型数组queen xff0c 角标 1 2 7 代表皇后所在的行 xff0c 值代表皇后所在
  • Latex闲谈

    关于latex呢 xff0c 首先它是一个排版工具 xff0c 是一个将文章排版和文章内容分开的一个排版工具 有个问题是你是边写边排版呢还是用word写完之后再来说是进行这个排版呢 xff0c 对于我而言 xff0c 我更倾向于后者 xff

随机推荐

  • Linux下phpmyadmin忘记root的登录密码,找回方法

    第一步 xff1a 执行 etc init d mysql stop 结束当前正在运行的mysql进程 第二步 xff1a 执行 usr bin mysqld safe skip grant tables 用mysql安全模式运行并跳过权限
  • matlab郭彦甫-听课笔记-02

    可以分块 xff0c 分块之后可以进行分块执行run section 关系运算符 xff1a 61 不等于 取余函数 xff1a mod a b rem a b switch case case case otherwise 连乘函数 xf
  • 51单片机硬件介绍

    1 单片机是啥 单片机 xff0c 简称MCU xff0c 是微型计算机 xff0c 集成了一部计算机许多硬件功能 xff0c 有CPU 存储器 xff08 ROM RAM xff09 等 2 有了这样一个单片机芯片后 xff0c 怎么将程
  • matlab硬件支持包离线安装-(安装文件夹错误)

    dSupport Software Downloader MATLAB amp Simulinkhttps ww2 mathworks cn support install support software downloader html
  • 小结:卸载SolidWorks2018->重新安装系统->安装SolidWorks2020

    因为卸载SW2018卸载不干净 xff0c 所以在安装SW20版一直在出错 xff0c 错误如下 xff1a 这个错误解决后继续安装 xff0c 又发现没有出现原本序列号的那一界面 xff0c 然后还有异型孔向导安装不了 xff0c 最后还
  • FreeRTOS信号量 基于STM32

    目录 概述 一 信号量基本概念 1 二值信号量 2 计数信号量 3 互斥信号量 4 递归信号量 二 二值信号量运作机制 三 计数信号量运作机制 四 常用信号量函数接口讲解 1 创建二值信号量 xSemaphoreCreateBinary 2
  • FreeRTOS互斥量 基于STM32

    文章目录 一 互斥量基本概念 二 互斥量的优先级继承机制 三 互斥量应用场景 四 互斥量运作机制 五 互斥量函数接口讲解 1 互斥量创建函数 xSemaphoreCreateMutex 2 递归xSemaphoreCreateRecursi
  • FreeRTOS事件组 基于STM32

    概述 文章对事件组的 xff0c 应用场景 xff0c 运作机制 xff0c 以及事件的创建 xff0c 删除 xff0c 等待 xff0c 置位 xff0c 同步等操作 文章目录 概述 一 事件标志组简介 1 事件位 事件标志 2 事件组
  • FreeRTOS任务通知 基于STM32

    文章目录 一 任务通知简介 二 任务通知的运作机制 三 任务通知的函数接口讲解 1 xTaskGenericNotify 2 xTaskNotifyGive 3 vTaskNotifyGiveFromISR 4 xTaskNotify 5
  • FreeRTOS软件定时器 基于STM32

    文章目录 一 软件定时器的基本概念 二 软件定时器应用场景 三 软件定时器的精度 四 软件定时器的运作机制 五 软件定时器函数接口讲解 1 软件定时器创建函数 xTimerCreate 2 软件定时器启动函数 xTimerStart 3 软
  • FreeRTOS内存管理 基于STM32

    目录 一 内存管理的基本概念 二 内存管理的应用场景 三 heap 4 c 1 内存申请函数 pvPortMalloc 2 内存释放函数 vPortFree 四 内存管理的实验 五 内存管理的实验现象 一 内存管理的基本概念 在计算系统中
  • 关于ECSHOP模板架设的服务器php版本过高报错的解决方法集合

    1 admin index php admin sms url php ECSHOP模板 报错 xff1a Strict Standards mktime You should be using the time function inst
  • FreeRTOS中断管理 基于STM32

    文章目录 一 异常与中断的基本概念 二 中断的介绍 三 和中断相关的名词解释 四 中断管理的运作机制 五 中断延迟的概念 六 中断管理的应用场景 七 中断管理讲解 八 中断管理实验 九 中断管理实验现象 一 异常与中断的基本概念 异常是导致
  • 链表基础知识详解(非常详细简单易懂)

    概述 xff1a 链表作为 C 语言中一种基础的数据结构 xff0c 在平时写程序的时候用的并不多 xff0c 但在操作系统里面使用的非常多 不管是RTOS还是Linux等使用非常广泛 xff0c 所以必须要搞懂链表 xff0c 链表分为单
  • FreeRTOS临界段的保护

    什么是临界段 临界段用一句话概括就是一段在执行的时候不能被中断的代码段 在 FreeRTOS 里面 xff0c 这个临界段最常出现的就是对全局变量的操作 xff0c 全局变量就好像是一个枪把子 xff0c 谁都可以 对他开枪 xff0c 但
  • SPI通讯协议详解 基于STM32

    SPI 协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议 Serial Peripheral Interface xff0c 即串行外围设备接口 xff0c 是 一种高速全双工的通信总线 它被广泛地使用在 ADC LCD 等设备与 MC
  • C语言编译过程

    C语言的编译过程 xff1a 预处理 编译 汇编 链接 gcc E hello c o hello i 1 预处理 gcc S hello i o hello s 2 编译 gcc c hello s o hello o 3 汇编 gcc
  • C语言数组详解

    目录 一 数组的概念 二 数组的分类 2 1 按元素的类型分类 2 2 按维数分类 三 数组的定义 3 1 一维数组的定义 格式 xff1a 3 2 二维数组的定义 四 定义并初始化 4 1 一维数组的初始化 4 2 二维数组的初始化 五
  • C语言动态分配内存

    文章目录 一 动态分配内存的概述 二 静态分配 动态分配 三 动态分配函数 3 1 malloc 3 2 free 3 3 calloc 3 4 realloc 四 内存泄漏 一 动态分配内存的概述 在数组一章中 xff0c 介绍过数组的长
  • 嵌入式C语言(入门必看)

    目录 STM32的数据类型 const关键字 static 关键字 volatile关键字 extern关键字 struct结构体 enum typedef define 回调函数 ifdef ifndef else if 嵌入式开发中既有