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

article/2025/8/22 21:35:05

     

目录

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用作计数器,初值为0count_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__cplusplusextern "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配合使用,判断某个宏是否被定义

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


http://chatgpt.dhexx.cn/article/jBYDmQjt.shtml

相关文章

用单层感知器完成逻辑或运算的学习过程

用单层感知器完成逻辑或运算的学习过程 这道题目是我“认知科学”&#xff08;专业必修/doge&#xff09;课程的结课作业题之一&#xff0c;目的在于加深对单层感知器的理解&#xff0c;对于后续学习神经网络打下基础。 有关知识&#xff1a; B站有关视频 单层感知器的学习过…

python中逻辑运算_【多选题】Python 中用于表示逻辑与、逻辑或、逻辑非运算的关键字分别是( ) A. and B. add C. or D. not...

【多选题】Python 中用于表示逻辑与、逻辑或、逻辑非运算的关键字分别是( ) A. and B. add C. or D. not 更多相关问题 A.He has been asked to join the committee.B.There are several new people on the c A.fill inB.equipC.fitD.prove A.encounterB.discernC.seeD.fre…

逻辑运算符简介, 逻辑与,逻辑或,逻辑非和逻辑运算符里的短路运算规则

1&#xff0c;逻辑与 && 符号两边都为true&#xff0c;结果才为true 一假则假 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"…

R语言的逻辑与、逻辑或和元素逻辑与、元素逻辑或的区别

版权声明&#xff1a;转载请注明作者&#xff08;独孤尚良dugushangliang&#xff09;出处&#xff1a;https://blog.csdn.net/dugushangliang/article/details/116463648 参阅&#xff1a;https://www.runoob.com/r/r-basic-operators.html 下图为R运行结果。首先对a、b赋值&a…

Java逻辑操作符——逻辑非、逻辑与、逻辑或和逻辑异或

先上一段java代码&#xff0c;通过具体例子来理解抽象概念 public class 布尔值 {public static void main(String[] args) {boolean 逻辑非的值_测试1 true;boolean 逻辑非的值_测试2 false;System.out.println("逻辑非的值_测试1:"!逻辑非的值_测试1);System.ou…

逻辑与和按位与、逻辑或和按位或的区别

首先分别明确一下他们各自的概念。 按位与和按位或 按位与和按位或都属于位操作符。 注意&#xff1a;位操作符的操作数必须是整数。 按位与“&” 按二进制位对应的位进行与运算&#xff0c;对应位都为1时&#xff0c;结果才为1 3&5 3的二进制&#xff1a; 00000…

JS中的逻辑与和逻辑或

JS中的逻辑或||符号&#xff1a; 从字面上来说&#xff0c;只有前后都是 false 的时候才返回 false&#xff0c;否则返回 true。 console.log(5 > 6|| 6 > 5) //返回true5>6为false 但是 6>5为true 所以返回 true 总结&#xff1a;一真为真 特殊运算方法&#xff…

逻辑或( || )和逻辑与( )的关系

逻辑或&#xff0c;符号为“||”&#xff0c;只有操作数都是假&#xff0c;结果才是假。&#xff08;全假才为假&#xff09; 逻辑与&#xff0c;符号为“&&”&#xff0c;只有操作数都是真&#xff0c;结果才是真。&#xff08;全真才为真&#xff09; 如下图&#xf…

计算机逻辑与 或 非的表达式,计算机算数和,逻辑与,逻辑或,逻辑非分别是什么意思...

蔷祀的回答: 1、算术和:算术和就是所有的加数都是非负的(整数或0)得到的和。 2、逻辑与:逻辑与即1101 & 0100,就是按位相与,与的概念可以同俗的理解为,一个电路有两个串联的开关,只有同时关闭两个开关电路才通,打开任意一个开关电路都不通,所以那两个数逻辑与的结…

逻辑与(),逻辑或(||),and(),or(|)

一、背景、 这四个逻辑运算符&#xff0c;大家都知道&#xff0c;但是有时候会凌乱&#xff0c;再者就是我自己想写一点基础的东西&#xff0c;巩固一下自己&#xff0c;也算是一种笔记&#xff0c;不但自己会了&#xff0c;还可以分享给大家一起学习。 二、目的、 巩固自己…

逻辑同或,逻辑异或,逻辑与,逻辑或

