嵌入式开发从入门到入土

写在前面的话

嵌入式开发涉及的层面很广,它既有底层硬件的开发,又涉及上层应用的开发,也就是所谓的系统集成的硬件和软件。而C语言不仅具有汇编语言操作底层的优势,又具有高级开发语言的功能性强的特点,当之无愧地成为了嵌入式开发中的主流语言。

所以,”在STM32开发过程中,不论是基于寄存器开发还是基于库开发,深入理解和掌握嵌入式C语言的函数、指针、结构体,这是学习STM32的关键“

嵌入式为何物?

网上一搜,教材一翻,关于嵌入式的简介满天飞,分析的很专业,解释的很透彻,但是…看不懂

伟大的现代哲学家吕小布说过,所谓教材就是把一堆简单易懂的名词扩写成一堆谁也看不懂的句子。

“沿波讨源,虽幽必显”,嵌入式其实就在我们身边,一些小家电,电饭煲、热水壶、冰箱、空调、洗衣机等,在这些琳琅满目的家电里面有那么一块电路板,上面焊满了各式各样的电子元器件和芯片。如果这些家电需要带上一些**“智能化”**功能如按键、显示屏、定时、感应等功能,则需要加一个可编程芯片,这个芯片就是单片机,也是微控制器,是这个电路板的大脑,单片机编程,从某种意义来说就是嵌入式开发

STM32的数据类型

  • 数据是嵌入式中C语言的基本操作对象,数据类型指的是数据在计算机内的存储方式

一些基本类型如下图:

在这里插入图片描述

  • 由于不同CPU定义的数据类型的长度不同,因此ARM公司联合其他半导体厂商制定了统一的CMSIS 软件标准,这个标准中预先定义了相关的数据类型,ST公司也为开发人员提供了基于C语言的标准外设库 :
1	STM32定义的数据类型
CSTM功能
unsigned charuint8_t0~255
unsigned short intuint16_t0~65535
unsigned intuint32_t0 ~ (2^32) - 1
unsigned long longuint64_t0 ~ (2^64) - 1
signed charint8_t(-128) ~ (+127)
signed short intint16_t(-32768) ~ (+32767)
signed intint32_t(-2^31) ~ (+2^31) - 1
signed long longint64_t(-2^64) ~ (+2^64) - 1
2	STM32的IO类型限定词
IO类型限定词类型说明
_IVolatile const只读
_Ovolatile只写
_IOvolatile读写

C语言中常用的关键字

1. const

  • const关键字用于定义只读的变量,其值在编译时不能被改变,注意,const关键字定义的是变量而不是
  • 使用 const关键字是为了在编译时防止变量的值被误修改,同时提高程序的安全性可靠性,一般放在头文件中或者文件的开始部分
  • const关键字定义的变量是全局变量
  • const 关键字与#definc关键字存在区别,#define关键字只是简单的文本替换,而const关键字定义的变量是存储在静态存储器中的 。
  • 使用**#define**关键字定义常量的形式为
#define PI 3.14159  
/*使用该方式定义后,无论在何处使用PI,都会被预处理器以3.14159替代,
编译器不对PI进行类型检查,若使用不慎,则很可能由预处理引入错误,
且这类错误很难发现。*/

用const声明变量的方式虽然增加了分配空间,但可以很好地消除预处理引入的错误,并提供了良好的类型检查形式,保证安全性。

  • 利用 const关键字进行编程时需要注意以下三点 :

    • 使用const关键字声明的变量,只能读取,不能被赋值。 如:
    const uint8t sum = 3.14;
    uint8_t abs=0;
     
    ...
    sum= abs; //非法,将导致编译错误,因为sum 只能被读取,不能赋值
    abs- sum: //合法
    
    • const关键词修饰的变量在声明时必须初始化,上述语句表示 sum值是3.14,且sum值在编译时不能修改,若在编译过程中直接修改sum值,则编译器会提示出错。
    • 函数的形参声明为const,则意味着所传递的指针指向的内容只能读,不能被修改。如C语言的标准函数库中用于统计字符串长度的函数 int strlen(const char*str)。

2.static关键字

static关键字可以用来修饰变量,使用static关键字修饰的变量,称为静态变量。

  • 静态变量的存储方式与全局变量一样,都是静态存储方式

  • 全局变量的作用范围是整个源程序,当一个源程序由多个源文件组成时,全局变量在各个源文件中都是有效的

  • 即一个全局变量定义在某个源文件中,若想在另一个源文件中使用该全局变量,则只需要在该源文件中通过 extern关键字声明该全局变量就可以使用了

  • 若在该全局变量前加上关键字static,则该全局变量被定义成一个静态全局变量,其作用范围只在定义该变量的源文件内有效,其他源文件不能引用该全局变量,这样就避免了在其他源文件中因引用相同名字的变量而引发的错误,有利于模块化程序设计。

    • static关键字不仅可以用来修饰变量,而且可以用来修饰函数。模块化程序设计中,若用static声明一个函数,则该函数只能被该模块内的其他函数调用
      #include "stm32f1xx_hal .h”
      static void DMA_SetConfig (DMA_HandleTypeDef *hdma,uint32_t SrcAddress,uint32_t DstAddress, uint32_t DataLength);
