发 帖  
原厂入驻New

[经验] 嵌入式应用程序的C编程语言简介

2020-9-8 20:56:45  420 c语言 应用程序
分享
3
按照现代技术的标准,C是一种相当古老的语言。最初的开发发生在70年代初,随后在70年代后期进行了修订,并在80年代实现了标准化。但是,我认为它没有失去活力。对于嵌入式应用程序而言,它仍然是一门伟大的语言,以我的经验,它是适用于从简单的基于微控制器的设备到复杂的数字信号处理等所有内容的编程环境。

对C的需求
毫无疑问,至少有几位电气工程师不知道如何用C编写程序,也永远不需要用C编写程序。如果您是那种喜欢硬件胜于软件的人,那么您可能会将这些人视为“幸运者”。
不管我们是否喜欢,编程都是电气工程中越来越重要的部分,实际上,我不仅对能够设计电路板而且能够为这些板编写固件感到非常满意。系统开发的这两个方面密切相关,我怀疑当同一人进行电路板设计和固件开发时,最终结果通常会更好。

C与汇编
从理论上讲,我是汇编语言的支持者。实际上,我到了人生的关键时刻,汇编语言对我的财务安全和理智都构成了威胁。以汇编形式编写固件速度慢且容易出错,而在复杂的长程序中维持适当的组织水平则无可救药。
但是,我一定会坚持认为,如果您不了解汇编语言,就无法真正理解高级语言。如果您从未有过使用汇编语言的扎实经验,则在进入C语言之前,至少应熟悉一些基本概念。以上“支持信息”部分中列出的文章是一个不错的起点。 。



如果您想了解有关此主题的更多信息,请查看我们有关Assembly vs. C的全文。

处理器了解什么?
仅机器语言。一和零。C语言的所有“程序员友好”方面都必须最终转化为处理器数字硬件的底层现实,即二进制算术,逻辑运算,数据传输,寄存器和存储器位置。
在不了解实际硬件的情况下当然可以成功地用C编写程序,但是在嵌入式系统开发的背景下,了解硬件以及C代码如何与该硬件交互是有帮助的,有时也有必要。


基础
C程序的范围从非常简单的程序到非常复杂的程序。在嵌入式世界中,许多程序将趋向于简单的一面,下面描述的基本编程元素为进一步研究C语言固件开发提供了良好的基础。

