- 博客(39)
- 收藏
- 关注
原创 常见的电源防反接电路
当输入的电压大于它的截止电压时,稳压二极管导通,输出电压等于稳压二极管的最大电压。当电源反接时,稳压二极管导通,稳压二极管的压降很小,输出的电压很小。PMOS管不导通再加上体二极管也是截止的状态,因此成功实现反接作用。当输入电压小于它的截止电压时,稳压二极管两边的电压等于输入的电压。电源反接时,电流无法通过PMOS管,因为源极没有电压。电源正接时,PMOS管的源极有电压,PMOS管导通。不管正接,还是反接,都能导通,这是整流桥的思路。稳压二极管有一个重要的特性,就是它的截止电压。2.稳压二极管防反接电路。
2025-11-16 12:32:54
225
原创 无源晶振和有源晶振最大的区别是什么?
无源晶振内部无振荡器,需要依靠外部电路(如MCU的振荡器)来进行工作。无源晶振和有源晶振最大的区别在于是否内置振荡器。有源晶振内置振荡器,直接通电就能够进行使用。
2025-11-04 17:00:33
112
原创 如何删除嘉立创EDA中多余的工程?
在日常使用嘉立创EDA的过程中,你会发现,你想要直接删除多余的无用的工程是不行的。如果遇到不能删除的情况,需要关闭嘉立创EDA软件,再次操作即可进行删除。打开工程的目录之后,选择我们想要删除的工程,直接进行删除即可。右键点击工程,我们会发现:并没有直接删除工程的这一个选项。右键工程,选择打开工程的目录。
2025-11-02 14:29:36
579
原创 新手小白如何使用字符串来控制LED的点亮与熄灭
第三步,在while(1)循环中,先接受字符串,再将字符串给发送出去(这一步主要是为了方便观察),然后使用strcmp函数进行字符串的比较,如果我们发送的字符串和strcmp函数的第二个参数相同,这个函数就会返回一个 ‘0’如果指向指向了换行符号,就让指针向后偏移一位,同时插入"\0"结束符号,代表字符串的结束。3.使用串口.h文件中的编程接口去接受一个字符,存储在*ch(对指针ch的解引用)中。1.首先我们是先定义一个函数,它的形参是我们想要接受字符串的首地址。第四步,执行对应的点灯和灭灯操作。
2025-11-02 11:23:32
165
原创 新手小白如何使用串口发送一个字符串
1.首先我们先定义一个函数,函数的形参是我们想要发送字符串的首地址,在这里面我们使用指针ch指向我们想要发送字符串的首地址。2.while(*ch),*ch是对指针的解引用,当指针所指向的字符串没有结束的时候,都会进入这个循环。第三点,一定要使能串口的时钟和关闭串口的开关,如果忘记了这两点中的任意一点,都会导致串口无法工作。ch是一个指针,这里面对指针所指向的位置进行偏移,指向字符串中的下一个字符。3.调用发送一个字节数据的函数,形参*ch是指针的解引用。又一个指针ch指向字符串的第一个字符。
2025-11-01 22:30:24
210
原创 新手写串口发送一个字符最容易犯的错误
USART的引脚模式配置。使用串口发送一个字符的代码。这里我们可以到ST的芯片手册中去寻找,找到外设的引脚配置这一个目录。4.不知道怎样编写串口发送一个字符的代码。2.使用串口.h文件中的函数发送一个字符。1.不知道串口的引脚配置为什么样的模式。2.忘记开启串口的时钟了。3.忘记闭合串口的开关了。这样也会导致串口无法工作。1.等待发送数据寄存器空。这样会导致串口无法工作。
2025-11-01 21:47:57
132
原创 如何通过芯片参考手册查看外设的引脚配置?
这里面有着各种各样外设的引脚应该如何配置的答案,通过浏览这一页,我们就能够得到我们想要的答案,这里面串口1的输出是复用推挽,输入可以是输入上拉或者输入浮空两种模式选择。打开芯片手册,在搜索框中输入GPIO,找到外设的GPIO配置这一选项。这里我们以查看串口引脚配置为例子。
2025-11-01 20:22:19
227
原创 单片机按键消抖
等待按键松开之后,才是真正的判断完一个按键状态的过程。这个时候再去执行其他的任务程序,实验现象才会稳定。按键消除抖动仅仅靠延时也会导致实验现象不明显。最后小编加入了一个等待按键松开的判断程序之后。小编最近在写按键消抖程序的时候发现,忽然就发现实验现象变得很稳定了。
2025-11-01 19:45:08
206
原创 关于联合体的一些知识
然后就是通过特定的类型比如:uint8_t b[4],uint16_t c[2],里面有着很多不同的类型定义。在main函数中定义联合体变量test,通过联合体变量test给联合体中的成员a。uint8_t b[4]的值是我们刚刚给uint32_t a赋予的值。联合体中定义了变量uint32_t a和数组uint8_tb[4]划分,分为了数据头,数据类型,数据长度,和空数组(有效数据部分)给其他的成员赋值,但是如果是两个不同类型的,不同的存储空间,比如,变量,数组,结构体,甚至位域等,这些都是不同的类型。
2025-07-10 15:55:05
450
原创 大小端模式如何影响位域中各成员的位序;位域的其他细节问题
再看看小端模式下的位域成员b,也是同样的道理,bit2<bit3<bit4。比如,看上图:在小端模式下,位域成员a的空间中,bit0(最低位)再看看大端模式下的位域成员a,bit1是高位,bit0是低位,大端模式下的位域成员b中,bit4是最高的位,因此它排在成员b。总结一下:大小端模式不会影响位域中成员的排列顺序,因为位域中。是没有什么影响的,但是大小端模式会影响位域中成员位序的排列。我们都知道,大小端模式对结构体和位域中的成员的排列顺序。在上面的示意图中,我们定义了一个位域,位域中的成员。
2025-07-10 13:23:56
368
原创 嵌入式中的“大小端”问题和位域的注意点
在前面的代表的是低地址,在后面的代表的是高地址,和高低字节的顺序正好相反。2.在位域的定义中,同一个类型域永远都是先定义低地址,然后地址。uint8_t这个类型的8位,可以看到每一个类型域中后面的数字。如果是低字节排在低地址,高字节排在高地址,那就是小端,如果是低字节排在高地址,高字节排在低地址,那就是大端,在这里面,0x12就是高字节,0X78就是低字节。它有两个类型域,这两个类型域中的成员都共同划分了。我们也讲了什么是低字节,高字节,低地址,高地址。所谓的大小端问题,就是字节在地址上的排布问题。
2025-07-09 23:37:27
264
原创 位操作配置STM32的端口模式;使用位域配置寄存器;使用位域的好处
在下面,我们将使用位域来操作寄存器,让PA15的端口模式为:输出推挽,输出速率50MHz。通过上面的代码,我们成功实现了PA15的端口模式为:输出推挽,输出速率50MHz。其实这是很浪费内存的(一个字节,有8个位,但是我们只使用到了其中的一个位)我们定义了这样的一个位域之后,就可以直接使用位域来操作我们的寄存器了。我们都知道,C语言中是没有位类型的,比如布尔类型这种典型的位类型。上面的这种方式呢,我们是使用位操作的方式去配置STM32的端口。最后使用这种类型的位域指针向位域中的一个成员CNF15赋值为0。
2025-07-09 22:54:25
1082
原创 Linux经典宏定义:container_of解析;GCC编译器中的typeof关键字
2.通过typeof获取member成员的类型 typeof (((type*)0)->member)通过这个结构体指针去访问member成员变量 (((type*)0)->member)// 使用关键字typeof获取x的类型用来定义变量y。// 相当于 int (*pfun)(int)4.(type*) 将计算出来的地址转换成指向type类型的结构体的指针;typeof(var) // 获取变量的类型,变量的类型是它本身的类型。typeof(fun()) // 获取函数的类型,类型为返回值加上参数。
2025-07-09 17:07:44
441
原创 结构体的嵌套如何赋初值;数组局部赋初值;Linux宏解析
"."+结构体变量名 = {"."成员名字 = 要赋的初值,,},2.通过TYPE类型的结构体指针0去访问结构中的成员MEMBER (TYPE*)0->MEMBER。首先是我们先定义了两个结构体,然后第二个结构体中有我们第一个结构体的结构体变量,我想要给下面的这个数据的第5,6,7号元素赋初值为10,其他为0。MEMBER(结构体成员)只给第一个元素赋了初值,因此其他剩下的九个元素的初值都是为0。在这个数组中,有10个元素的空间,但是我们在赋初值的时候,在上面的这篇博客中,我们讲到了嵌套结构体的赋初值。
2025-07-09 15:12:04
443
原创 结构体“空洞”引发平台兼容性问题以及如何强制结构体对齐
在32平台上,结构体的体积是8个字节,而在51平台上,则是6个字节。在上面的示意图中,同一个结构体,但是在不同的平台上(32和51)因为51这边准备的数据缓冲区的长度是6,而接收到的数据长度为8。我们讲到了结构体的空洞问题,讲到了因为结构体的空洞问题。对吧,同一个结构体,因为不同的硬件平台,不同的编译器。对于不同的编译器,都有着不同的方法让它们的结构体对齐。这样不管在什么的平台上面,结构体的体积都是一样的了。有效数据的空闲字节,这就是结构体的空洞问题。所谓的结构体空洞问题,就是结构体在分配内存的时候。
2025-07-09 00:14:26
474
原创 为什么说结构体前128个字节的访问速度比较快?结构体的“空洞”问题;如何计算结构体的体积
第二个变量是float b,它的字节大小是4,和编译器默认的默认对齐数相同,如果我们遇到最终计算出来的结构体的体积是14,最大的结构体成员变量是4。由于成员变量的对齐规则,导致结构体内部出现未被使用的空闲字节的现象。因此对齐数是4 因为所有的成员变量都要对齐到对齐数的整数倍的地址处。第三个变量的大小是2个字节,和默认的对齐数4进行对比,取最小的那个。我么需要根据默认的对齐数和我们结构体中的成员变量的字节大小进行对齐。面向用户,我们需要良好的代码的观感,常常将相同数据类型的数据。
2025-07-08 22:31:19
340
原创 魔码(Magic Mode)的应用场景
魔码是一种具有特定意义的特殊值,它常用于检测数据的有效性和监视内存是否越界,第一,如果数据越界,修改的内存是一个空内存,那对程序的整体就没有什么影响,当我们需要将它们读取出来的时候,我们不知道存储器里面的数据有没有被修改过。通过判断魔码的值和原理的值是否一样就可以判断我们数据的是否有效性了。第二,如果数组越界修改的是变量,这样虽然不会导致程序的崩溃,第三,如果数组越界修改的是函数栈,这样就会直接导致程序的崩溃。数组的越界,它造成的结果往往是不可预料的,这主要是看数组的越界,修改的是什么的内存。
2025-07-08 21:05:24
257
原创 使用结构体化方法进行选择性数据解析
在上面的代码中,首先是定义了三个结构体,一个接受缓冲区,一个暂存缓冲区。在datatype不同的情况下,使用不同的结构体进行数据的解析。我们来看这样的一个代码,这里面使用到了结构体对数据的选择性解析。使用结构体2来解析数据也是相同的逻辑,这里我们就不在赘述了。这是因为在很多情况下,我们所接收到的数据帧并不是那么的单纯。再取出其中的有效数据部分,然后赋值给结构体指针pabc。它在不同的情况(数据类型)下,有着不同的情况,如果是结构体1,则使用结构体1进行数据解析。我们使用不同的结构体来对数据进行解析。
2025-07-08 18:33:09
229
原创 结构体变量赋初值的三种方法(基本方法,数组方法,成员化方法);结构体之间的复制
在讲完结构体初始化的三种方法之后,下面我们来讲一下结构体复制的三种方法。直接将结构体变量a中的内存数据直接拷贝到结构体变量b的内存数据中。这是C99编译器提供的一种比较快捷的结构体成员变量初始化的方法。我们要看透C语言中的一切,所谓的C语言中的变量,数组,结构体,在我们的实际开发中,我们经常会使用到这种空结构体,还有空数组。我们需要知道的是,在C语言中,不管是变量,数组,还是结构体,// 这里面我们想把a的值赋给b。// 这里面我们想把a的值赋给b。因此变量的复制,结构体的复制可以等效理解为内存的复制。
2025-07-08 16:43:42
627
原创 变量初始值未定义会导致什么问题?字符串给指针变量赋初值的具体解析
字符串作为指针的初始值,它是存储在FlashROM中的RO_data(只读数据段)中的。不能通过指针p1对字符串的内容进行修改,例如:p1[0] = 'd';从而在单片机上电的时候,把字符串从RO_data区转移到内存中。从而在单片机上电的时候,将字符串从RO_data加载到内存中来。在日常的编程中,我们经常会遇到没有给变量付初始值的情况。函数内的局部变量,如果未赋初值的话,那么它的值是随机的。但是前面我们明明是可以通过指针去修改字符串的内容的。但是如果我们涉及到对这些字符串的修改的时候。
2025-07-08 13:40:23
218
原创 结构体指针强转解析数据帧以及预留空结构体直接解析数据帧
同样的,转换的代码是:((struct data_frame*)buf)->payload。在上面的代码中,sensor_data结构体描述了数据帧中payload的数据格式。它也有它自己的数据格式,比如说它存储了传感器的数据,电压、电流、温度、湿度等等。而且这个结构体的类型和sturct data_frame这个结构体的类型相同。空数组其实是一个占位符来着的,在你不知道你要解析的数据的字节数的时候。与第一种解析相比,变长数据帧的解析关键在于你不知道数据位的多少。// 数据头 0XAA55。
2025-07-07 14:23:00
1405
原创 什么是“硬件栈”?STM32硬件栈操作如何知道“栈”在哪里?“硬件栈”和中断之间的关系?
在上面的示意图中,fun1主动调用fun2函数,然后我们就可以对fun1的现场。1.执行效率高,可以显著提高代码的运行效率(在函数的调用比较多的代码中),硬件栈可以大大缩短函数的入栈和出栈所消耗的时间,提高这个系统的编译效率。肯定不是main函数的执行,main函数的执行,对与单片机的启动来说,我们可以看到,在上面的那个递归程序中,涉及到了大量的入栈和出栈操作。所谓的入栈,就是将函数的相关值从CPU的内核寄存器中移入到栈空间中。这就需要我们来看一下,单片机一上电的时候,执行的第一件事情是什么?
2025-07-06 18:22:53
446
原创 函数的调用和返回,CPU都干了些什么?入栈和出栈具体解释
将当前函数代码的相关值从CPU的内核寄存器中移出存入编译器为当前函数的内存中。函数的调用,需要把当前函数的“现场”给保护好,也就是把“现场”的一些信息。本质原因就是栈的空间是有限的,一般来说,它的空间是1KB ~ 2KB。比如当函数fun2运行到了它的return指令,需要返回的时候。所谓的栈溢出,就是你定义的局部变量过大或者函数调用的层数过深。同时我们需要为被调用的函数从栈中开辟栈帧来存储它的个人信息。这样我们就实现了从一个函数的运行到另外一个函数的运行了,
2025-07-06 13:57:26
1648
原创 函数运行的本质是什么?局部变量的存储地址在哪里?为什么说函数的调用层数一般不要超多4层,最好不要超过7层
所以,CPU没有运行fun,是因为当前CPU内核寄存器中的值不是fun函数代码的相关值。也就是说CPU的内核寄存器装入的是哪一个函数代码的相关值,CPU此时就是在运行该程序。当函数被调用的时候,编译器才会在内存中划分一小块区域作为局部变量的存储空间。不过需要强调的是:当函数没有被调用的时候,局部变量并没有被分配内存空间。函数被调用时,局部变量被编译器分配到函数内部的栈帧中(也称为函数栈,溢出的栈数据会覆盖掉相邻的内存(如全局变量,其他函数栈等),好的,按我们今天的博客就更新到这里,觉得主编内容写的不错的,
2025-07-05 23:03:02
278
原创 单片机的存储空间以及为何在main函数中定义超大数组程序运行不起来
我们常说的单片机有几十k,指的是单片机的全局内存(RAM)加上程序存储区(flash ROM)。我们所说的几十K内存,其实是全局内存(RAM)加上程序存储区(flash ROM)。也就是说,单片机的内存很多,但是广阔的全局内存,并不属于某一个函数所有。对于大部分的单片机来说,栈的空间大小一般小于全局内存(ROM)的大小。ZI_data:未初始化数据段,用于存储未初始化的全局变量,函数中的变量,也就是局部变量,它是分配在函数的运行栈上面的。而全局变量或者静态局部变量,它是分配在广阔的全局内存中的。
2025-07-05 19:40:53
386
原创 sizeof计算数组大小出错以及如何处理
当我们需要在另一个.c 文件中去使用其他文件中定义的数组时,我们要用 extern 对其进行声明,当你在文件中使用extern声明一个数组,但没有指定数组的大小时,这个数组被称为不完全类型。这里的 a 是不完全类型,因为编译器只知道它是一个数组,但是不知道数组的大小。不完全类型是指编译器只知道该类型的某些信息,但不知道其完整的定义。sizeof计算数组大小出错主要原因是因为引用的数组是未完全类型,对于不完全类型,编译器无法确定其大小,因此不能用sizeof。sizeof的计算是在编译时完成的而不是运行时,
2025-07-05 15:56:10
301
原创 什么是函数指针数组以及它的使用方法
函数指针数组本质上还是一个数组,只不过它的元素由普通的常量变成了函数指针,函数指针指向函数的入口地址,通过函数指针可以起到调用函数的作用。总而言之,函数指针函数是为了方便管理具有相同签名(特征)的函数推出来的,这些函数指针所指向的函数的返回类型是int,参数类型也是int。它能够存储5个同样类型(返回值相同,参数类型相同)的函数指针。在上面的程序中,先定义一个函数指针数组用来存储两个函数指针,相当于是把函数放在了数组之中,方便了函数的管理和调用。函数指针数组是数组,里面的元素是函数指针。
2025-07-05 12:36:14
222
原创 通过指针修改const变量以及关于const的保护问题
关于const指针的定义,const仍然是起到一个保护的作用,也就是说,你不希望谁被修改或者说你希望谁被保护,那么在定义的时候,你就把const离谁近一点。// p2指针指向的变量被保护了,p2指针本身也被保护了。第三行:定义了一个指针变量p1,它指向收到保护的整型变量b,指针p1所指向的int类型变量是受到保护的。第六行:因为p2被保护了,所以一开始它指向了变量b,以后它也只能是指向变量b,而不能重新指向新的地址。通过上面的程序呢,我们成功的修改了const变量的值,它的值从3.1415变成了100。
2025-07-04 20:23:41
478
原创 const变量与常量有何区别以及它的存储地址
一般来说,const变量和常量都一样,被存储到了flashROM中,但是当const变量所占空间比较小的时候而且程序需要频繁的对const变量进行访问的时候,编译器就会对const变量进行优化,将它们放到RAM中。这就导致同一个常量,却占据了多份的flash闪存空间,大大增加了固件的体积。但是如果你使用const修饰一个变量,这个变量不允许被修改,编译器只会在flash中为这个变量分配一次空间,也就是当你在程序中多次用到这个变量的时候,其实这些变量的内存空间都是在同一个地方,也就是它们共用内存空间。
2025-07-04 13:18:41
309
原创 定义复杂的函数指针
函数返回值为int类型,有三个参数,第一个参数是字符指针,第二个参数是函数指针,第三个参数是整型,其中第二个参数所指向的函数的参数是字符指针,请写出这样的一个函数指针,名为pfun。// 成功定义了名为pfun的函数指针,以后可以直接使用这个函数指针类型Ops_Ptr_Type来定义同类型的函数指针变量。不管定义如何复杂的函数指针,我们都不需要看它所指向的函数的参数多么的复杂,定义一个函数指针,它指向这样的一个函数。
2025-07-04 12:23:57
228
原创 函数指针的定义
typedef int (*pfun) (int int) // 使用typedef定义函数指针类型pfun。// 通过函数指针p_fun调用add函数,并传递参数 1 和 1。来看一下函数指针是如何调用它所指向的函数的以及如何使用typedef关键字简化函数指针的定义。函数指针本质上是一个指针,只不过它指向函数的入口地址,通过它可以调用函数。pfun p_fun;// 使用函数指针类型定义函数指针p_fun。比如:int (*function)(int,int)
2025-07-02 23:21:20
135
原创 一道面试题:写一个宏,用来计算成员字段在结构体中的偏移量
ifndef :检查宏是否定义 如果宏没有定义,则执行这个预编译指令和下一个预编译指令之间的代码,否则跳出。#ifdef : 检查宏是否定义 如果宏已经定义,则执行这个预编译指令和下一个预编译指令之间的代码,否则跳出。C语言中常见的预编译指令。#if : 检查表达式是否为真 如果表达式为真,则执行这个预编译指令和下一个预编译指令之间的代码。偏移量也就是结构体中的成员字段的起始地址相对于结构体的起始地址之间的字节数的多少。3.(((type*)0)->file):通过这个指针访问结构体中的成员file。
2025-07-02 16:13:18
161
原创 类型重定义,最好是用typedef呢还是#define呢
由于我们使用了typedef进行了类型的重定义,因此uin8_t ptrl在被编译之前不再是简单被文本替换,它已经是一种数据类型了,和int,char ,long这些数据类型并没有什么区别,所以它定义的a,b变量都是指针类型的变量。总结一下,在嵌入式编程中,当我们需要进行类型的重定义的时候,最好是使用typedeg而不是#define,这是因为typedef是C语言中专门用来进行类型重定义的工具,而#define只是在编译之前进行了简单的文本替换(对指针类型变量的连续定义并不友好)。
2025-07-02 13:46:20
368
原创 早期GCC编译器中存在的坑以及引出static关键字
这样就会导致我们在不同的.c文件中对我们的同名变量中进行赋值操作时,实际上是在更改其他.c文件中的变量的值,那我们变量的值就会被不断的改来改去,这样我们的程序就直接是乱成一锅粥了。这是因为它把我们定义的多个同名变量都看做成了是同一个变量,也就是说虽然你定义了很多变量,但是因为他们是同名的,因此GCC编译器会把它们看成是同一个变量,会分配到同一个内存中。笨方法就是:我在不同的.c文件中根据我这个.c文件的特性给变量加上特有的前缀,那这样我们不同的.c文件中变量的重名问题就能够顺利的解决了。
2025-06-20 17:32:02
202
原创 如何简化变量或者函数的外部声明?
如果有一天我需要对这个被调用的函数进行维护,我修改了它的一个形参,然而我们多个.c文件都引用了这个函数,那这样我们就需要分别对调用过这个函数的.c文件中的程序进行重新的修改,大大增加了我们的工作量。一般我们需要调用哪一个变量或者函数的做法都是,在该.c文件中使用extern关键字对这个变量或者函数进行外部声明,外部声明的含义就是说这个变量或者函数是其他.c文件中的,不是这个调用的.c文件中的。那如果有一天我们对被调用的函数进行了维护,修改了它其中的一个形参,但是也没有影响的,因为我们包含了它的.h文件。
2025-06-20 15:16:24
227
原创 int类型到底有多少个字节?
同时的话,在TI的DSP(数字信号处理芯片中),unsigned char 所占的字节数是2个字节(16位),而不是一个字节。比如说:char类型至少是一个字节,short类型至少是两个字节,int类型至少是两个字节,long类型至少是4个字节。比如:在TI的DSP(数字信号处理芯片)中,unsigned char 类型就是两个字节。所以,我们总结一下我们这个小结的内容,Int 类型到底有多少个字节取决于他所在的CPU平台。先说结论,int 类型在51单片机上面是两个字节,在STM32上面是4个字节。
2025-06-18 00:59:42
635
原创 如何根据数值的大小确定基本类型?
内存有限,使用short(短整型),占两个字节或者char(字符型),占一个字节。2.为什么uint8_t 比uint32_t 在STM32中更加占内存?我们会发现两个程序编译之后,前一个的代码体积比后一个要大。1.如果数值范围超过-32768~32768,则使用long(长整形)当成“小整数”来使用,但是很多时候在编译器看来,它是一个。2.如果在-32768~32768范围内,仅是为了读写一个字节。位,所以它每次访问内存,读写数据都是。位变量效率是最高的,原生的。位的内核,因此它处理。
2025-06-16 22:37:56
163
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅
1