自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(43)
  • 收藏
  • 关注

原创 AD20软件学习

1.库与原理图编辑框2.添加库,查看对应器件的封装选择要加入的文件库查看封装。

2023-09-30 00:36:31 1186

原创 FreeRTOS进阶-任务管理实践

StaticTask_t * const pxTaskBuffer // 静态分配的任务结构体的指针,用它来操作这个任务。// 任务句柄, 以后使用它来操作这个任务。TaskFunction_t pxTaskCode, // 函数指针, 任务函数。TaskFunction_t pxTaskCode, // 函数指针, 任务函数。//依次分别为:任务函数,任务名,栈大小,任务函数传入形参,优先级,句柄。

2023-09-17 20:47:10 296

原创 FreeRTOS进阶-创建自己的工程

使用CubeMX配置LED PC13,默认低电平,推挽输出,无上下拉 创建驱动文件夹,添加自己的驱动程序(.c和.h文件),并添加头文件的路径。在CubeMX中,开启I2C1(PB6和PB7),软件默认自动配置GPIO,添加对应的驱动到"MyDriver"文件中(OLED.c和.h,Lcd.c和.h,ascii_font.c)3.配置FreeRTOS和参数。设置频率为72MHz。4.生成keil工程。

2023-09-17 17:35:11 186

原创 数据结构与算法-队列

队列逻辑结构:与线性表相同,为1对1的关系。存储结构:顺序队列和链式队列, 循环顺序队列最常见。操作的线性表,"队尾"是允许进行存入的一端,"队头"是允许进行删除的一端。若线性表中没有元素,称为"空队",队列的特点是"先进先出(FIFO)"。(4)判断空队和满队。

2023-09-08 23:26:40 346

原创 数据结构与算法-二叉树

(1)先序遍历:根节点->左子树->右子树 (2)中序遍历:左子树->根节点->右子树 (3)后序遍历:左子树->右子树->根节点。

2023-09-08 15:11:16 315 1

原创 数据结构与算法-链表

6.链表的优点和缺点 优点:(1)数据元素的个数可以自由扩充 (2)插入和删除等操作不必移动数据,只需要修改指针 缺点:(1)存储密度小 (2)存取的效率不高,必须采取顺序存取,即存取元素时,只能按链表的顺序,顺藤摸瓜。4.如何判断链表为空?

2023-09-05 00:16:47 45

原创 数据结构与算法-排序

(2)查找插入位置下标 low = 1,high = i-1(前面有序元素的长度) 判断arry[ 0 ] 与 arry[ mid ]的大小,若arry[ 0 ] < arry[ mid ],high = mid -1;(2)记录后移,查找插入的位置 j = i - 1 arry[ j ]为插入元素的前一个元素 判断arry[ 0 ] < arry[ j ],high+1以后的元素(包括high+1)

2023-09-02 19:32:47 38

原创 FreeRTOS-内存管理

答:在FreeRTOS中创建任务、队列、信号量等对象时,一般分为两种方法:动态创建、静态创建 动态创建:FreeRTOS管理内存堆中自动分配创建所需的内存 静态创建:需要用户提供各种内存空间,使用静态方式占用内存空间一般固定下来了,即删除任务、队列等,这些占用的内存一般不会被用作其他用途,会一直放着。1.设计Task1:按下KEY0申请内存,按下KEY1释放内存,并打印剩余内存信息。

2023-08-27 15:36:09 346

原创 FreeRTOS-软件定时器

软件定时器的任务回调函数在软件定时器服务任务中调用,服务任务不单单为一个软件定时器服务,还处理其他定时器。答:FreeRTOS中有许多软件定时器相关的API函数,通过这些API函数往定时器队列中写入消息(发送命令),该队列是提供给软件定时器使用的,用户不能直接访问。缺点:(3)软件定时器精度不高(因为它一系统时钟为基准,系统时钟中断优先级低,容易被打断),对于精度要求高的场合,不建议使用软件定时器。(3)处理软件定时器命令队列。:(1)负责软件定时器超时的逻辑判断 (2)调用超时软件定时器的回调函数。

