当前位置:网站首页 > 编程语言 > 正文

单片机程序编写(单片机程序编写步骤)




  介绍一下单片机开发的C语言使用,C语言知识博大精深,基础还是需要系统学一下的,这里由于篇幅有限


在这里插入图片描述

1.1.1 基本数据类型

  数据类型就是一个数据的存储类型,体现为占据空间的大小。单片机的 C 语言中常用的基本数据类型如下:
在这里插入图片描述

注意:当数据类型在运算时不同会进行类型转换,优先级如下:
  bit→char→int→long→float→signed→unsigned
  也就是说,当 char 型与 int 型进行运算时,先自动对 char 型扩展为 int 型,然后与 int 型进行运算,运算结果为 int 型。

补充:C51扩充数据类型主要如下(在文件“reg51.h”中):
在这里插入图片描述

1.1.2 常量与变量

  C语言运算量分为常量和变量,常量其实和变量没有多大区别,有名字,占据存储空间,可以是任何的基本类型,但只有一点不同,常量的值不允许变更,通常用const关键字定义常量,如下所示:

 
    

补充

  1. 布尔型变量
      _Bool类型长度为1,只能取值范围为0或1。将任意非零值赋值给_Bool类型,都会先转换为1,表示真。将零值赋值给_Bool类型,结果为0,表示假。如下所示变量MCU_IO1只能取0或者1:
 
    
  1. 位变量
      在 C51 中,允许用户通过位类型符定义位变量。位类型符有两个:bit 和 sbit。可以定义两种位变量。bit 位类型符用于定义一般的可位处理位变量。sbit 位类型符用于定义在可位寻址字节或特殊功能寄存器中的位,定义时须指明其位地址,可以是位直接地址,可以是可位寻址变量带位号,也可以是特殊功能寄存器名带位号。格式如下:
 
    
  1. 特殊功能寄存器变量
      在 C51 中,允许用户对特殊功能寄存器进行访问,访问时须通过 sfr 或sfr16 类型说明符进行定义,定义时须指明它们所对应的片内 RAM 单元的地址。sfr 用于对 51 单片机中单字节的特殊功能寄存器进行定义,sfr16 用于对双字节特殊功能寄存器进行定义。特殊功能寄存器名一般用大写字母表示。地址一般用直接地址形式。格式如下:
 
    

1.1.3 存储属性

  1. register
      使用 register 定义的变量称为寄存器变量。它定义的变量存放在 CPU 内部的寄存器中,处理速度快,但数目少。C51 编译器编译时能自动识别程序中使用频率最高的变量,并自动将其作为寄存器变量,用户可以无需专门声明。
  2. auto
      使用 auto 定义的变量称为自动变量,其作用范围在定义它的函数体或复合语句内部,当定义它的函数体或复合语句执行时,C51 才为该变量分配内存空间,结束时占用的内存空间释放。自动变量一般分配在内存的堆栈空间中。定义变量时,如果省略存储种类,则该变量默认为自动(auto)变量。
  3. static
      使用 static 定义的变量称为静态变量。它又分为内部静态变量和外部静态变量。在函数体内部定义的静态变量为内部静态变量,它在对应的函数体内有效,一直存在,但在函数体外不可见,这样不仅使变量在定义它的函数体外被保护,还可以实现当离开函数时值不被改变。外部静态变量上在函数外部定义的静态变量,它在程序中一直存在,但在定义的范围之外是不可见的。如在多文件或多模块处理中,外部静态变量只在文件内部或模块内部有效,内部静态变量是全局变量
  4. extern
      使用 extern 定义的变量称为外部变量。C语言中extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里面要注意,对于 extern 申明变量可以多次,但定义只有一次
  5. typedef针对标识符
      typedef用于为现有类型创建一个新的名字,或称为类型别名,用来简化变量的定义。typedef 在 MDK 用得最多的就是定义结构体的类型别名和枚举类型了。
 
    

补充:存储器类型
  存储器类型是用于指明变量所处的单片机的存储器区域情况。存储器类型与存储种类完全不同。C51编译器能识别的存储器类型有以下几种,见表所示:

存储器类型 描述 data 直接寻址的片内 RAM 低 128B,访问速度快 bdata 片内 RAM 的可位寻址区(20H~2FH),允许字节和位混合访问 idata 间接寻址访问的片内 RAM,允许访问全部片内 RAM pdata 用 Ri 间接访问的片外 RAM 的低 256B xdata 用 DPTR 间接访问的片外 RAM,允许访问全部 64k 片外 RAM code 程序存储器 ROM 64k 空间
  1. 赋值运算符

变量=表达式;

  1. 算术运算符
符号 含义 + 加或取正值运算符 - 减或取负值运算符 * 乘运算符 / 除运算符 % 取余运算符
  1. 关系运算符
Operator 符号 等于 == 不等于 != 大于 > 小于 < 大于或等于 >= 小于或等于 <=
  1. 逻辑运算符
Operator 符号 与 && 或 || 非 !

注意:&&左右都得成立为真;||左右有一个成立为真

  1. 位运算符