一、逻辑异或 真⊕假真 假⊕真真 假⊕假假 真⊕真假 或者为&#xff1a; True ⊕ False True False ⊕ True True False ⊕ False False True ⊕ True False 二、逻辑同或 相同为一&#xff0c;不同为零。 三、逻辑与 1.逻辑与&& 表示逻辑与的意思&#xff0…

按位或与逻辑或的区别

按位或&#xff08;|&#xff09;和逻辑或&#xff08;||&#xff09;的区别&#xff1a;逻辑或&#xff1a;逻辑或是三种逻辑运算符之一。 逻辑或相当于生活中的或者&#xff0c;当两个条件中有任一个条件满足&#xff0c;逻辑或的运算结果就为真。按位或&#xff1a;按位或运…

Axure8.0 注册码

我的Axure升级到8.1.0.3382&#xff0c;使用最后一个可用的&#xff01; 其他版本的小伙伴&#xff0c;请自行试验吧~ 升级了8.1.0.3377版本后&#xff0c;需要使用下面这组注册码 license&#xff1a;zdfans.com key&#xff1a;gP5uuK2gH iIVO3YFZwoKyxAdHpXRGNnZWN8Obn…

Axure下载安装-汉化-注册码

安装版本&#xff1a;8.1.0 一、下载、安装 链接&#xff1a;https://pan.baidu.com/s/1GbQKSn2aWnFOAkPsLITWQA 密码&#xff1a;qcf6 安装最后一步&#xff0c;不要点Run xxx 二、汉化 下载一个01053230.zip的压缩包&#xff0c;解压后把lang文件夹放到Axure的安装目录下…

RFID-RC522/STM32F103RB/KEIL5 简单实现读取卡片ID

文章目录 序章简单使用核心源码工程下载 序章 在这篇文章【 https://blog.csdn.net/qq_28877125/article/details/80437095 】的基础上修改完成&#xff01; 简单使用 1).环境配置 MCU芯片型号&#xff1a;STM32F103RB开发板&#xff1a;理论任何STM32开发板KIDE&#xff1…

STM32CubeMX(13)——SPI时序读写RFID-RC522

SPI时序读写RFID-RC522 目录 STM32 Cubemax(十三) ——SPI时序读写RFID-RC522 前言 一、SPI时序通信 二、模块接线 三.Cubemax配置 四.核心代码 延时函数 写RC522寄存器 读RC522寄存器 复位RC522 使用代码 1.复位 2.寻卡并得到其序列号 总结 前言 用RFID来学习一…

基于STM32+RC522设计的门禁系统

一、项目背景 门禁系统是现代社会中非常重要的安全控制系统之一,其功能是在保障建筑物安全的同时,为合法用户提供便利。当前设计一种基于STM32+RC522的门禁系统设计方案,通过RFID-RC522模块实现了对用户卡的注册、识别及身份验证,通过控制SG90舵机实现门锁的开关,具有较高…

硬件速攻-RC522射频模块

介绍 RC522是一种射频识别&#xff08;RFID&#xff09;模块&#xff0c;用于读取和写入基于ISO/IEC 14443 A/MIFARE协议的13.56MHz RFID标签。该模块可以通过SPI接口与微控制器进行通信&#xff0c;并支持多达25个字节的数据传输。 RC522模块包括一个天线、收发器、调制解调…

基础篇010.3 STM32驱动RC522 RFID模块之三:STM32软件模拟SPI驱动RC522

目录 1. 实验硬件及原理图 2. 利用STM32CubeMX创建MDK工程 2.1 STM32CubeMX工程创建 2.2 配置调试方式 2.3 配置时钟电路 2.4 配置时钟 2.5 配置GPIO 2.6 配置串口 2.7 项目配置 3. MDK工程驱动代码调试 3.1 按键、LED程序 3.2 SPI软件模拟程序 3.3 RC522驱动程序…

[STM32] Stm32f103c8t6+RC522 实现读卡写卡功能(超详细,零基础,小白)

本篇文章内容总结下来就是 读卡 使用默认密码读卡所有扇区所有块的数据写ID 使用默认密码读取卡一的0扇区的第一块数据并写入到卡二的0扇区的第一块里密码读卡 不同厂家的初始密码不同,整理了一些默认密码,如果有收集到新的也可以补充进去写全卡 …