TI-RSLK 模块 4 - 讲座视频 - C 语言编程

+荐课 提问/讨论 评论 收藏
大家好,我是 Jon Valvano。 在本次讲座中,我们将讨论 C 语言编程。 我建议您找一本 比较好用的C 语言参考书, 以便在本课程中使用。 本讲座的目标是简要介绍一下 一些您需要在C 语言编程过程中 时刻注意的问题和概念。 在实验中,您将通过实施该双曲线函数 完成转换,您采用该输入, 将其拟合到该曲线,然后得到对应的输出。 在 C 语言编程实验中,您需要解决的另一个问题是, 思考机器人在跑道上的位置。 所以,当机器人来到迷宫中的这个点时, 您将会询问,我能直行吗? 能右转吗? 或者能左转吗? 您将会通过一系列条件语句 解决这个问题。 好,让我们开始吧。 如果您知道流程图是什么, 我们建议您使用这种图,因为这种方式能够让您 以图表的形式描述软件算法、方法、 一组步骤,或者是软件必须 遵循的执行序列。 我们具有起始点和结束点。 具有可以选择向左还是向右的条件。 我们可以进行输入、输出。 可以执行计算。 我们甚至可以让一个函数调用另一个函数。 在 C 语言中,这称为结构化语言, 因为它的构建形式包括以下四种构建块。 如果我们有一个序列,先执行 A,然后再执行 B, 这种情况便称为序列。 我们可能会有一个测试条件, 如果测试结果为 true,则从这边走, 如果测试结果为 false,则从这边走。 此外,还有两种循环。 我们可以先执行测试,如果测试结果为 true, 我们将循环执行while 循环的主体, 直至测试结果成为 false。 或者,我们将至少执行主体一次, 然后进行测试。 同样,如果测试结果为 true, 我们将循环反复执行该主体, 直至测试结果成为 false。 再强调一次,如果您知道流程图是什么, 而且您绘制的软件可以归类为算法, 我们建议您,先绘制流程图, 再写代码。 逻辑运算在嵌入式系统中 非常重要。 我们将会在两种情况下使用“与”运算。 我们可以将其作为一个掩码来选择位。 如果使用 1 来进行掩码运算,使用 1 进行“与”运算, 我们将选择相应的位。 如果使用 0 进行“与”运算,则会清除相应的位。 这个运算就在这里,您可以看到, 它会选择第 1 和第 0 位,因为这两个位 是恒定的。 我们可以使用“或”运算来设置一个位。 如果我们用 1 对其进行“或”运算,便会设置该位。 我们还可以使用“或”运算来取并集, 我们可以取两个不同的值,在二者之间进行变换, 使用“或”运算将两个值的结果 合并到一个变量中。 然后是“异或”运算,我们将用其进行切换。 切换即翻转,当我们使用 1进行“异或”运算时, 如果原来是 0,则会变成 1。 如果原来是 1,则会变成 0, 这是幅度与时间的关系。 使用 0 进行“异或”运算时不会带来变化。 这种运算以按位方式完成。 所以,对于这里的这个“或”运算, x 是一个 32 位的数字-- 第 31 位,第 29 位-- 我的意思是从第 30 位,第 29 位,一直到最后的 第 0 位。 Y 也是一个 32 位的数字-- 第 31 位、30 位、29 位,一直到第 0 位。 当我执行所有这些 逻辑运算时,系统会以按位方式进行。 因此,举例来说,系统会将 x 的第 29 位的值 与 Y 的 第 29 位进行“或”运算,并将结果存储在 Z 的第 29 位中。 这个过程适用于所有的 32 个位。 以切换为例-- 我们将在整个课程中了解各种端口-- 但这是第一个端口。 这是微控制器上的一个引脚。 它是一个输出引脚。 如果我们想要生成这个波形, 我们可以执行这行 C 代码,这行代码只会对第 3 位进行切换, 其他 31 位会保持不变。 我们可以在这些时间执行该行代码。 同样,这也是振幅与时间之间的关系。 如果我们在这个时间执行这行 C 代码, 我们将会生成这段波形。 所以,我们将会在这节课中使用切换。 我们会在多种情况下使用移位。 如果我们想做除法,我们可以执行右移。 那么,让我们除以 2。 如果我们想做乘法,我们可以执行左移。 我们可以针对 2 的任何次方进行运算。 我们可以一次移动多位。 但是,具体的移动方式应由您自己决定, 因为您需要了解运算对象是否有符号, 因为如果没有符号,您将需要移入 0。 如果有符号,则需要保留该位。 所以符号位-- 所以,进行移位的负数在除以 2 的次方后, 仍然为负数。 要做到这一点的方式是,选择相应的类型。 在 C99 中,以 U 开头的类型为无符号类型。 不是以 U 开头,而是以 I 开头的类型 则是有符号类型。 当您使用左移执行乘法运算时, 这两种类型都没有问题。 再强调一下,移位运算用于做除法或乘法。 它通常是先进行各自的移位运算,然后再取它们的 并集。 同样,您需要记录并确保 自己清楚地了解您的数字是有符号的 还是无符号的。 算术运算也同样如此。 所以您同样需要了解运算对象是否 有符号。 但是我们还会遇到另外一个问题,那就是, 如果我取两个 32 位的数字,将其相加, 我实际上会得到 33 位。 如果我尝试将这个33 位的数字压缩到 32 位的变量中,数据将会被破坏。 系统将会给出一个严重错误的答案, 这种现象称为溢出。 乘法运算时的情况会更糟糕。 取两个 32 位的数字,将其相乘, 我实际上会得到 64 位。 同样,如果您尝试将这个64 位的结果压缩到 32 位的变量中,系统可能会给出错误的答案。 因此,加法、减法和乘法都有可能 发生溢出。 您将可以通过两种方式来处理这种 溢出。 一种方法是限制输入值。 例如,如果您知道输入是一个 12 位的数字, 如果您知道它不是 32 位的数字,而是 12 位的数字, 那么它的范围为 0 到 4,095。 然后,您使用另外一个数值已知的 数字与该数字进行运算。 举个简单的例子,1,000, 1,000 是一个 10 位的数字。 如果您乘以这个数字,您知道可能的最大值为 4 百万 不可能再比它更大了。 我们知道 4 百万是可以放在一个 32 位的变量中的。 所以,您知道,在这种情况下, 如果我对输入进行限制,运算就不可能出现溢出。 我们可以看到,如果您取一个 12 位的数字, 将其与一个 10 位的数字相乘, 您会得到 22 位,这能够装入 32 位的结果中。 所以,您用于处理溢出的第一种方式是, 了解您所有输入变量的取值范围。 然后,通盘考虑所有的计算, 确保没有超出 32 位的 中间结果。 另外一种处理方式是,升级、执行、检查, 然后降级。 我们将在下面进行说明。 如果您有两个8 位的数字, 您想要将这两个数字相加, 那么您将会得到一个 9 位的数字。 这时便没有什么转圜的余地。 但是,如果您将 8 位的数字升级到 32 位-- 我已经进行了升级。 这是一个 32 位的数字。 我在 32 位模式下执行运算, 然后检查结果是否超出 8 位的变量。 如果超出,我会切掉相应的高位。 然后降级至 8 位。 这并不是正确的答案, 但要比允许溢出的情况好。 在处理算术运算时,您的工作是 正确处理您的数字是无符号数字, 还是有符号数字。 同样,在 C99 中,您将通过选择相应的 类型来做到这一点。 无论您使用的是8 位类型、16 位类型, 还是 32 位类型。 对于除法,您不会想要除以 0。 关于除法的另一个问题是 掉出,即信息丢失。 这种情况很常见。 如果我任意取一个数字,将其除以 1,024, 这是一个整数除法。 它从本质上是一个右移运算。 我们将会丢失 10 位, 就是这样。 这个运算将会取一个 32 位的数字, 并切掉它后面的 10 位。 所以每次在做除法或者说右移运算时, 我们都会遇到掉出的问题,也就是数据丢失。 当我们执行计算,以了解数字 在计算中的运行方式时, 我们将会再次清晰地认识到这一点。 所以这两个问题是加法和乘法或左移运算中的溢出问题, 以及右移运算或除法中的掉出问题。 条件语句,希望您注意这个元素, 因为我们可以看到,“与”运算是针对 总共 32 位上的值以按位方式执行的 逻辑运算。 而双与,还有双或, 则是布尔运算。 布尔值是 true或 false 中的一个。 0 代表 false,非 0 则代表 true。 双与、双或和非 是布尔运算。 也就是说,它们对其他 true、false 进行 true、false 运算,得到值为 true 或 false 的结果。 关系运算是取两个数字, 一个数字 n,一个数字 m,结果是一个布尔值。 当我执行关系运算时, 比如大于、小于、大于等于、等于 或不等于,我将会得到一个布尔输出。 而且我可以将这些运算置于类似这样的 决策中,如果 G1小于 G2, 且 G3 不等于 G4,那么我将会 执行这一步,否则,则会执行这一步。 我可以在if 语句中 使用“与”运算。 如果设置了第 7 位,则结果为 true。 如果清除了第 7 位,则结果为 false。 要再次提醒您的是,您必须清楚, 自己谈论的是以按位方式 进行的数字运算,还是以每次一个的方式 进行的布尔运算。 上述情况同样适用于循环结构。 while 循环和 do while 循环都是采用布尔值。 因此,这样会计算得到true 或 false。 我们将在这里放置 true。 因此,在本例中,while 循环会先执行测试。 如果 G2 大于 G1,则会一遍又一遍地 执行该主体, 直至 G2 小于或等于 G1, 然后停止执行主体。 do while 循环会执行主体至少 一次,然后进行测试。 同样,如果 G2大于 G1, 则会执行主体一次,然后同样一遍又一遍地 执行,直至 G2 小于或等于 G1。 有时,我们会一遍又一遍地执行某个操作, 更具体一点,我们可以执行某个操作 10 次。 但是如果您注意一下for 循环,它非常 简单,本质上也是一个 while 循环。 我们将会取用这部分代码, 并使其执行一次。 我们将会取用这部分代码, 这部分将用作测试。 我们将会执行主体。 然后这部分代码会在主体执行之后, 一遍又一遍地执行。 这种情况下会执行主体 10 次。 您可以使用向上计数或向下计数。 这都没有关系。 while 循环允许您在条件 仍然为 true 的情况下,一遍又一遍地执行 某个操作。 上次我们看到,函数在这个抽象中 非常重要。 允许您将高层次的功能 与低层次的工作方式 分离开来。 我们会在头文件中 将它的功能作为公有函数的原型。 我们将会实施该函数,并在代码 文件中展示所有琐碎细节, 同时尽量隐藏这些细节。 实施文件或代码文件中 包含公有函数的 所有细节和原型。 也就是说,使用该模块所需要 了解的内容都将被放在头文件中。 这种抽象使得我们能够 实现非常高的复杂性。 函数的第三个方面是如何进行调用。 在本课程中,您将会看到 许多主程序,用来说明如何使用函数。 我们可以在这里看到,我们通过调用函数的名称 来调用函数。 而且我们可以传入其参数。 这个是 1,我们将其传入该函数。 数字 1 被传递给 x。 x 的值被传递给这个全局变量-- 好吧, 是静态全局变量 m。 然后,我们也可以从函数返回参数, 并将其存储到一个位置。 同样,这里的返回操作 将会传回一个参数。 这是一个随机数生成器。 这不是一个非常好的随机数生成器, 但是它会返回 0 到255 之间的一个数字。 因此,函数在 C 语言编程中 非常重要。 建议您看看示例文件是 如何设置的,以了解您该在本课程中如何进行操作。 变量,这张幻灯片,再加上后面的两张, 可能是本讲座中最重要的幻灯片了, 因为,它们介绍了可让您成为一个优秀 程序员的各种变量。 我们可以讨论重要变量的名称, 而且一个变量的名称应该阐明这个变量是什么。 但是今天我想要讨论以下两点。 我想要讨论的是范围,也就是谁可以访问这个变量。 分配则是关于这个变量何时存在。 所以,当我们限制范围时,我们称其为 私有变量,不限制范围时,则为公有变量。 分配则分为临时分配和永久性分配。 也就是说,变量会永久存在吗? 所以,全局变量是一个具有公有范围的变量, 这意味着任何函数都可以使用它。 如果我定义这样一个变量, 并将其置于 软件中的任意位置, 其他模块便可以将其用作外部变量, 并拥有对这个变量的读写权限。 这是一件很糟糕的事情。 它具有永久性分配, 也就是说,它会永远存在于存储器内的 某个地址上。 有时,我们确实需要永久性分配,但是我们 可以不使用全局变量。 这时,我们会创建一个静态变量。 这里便是一个静态变量的例子。 它具有永久性分配, 但是其范围是私有的-- 针对该文件的私有范围。 因此,只有该文件中的函数才能访问 m。 其他函数无法将其用作外部变量并获取该变量。 这种范围限制将会降低复杂性。 局部变量具有私有范围和动态分配, 其中动态分配 意味着它临时存储在寄存器中或堆栈上。 这是一件好事,因为这样您便可以 重复使用该资源。 这种变量的范围局限于相应的函数。 例如,这里便有一个局部变量。 这里是另外一个局部变量。 它们具有相同的名称,但是却是不同的 变量。 所以,这个局部变量的范围是这个函数。 而这个局部变量的范围是这个函数。 事实证明,我们还需要考虑局部参数。 这个参数 x 的访问范围仅限于 这个函数。 所以这是一个局部变量。 因此,还有另外一种静态变量, 这种静态变量也具有永久性分配 和私有范围。 但是,如果我将该静态变量放在这里, 那么它的范围将仅限于该函数内。 这是一个仅发生一次的静态变量,它等于 0, 因此,它在存储器的某个位置上具有 永久性分配,而且会在启动时初始化为 0。 之后每次调用该函数, 它都会递增。 所以,您可以看到它的功能是什么。 它将会对调用 随机数生成器的次数进行计数, 如果这是您想要的。 所以,在这里,我们的工作是 了解范围和分配。 我们想要做的是,尽量减小范围。 我们对范围的限制越严格, 我们的系统就越简单。 因此,我们必须了解,谁实际上需要知道, 或者说访问该变量。 如果我能减小它的范围,我的系统就会变得更简单。 这个原则同样适用于分配。 如果我能够动态分配变量,方法包括将变量置于堆栈上, 在寄存器中使用变量,或者在 C 代码中将其设置为局部变量, 那么我就可以重复使用该资源。 有时,我真的需要永久性地记录某些信息, 那么,我将会为其提供永久性分配。 但是,正如在上一张幻灯片中所讲的,我希望将其作为静态变量, 以便仅允许相应文件访问该变量。 跟其他问题一样,我们也在 几乎每张相关的幻灯片内反复提及以下问题, 即处理对象是有符号的还是无符号的。 再说明一次,无符号C99 变量以 U 开头, 有符号变量以 Int 开头。 请注意并明确自己谈论的是 8 位、16 位, 还是 32 位类型。 我们在前面提到过,其中一种处理方式是 进行升级,因为您无法将一个有符号 数字与一个无符号数字相加。 您无法将一个有符号数字与一个无符号数字 进行比较,但是您可能又想要这样做。 您将要做的是,将它们升级到 同一类型,在这一新类型下执行运算, 然后将其降级或保持不变。 这向您展示了一种可以在不丢失信息的情况下 进行升级的方式。 所以,一个 8 位数字可以成为一个 16 位数字, 一个 8 位数字可以成为一个16 位或 32 位数字, 无符号 16 位可以成为无符号和有符号的 32 位, 有符号的 16 位可以成为有符号的 32 位。 在讨论变量的同时, 让我们来讨论一下 I/O 端口。 I/O 端口 1,输出。 我们将会在后面详细介绍各个端口, 这里只是想说明该端口存在于存储器中, 所以其行为方式与变量类似。 当您从德州仪器获取该端口时, 它存在于一个大家 都知道的地址上。 由于它具有永久性的地址, 而且大家到知道具体的位置, 因此,它在形式上和规则上是一个全局变量。 它支持公共访问,而且具有永久性分配。 我说过这样很糟糕。 任何软件都可以访问该端口。 但是,为了降低复杂性, 我们将会从另外一种角度来看待端口寄存器。 不是关注谁可以访问,而是关注谁会访问。 如果我们限制谁会访问我们的端口寄存器, 这将会大大降低软件的复杂性。 因此,从实践角度出发, 我们将把 I/O寄存器视为 类似静态变量的私有永久性元素。 所以,您对程序中各元素的范围的 限制越严格,您的软件就越简单。 常量,我们可以将它们放在这里,并使用定义语句。 这里又用到了这个非曲线函数, 我们取输入值,并计算距离。 该曲线的形状将通过这两个 数字进行编码。 如果我们有许多常量,我们可以将它们放在 ROM 中, 这一点可通过 Const 实现。 有时,我们可能想要使用词语,而不是数字。 这时,您将会使用枚举类型。 所以,如果机器人-- 这是我的机器人,将沿这条路移动。 这是墙壁。 如果我离右侧墙壁太近了, 我可能想要说,我离右侧墙壁太近了, 而不是简单地说X 等于 2, 虽然这也是在表示离右侧墙壁太近,我能做的是 使用枚举类型。 这是一个标头, 它实际上并不是变量, 而只是一个结构。 如果我想要一个变量,我将会这样做。 比如说 scenario_t,这是一个类型-- 下划线 t 表示这是一个类型。 然后,我将会创建一个变量。 如果我的情况是离右侧墙壁太近, 我可以将 me 设置为等于 right too close。 总的来说,这两者其实代表的是 同一件事情。 只是这可以让您的代码更易于阅读。 这同样也是一个常量,我们都知道它的值 将会是 2。 但是,这让我的软件更加易于阅读。 这便是创建常量的三种不同的方式。 我们可以讨论您的行事方式。 如果您有一个 A,一个 B。执行 A,然后 执行 B,这句话是一个序列。如果 A 为 true, 那么执行 B,这是条件语句。 执行 A,直至 B,这可能是一个 while 循环。 我们会看到一些事件,看到很多中断。 所以,我们可以创建一些触发器。 当您触摸按钮时,我们可能会 执行某个操作,比如停止电机转动。 如果撞到墙壁,则停止电机转动。 这便是一个中断。 我们将会看到的另外一种中断是, 每秒钟执行某个操作 100 次。 比如,我们可能会每秒对传感器采样 100 次。 好的,总结一下,我们了解了 “与”运算相关的一些基本问题, 并且我还提醒您注意处理对象是有符号的 还是无符号的,是 8 位、16 位, 还是 32 位。 对于变量,请确保您了解 其范围,也就是谁可以访问,并且如果可以, 尽可能地将其作为静态变量或局部变量, 以限制其范围。 然后是关注分配, 也就是变量存在于哪里。 希望您喜欢本课程,我们下次再见。
课程介绍 共计5课时,1小时11分51秒