2023-08-23 00:44:26 255

原创 FreeRTOS-任务通知

StartTaskKeySend:按键KEY0按下,任务通知值++,并发给StartTaskRecMessage任务。StartTaskRecMessage:接收StartTaskKeySend发送的任务通知值,并打印,未接收为阻塞态。StartTaskKeySend:按键KEY0按下,发送任务通知值发给StartTaskRecMessage任务。(3)无法缓存多个数据:任务通知通过更新任务通知的值来发送数据,任务结构体只有一个任务通知值,

2023-08-21 17:32:10 43

原创 FreeRTOS-事件标志组

特点:(1)每一位代表一个事件(高8位不算) (2)每一位事件的含义都由用户自己决定 如:bit0表示按键按下,bit1表示.....(1:表示事件发生,0:事件未发生)答:事件标志组是16位/32位的无符号数据类型,用来存放事件标志,其中高8位用作存储事件标志组的控制信息,低8位/24位用作存储事件标志,所以一个事件组,最多存储24个事件标志。答:事件标志组是一组事件标志位的集合,可以简单的理解为事件标志组是一个整数(u16)。

2023-08-19 22:43:17 51

原创 FreeRTOS-互斥信号量

答:当一个互斥信号量正在被一个低于优先级的任务持有时,如果此时高优先级任务尝试获取这个互斥信号量,那么高优先级的任务会被阻塞,不过这个高优先级任务会将低优先级任务的优先级提升到与自己相同的优先级(等待低优先级任务运行完再执行高优先级任务,减少阻塞时间)。原因:(1)互斥信号量有任务继承的机制,中断不是任务,没有任务优先级。使用流程:创建互斥信号量->任务获取信号量->释放信号量。互斥信号量获取和释放使用的函数与二值信号量相同。:创建完互斥信号量,会主动释放一次信号量。:互斥信号量不能用在中断中!

2023-08-18 23:06:03 361

原创 FreeRTOS-优先级翻转

答:在实时系统中是不允许优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能导致未知的严重结果。使用二值信号量会存在优先级翻转的问题,实验通过模拟的方式实现优先级翻转,观察优先级翻转对抢占式内核的影响。high_Task:高优先级任务,获取二值信号量,获取成功以后打印提示信息,处理完释放信号量。1.创建3个优先级不同的任务,分别为high_Task,mid_Task,low_Task。low_Task:低优先级任务,同高优先级任务一样,不同的是占用信号量时间久一点。2.如何避免优先级翻转的问题?

2023-08-18 17:51:50 222

原创 FreeRTOS-计数型信号量

适用场景:(1)事件计数:当事件发生后,在事件的处理函数中释放计数型信号量(计数值+1),其他任务会获取计数型信号量(计数值-1)。计数型信号量相当于队列长度大于1的队列,因此,计数型信号量能够容纳多个资源,这在计数型信号量创建时就确定了。使用计数型信号量过程:创建计数型信号量->释放计数型信号量->获取计数型信号量。(1)Task1:按键KEY1按下,释放计数信号量(+1)(1)定义计数型信号量句柄(全局变量),创建计数型信号量。(2)Task2:每1秒,获取计数信号量(-1)一.计数型信号量的简介。

2023-08-17 01:13:48 156

原创 FreeRTOS-二值信号量

二值信号量通常适用于互斥访问和任务同步,与互斥信号量比较类似,但是二值信号量有可能导致优先级翻转的问题,所以二值信号量。使用二值信号量过程:创建二值信号量->释放二值信号量(++)->获取二值信号量(--)(3)设置阻塞时间为1000ms,获取信号量,成功打印字符串,翻转LED1。二值信号量的本质是队列长度为1的队列,该队列只有空和满两种情况。(2)Task2:获取二值信号量,成功获取后打印,翻转LED1。(1)Task1:按下KEY1按键,释放二值信号量。(2)按下KEY1按键,释放二值信号量。

