前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【RTOS训练营】GPIO知识和预习安排 + 晚课提问

【RTOS训练营】GPIO知识和预习安排 + 晚课提问

作者头像
韦东山
发布2022-09-16 09:37:03
4350
发布2022-09-16 09:37:03
举报
文章被收录于专栏:韦东山嵌入式韦东山嵌入式

一、GPIO

下面我们来讲GPIO和I2C。

我们先来看看gpio的框图:

请添加图片描述
请添加图片描述

在嵌入式系统中,在一个芯片上面有CPU,有gpio,有串口,有USB等等外设模块。

有一些模块平时为了省电,他是不工作的。

你要去使用它,要先使能它,就是给他提供时钟。

一个芯片,它外面有密密麻麻的引脚,这些引脚接到芯片内部哪一个模块?

请添加图片描述
请添加图片描述

因此还需要去选择这些引脚的功能。

无论是什么芯片,对于gpio它操作都是这几个步骤:

第1步:使能GPIO模块

第2步:接着就是去设置芯片的外围引脚,让它连接到GPIO模块;

第3步:选择它的方向,选择输出还是输入;GPIO的意思就是通用的输入输出脚,有输入、也有输出;

第4步:就是去操作数值:

代码语言:javascript
复制
		4.1 对于输出引脚,我们可以让他输出高电平,低电平;
		4.2 对于输入引脚,我们可以去读取它的当前电平,得到高或低;

我们使用HAL库的时候,并不需要我们深入到寄存器,

所以我们大家来浏览一下代码,就可以了。

请添加图片描述
请添加图片描述

这些代码都是cubemx生成的,

如果想看到寄存器操作的话,在后面我们讲ARM架构的时候会深入到寄存器。

这个函数先使能了GPIO模块, 并且把引脚连接到了GPIO模块, 再去设置了他的方向, 最后,对于输出引脚就去写它的值,对于输入引脚,就去读他的值

请添加图片描述
请添加图片描述

二、预习安排

请添加图片描述
请添加图片描述

三、晚课学员提问

1. 问: 向链表放了一个元素,不算链表吧?

答: 一个链表可以是空,可以有一个元素,也可以有多个元素。只有一个元素,它也是链表。

2. 问: 晚课示例链表中的phead,在内存中也应该有地址吧?

答: pHead它是个变量, 是变量必定在内存里面,必定有地址。我们用这个pHead来保存第1个元素的地址。

3. 问: 晚课示例链表中的phead,为什么是NULL?

答: pHead是一个链表头,如果他不是空的话,他肯定等于某一个结构体的地址。这个结构体在内存里,它的地址一般来说都不会等于0。所以我们使用NULL(就是零),用来判断一个链表,它的值是不是有效的,也就是否指向一个结构体。

4. 问: 晚课示例链表中, A.next_addr = pHead 等于初始值 NULL,A.next_addr不是一直是NULL吗?

答: 在一开始的时候,A的next_address是NULL,这里是再一次复制,为了确保万无一失。

对于全局变量你没有给它赋值的话,它的初始值就是0,但是对于局部变量你没有给它赋值的话,它的初始值并不一定是0。 对于使用malloc分配出来的结构体,你没有给它赋值的话,它的初始值也并不一定是0。

5. 问: 晚课示例链表中, A.next_addr不设置NULL会发生什么?

答: 如果不设置为NULL的话,我们无法分辨next_addr是否有效。

6. 问: 晚课示例链表的删除中,在函数内定义局部变量tmp找特定节点的思路是怎么来的呢?自己做的话很有可能无法想到定义一个temp变量。

答: 要去遍历这个链表,要把里面的每个元素拿出来判断一下,那肯定得定义一个局部变量。

7. 问: 晚课示例链表的删除中,删是删了,但是删除的点在内存中还是占据着空间,实际用的时候,要不要考虑内存优化?

答: 常规的用法是:

  1. 先用malloc得到节点,
  2. 插入链表,
  3. 用完之后从链表中把它删除,所谓删除只是不在列表中而已,
  4. 最后我们用free把它释放掉

8. 问: 晚课示例链表的使用中,内存中list是不是会开启一个list node的内存?

答: 我们来画一下这个链表的内存图:

请添加图片描述
请添加图片描述

这个list结构体,它里面又有其他结构体。

这个RootNote它里面放的是指针:指针都是4字节。

9. 问: 晚课示例链表的使用中,根节点是干嘛的?