包含陈述
嵌入式C程序将至少以一个#include语句开头。这些语句用于将单独文件的内容引入源文件。这是使代码井井有条的便捷方法,并且还允许您使用库功能,硬件配置例程以及制造商提供的寄存器定义。
下面的代码摘录显示了我在一个微控制器项目中使用的include语句。请注意,“ Project_DefsVarsFuncs.h”文件是程序员(即我)创建的自定义头文件。我使用它作为将预处理器定义,变量和函数原型合并到多个源文件中的便捷方法。
  1. //-----------------------------------------------------------------------------
  2. // Includes
  3. //-----------------------------------------------------------------------------
  4. #include                   // SFR declarations
  5. #include "Project_DefsVarsFuncs.h"
  6. #include "InitDevice.h"
  7. #include "cslib_config.h"
  8. #include "cslib.h"

  9. 预处理程序定义

  10. 您可以使用#define语句创建将被数字替换的字符串。预处理器定义不是必需的,但是在某些情况下它们非常有用,因为它们使您可以轻松地修改出现在程序各个不同部分的值。

  11. 例如,假设您正在使用微控制器的ADC,并且您的代码在多个单独的计算中使用了ADC的采样率。预处理程序定义允许您使用直观的字符串(例如SAMPLE_RATE)代替计算代码中的数字本身,并且,如果您尝试使用不同的采样率,则只需更改预处理程序定义中的一个数字值。

  12. #define SAMPLE_RATE 100000

  13. 您可以将100000更改为任何其他数字,并且该新数字将用于替换字符串SAMPLE_RATE的所有实例。

  14. 预处理程序定义也是使代码更具可读性的好方法。以下是方便的#define语句的列表,我将它们合并到所有固件项目中。

  15. #define BIT7 0x80
  16. #define BIT6 0x40
  17. #define BIT5 0x20
  18. #define BIT4 0x10
  19. #define BIT3 0x08
  20. #define BIT2 0x04
  21. #define BIT1 0x02
  22. #define BIT0 0x01

  23. #define HIGH 1
  24. #define LOW 0

  25. #define TRUE 1
  26. #define FALSE 0

  27. #define SET 1
  28. #define CLEARED 0

  29. #define LOWBYTE(v)   ((unsigned char) (v))
  30. #define HIGHBYTE(v)  ((unsigned char) (((unsigned int) (v)) >> 8))

  31. 重要的是要了解预处理器定义与硬件没有直接关系。您只是在告诉编译器在程序编译之前将一个字符串替换为另一个字符串。

  32. 变量

  33. 处理器将数据存储在寄存器和存储器位置中。就硬件而言,确实没有任何变量。但是,对于程序员而言,当我们可以使用直观命名的变量而不是内存地址或寄存器号时,编写代码要容易得多。

  34. 编译器可以在无需程序员大量输入的情况下管理与变量相关的低级细节,但是如果您想优化变量的使用,则需要了解一些有关设备内存配置及其处理不同数据的方式的知识。位宽。

  35. 以下代码摘录给出了变量定义的示例。这是为Keil Cx51编译器编写的,该编译器为“ unsigned char”定义保留一个字节的内存,为“ unsigned int”定义保留两个字节,为“ unsigned long”定义保留四个字节。

  36. unsigned long Accumulated_Capacitance_Sensor1;
  37. unsigned long Accumulated_Capacitance_Sensor2;

  38. unsigned int Sensor1_Unpressed;
  39. unsigned int Sensor2_Unpressed;

  40. unsigned int Sensor1_Measurement;
  41. unsigned int Sensor2_Measurement;

  42. unsigned int AngularPosition;

  43. unsigned int TouchDuration;

  44. unsigned char CurrentDigit;
  45. unsigned int CharacterEntry;
  46. unsigned char displayDivider;

  47. 运算符,条件语句和循环


  48. 计算功能的核心包括移动数据,对数据执行数学计算和逻辑运算,以及根据存储或生成的数据的值进行程序决策。

  49. 数学运算和位操作通过运算符完成。C有很多运算符:等于(=),加法(+),减法(-),乘法(*),除法(/),按位与(&),按位或(|)等。运算符语句的“输入”是变量或常量,结果存储在变量中。

  50. 条件语句允许您根据给定条件是true还是false来执行或不执行操作。这些陈述使用“ if”和“ else”等词;例如:

  51. if(Sensor1 < Sensor2 && Sensor1 < Sensor3)
  52.         return SENSOR_1;

  53. else if(Sensor2 < Sensor1 && Sensor2 < Sensor3)
  54.         return SENSOR_2;

  55. else if(Sensor3 < Sensor2 && Sensor3 < Sensor1)
  56.         return SENSOR_3;

  57. else
  58.         return 0;

  59. for循环和while循环提供了一种方便的方式来重复执行代码块。这些类型的任务在嵌入式应用程序中经常出现。For循环更适合于必须执行一定次数的代码块的情况,而当处理器应继续重复相同的代码块直到条件从true变为false时,while循环很方便。这是这两种类型的示例。


  60. for (n = 0; n < 16; n++)
  61. {
  62.         Accumulated_Capacitance_Sensor1 += Measure_Capacitance(SENSOR_1);
  63.         Delay_us(50);
  64.         Accumulated_Capacitance_Sensor2 += Measure_Capacitance(SENSOR_2);
  65.         Delay_us(50);
  66. }

  67. while(CONVERSION_DONE == FALSE);
  68. {
  69.         LED_STATE = !LED_STATE;
  70.         Delay_ms(100);
  71. }

  72. 功能

  73. 好的C代码在组织和可读性方面大大优于汇编代码,这在很大程度上是由于函数的使用。

  74. 函数是可以轻松合并到代码其他部分中的代码块。使处理器执行功能中包含的指令称为“调用”功能。一个函数可以接受一个或多个输入,并且可以提供一个输出,称为返回值。
复制代码



C的函数,条件语句和循环使将流程图转换为工作代码相当容易。本示例来自一个项目,在该项目中,我使用SPI通信来控制LCD。
函数的使用确实会带来一些开销,因此我们必须小心,不要给处理器增加过多的函数调用负担,但总的来说,函数的收益远大于成本。
这是一个函数的示例,该函数具有三个数字输入,并使用这些输入生成一个真或假返回值。
  1. bit Is_In_Range(int input, int LowerBound, int UpperBound)
  2. {
  3.         if(input >= LowerBound && input <= UpperBound)
  4.                 return TRUE;

  5.         else
  6.                 return FALSE;
  7. }
复制代码

结论
几乎可以无限期地进行有关C语言的全面讨论,而本文只是从头开始。我什至不愿发表一些忽略很多重要信息的东西,但我们必须从某个地方开始。我们计划发布更多有关在嵌入式应用程序中使用C语言的文章,并且在其他资源可用时,我们将在本入门文章中添加链接。
如果您想了解与C相关的主题,请随时在下面的评论部分中告诉我们。

可能你还想学习:
了解C编程中的变量

了解C编程中的数组

C编程中的指针:什么是指针,它做什么?

C编程中的函数是什么?

如何将功能整合到嵌入式固件中

如何在C语言固件中使用指针

在C语言固件中使用功能的五个技巧


评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发经验
关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表