2023-08-16 20:01:51 194

原创 FreeRTOS-临界段代码保护及任务调度器挂起与恢复

(3)用户需求,如:使用start_Task任务,创建其他任务,我们使用临界段代码保护,使任务创建的过程无法打断。taskEXIT_CRITICAL_FROM_ISR() //中断级退出临界段。taskENTER_CRITICAL_FROM_ISR() //中断级进入临界段。临界段代码保护也叫临界区(直接屏蔽中断),指必须完整运行,不能被打断的代码段。(1)挂起任务调度器:单纯挂起调度器使任务调度器无法调度,但中断正常。(1)中断(优先级5-15) (2)任务调度。

2023-08-16 15:57:02 188

原创 FreeRTOS-中断管理

1.使用两个定时器,一个优先级为4,一个优先级为6,注意:系统管理的中断优先级为5-15,现象:两个定时器,每个定时器定时1s,打印一串字符,关闭中断,停止打印,开启中断持续打印。注意:需要在定时器初始化函数MX_TIMx_Init()中,手动添加" HAL_TIM_Base_Start_IT(&timx) ",否则无法启用定时器中断!将PendSV和Systick中断优先级配置为15,为最低优先级,保证系统任务切换不会阻塞其他中断的响应(即中断可以打断任务,任务不可以打断中断)。2.中断优先级分组配置(

2023-08-15 00:43:39 215

原创 FreeRTOS-队列

(4)出队、入队阻塞:当任务向一个队列发送消息时,可以指定一个阻塞时间,当队列已满无法入队时,设置阻塞时间:0 -> 直接返回不等待。如果使用全局变量,任务1修改变量a,等待任务3处理,任务3处理速度很慢,在处理的过程中,任务2修改变量a,这会导致任务3得到的数据不准确。(2)数据传递方式:采用实际值传递,将数据拷贝到队列中进行传递,也可以通过传递指针,在传递较大的数据时,采用指针传递。队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务之间、中断与任务之间传递消息。

2023-08-13 17:20:03 126

原创 FreeRTOS-任务调度

(3)TaskKEY0:如果TaskLED0已经存在,按下KEY0删除TaskLED0,否则创建TaskLED0。(4)TaskKEY1:如果TaskLED1正在运行,按下KEY1挂起TaskLED1,否则恢复TaskLED1。(1)抢占式调度:针对优先级不同的任务,优先级高的任务可抢占优先级低的任务(序号越大,优先级越高,与中断相反)1.创建4个任务,TaskLED0,TaskLED1,TaskKEY0,TaskKEY0。1.运行态:正在执行的任务,注意:STM32中,同一时间只能有一个任务处于运行态。

2023-08-12 16:06:57 314

原创 FreeRTOS-任务创建

const uint16_t usStackDepth, //任务堆栈大小。TaskFunction_t pxTaskCode, //任务函数。TaskHandle_t * const pxCreatedTask //任务句柄/控制块。任务可以理解为进程/线程,创建一个任务,机会在内存开辟一个空间。(1)选中任务与队列。

2023-08-11 00:31:16 196

原创 FreeRTOS-移植STM32(HAL库)

裸机开发的时钟源默认是Systick,使用FreeRTOS后,FreeRTOS会占用Systick(用来生成1ms的时间片,用于时间片调度),所以需要另外的时钟源。1.Timebase Source 为什么不使用Systick作为时钟源?V2版本更高级,功能更多,但V1版本大多情况下完全够用。此处不使用Systick作为Timebase的时钟源。2.FreeRTOS 版本为什么使用V1?3.FreeRTOS 各项配置选项卡的解释。二.FreeRTOS一些常见的问题。4.选择FreeRTOS。

2023-08-10 23:30:19 445

原创 FreeRTOS-基础知识

2.Task2运行时,Task3进入就绪状态,Task3抢占Task2运行,当Task3进入阻塞状态(系统延时或等待信号量),此时,就绪状态中优先级最高的任务Task2运行。3.Task3运行过程中(还不到一个时间片),Task3阻塞了,此时直接切换到下一个任务Task1运行。4.当Task3恢复为就绪状态,Task3存放到就绪列表中,再次查询,运行Task3。3.Task3解除阻塞状态,Task3恢复就绪状态,Task3抢占Task2运行。(3)这4种状态中,除了运行态,其他三种任务都有对应的。

2023-08-10 20:59:44 338

原创 嵌入式学习之Linux 网络编程

回顾前面学的进程间的通信,依赖与Linux内核,无法实现多机通信,如:Linux与安卓、Linux与单片机、Linux与Linux等,所以引出网络通信,网络通信需要地址(即ip地址与端口号),协议(http、TCP、UDP)。端口号的作用:主机上运行许多服务,如Web服务、FTP服务、SMTP服务等,通过"IP地址+端口号"区分不同的服务,端口设置一种访问通道。参数domain:表示协议或地址族,对于TCP/IP通常为AF_INET,与socket_addr中的sin_family的含义和取值一样。

2023-07-27 01:17:22 402

原创 嵌入式学习之Linux 线程

(2)线程间的通信机制方便,进程具有独立的地址空间,数据传递需要通信的方式,同一个进程下的线程之间共享数据空间,所以一个线程的数据可以被其他线程所用,但是无法同时被两个线程修改,故对于static的数据需要特别注意。进程具有独立的地址空间,一个进程崩溃,不会对其他进程产生影响,线程死掉,整个进程也死掉,线程有自己的堆栈和局部变量,但线程没有单独的地址空间,所以多进程比多线程更健壮,但进程切换时,耗费资源大,效率差。练习:线程条件控制实现线程的同步 实现线程2计数到3,唤醒线程1清空计数。

2023-07-23 00:25:49 62

原创 嵌入式学习之Linux 进程间的通信(2)

(3)创建联合体value,设置发送数据的值 (4)调用siggueue(pid,signum,value)函数,发送数据。概述:每个信号都有名字和编号,这些名字以"SIG"开头,例如:"SIGIO","SIGCHLD"等,通过指令 kill -l,(1)定义signum信号,定义pid进程ID (2)使用atoi()函数,将输入的字符串ignum,pid转换为整型。(2)信号发送函数:自己编写Mykill程序,杀死进程,通过调用kill()函数/system()函数,发送信号。

2023-07-20 23:32:06 58

原创 嵌入式学习之Linux 进程间的通信(1)

特点:(1)半双工(数据只能在一个方向上流动),具有固定的写端和读端 (2)只能用于具有亲缘关系的进程间的通信 (3)它是一种特殊的文件,可使用read 、write等函数进行读写,它不属于文件系统,只存在于内存中,管道内的数据读取完就没了,就像水流过水管,流过就没了。不同的进程之间传播或交换信息,每个进程都有不同的用户地址空间,进程A的全局变量,进程B无法看到,所以进程间的通信需要经过内核,在内核开辟一个缓冲区,进程A把数据复制到缓冲区,进程B从缓冲区读取数据,这种机制成为IPC。

2023-07-19 01:30:25 66

原创 嵌入式学习之Linux 进程编程

进程退出分为:正常退出和异常退出;调用_exit()或_Exit()函数。我们在fork函数创建新进程,经常会在新进程中调用exec函数去执行另一个程序,该进程被替换成新的程序,调用成功,原程序剩下部分不执行,但前后进程ID没有改变。父进程不等待子进程就退出了,此时子进程叫孤儿进程,孤儿进程由init进程托管,init进程变为孤儿进程的父进程,此时子进程的ppid为1。pid_t fork(void) //函数返回两次,返回0,表示当前为子进程,返回非负数,表示当前为父进程,返回-1,表示失败。

2023-07-17 23:58:33 247 1

原创 嵌入式学习之Linux 进程概述

两个特殊的进程:交换进程(PID=0),用于进程调度;init进程(PID=1),用于系统初始化(开机程序)。若结合管道grep,可指定查看对应的进程 ps -aux|grep init。是动态的,是程序执行的过程,当执行一个程序时,就启动一个进程。:相同程序每次运行产生的PID是唯一的,但是又是不一样的。进程A创建进程B,那么A是B的父进程,B是A的子进程。是静态的,是保存在磁盘上的指令的有序集合;4.如何通过编程获取进程的ID号?4.什么是父进程,什么是子进程?1.什么程序,什么是进程?

2023-07-16 15:23:31 41 1

原创 嵌入式学习之Linux 文件I/O (2)

思路:a)打开src.c文件 b)计算src.c文件的字数,并复位光标 c)读取src.c文件,并保存到readbuf中 d)创建des.c文件,并设置文件权限 e)将readbuf的内容写入des.c文件 f)关闭两个文件。:文件复制过程中有bug,若创建的文件本身存在且里面有内容,则会出现内容覆盖后任然有多余的原码,故在打开/创建文件时,应附加上一句flags:O_TRUNC,清空里面的内容,再执行写入。写入 fwrite(存放字符的空间,每次发送字符长度,发送次数,文件流指针)

