STM32 嵌入式学习入门(0)——C语言基础复习

摘要

    主要介绍了嵌入式编程中几个常用,但软件编程中用得不是很多的C语言知识。包括位操作、条件编译、结构体和结构体指针、typedef声明类型、以及extern变量声明、static关键字等内容。

   本文并没有将相关C语言知识点介绍地很详细,毕竟这么多知识点要想掌握绝对不是看几篇文档就能掌握的。因此博主建议,如果上述的C语言知识掌握得还不是很好的话,找一本C语言的书好好研究研究。尤其是结构体和结构体指针、还有函数的知识(本文没提到),一定要很熟练。

    本文除了简要介绍C语言知识,也结合博主自己的感受简单谈了各个知识点用在了嵌入式编程的什么地方,有不详细和描述不准确的地方欢迎大家留言讨论。

 

 

要想学习STM32,C语言的基础是必须的。除了最基本的C语言的语法,如循环、判断、数组、结构体、函数、指针这些软件编程常用的知识外,还包括位操作、条件编译、结构体指针、typedef声明类型、以及extern变量声明、static关键字等常用内容。这里结合实际代码分析一下这些知识点,如果想完整系统地了解这些C语言知识,大家可以翻翻C语言教材,比如《C Primer Plus》(第六版)这本书,尤其对于位操作的知识讲得很详细。

 

一、位操作:

位操作简单说就是指对基本类型变量可以在位级别进行操作。下面先看几种位操作符:

&按位与~取反
|按位或<<左移
按位异或 >>右移

 

掌握了这六种操作否的用法,C语言的位操作就差不多了。这六种操作符的解释如下:

1. & 按位与: 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。//   1&1 = 1   1&0 = 0   0&1 = 0   0&0 = 0

2.|按位或:两个相应的二进制位中只要有一个为1,该位的结果值为1。//   1|1 = 1   0|1 = 1   1|0 = 1   0|0 = 0 

3.^按位异或: 若参加运算的两个二进制位值相同则为0,否则为1。//   1^1 = 0   0^1 = 1   1^0 = 1   0^0 = 0

4.!取反:  对一个二进制数按位取反,即将0变1,将1变0。//    1! = 0    0! = 1

5.<<左移:用来将一个数的各二进制位全部左移N位,右补0。//   00001100 << 2 = 00110000

6.>>右移:将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0。//   00001100 >> 2 = 00000011

 

下面介绍一些用寄存器开发STM32时候实用的位操作技巧:

1)不改变其他位的值的状况下,对某几个位进行设值。
这个场景单片机开发中经常使用,方法就是先对需要设置的位用 & 操作符进行清零操作,然后用 | 操作符设值。比如我要改变GPIOA的状态,可以先对寄存器的值进行 & 清零操作
然后再与需要设置的值进行 | (或运算)。

GPIOA->CRL&=0XFFFFFF0F; //将第 4-7 位清 0
GPIOA->CRL|=0X00000040; //设置相应位的值,不改变其他位的值 (将CRL寄存器第7位设置为1)

2)取反操作使用技巧
SR 寄存器的每一位都代表一个状态,某个时刻我们希望去设置某一位的值为 0,同时其他位都保留为 1,简单的作法是直接给寄存器设置一个值:
TIMx->SR=0xFFF7;
这样的做法设置第3位为0,但是这样的作法同样不好看,并且可读性很差。看看库函数代码中怎样使用的:
TIMx->SR = (uint16_t)~TIM_FLAG;


而 TIM_FLAG 是通过宏定义定义的值:
#define TIM_FLAG_Update ((uint16_t)0x0001)
#define TIM_FLAG_CC1 ((uint16_t)0x0002)
看这个应该很容易明白,可以直接从宏定义中看出 TIM_FLAG_Update 就是设置的第 0 位了,可读性非常强。

注:在STM32的开发中,更多的时间可能会直接使用官方的库函数,库函数实际上是将复杂的寄存器封装了一下。使用库函数可以避免复杂的位操作,使代码更具有可读性,但同样的项目,使用库函数其代码量可能会比直接通过操作寄存器写出来的工程的代码量稍微多一点,执行效率可能会稍微低一点,当然这只是一点点…………