答: 你排队的时候总得找到队伍的头部呀,否则在茫茫人海中,你怎么去找到你的队伍。

10. 问: 晚课中的 “来看一下我们一个芯片,它外面有密密麻麻的引脚”,是不是CPU的外面?芯片指的是整个板卡嘛?CPU的引脚和哪个模块连接不都是确定好的么,还能选择吗?

答:

请添加图片描述
请添加图片描述

一个芯片里面有很多模块,就比如说上面的图里面,里面除了CPU之外,还有gpio,还有UART。

一个芯片的外面,你看它的周边那些引脚,是已经确定下来了,就是上面图中那些白色的发光的引脚。

但是这些引脚要接到芯片里面哪一个模块呢?这是可以编写程序来控制的。

就比如说上面图里那些蓝色的外围的引脚, 可以接到gpio的红色的引脚,也可以接到UART的绿色的引脚。

11. 问: 针对stm32 高电平是3.3v,原因是因为stm32的供电电源是3.3v决定的吗,如果某个芯片的供电电源是5V, GPIO输出的高电平就是5v吗?

答: 这样理解没问题,那个高电平它都是有一个范围的,并不是说一定要到达3.3V,一定要到达5V。比如引脚的电压是1.7伏到3.3伏,我们就可以认为它是高电平。(1.7V这个数字是随便举例的)

12. 问: 为什么要用HAL库,比标准库和操作寄存器好吗?

答: ST公司建议使用HAL库,为了效率,有库就用库,没库再操作寄存器。

13. 问:

请添加图片描述
请添加图片描述

答: 首先对于所有的引脚,默认情况下都是输入状态,不会影响到外面的电路,

如果你要把它配置成输出引脚,在变为输出引脚的瞬间,他就会输出高电平或者低电平。

那么在变为输出引脚的瞬间,你要让他输出高电平还是低电平?

是不是在设置为输出引脚之前,我们先去设置它的输出值?

这就是答案了。

14. 问: assert_param怎么理解?有效性?

答:

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

简单的说他就是一个判断语句:

代码语言:javascript
复制
void assert_param(expr)
{
  if (expr)
    assert_failed();
}

大概就这意思,他会打印某些语句。

15. 问:

请添加图片描述
请添加图片描述

答:

请添加图片描述
请添加图片描述

16. 问: CORTEX-M3(还是该说STM32)里面有哪些模块呢,我一直以为GPIO和串口都是板卡上的,那板卡上的那些都是啥,没有什么CAN控制器之类的吗?

答: 只要去打开芯片手册,一看就明白了,我给你演示一下。

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

你看这个图,这就是103这个芯片,里面左上角是CPU。

其他都是各种:片上设备。

所谓片上设备就是:在芯片里面、CPU之外那些设备,也就是GPIO,UART模块呀,flash等等。

在芯片之外,我们还可以连接各种设备,这些设备叫做片外设备,就比如说103可以通过串口来连接WiFi模块,这个WiFi模块就是103这个芯片之外的设备。

17. 问: 老师能否解答下,我的注释是不是理解正确。

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

答: 理解的非常到位。

18. 问: 老师能讲一下什么情况下用到堆和栈,都是存在RAM上还是FLASH上的呀?

答: 堆和栈它是不一样的,今晚下课之后,对这个问题比较感兴趣的同学,可以去看这两个视频。

请添加图片描述
请添加图片描述

堆和栈都是内存,不是flash,我来画一个图:

请添加图片描述
请添加图片描述

我们写好程序之后,烧写进flash。

开板断电,没有程序运行,没有人去使用内存。

开发板上电,程序运行的时候要去初始化全局变量。 再次默念我们的口诀:变量变量变量,可以变,必定在内存里。

但它这些全局变量,它的初始值在哪里,初始值肯定在程序里,肯定在flash上面。

所以这个程序的代码会使用这些初始值去写内存,就是去初始化变量。

好了,内存有一块区域,用来保存这些全局变量。

那么局部变量呢,保存在哪里?保存在栈里。

栈起什么作用?在C语言里面必须使用栈,栈也指向一块内存。

要想弄清楚栈、局部变量,他们是怎么使用的,这会涉及一些汇编。

我先讲完堆,再给大家讲栈。

我要假设你们知道了栈的作用, 内存有一部分用来保存全局变量, 有一部分用作栈, 剩下的那一部分怎么办?

剩下的那一部分你可以用也可以不用。