2023-07-15 22:44:18 46 1

原创 嵌入式学习之Linux 文件I/O (1)

创建文件 int creat(文件路径(pname),文件权限(mode)) 返回文件描述符(非负整数),出错返回-1。whence:SEEK_SET(文件头),SEEK_CUR(目前光标所在之处),SEEK_END(文件尾)int open(文件路径(pname),文件打开方式标志(flags),文件权限(mode))ssize_t write(文件描述符(fd),数据缓存区(buf),字节数(count))ssize_t read(文件描述符(fd),数据缓存区(buf),字节数(count))

2023-07-14 20:19:06 144 1

原创 嵌入式学习之Linux 链表

a)声明结构体指针new b)嵌套while,为结点开辟空间,输入结点的数值 c)判断输入的数值是否为0,为0则释放新开辟的new空间,返回头指针 e)判断链表是否为空,若为空则将new作为头结点,返回头指针,反之,若不为空,遍历到链表尾,令尾结点的指针指向为new新结点,p->next=new ,返回头指针。a)声明结构体指针new b)为结点开辟空间 c)输入结点的数值 d)新的头结点指向为旧的头结点,新结点成为头结点(

2023-07-13 23:46:33 85 1

原创 嵌入式学习之Linux 初识Linux

通过物理网卡虚拟出虚拟交换机,如:VMnet8,连接上多台虚拟机,每台都能上网,拥有虚拟的ip地址,相同DNS,单线通信,虚拟机可以访问Windows,Windows不可以访问虚拟机。将物理网卡作为交换机连接上路由器,交换机另一端连接多台虚拟机和真机,它们的拥有独立的ip地址,每台都可以上网,互相之间可以通信,缺点:每台都需要独立配置DNS,DNS用来解析域名。e)mv命令 移动文件/重命名文件 例如:mv hello.c HELLO.c //重命名文件名为HELLO.c。