学习STM32的时候要从寄存器上去理解原理,理解实现过程,但是如果真的需要做一个嵌入式项目,可能用库函数去开发比较方便,效率更好一点,这是博主自己的感受和观点。

 

二、条件编译:

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

#ifdef 标识符
程序段 1
#else
程序段 2
#endif

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

#ifdef
程序段 1
#endif

这个条件编译在 MDK 里面是用得很多的,在 stm32f10x.h 这个头文件中经常会看到这样的语句:

#ifdef STM32F10X_HD
大容量芯片需要的一些变量定义
#end

而 STM32F10X_HD 则是我们通过#define 来定义的。

条件编译理解起来也不是很困难,可以类比于C语言中的 if-else 语句去理解。条件编译在STM32的开发中还是比较常用的。自己写代码写 .h 文件的时候开头会用到。此外就是要能看懂库函数里面的条件编译了。

 

三、结构体和结构体指针:

结构体是C语言中的基础知识,同时结构体和结构指针也是STM32开发中非常重要的东西,尤其在使用库函数的时候,库函数中很多函数的入口参数中都有结构体指针,所以如果我们要调用这种函数,就先在主调函数中声明一个结构体变量,然后对这个结构体变量的各个成员赋值,最后再调用相关函数,调用的时候看清楚函数原型,入口参数是结构体类型还是结构体指针,不要搞错了。这里再多说两句,这里的结构体每个成员可以赋的值往往都是通过枚举或者宏定义确定好的,不能自己乱写,而应该去查找宏定义部分的代码,选定需要的那个枚举字面值作为结构体相关成员的值。

关于结构体和结构体指针的例子可以看GPIO的初始化,这里就不再多说了:STM32 GPIO的介绍

 

四、typedef声明类型:

如果学过数据结构,相信对typedef也不陌生。用typedef的一个好处就是使代码的可读性更高,写代码也更方便。typedef 在代码中用得最多的就是定义结构体的类型别名和枚举类型了。

 

struct _GPIO
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
};

定义了一个结构体 GPIO,这样我们定义变量的方式为:

struct _GPIO GPIOA;//定义结构体变量 GPIOA

但是这样很繁琐, MDK 中有很多这样的结构体变量需要定义。这里我们可以为结体定义一个别名 GPIO_TypeDef,这样我们就可以在其他地方通过别名 GPIO_TypeDef 来定义结构体变量了。方法如下:

typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
…
} GPIO_TypeDef;

Typedef 为结构体定义一个别名 GPIO_TypeDef,这样我们可以通过 GPIO_TypeDef 来定义结构体变量:

GPIO_TypeDef GPIOA,GPIOB;

 

这里的 GPIO_TypeDef 就跟 struct _GPIO 是等同的作用了。 这样是不是方便很多? 

除了用在结构体上,typedef类型别名也大量用在int、short等这种变量上, 所以写STM32代码的时候几乎就不会出现类似于定义int型变量这样的语句,全部用 u8、u16这样的量代替了,比如u16代表的就是一个无符号的16位整型数据(这一个描述可能有一点偏差)。

 

五、extern关键字:

C 语言中 extern 可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里面要注意,对于 extern 申明变量可以多次,但定义只有一次。在我们的代码中你会看到看到这样的语句:

extern u16 USART_RX_STA;

这个语句是申明 USART_RX_STA 变量在其他文件中已经定义了,在这里要使用到。所以,你肯定可以找到在某个地方有变量定义的语句:

u16 USART_RX_STA;