TI-RSLK 模块 4 - 使用 MSP432 进行软件设计

TI 机器人 MSP432 软件设计 RSLK

此模块除了讲解使用 MSP432 和 TI Code Composer Studio™ 进行编译和调试的概念外,还介绍了 C 语言(一种通用编程语言)。在开发与机器人相关的复杂系统时,调试技能很重要。

推荐帖子

发现之旅,让你身边的电源无处可藏!(07.21-08.02)
获奖名单已经公布: 【颁奖礼】7月“挖电源”主题月!!!https://bbs.eeworld.com.cn/thread-298588-1-1.html     离开了电源怎么活?大家来给答案吧!既然电源弥漫在生活各处,咱们就从边边角角把他们挖出来、用相机记录下来,曝光出来、整整他们的“猛料”! 让咱的电子设计工作也乐起来,与生活更贴近~~~~   活...
EEWORLD社区 模拟与混合信号
bootloader远程升级
以前做过远程升级,但用的是IAP开发环境,现在用keil不知道怎么用了。我记得在IAR中有个地方要设置options->linker->config 选择LM3S_APP.icf若不要用bootloader则选择LM3S_Debug.icf。请问各位高手在keil中这些东西在哪设置,怎么设置? 方便的话可以加qq:540655355,大家一起学习学习...
allan0508 微控制器 MCU
油站油气回收自动监测系统中的流量原理介绍
502 Bad Gateway 502 Bad Gateway openresty ...
灞波儿奔 微控制器 MCU
弱问有人使用28035的IQmath成功过吗
502 Bad Gateway 502 Bad Gateway openresty ...
qunge12345 微控制器 MCU

dingxilindy

学习TI-RSLK 模块 4 - 使用 MSP432 进行软件设计

2019年09月26日 15:21:30

hawkier

学习了

2019年08月03日 13:19:16

zwei9

学习-TI-RSLK 模块 4 - 使用 MSP432 进行软件设计

2019年07月06日 03:04:25

大明58

好好学习天天向上。。。

2019年07月03日 20:53:48

hellokt43

好好学习天天向上。。。

2019年05月19日 13:42:45

凤凰息梧桐

学习一下

2018年12月30日 20:17:16

百万千万

学习

2018年10月18日 17:26:38

warMan

学习看看。

2018年10月15日 23:11:24

dl265361

学习

2018年10月15日 21:51:36

273734588

学习

2018年10月11日 07:50:19

分享到X
微博
QQ
QQ空间
微信

EEWorld订阅号

EEWorld服务号

汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新文章 手机版

站点相关: EEWORLD首页 EE大学堂 论坛 下载中心 Datasheet 活动专区 博客

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2023 EEWORLD.com.cn, Inc. All rights reserved