2023-07-12 23:19:17 96 1

原创 嵌入式学习之C语言10-结构体

/分号不可少 };struct 结构体名{ //结构名首字母大写(好看) struct Student{当出现不同类型的数据,无法用数组表达(数组里的元素都是相同类型的)结构体也是变量,访问的方式:1.变量名 2.地址。若想通过地址访问结构体,就需要用结构体指针。指针就是地址,指针变量是存放地址的变量。结构体定义在main函数的外面。1.为什么定义结构体?2.如何定义结构体?

2023-07-01 17:50:17 71

原创 嵌入式学习之C语言9-字符串

c).拼接函数 strcat( dest , src ):把src字符串的结束符 '\0' 删除,并接上新的字符串,但要保证dest长度足够,返回指向dest的指针。malloc(申请长度) free(内存名) memset(内存名,字符,长度) strcpy(内存名,字符串)b)部分拷贝函数strncpy(dest,src,n)e)部分比较函数strncmp(dest,src,n)字符串的结尾会有 ' \0 ' ,是字符串的结束符。a)拷贝函数strcpy(dest,src)

2023-06-30 16:57:53 103

原创 嵌入式学习之C语言8-二级指针

pp(21行),getScore2函数增加一个二级指针作为形参,用来传递main函数中pp的地址,函数内**q获取pp的地址,*q本身的地址是**q获取的地址(即pp的地址),*q指针的内容是父数组的地址,下图,程序运行跑崩溃了!printf函数放在main函数无法输出。printf函数放在函数内可以实现输出。二级(多级)指针保存上一级指针的地址。函数目的打印某子数组(行),将。故此处需要用到二级指针。1.二级(多级)指针。在main函数中定义。

