物联网
您现在所在的位置:首页>企业动态>物联网

总结STM32开发中常用的C语言知识|技术文章

编辑:学到牛牛IT培训    发布日期: 2023-06-25 08:45:53  

1. 指针和内存

假如我们知道一个寄存器GPIOH_ODR的地址是 0x4002 1C14, 该寄存器是32bit,低16bit有效,对应着 16 个外部 IO,对应位写0/1代表输出低/高电平。我们可以通过指针去访问该地址,从而控制IO口输出。例如:


     unsigned int *p = ( unsigned int * )( 0x4002 1C14 );


     *p = 0xFFFF;


 亦可简写为:


*(volatile unsigned int *)( 0x4002 1C14) = 0xFFFF;


我们还可以通过宏定义的方式来操作:


#define GPIOH_ODR  (*(volatile unsigned int *)(0x4002 1C14))


GPIOH_ODR=0xFFFF;


2. #if

#if和#endif是一组同时使用的,叫做条件编译指令。#if与#define、#include等指令一样是由预处理器这个强大的工具处理的,预处理器可以在编译前处理c程序。在STM32中,相近平台的编程处理相近,一个库可能支持多个平台,但是平台间也有差异,通过条件编译指令进行编译选择。


1.png

2.png


3. #define

#define是 C语言 和 C++ 中的一个预处理指令,其中的“#”表示这是一条预处理命令·。凡是以“#”开头的均为预处理命令,“define”为宏定义命令,“标识符”为所定义的宏名。#define的部分运行效果类似于word中的ctrl+F替换,与常量const相比有着无法替代的优势。


3.png 

4.png 


4. 结构体内存对齐

一组寄存器(同一外设下的不同功能寄存器)具有相同的基地址,不同的偏移地址。比如:每个通用 I/O 端口包括 4 个 32 位配置寄存器( GPIOx_MODER、 GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR)、 2 个 32 位数据寄存器(GPIOx_IDR 和GPIOx_ODR)、 1 个 32 位置位/复位寄存器 (GPIOx_BSRR)、 1 个 32 位锁定寄存器(GPIOx_LCKR) 和 2 个 32 位复用功能选择寄存器( GPIOx_AFRH 和 GPIOx_AFRL)。


同组GPIO的基地址相同,但是偏移地址不同。如下图:


5.png 


常规映射可通过:


#define GPIOH_MODER   (*(volatile unsigned int *)(0x4002 1C14 + 0x00 ))


#define GPIOH_OTYPER   (*(volatile unsigned int *)(0x4002 1C14 + 0x04 ))


#define GPIOH_OSPEEDR   (*(volatile unsigned int *)(0x4002 1C14 + 0x08)


#define GPIOH_PUPDR  (*(volatile unsigned int *)(0x4002 1C14 + 0x0C ))


……


此方法可以解决映射,但是操作繁琐不便。


可通过寄存器分组及内存对齐,以组为一个对象抽象结构体,通过内存对齐,确定排序方式及单属性字节长度。通过结构体指针直接访问基地址,即解决映射问题,后期访问也方便。如下图:


6.png

7.png 


5. enum

enum是计算机编程语言中的一种数据类型。枚举类型:在实际问题中,有些变量的取值被限定在一个有限的范围内。取值范围闭环,并结合其他方式判断取值是否合法。


7.png

8.png

9.png


6. typedef

C语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。起别名的目的不是为了提高程序运行效率,而是为了编码方便,或者简化复杂类型的理解。例如有一个结构体的名字是 student,要想定义一个结构体变量就得这样写:


struct student STU;


或者:


10.png

11.png 


7. 结构体传参

在函数参数传递过程中,如果函数有多个参数需要传递,并且参数之间存在某种关联时,一般定义一个传参结构体进行参数传递。下面我们以GPIO为例进行说明。


每个通用 I/O 端口包括 4 个 32 位配置寄存器( GPIOx_MODER、 GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR),分别控制工作方式、开漏推挽、上拉下拉、工作速度等。


如果需要进行IO口初始化,那么函数最基本需要四个输入参数。比如:


void GPIO_Init(GPIO_TypeDef* GPIOx, int moder, int otyper, int ospeedr, int pupdr )


更好的方式采用:


// 传参结构体


12.png


// 函数定义


微信图片_20230625085149.png


8. 位运算

6.1 位清零操作(某些位清零,其他位不变)

GPIOH_ODR &= ~(1<<10); // 第10位清零


GPIOH_ODR &= ~(3<<10); // 第11、12位清零


GPIOH_ODR &= ~((1<<10)|(3<<15)); //第10、15、16位清零


6.2 位置一操作(某些位置一,其他位不变)

GPIOH_ODR |= (1<<10); // 第10位置一


GPIOH_ODR |= (3<<10); // 第11、12位置一


GPIOH_ODR |= ((1<<10)|(3<<15)); //第10、15、16位置一


6.3 寄存器赋值操作

    寄存器位经过上面的清零操作后,接下来就可以方便地对某几位写入所需要的数值了,且其它位不变。


GPIOH_ODR |= (2<<10); // 第11、12位赋值为2(先清零)


6.4位取反操作

  某些情况下,我们需要对寄存器的某个位进行取反操作,即 1 变 0 , 0 变 1,这可以直接用如下操作,其它位不变。


GPIOH_ODR ^= (1<<10); // 第10位取反


免费试学
课程好不好,不如实地听一听

封闭学习

2

1

联系我们

电话:028-61775817

邮箱:1572396657@qq.com

地址:成都市金牛区西城国际A座8楼

  • 物联网_物联网专题新闻_物联网IOT资讯-学到牛牛
    物联网_物联网专题新闻_物联网IOT资讯-学到牛牛

    扫一扫,免费咨询

  • 物联网_物联网专题新闻_物联网IOT资讯-学到牛牛
    物联网_物联网专题新闻_物联网IOT资讯-学到牛牛

    微信公众号

  • 物联网_物联网专题新闻_物联网IOT资讯-学到牛牛
物联网_物联网专题新闻_物联网IOT资讯-学到牛牛

学一流技术,找高薪工作

物联网_物联网专题新闻_物联网IOT资讯-学到牛牛

7-24小时服务热线:

028-61775817

版权声明 网站地图

蜀ICP备2021001672号

课程问题轻松问