你想用的话,你就可以把它当做堆,也就是说你得去管理,在上面实现malloc函数,实现free函数。

在我们这个图里面,你看对于内存它分为三部分。

堆,就是一块空闲的内存,你去使用它,它就叫做堆,你不用他,他啥都不是。

我们怎么使用它呢,我来举一个最简单的例子:

请添加图片描述
请添加图片描述

我们假设这块内存的起始地址是addr1,结束地址是addr2。

我来写一个malloc函数,最简单的:

请添加图片描述
请添加图片描述

我给大家简单讲解一下这个函数:

请添加图片描述
请添加图片描述

这就是最简单的malloc函数,但是它只能够实现分配,不能够实现释放。

为什么不能够实现释放呢?

代码语言:javascript
复制
int addr = malloc(100);
free(addr); // 你怎么知道释放多大?

我们申请一块内存的时候,得到他的地址,释放的时候也传入他的地址。

在我们这个例子里面,我怎么知道你要释放了,这块内存多大呀?根本就没有办法知道。

所以我们使用这种方法实现的分配函数,它不支持释放,对于真正的分配函数,我们应该怎么做?

我再举一个稍微复杂点的例子:

请添加图片描述
请添加图片描述

我们来看这个图,他要去分配100字节的空间,他并不仅仅分配这100字节。

他还会额外分配一个头部,在头部里面会保存有100这个数字,以后去释放这块空间时:free(p)

他会根据这个P往前面查,找到这个头部,从头部就知道了,你要是释放的是100字节的空间。

所以对于堆,如果越界访问的话,就有可能会破坏掉头部信息,整个系统什么时候崩溃都不知道。

我们现在大概知道堆的原理之后,我们就来看看堆有什么作用。

就像我们之前讲的那个例子,你的班主任让你去记录每个同学的信息, 因为同学的人数是不能够事先确定的,这个时候你就可以使用堆来动态分配结构体

19. 问: malloc函数怎么确定可用的堆大小呢?

答: malloc函数本身没有办法确定可用的堆的大小,他只有一个返回值,要么成功要么失败。

20. 问: 右边的1、这种格式写法对吗?

请添加图片描述
请添加图片描述

答: 正确。

21. 问: 除了编码时注意,如何防止堆、栈的溢出呢?

答: 防止栈溢出的话,就尽量的少定义非常庞大的局部数组。

22. 问: 这样的话使用malloc函数不就是会有改写栈的风险么?

答: 你要确定malloc管理的内存的边界。

23. 问: 老师分配节点使用malloc,实在堆里面分配空间吗?

答: 是的

24. 问: 堆都是用malloc申请么?什么时候才会用到它还是不太理解。

答: malloc是从堆里分配空间,不是反过来说:堆是用malloc申请。

25. 问: 怎么知道堆的起始地址?是通过编译器分配的吗?

答: 我们可以通过编译器来确定,甚至可以直接定一个巨大的数组,把这个数组就当做堆,freertos里面就是把一个巨大的数组用作堆。

26. 问: 定义一个数组不就被放到全局变量或者栈嘛?

答: 是呀,堆的含义是什么?堆的含义就是一块空闲内存嘛,这个全局数组我不用它,它就是空闲内存。

27. 问: 老师,讲一下栈吧?

答: 对于栈,我找个程序,需要给大家展示汇编,才能讲清楚。

代码语言:javascript
复制
int add(int a, int b)
{
	volatile int i = 10;
	while (i--);
	return a+b;
}

int main(void)
{
	int c;
	c = add(1,2);
	return 0;
}
请添加图片描述
请添加图片描述

1.main函数调用add函数

add的函数执行完之后,返回到内函数的哪里?

请添加图片描述
请添加图片描述

我们可以看得出来他会返回到这个语句:return 0

但是在add的函数里面,他怎么知道返回到这个语句?

是不是得由main函数告诉他呀?

是的,那么main函数怎么告诉add的函数,你的返回地址是下面的那条语句?

请添加图片描述
请添加图片描述

了解这个流程就行了:

  1. main调用add
  2. 会把add的返回地址保持在某个寄存器里,比如LR

下面我们进入add函数:

请添加图片描述
请添加图片描述

你看现在就用到了栈,栈这块内存它的使用情况,我来画一个图:

请添加图片描述
请添加图片描述

在栈里面他使用了两个空间, 一个用来保存函数的返回地址LR,另外一个用来保存R3。