2023-06-28 21:39:48 87 1

原创 嵌入式学习之C语言8-数组指针,函数指针,指针数组,指针函数

int getData(int a,int b) int (*p)(int a,int b)一个数组,若每个元素都为指针类型,称为指针数组。注意:第31行处,函数指针-->函数指针数组,后面需要带上调用函数中的函数名(地址),否则程序空跑无输出。数组a++偏移长度为16字节,结合上图,输出地址偏移也是16字节。一个函数的返回值可以是整型,浮点型等,也可以是指针型数据(即地址),b)能不能定义一个指针,让指针偏移的长度对应数组的偏移长度?在二维数组中,行地址的偏移与列地址的偏移是不一样的。

2023-06-27 00:06:36 115 1

原创 嵌入式学习之C语言7-指针与二维数组

arry[0] = &a[0][0] , arry[1] = arry[1][0] , ...//表示每一列的第一个元素。printf("地址: %p, 值: %d ", a[i]+j , *(a[i]+j) );将二维数组拆分为父数组与子数组,父数组的元素包含子数组的元素(二维数组回归一维数组)arry[0],arry[1],arry[2], 每1个行元素又是一维数组,包含。的地址即arry[0] , arry[1] , arry[2]arry[0]是第0行第0列的元素 3 的最地址。

2023-06-26 00:41:39 114 1

原创 嵌入式学习之C语言6-指针,指针与一维数组

使用指针打印数组 printf("p=&arry[0]=%d\n",*p);//打印首地址的数据。//数组a的第三个数据。补充打印方法:printf(" %d " , *(arry+i) );将地址++,对应增加的长度不同,int(4个字节) char(1个字节)printf("%d\n",p[2]);数据所占内存长度不同,如图,不同类型的指针指向同一个变量,打印出的。//输出变量a的地址。

2023-06-25 19:39:37 51

原创 嵌入式学习之C语言5-函数进阶(一维数组,二维数组)

输出时,也可使用如:printf_Arry( &myArry[0][0] ) 与 printf_Arry( myArry )相同,后者数组名代表数组的首地址,前者代表第一个元素的地址,也是数组的首地址。如图2,data作为普通变量时,函数中生成data的地址与main函数中data的地址不同,故对二者进行操作输出的数值不同。为函数增加 len 的形参,作为传递数组长度 len=sizeof(数组名)/sizeof(数组名[0]);,与main函数中的data数组指向的是相同的地址。

2023-06-24 20:29:34 47

原创 嵌入式学习之C语言4-函数

注意:函数的创建要写在main函数的前面,否则会有warning,必须在前面加一句函数的声明,warning才会消除。形参在被调用时,才会生成内存,调用结束,释放内存。1.函数的三要素:函数名 入口参数 返回值。实参:用于调用函数,可以是表达式,常数或常量。函数也可以当做表达式,如图第44行。形参:函数创建时,需要用形参传递数值。说明:函数必须先定义,在使用。注意:且二者存储的内存地址不同。2.形参和实参的区别。2.函数的封装与调用。

2023-06-22 00:36:34 36 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除