STM32 学习笔记_3 程序编写基础;arm 内核架构

程序编写基础

Keil 编辑器设置

STM32 学习笔记_3 程序编写基础;arm 内核架构_第1张图片

抛开 tab 和空格哪个好看不谈,不同编译器设置格式不同,空格比较保险。

用户关键字:打出来的时候会高亮。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第2张图片

代码提示:(symbols after 是几个字符后开始提示关键字的意思)

STM32 学习笔记_3 程序编写基础;arm 内核架构_第3张图片

以上的四个配置会保存在 global.prop 文件里,以后重装保存这个文件就可以保存配置。

常用操作

shift tab 整体左移,直接 tab 右移。

函数变量快速定位:魔术棒-output-browse information。右键 goto definition 即可跳转。

快速注释:有一个 // 的符号,选中代码段后点击一下即可快速注释。

快速打开头文件:右键头文件名-open document xxx.h

查找:STM32 学习笔记_3 程序编写基础;arm 内核架构_第4张图片

replace 是替换。

build output 窗口里双击 error 是可以快速定位过去的。

窗口视图恢复默认状态的方法:window à Reset View to Defaults + Reset

C语言基础

stdint.h

c99中的标准库文件。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第5张图片

STM32 学习笔记_3 程序编写基础;arm 内核架构_第6张图片

位操作

& | ~ ^ << >> 没啥多说的。

给某一位赋值:1. 先&把其他位保留,该位置0,再|把其他位保留,该位置1. temp &= 0xFFFFFFBF; temp |= 0x00000040;

  1. temp &= ~(1<<6); temp |= 1<<6;

宏定义

#define PI 3.14159

STM32 学习笔记_3 程序编写基础;arm 内核架构_第7张图片

#define __set_task_state(tsk, state_value)   \
  do { (tsk)->state = (state_value); }  while (0)

一定要用 do while(0) ,这样程序才会按照我们期望的方式执行。

宏定义为什么要使用do{……}while(0)形式_土豆爸爸的博客-CSDN博客

宏定义避免影响控制流程,比如宏定义的函数里面可以 return 就比较危险。

image-20230413131450340

宏定义传参避免参数变化,如 (SQUARE(a++))

image-20230413131533236

STM32 学习笔记_3 程序编写基础;arm 内核架构_第8张图片

extern

用 extern 声明的函数或变量代表是在其他文件定义的。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第9张图片

typedef

typedef unsigned char uint8_t;

struct

STM32 学习笔记_3 程序编写基础;arm 内核架构_第10张图片

STM32 学习笔记_3 程序编写基础;arm 内核架构_第11张图片

指针

char *ptr="234";

代码规范

tab 设置为4个字符。

80列后的字符分行。

image-20230413033058738

image-20230413033117662

相对独立的代码块,变量之间加空行。

多行语句不要写在一行里。if 语句也是,而且 if 语句后面哪怕只有一个语句也不要偷懒,加大括号。while 后面没有执行语句的话可以不用大括号。

左括号另起一行。

if、swich、case、for、do、while 后加空格。

sizeof、typedof、alignof 后面不加空格。

指针的*靠近变量名,而不是数据类型。

= + - < > * / % | & ^ <= >= == != ? : 左右加空格。

一元操作符后不加空格, & * + - ~ ! sizeof typeof alignof __attribute__ defined。

++ – . -> 前后都不加空格。

逗号和分号只在后面加空格。

注释 /* 内容 */ 和内容之间加空格。

注释规范

STM32 学习笔记_3 程序编写基础;arm 内核架构_第12张图片

STM32 学习笔记_3 程序编写基础;arm 内核架构_第13张图片

image-20230413035001669

星数必须100个。和代码开始隔一行。

函数注释:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第14张图片

image-20230413035535796

STM32 学习笔记_3 程序编写基础;arm 内核架构_第15张图片

image-20230413035945902

代码注释:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第16张图片

过长放在代码前。

标识符命名:小写,下划线分割,这是 unix 风格。

常用反义词:

image-20230413120036503

循环变量允许 ijk。可以用 g_ p_ 开头表示是全局变量或指针。

不用 u8 u16 u32,使用:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第17张图片

函数命名同变量。

宏命名全大写,单词间用下划线分隔。

函数:一个函数只实现一个功能。

函数之间空行分隔,export 紧跟着函数。

image-20230413120402318

嵌入式开发 linux 常用 goto,清理操作之类很方便。

函数嵌套不建议>4层。

函数要处理好输入参数的合理性,出现错误也能准确返回错误信息。

只在本文件范围内定义的函数变量 static 修饰。

一个变量最好不要多用途。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第18张图片

少用全局变量,避免全局变量和局部变量重名。

初始化尽量使用初值。直接赋值或者 ?: 赋值。

明确全局变量的初始化位置,且减少不必要的数据类型转化。