接下来我们定义了一个局部变量i,它的初始值是10。

volatile int i = 10;

我们说局部变量保存在栈里,它是怎么体现的呢?

请添加图片描述
请添加图片描述

看箭头的代码,他让寄存器R0等于10,然后把R0的值写到栈里面去。

我来画一个图:

请添加图片描述
请添加图片描述

看到了吧,变量i它在内存哪里呀?在栈里面。

所以看到这里我们就知道了: 1.栈,他会用来保存返回地址 2.也会用来给局部变量分配空间

大家不用灰心,这部分讲的内容超纲了,后面我们讲ARM架构的时候会从头教大家,先从汇编教起。

28. 问: 老师,后续先讲arm架构还是先freertos?

**答: **

1.先讲FreeRTOS快速入门 2.再讲ARM架构 3.最后讲 FreeRTOS内部实现

29. 问: 老师预习FREERTOS的课程,代码裁剪需要掌握嘛,如何有效掌握呢?

答: FreeRTOS它就几个文件,裁剪也裁剪不出什么东西,主要是配置各种宏。某个函数,你要去使用它的话就得去打开某个宏

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、GPIO
  • 二、预习安排
  • 三、晚课学员提问
    • 1. 问: 向链表放了一个元素,不算链表吧?
      • 2. 问: 晚课示例链表中的phead,在内存中也应该有地址吧?
        • 3. 问: 晚课示例链表中的phead,为什么是NULL?
          • 4. 问: 晚课示例链表中, A.next_addr = pHead 等于初始值 NULL,A.next_addr不是一直是NULL吗?
            • 5. 问: 晚课示例链表中, A.next_addr不设置NULL会发生什么?
              • 6. 问: 晚课示例链表的删除中,在函数内定义局部变量tmp找特定节点的思路是怎么来的呢?自己做的话很有可能无法想到定义一个temp变量。
                • 7. 问: 晚课示例链表的删除中,删是删了,但是删除的点在内存中还是占据着空间,实际用的时候,要不要考虑内存优化?
                  • 8. 问: 晚课示例链表的使用中,内存中list是不是会开启一个list node的内存?
                    • 9. 问: 晚课示例链表的使用中,根节点是干嘛的?
                      • 10. 问: 晚课中的 “来看一下我们一个芯片,它外面有密密麻麻的引脚”,是不是CPU的外面?芯片指的是整个板卡嘛?CPU的引脚和哪个模块连接不都是确定好的么,还能选择吗?
                        • 11. 问: 针对stm32 高电平是3.3v,原因是因为stm32的供电电源是3.3v决定的吗,如果某个芯片的供电电源是5V, GPIO输出的高电平就是5v吗?
                          • 12. 问: 为什么要用HAL库,比标准库和操作寄存器好吗?
                            • 13. 问:
                              • 答: 首先对于所有的引脚,默认情况下都是输入状态,不会影响到外面的电路,
                                • 14. 问: assert_param怎么理解?有效性?
                                  • 15. 问:
                                    • 16. 问: CORTEX-M3(还是该说STM32)里面有哪些模块呢,我一直以为GPIO和串口都是板卡上的,那板卡上的那些都是啥,没有什么CAN控制器之类的吗?
                                      • 17. 问: 老师能否解答下,我的注释是不是理解正确。
                                        • 18. 问: 老师能讲一下什么情况下用到堆和栈,都是存在RAM上还是FLASH上的呀?
                                          • 19. 问: malloc函数怎么确定可用的堆大小呢?
                                            • 20. 问: 右边的1、这种格式写法对吗?
                                              • 21. 问: 除了编码时注意,如何防止堆、栈的溢出呢?
                                                • 22. 问: 这样的话使用malloc函数不就是会有改写栈的风险么?
                                                  • 23. 问: 老师分配节点使用malloc,实在堆里面分配空间吗?
                                                    • 24. 问: 堆都是用malloc申请么?什么时候才会用到它还是不太理解。
                                                      • 25. 问: 怎么知道堆的起始地址?是通过编译器分配的吗?
                                                        • 26. 问: 定义一个数组不就被放到全局变量或者栈嘛?
                                                          • 27. 问: 老师,讲一下栈吧?
                                                            • 28. 问: 老师,后续先讲arm架构还是先freertos?
                                                              • 29. 问: 老师预习FREERTOS的课程,代码裁剪需要掌握嘛,如何有效掌握呢?
                                                              领券
                                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档