符号 作用 & 按位与 I 按位或 ^ 按位异或 ~ 按位取反 << 左移 >> 右移

注意:~是按位取反;!是逻辑取反。

  1. 其他运算符
    1)复合赋值运算符
      C语言中支持在赋值运算符“=”的前面加上其它运算符,组成复合赋值运算符。如“+=”,a+=b等价于a=a+b
    2)逗号运算符
      在C语言中,逗号“,”是一个特殊的运算符,可以用它将两个或两个以上的表达式连接起来,称为逗号表达式。
    3)条件运算符
      条件运算符“?:”是C语言中唯一的一个三目运算符,它要求有三个运算对象,用它可以将三个表达式连接在一起构成一个条件表达式。其功能是先计算逻辑表达式的值,当逻辑表达式的值为真(非 0 值)时,将计算的表达式 1 的值作为整个条件表达式的值;当逻辑表达式的值为假(0 值)时,将计算的表达式 2 的值作为整个条件表达式的值。条件表达式的一般格式为:





逻辑表达式?表达式 1:表达式 2

  顺序结构是最基本、最简单的结构,在这种结构中,程序由低地址到高地址依次执行,即程序是从上执行到下。除了顺序结构,还有选择结构和循环结构

1.3.1 选择结构

  选择结构可使程序根据不同的情况,选择执行不同的分支,在选择结构中,程序先都对一个条件进行判断。当条件成立,即条件语句为“真”时,执行一个分支,当条件不成立时,即条件语句为“假”时,执行另一个分支。如图:
在这里插入图片描述
  在C中,实现选择结构的语句为 if/else,if/else if 语句。另外还支持多分支结构,多分支结构既可以通过 if 和 else if 语句嵌套实现,可用 swith/case 语句实现。

  1. if-else语句
 
    
  1. switch语句
      使用break关键字跳出switch语句,若没有,则会顺次执行后面的语句,直到遇到 break 或结束。
 
    

1.3.2 循环结构

  在程序处理过程中,有时需要某一段程序重复执行多次,这时就需要循环结构来实现,循环结构就是能够使程序段重复执行的结构。循环结构可以用while和for语句,如下:
在这里插入图片描述

  1. while
      while语句特点是先判断条件,后执行循环体。循环语句可以使用continue结束本次循环进入下一次循环。也可以使用break直接跳出循环体,执行循环体后面的语句。如:
 
    
  1. do-while
      do-while语句特点是先执行循环体,后判断条件,如
 
    
  1. for循环
      for循环执行流程:

①表达式1->表达式2->语句->表达式3
②表达式2->语句->表达式3
③一直循环到表达式2不成立停止循环

 
    

  C语言函数可以将一个常用的功能封装成API,给以后需要时来调用,函数定义如下:

 
    

  函数类型是函数返回类型,要配合return,如:

 
    

  如果函数类型是void即空类型,可以不用加return返回。修饰符在C51中常用的就是interrupt m 修饰符,m 的取值为 0~31代表中断向量表,如

 
    

注意:当在一个C文件调用另一个C文件定义的函数时,除了要加头文件,还需要用extern来申明一下函数,函数原型一般形式如下:

 
    

  数组在内存里是以堆栈形式存在的,它可以截取一段空间来存取固定数据类型的数据。一维数组定义形式如下:

 
    

  数组的数据类型可以是数值也可以是字符,如下:

 
    

注意:除了一维数组还有高维数组,比如二维数组一般用来进行矩阵运算,这里就不展开了

1.6.1 指针的定义

  指针是C语言中的一个十分重要的概念,在C中的数据类型中专门有一种指针类型。指针为变量的访问提供了另一种方式,变量的指针就是该变量的地址,还可以定义一个专门指向某个变量的地址的指针变量(指针即地址)。C中提供了两个专门的指针运算符:

符号 作用 * 指针运算符 & 取地址运算符

  指针运算符“*”放在指针变量前面,通过它实现访问以指针变量的内容为地址所指向的存储单元。取地址运算符“&”放在变量的前面,通过它取得变量的地址,变量的地址通常送给指针变量。例如:

 
    

1.6.2 指针数组与数组指针

  1. 指针数组
      指针数组本质上还是一个数组,只是数组的元素是指针形式,如下:
 
    
  1. 数组指针
      数组指针首先是一个指针,只不过这个指针是一个数组,可以理解为指向数组的指针
 
    

1.6.3 函数指针与指针函数

  1. 函数指针
      函数指针是指向函数的指针变量,即本质是一个指针变量。它允许通过变量名引用函数,而不是通过函数名。在C语言中,函数名实际上是函数代码的内存地址。因此,函数指针存储着代码段中相应的地址。使用函数指针可以方便地在代码中传递和使用函数作为参数,也可以在程序运行时动态地指定需要调用的函数。如:
 
    
  1. 指针函数
      指针函数是返回指针的函数,即本质是一个函数。它允许返回指向指针的指针,也可以返回指针数组。指针函数可以用于动态内存分配、数据结构遍历等场景。此外,它也可以浓缩代码思路,提高代码的可读性和可维护性。如:
 
    