...
      HAL_statusTypeDef HAL_DMA_start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
      HAL_StatusTypeDef status- HAL_OK;.... ...
      if(HAL_DMA_STATE_REA.DY m- hdma->state)
  {
        DMA_Setconfig(hdma, SrcAddress, DstAddress, DataLength);
       ... ...
  }
      ... ...
}

/*上述代码为DMA模块的源文件stm32f1xx_hal_dma.c,
若利用static将DMA_SetConfig()函数声明为一个静态函数,
则 DMA_SetConfig)函数只能被stm32flxx_hal_dma.c中的其他函数调用,
而不能被其他模块的文件使用,即定义了一个本地函数,
有效避免了因其他模块的文件定义了同名函数而引发的错误,
充分体现了程序的模块化设计思想*/
    • static除了用于定义静态全局变量,还用于定义静态局部变量,保证静态局部变量在调用过程中不被重新初始化。典型应用案例有实现计数统计功能。
void fun_count()
{
      static count_num=0;
      //声明一个静态局部变量,count_num用作计数器,初值为0
      count_num++;
      printf("%d\n",count_num) :
}
int main(void)
(
     int i=0;
     for( i=0;i<=5;i++)
  {
     fun_count();
  }
     return 0;
}
    
/*在main函数中每调用一次 fun_count()函数,静态局部变量count_num加1,
而不是每次都被初始化为初值0。*/

3.volatile关键字

volatile关键字,它是一个类型修饰符,含义为“易变的”

volatile char i;
/*使用volatile关键字定义了一个字符型的变量i,指出i是随时可能发生变化的,
每次使用该变量时都必须从i的地址中读取*/
  • 由于内存的读/写速度远不及CPU中寄存器的读/写速度
  • 为了提高数据信息的存取速度
    • 一方面在硬件上引入高速缓存Cache
    • 另一方面在软件上使用编译器对程序进行优化 – 将变量的值提前从内存读取到CPU的寄存器中,以后用到该变量时,直接从速度较快的寄存器中读取
  • 这样有利于提高运算速度,但同时也可能存在风险:
    • 如该变量在内存中的值有可能被程序的其他部分(如其他线程)修改或覆盖
    • 而寄存器中存放的仍是之前的值,这就导致应用程序读取的值和实际变量值不一致
    • 也有可能是寄存器中的值发生了改变,而内存中该变量的值没有被修改,同样也会导致不一致的情况发生
  • 为防止由于编译器对程序进行优化导致读取错误数据,使用 volatile关键词进行定义
  • 使用volatile关键字就是不让编译器进行优化,即每次读取或者修改值时,都必须重新从内存中读取或者修改,而不是使用保存在寄存器的备份。
  • 使用 volatile关键字定义变量后,该变量就不会因外因而发生变化了 :
    • 中断服务程序中修改的、供其他程序检测的变量需要使用volatile关键字
    • 多任务环境下各任务间共享的标志应添加 volatile关键字
    • 外设寄存器地址映射的硬件寄存器通常要用volatile关键字进行声明

4.extern关键字

extern关键字用于指明此函数或变量定义在其他文件中,提示编译器遇到此函数或变量时到其他模块中寻找其定义

extern关键字声明的函数或变量就可以在本模块或其他模块中使用,因此,使用extern关键字是一个声明而不是重新定义

extern int a;
/*第一条语句仅仅是变量a的声明,而不是定义变量a,并未为a分配内存空间,
变量a作为全局变量只能被定义一次*/
extern int  funA( ):
/*第二条语句声明函数funA(),此函数已在其他文件中定义*/

下期预告

今天简单介绍了嵌入式开发的几个方向和几个常见的关键字介绍,其实很多知识都是我从别的博主中的博客中看到的,然后进行一个搬运总结,下期继续回顾结构体等C语言常用类型

万事开头难,所有的领域在学习的初期都是一个从无到有的过程,独自探索这个过程无疑是非常枯燥且痛苦的,没有结果产出的喜悦,也没有醍醐灌顶的振奋。
慢慢来吧,先搞起来再说,希望在这个领域,能遇到许多不以山海为远的相知者,一起交流
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值