嗯,extern关键字,说实话,博主自己写代码确实没用过。So……

 

 

 

  • 26
    点赞
  • 154
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: STM32是一种常用的嵌入式系统开发平台,其开发语言主要使用C语言STM32嵌入式C语言是在C语言基础上进行了一些适配和优化,以便于在STM32芯片上进行嵌入式系统的开发。 使用STM32嵌入式C语言开发,首先要了解STM32系列芯片的特性和寄存器架构。然后,可以使用C语言中的各种语法和函数来编写嵌入式系统的程序。在C语言基础上,还需要了解一些特定的STM32相关的库函数和驱动程序,以便更好地利用STM32芯片的功能和资源。 STM32嵌入式C语言开发具有以下特点和优势。首先,C语言作为一种高级语言,具有丰富的语法和强大的数据处理能力,能够满足嵌入式系统开发的需求。其次,STM32嵌入式C语言支持直接访问芯片寄存器和外设,使开发者可以更好地控制和管理硬件资源。此外,使用C语言进行开发,能够更好地编写可移植、可维护和可扩展的嵌入式系统程序。 在STM32嵌入式C语言开发中,开发者可以使用各种开发工具和环境,如Keil、IAR等,来进行代码编写、调试和下载。同时,还可以利用丰富的开发资料和示例代码,快速上手和学习STM32嵌入式C语言开发技术。 总之,STM32嵌入式C语言是一种常用的嵌入式系统开发语言,通过熟练掌握C语言的语法和STM32芯片的特性,可以高效地开发出功能强大的嵌入式系统应用。 ### 回答2: STM32是一种基于Cortex-M系列内核的嵌入式微控制器的系列产品,它广泛应用于各种嵌入式系统的开发中。C语言是一种高级编程语言,具有简洁、高效、可移植的特点,非常适合嵌入式系统的开发。 在STM32嵌入式开发中,C语言扮演着重要的角色。首先,C语言可以直接访问硬件资源,比如外设寄存器和内部存储器,方便了对嵌入式系统的底层控制。其次,C语言具有丰富的数据类型和操作符,在算法设计和数据处理方面非常灵活。此外,C语言还提供了丰富的库函数,可以方便地完成各种常用的功能,比如串口通信、定时器控制、中断处理等。 对于STM32嵌入式C语言开发,开发者一般需要掌握以下几个方面的知识和技能。首先是C语言的基本语法和程序结构,包括变量、运算符、条件语句、循环语句等。其次是对于STM32微控制器的架构和外设的了解,比如GPIO、ADC、UART、SPI等。然后是掌握相关的开发工具和调试技巧,比如Keil、IAR等集成开发环境和调试器。最后是对于嵌入式系统的特性和应用场景的了解,以便根据具体需求进行系统设计和优化。 综上所述,STM32嵌入式C语言开发是一项非常重要且有挑战性的技术工作。掌握C语言基础知识和对STM32系列产品的了解是必不可少的,通过不断学习和实践,开发人员可以更好地利用STM32的特性和功能,开发出高效、可靠的嵌入式系统。 ### 回答3: STM32是一种广泛应用于嵌入式系统开发的微控制器系列产品,而C语言则是一种面向过程的计算机编程语言。STM32嵌入式C语言是指在STM32系列芯片上使用C语言进行嵌入式系统开发的方式。 使用嵌入式C语言开发STM32可以实现各种功能,如控制IO口、定时器、中断等。通过编写C语言代码,可以直接对STM32的内部寄存器进行操作,从而实现对外设的控制。同时,C语言具有跨平台性,编写的代码可以在不同型号的STM32芯片上运行,提高了开发效率。 嵌入式C语言相对于其他编程语言的优势在于其轻量级、高效性和灵活性。由于嵌入式系统往往对资源有限制,需要占用较少的内存和处理器时间,而C语言作为一种底层语言,具有较高的运行效率和内存控制能力,非常适合嵌入式系统的开发。 在STM32嵌入式C语言开发过程中,通常需要掌握基本的C语言语法、数据类型和运算符等基本知识。此外,还需要了解STM32的外设寄存器、内部时钟和编程接口等硬件相关知识,才能更好地进行嵌入式系统的开发和调试。 总之,STM32嵌入式C语言是一种在STM32芯片上使用C语言进行嵌入式系统开发的方式。它具有快速、高效、灵活等优势,能够满足嵌入式系统对资源的限制,是嵌入式系统开发中常用的编程语言。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值