注意:函数、指针和数组可以结合一起使用,如下:

 
    

1.7.1 结构体

  结构体是很实用的数据类型,与数组的区别是,结构体可以定义不同变量类型的成员。声明结构体类型:

 
    

  结合指针,可以申明一个结构体指针,结构体指针成员变量引用方法是通过“->”符号实现

 
    

  结构体就是将多个变量组合为一个有机的整体,这样方便对数据的管理。如串口设置:

 
    

  于是,我们在初始化串口的时候入口参数就可以是 USART_InitTypeDef 类型的变量或者指针变量了,MDK 中是这样做的:

 
    

1.7.2 共用体

  结构体的定义是需要使用关键字 struct,而共用体则是需要另一个关键字 union来进行定义。共用体只能在定义的时候声明变量,无法在后续的程序中再次声明变量的问题,可以通过 typedef 关键字来自定义数据类型的名称。共用体的定义方式:

 
    

注意:共用体变量所占用的内存中仍然只是存储一个数据,空间为最大的数据所占用的空间大小。所以引用不同的类型的时候,会将内存中的数据进行覆盖重写。作用有两个:
①初始化时,可以直接对最长的变量初始化,其他都跟着初始化了
②当一个位置需要存储两种不同类型的数据的时候,可以单独存储(即只用其中一个类型)
③共用体是小端模式


1.7.3 枚举类型

  如果变量的值确定,则可以定义枚举类型

 
    

注意
①枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。
②第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。在当前值没有赋值的情况下,枚举类型的当前值总是前一个值+1.

电平(V) VOHmin VOLmax VIHmin VILmax TTL电平 2.4 0.4 2.0 0.8 CMOS电平 4.99 0.01 3.5 1.5

  TTL和CMOS 的逻辑电平转换:CMOS 电平能驱动 TTL 电平,但 TTL 电平不能驱动 CMOS 电平,需加上拉电阻。

  1. 进制转换
      在学逻辑运算前,首先要知道逻辑运算是对二进制的逻辑运算。而二进制的0he1就代表低电平和高电平,不过由于位数多了二进制太长,不方便阅读,又有了八进制、十进制和十六进制。有关具体进制转换这里不做介绍,一般在数电第一章就介绍,可以用电脑计算器直接计算,如下图所示:
    在这里插入图片描述

  2. 逻辑运算作用

1)位与:操作对象&=屏蔽字

可实现目标字段清0,即屏蔽字为0的清零

2)位或:操作对象|=屏蔽字

可实现目标字段置位,即屏蔽字为1的置1

3)异或:操作对象^=屏蔽字

可实现目标字段取反,即屏蔽字为1的取反

  @是IAR编译器里指定变量存储地址的一个符号

 
    

  如设置绝对地址

 
    
 
    

  不是给a赋初值,在内存中存取数据的最小单位一般是字节,但有时存储一个数据不必用一个字节。这是一种位域的结构体,这个结构里a占用的是一个字节中的1位,所以这里的a取值只能是0和1,因为它们都是用1位来表示的。类似bit和_Bool

  用volatile申明的变量可以防止被编译器优化而省略

  define 是 C 语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。宏定义在编译时,会将目标字符直接替换。常见的格式:

 
    

注意:宏定义#define用换行

  单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。条件编译命令最常见的形式为:

 
    

  它的作用是:当标识符已经被定义过(一般是用#define 命令定义),则对程序段 1 进行编译,否则编译程序段 2。 其中#else 部分也可以没有

 
    

注意:在STM32F407的ADC配置里,这两个等效

 
    
  1. 如何提高代码的可移植性——就是把跟硬件相关的IO都用宏定义来实现
  2. 在建工程Define里调用的宏定义必须和头文件参数一致,或者修改与硬件一致
  3. 字长定义
    unit8_t= u8是unsigned char(无符号字节,其中unit8_t是标准定义)
    unit16_t=u16是unsigned short
    unit32_t=u32是unsigned int


  4. 命名
    宏定义全部大写字母
    函数、数组、变量首字母大写,如果全局变量、数组要用_
    局部变量小写字母


到此这篇单片机程序编写(单片机程序编写步骤)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 打印机控件怎么装(打印控件怎么安装)2025-09-18 21:36:09
  • ubuntu镜像怎么下载(ubuntu镜像下载地址)2025-09-18 21:36:09
  • 生成范围内的随机数(生成有范围的随机数)2025-09-18 21:36:09
  • 有趣的代码游戏(有趣的代码游戏迷你 枪战)2025-09-18 21:36:09
  • 爱普生C7000和7845哪个好(爱普生tw7000和7400)2025-09-18 21:36:09
  • 免费海报制作模板(免费海报制作模板_可画)2025-09-18 21:36:09
  • endnote(endnote主要用来干什么)2025-09-18 21:36:09
  • ip地址换算网络地址(ip地址计算网络地址)2025-09-18 21:36:09
  • max6921程序(max6921中文手册)2025-09-18 21:36:09
  • 民间游戏的分类有哪些(民间游戏的定义及分类)2025-09-18 21:36:09
  • 全屏图片