单片机stm32详解(STM32单片机的位计算)
单片机stm32详解(STM32单片机的位计算)FM24C128D产品特点:为了减少 PLC 开发中的外围器件,充分利用 STM32F429 单片机的内部存储器资源,所以本 PLC 开发板没有外配 Nor Flash 或 NAND Flash,但增加了一个 8 脚的 I²C 存储器,型号为:FM24C128D。这个芯片是一个串行电可擦除只读存储器,存储容量为 16K 字节,每个字节 8 位,如果用来存储 16位的 PLC 的用户程序,最多只能保存 8K 步。PLC内存结构示意图4.1 Flash Memory。地址 0x0800 0000到 0x081F FFFF,这个地址为Flash Memory区,主要用来保存系统运行的程序,当然这些程序由 PLC 开发商编写,运行系统的初始化、通信、中断、PLC 语句的执行函数代码等。STM32F429ZGT6的Flash的容量为 1024K,地址从 0x0800 0000到 0x080F A00
4、STM32单片机的位读写
STM32 有很多系列,从内核上分有Cortex-M0、M3、M4和M7 这几种,每个内核又大概分为主流、高性能和低功耗。STM32系列单片机选型时可以选择F1 或F4。F1 代表了基础型,基于Cortex-M3 内核,主频为72MHz。F4 代表了高性能,基于Cortex-M4 内核,主频180 MHz。
图,STM32单片机内存示意图
我们选用STM32F429ZGT6单片机来开发上一节中提到的PLC。一个ARM单片机的功能非常强大,所以学习的内容很多,从总线、内存到各种功能外设,前后有一千多页内容可以介绍。在使用单片机开发PLC时,我们也从单片机的内存开始学习和了解。上图是一款单片机的内存分布结构示意图,图中表明了STM32F4xx单片机的程序存储器、数据存储器、寄存器和 I/O 端口排列在同一个顺序的 4GB 地址空间内,地址从 0x0000 0000到 0xFFFF FFFF。可寻址的存储空间分为 8 个主要块,每个块为 512 MB。从 0x4000 0000到 0x5FFF FFFF 这个空间主要用于片上外设的地址映射。从 0x6000 0000到 0xDFFF FFFF 这个空间主要用于 FMC 地址通信。具体的内存地址映射可以参考手册 STM32F4xx 单片机寄存器边界地址表。在这里我们重点介绍空间地址 0x0000 0000到 0x3FFF FFFF。
PLC内存结构示意图
4.1 Flash Memory。地址 0x0800 0000到 0x081F FFFF,这个地址为Flash Memory区,主要用来保存系统运行的程序,当然这些程序由 PLC 开发商编写,运行系统的初始化、通信、中断、PLC 语句的执行函数代码等。
STM32F429ZGT6的Flash的容量为 1024K,地址从 0x0800 0000到 0x080F A000。系统运行的程序可以通过:a,串口方式下载;b,ST-Link(J-Link)下载;c,MDK 下载。具体的下载方法大家可以参照网上的资料,这里不展开讲解。
为了减少 PLC 开发中的外围器件,充分利用 STM32F429 单片机的内部存储器资源,所以本 PLC 开发板没有外配 Nor Flash 或 NAND Flash,但增加了一个 8 脚的 I²C 存储器,型号为:FM24C128D。这个芯片是一个串行电可擦除只读存储器,存储容量为 16K 字节,每个字节 8 位,如果用来存储 16位的 PLC 的用户程序,最多只能保存 8K 步。
FM24C128D产品特点:
工作电压为 1.7V~5.5V;
采用I²C 的二线串行接口通信方式,双向数据传输协议;
兼容 1MHz 和 400KHz操作;
支持硬件写保护;
支持64字节页写模式,支持部分页写;
写周期内间隔时间不小于 5ms;
高可靠性:写次数 100万次,数据保存 100 年;
关于 FM24C128D 芯片的使用,我们将在介绍用户程序时具体说明。
4.2 SRAM。
4.2.1 用户程序和用户数据在运行时放置在 SRAM 中。用户数据放置在 SRAM 可以理解,这样方便内存数据的读写。但为什么用户程序也放置在 SRAM 中?其实 PLC 的梯形图通过上位机电脑或编程器下载到 PLC 内部时呈现的是 16 位的指令数据,PLC 是支持程序在线修改的,程序的运行分为程序的读和程序的执行两个动作,如果要兼顾这两个方面就需要选用外部 ROM,我们想通过最少的外围器件完成 PLC 功能,就需要充分发挥内部存储器的作用。现在我们将执行时的用户程序存放在 SRAM 中,需要掉电保持时存放在 FM24C128D 中,在系统上电完成初始化后将首先读取用户程序到 SRAM 中,如果有在线修改后下载到 PLC 的用户程序将实时保存到 FM24C128D 中。
4.2.2 用户数据。PLC中的用户数据可以通过位或字节读写的内存变量,为了提高读写效率,将这部分数据放在 SRAM 中是非常方便的。如果希望有些数据在掉电后仍然保持,可以将这些数据备份在 FM24C128D 中,这些数据如果修改后将重新保存到 FM24C128D 中,覆盖原先的数据。这些数据可能是一些用户设置,如电机的速度值,位置值或某个元件的执行时间等。
利用单片机片内 SRAM 可以充分利用单片机的内部资源,不需要增加外围的 SRAM 的配置。所有的用户程序都在片内读取和执行,方便总线的快速读写。STM32F429ZGT6的 SRAM 容量为 256 K,作为PLC的内存是绰绰有余。
4.3 了解了单片机的内存后,我们试着用单片机的内存实现PLC的内存。首先定义一个大的16位变量的数组:
unsigned short int Data[10000] __attribute__((at(0x20013B30)));
这句话的含义是定义了一个数组名为Data的数组,数组内有10000个数组成员,每个成员都是无符号短整数即16位字。“__attribute__”用于绝对定位,地址是0x20013B30,不需要纠结于某个地址。总之,通过这个定义就可以访问每一个16位字的成员变量。
为了程序中的编写方便,在头文件里定义了如下地址名:
#define WxBaseAddr 0 //0x20013B30
#define WyBaseAddr 13
#define WrBaseAddr 26
#define WrSpBaseAddr 90
#define WtcBaseAddr 100
#define SVDataAddr 120
#define EVDataAddr 300
#define IXAddress 470
#define IYAddress 471
#define M_RlyData 480
#define DtBaseAddr 600
#define DtSpecBaseAddr 9600
4.4 读位变量。如上一节中提到的位变量或数据变量,我们访问一个位需要怎么操作?比如 X16,X16 是字节 WX1 中的第6位位变量。在数组 Data 中,WxBaseAddr 对应于 PLC 中的 WX0,WX1 就是 WxBaseAddr 1,第 6 位可以通过移位的方法求得结果。假设我们需要将 X16 的位变量值放置到暂存器 TempR,在梯形图中的语句为 LD X16。这个语句下载到单片机里是一个包含操作指令与操作数的 16 进制数,数据为 B816。其中 B8 是操作指令代码,表示 Load X 的意思;16 是操作数,表示位变量的地址。我们可以通过以下步骤实现。
- 方法一,字节操作。
1 unsigned short Value; //定义16位变量,用于保存中间值
2 unsigned char Bit;
3 Void LDX(void){
4 Value = code & 0x00FF; //code = 0xB816 Value = 0x16
5 Bit = code & 0x000F; //Bit = 0x06
6 Value = Data[WxBaseAddr (Value>>4)] ; //Value = WX1
7 Value = (Value>>Bit) & 0x0001;
8 if(Value >0){
9 TempR = 1;
10 }
11 else TempR = 0;
12 }
这种方法比较好理解,将指定字节的数据右移位变量个数,得到的数值和常数 1 相与,如果这个值为 1 ,TempR就为 1,否则为 0。
- 方法二,位操作。
位的操作就是单独的对一个比特位读和写,这个在51 单片机中非常常见。51 单片机中通过关键字 sbit 来实现位定义,F429 中没有这样的关键字,而是通过访问位带别名区来实现。在F429 中,有两个地方实现了位带,一个是SRAM区的最低1MB 空间,另一个是外设区最低1MB 空间。这两个1MB 的空间除了可以像正常的RAM一样操作外,他们还有自己的位带别名区,位带别名区把这1MB 的空间的每一个位膨胀成一个32 位的字,当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。
F429 位带地址
SRAM的位带区的地址为:0X2000 0000~X200F 0000,大小为1MB,经过膨胀后的位
带别名区地址为:0X2200 0000~0X23FF FFFF,大小为32MB。我们可以通过指针的形式访问位带别名区地址从而达到操作位带区比特位的效果。那这两个地址如何转换?对于SRAM位带区的某个比特,则该比特在别名区的地址为:
bit_word_addr = bit_band_base (byte_offset x 32) (bit_number × 4)
其中:— bit_word_addr 代表别名区域中将映射到目标位的字的地址
— bit_band_base 代表别名区域的起始地址 (0x22000000)
— byte_offset 代表目标位所在位段区域中的字节编号
— bit_number 代表目标位的位位置 (0-7)
示例 :下例说明如何将 SRAM 地址 0x20000300 处字节的位 2 映射到别名区域:
0x22006008 = 0x22000000 (0x300*32) (2*4)
对地址 0x22006008 执行写操作相当于在 SRAM 地址 0x20000300 处字节的位 2 执行读-修 改-写操作。对地址 0x22006008 执行读操作将返回 SRAM 地址 0x20000300 处字节的位 2 的值(0x01 表示位置位,0x00 表示位复位)。(内容选自 RM0090 参考手册)
对于 LD X16 用这种方法操作如下:
1 #define BitWxBaseAddr 0x22276600
2 Void LDX(void){
3 if(*(unsigned int*)( BitWxBaseAddr ((code & 0x00FF)<<2)) == 0) {
4 TempR = 0;
5 }
6 else TempR = 1;
7 }
*(unsigned int*)( BitWxBaseAddr ((code & 0x00FF)<<2) 这是怎么得来的?我们先通过 WxBaseAddr 计算出它的位别名地址
① BitWxBaseAddr = WxBaseAddr * 32 = (0x20013B30 – 0x20000000)*32 0x22000000 = 0x22276600;
② X16的字节地址偏移量 = (code & 0x00FF)>> 4;
③ X16的字节偏移地址的位别名 = ((code & 0x00FF)>> 4)* 32 *2; 这里乘以 32 后再乘以 2 是因为 Data 是16位字节数组,如果是 8 位字节数组就只需要乘以32。((code & 0x00FF)>> 4)* 32 *2 等价于((code & 0x00FF)>> 4)<<6 所以 X16 的字节偏移地址的位别名 = (code & 0x00F0)<< 2;
④ X16 的位地址 = code & 0x000F;
⑤ X16 的位别名 = (code & 0x000F)<<2;
⑥ X16 的位别名地址 = BitWxBaseAddr ((code & 0x00FF)<< 2);
⑦ X16的位变量值 = *(unsigned int*)( BitWxBaseAddr ((code & 0x00FF)<<2))。