内核架构

内核 ARM 厂商授权,外设其他公司添加。板子上黑色的 STM32 一整个就是 arm 公司架构和已发半导体公司合作的结果。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第19张图片

F1 架构

STM32 学习笔记_3 程序编写基础;arm 内核架构_第20张图片

STM32 学习笔记_3 程序编写基础;arm 内核架构_第21张图片

主动单元可以给被动单元发起通信。

以总线矩阵为分界线,左边是主动单元,右边是被动单元。

ICode 直接连接到 FLASH 而不需要总线矩阵做中介,里面存储的是程序,这样访问程序速度很快。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第22张图片

ICode 总线对应图中的 IBus。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第23张图片

外设分为不同频率满足不同外设的需求。

cortex-M3 内核:

左上和右上是跟踪调试,左下是下载。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第24张图片

SDIO 和时钟:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第25张图片

APB 外设:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第26张图片

ICode:

STM32 学习笔记_3 程序编写基础;arm 内核架构_第27张图片

以及一些正点课件里没有详细展开说明的内容:从上到下依次是电源,电源管理,外部晶振,看门狗计时器。

image-20230413200708790

此外,互联型的开发板还会添加网络模块的主动单元,不过我们的不是。

F4 架构

STM32 学习笔记_3 程序编写基础;arm 内核架构_第28张图片

在 ARM Cortex-M4 中,FSMC 是一种嵌入式外设,它代表外部存储器接口。FSMC 支持连接到存储器、LCD 显示器和其他外部设备,可以实现高速数据传输和存储器扩展,以满足大多数嵌入式系统的要求。——ChatGPT

image-20230413201237816

CCM 存数据,访问速度快,但是不支持 DMA。

总线时钟频率:

AHB1/2:168/180MHz (Max)

APB1:42/45MHz (Max)

APB2:84/90MHz (Max)

系统原理图基本和 F1 差不多。

F7 架构

STM32 学习笔记_3 程序编写基础;arm 内核架构_第29张图片

image-20230413202154993

STM32 学习笔记_3 程序编写基础;arm 内核架构_第30张图片

寻址范围

32位单片机,32位地址总线。

存储单元按字节编址。就是说有2^32个按字节编址的存储单元。

每个存储单元的寻址范围:0x0000_0000~0xFFFF_FFFF。

存储器映射

存储器自己是没有地址的,是我们给他映射过去的。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第31张图片

前三个是学习的重点。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第32张图片

寄存器映射

寄存器是单片机内部的控制结构,我们的目的归根结底就是控制寄存器,进而控制单片机。

我们主要学习外设寄存器。

给寄存器地址命名的过程叫寄存器映射。如 0x4001080c -> GPIOA_ODR。

stm32 GPIO 每组16个 IO 口,比51多一倍。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第33张图片

名字:GPIOx_ODR。

地址偏移:基于 00 最小的地址加一个偏移值。

寄存器复位值:0x0000_0000.

寄存器位表:查看每个位的偏移量,名称,权限。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第34张图片

位功能描述:比如1亮灯,0灭灯。

操作寄存器:比较逆天的方式是直接操作寄存器地址。

*(unsigned int *)(0x4001_080c)=0xFFFF;

寄存器映射:

#define GPIOA_ODR *(unsigned int *)(0x4001_080c)

GPIOA_ODR=0XFFFF;

但是上百上千个寄存器,怎么计算地址和映射?

寄存器地址计算

  1. 总线基地址/外设基地址,BUS_BASE_ADDR.
  2. 外设基于总线基地址的偏移量 PERIPH_OFFSET.
  3. 寄存器相对于外设地址的偏移量 REG_OFFSET,即上图中每个寄存器的偏移量(0C)。

三者求和计算总线基地址。

总线基地址:APB1 0X4000_0000,APB2 0X4001_0000,AHB 0X4001_8000.

image-20230413212938834

STM32 学习笔记_3 程序编写基础;arm 内核架构_第35张图片

在存储器映像图里可以看到:

image-20230413213233899

比如 GPIOA,外设基地址 0X4001_0000,偏移量 0X800. = 0X4001_0800.

其中的一个寄存器 GPIOA CRH 基于 GPIOA 外设基地址的偏移地址 0X04. = 0X4001_0804.

批量定义寄存器用结构体会很方便。

STM32 学习笔记_3 程序编写基础;arm 内核架构_第36张图片

左边,我们定义了一个7*4的连续空间,因为结构体也是连续存储。

然后通过右边的方式定义了开头指针,则从上到下地址逐渐变大存储。

详细内容可以看 stm32f103xe.h 文件中。

image-20230414004919334

可见前几行的内容对应 block0 block1.

STM32 学习笔记_3 程序编写基础;arm 内核架构_第37张图片

你可能感兴趣的:(#,STM32,c++,linux,单片机,学习,硬件架构)