我相信昨天的文章你一定大饱眼福了,没关系,接下来的更精彩,也会对c语言有个全新的理解。
今天这个文件属于cm3核心定义:有cmsis核心的所有结构和符号
cortex-m核心寄存器和位域,cortex-m核心外设基址。
今天的对象在这里
先看h文件的前面几行
根据前面三行宏定义,最终计算出的cmsis hal库完整版本号为:__cm3_cmsis_version = (0x01
uint32_t implementer = (scb->cpuid & scb_cpuid_implementer_msk) >> scb_cpuid_implementer_pos;
变体编号:
uint32_t variant = (scb->cpuid & scb_cpuid_variant_msk) >> scb_cpuid_variant_pos;
cpu型号:
uint32_t partno = (scb->cpuid & scb_cpuid_partno_msk) >> scb_cpuid_partno_pos;
cpu修订版本:
uint32_t revision = (scb->cpuid & scb_cpuid_revision_msk) >> scb_cpuid_revision_pos;
arm cortex-m内核的cpuid寄存器包含这些关键字段,方便识别和区分不同的芯片,并获取其精确的型号与修订信息。宏定义极大地简化提取这些信息的过程,只需要通过位域操作和移位就可以获得所需要的id参数,这在很大程度上增强了代码的可读性。
不在乎含义,在乎写法,接下来看写法
scb_cpuid_implementer_pos代表:
implementer字段在cpuid寄存器中的起始位置(偏移),其值为24。
scb_cpuid_implementer_msk代表:
implementer字段的掩码,通过将0xff左移24位得到,其值为0xff000000。所以,要读取implementer字段,我们可以像下面这样使用这两个宏:
uint32_t implementer = (scb->cpuid & scb_cpuid_implementer_msk) >> scb_cpuid_implementer_pos;
该语句通过与scb_cpuid_implementer_msk的位与操作获取implementer字段,然后右移scb_cpuid_implementer_pos(24)位,将其移到最低8位,obtaining the implementer code.
例如,如果cpuid的值为0x410fc241,那么:scb->cpuid = 0x410fc241
scb_cpuid_implementer_msk = 0xff000000
通过与操作:0x410fc241 & 0xff000000 = 0x41000000
右移24位:0x41000000 >> 24 = 0x41 = 65(十进制)所以,implementer字段的值为65(十进制),表示cpu的制造商是arm。位域操作通过掩码获取目标字段,位移则将其移到需要的位置。
位域和位移都是位运算的概念,用于在二进制位级别操作和访问数据。位域操作用于在一个数据域(如寄存器)的不同位上访问多个字段。它通过掩码来选择和操作目标字段中的位。
常用的位域操作有:与(&):如果两个操作数的对应比特位都是1,则该位的结果为1,否则为0。用于选取目标字段。或(|):只要两个操作数的对应比特位有一个为1,则该位的结果为1。用于修改或设置字段的值。非(~) :反转操作数的每一位,0变1,1变0。用于对字段取反。
位移则用于将数据的位向左或向右移动给定的位数,实际上是在给定方向上对数据的表示形式进行扩展或截断。
按方向分为:左移():向右移动,根据数据类型,高位或补0或补符号位,用于缩小数据类型或实现除法。
所以,要访问scb->cpuid寄存器的不同字段,我们可以:1.使用与操作和掩码获取目标字段,例如用scb_cpuid_implementer_msk获取implementer字段。2.必要时使用位移将字段移到需要的位置,例如用scb_cpuid_implementer_pos右移24位将implementer移到低8位。3.组合位域操作读取和修改字段。例如用或操作将某位设置为1,用与操作清0某位。
例如,要读取cpuid的implementer字段:
uint32_t implementer = (scb->cpuid & scb_cpuid_implementer_msk) >> scb_cpuid_implementer_pos;
要设置cpuid的revision字段的第3位:
scb->cpuid |= (1 继续放大镜看这个代码,我们看这个1ul的定义方式:
1ul
1ul是一个无符号长整型(unsigned long)常量,其值为1。在c语言中,整型常量的默认类型为int,但可以通过后缀来指定不同的类型。常见的后缀有:无符号(unsigned):- u或u:无符号整型,如1u
- ul或ul:无符号长整型,如1ul长整型(long):- l或l:长整型,如1l无符号长整型(unsigned long):- ul或ul:无符号长整型,如1ul大小写无关,所以1u、1ul、1u和1ul都是等价的。
使用这些后缀的主要目的是为了在某些情况下指定常量的精确类型,避免由默认类型带来的怪异行为。例如,在32位系统上,int和unsigned int都是32位,所以1和1u的值相同。
但long可能是32位,而unsigned long是64位,所以1l和1ul的值会不同。所以,当我们需要一个无符号的32/64位整型常量时,就可以使用1u或1ul来指定其精确类型,这可以避免一些潜在的问题。
另外,这些后缀也常用于定义寄存器和位域的掩码常量,例如:
#define uart_data_mask 0xfful // 8位无符号数据掩码 #define uart_parity_mask 0x01ul // 1位无符号奇偶校验位掩码
这里使用ul是为了确保掩码常量被定义为32位,与寄存器大小一致。所以,总结来说:1. 1ul是一个无符号长整型常量,其值为1。2. 后缀u、ul、u和ul用于定义无符号整型和无符号长整型常量。3. 使用这些后缀可以指定常量的精确类型,避免默认类型带来的问题。4. 这些后缀常用于定义寄存器和位域的掩码常量,确保其大小与目标寄存器一致。
这个结构体定义了systick定时器的寄存器集。systick是cortex-m内核的一部分,用于生成定时中断和延时。
systick_type结构体包含以下成员:
__io uint32_t ctrl; systick控制和状态寄存器,用于使能systick定时器,选择时钟源和计数模式。
__io uint32_t load; systick重载值寄存器,设置systick定时器的重载值,该值决定定时周期。
__io uint32_t val; systick当前值寄存器,在运行过程中存储systick定时器的当前值。
__i uint32_t calib; systick校准值寄存器,提供设备特定的时钟频率信息,用于计算延时。
所以,通过这个结构体,我们可以访问systick定时器的所有控制/状态寄存器和校准寄存器,并完成:
1. 使能或关闭systick定时器。
2. 选择systick的时钟源,如内核时钟ahb或外部参考时钟。
3. 选择递减计数模式或递增计数模式。
4.设置systick定时器的重载值,配置其定时周期。
5.读取当前的计数值val。
6.获取设备的时钟频率信息calib,用于生成精确延时。
7.systick定时器溢出时产生中断,所以也用作系统的节拍定时器。
systicktimer(stk)处理器有一个24位系统计时器systick,它从重新加载值开始计数到零,在下一个时钟边缘重新加载(封装到)load寄存器中的值,然后在随后的时钟上计数。当处理器停止调试时,计数器不会减少。
再详细一些介绍这个:
1.最大计数值为24位,所以最大延时为16777216个时钟周期。
2.可以选择内核时钟ahb或外部参考时钟作为时钟源。
3.可以选择递增计数模式或递减计数模式。
4.重载值寄存器load用于设置定时周期,每次定时器溢出时重新装载该值。
5.当前值寄存器val存储定时器的实时计数值。
6.定时器溢出时触发systick异常请求,可以配置为产生中断。
7.时钟频率预分频因子固定为8,不可配置。
8. 中断优先级固定为最低级别,仅可屏蔽但不可修改。
9.包含一设备特定的校准寄存器,提供系统时钟频率信息,用于实现准确延时。基
于以上特性,我们可以这样配置和使用systick定时器:
1.使能systick定时器,选择ahb时钟源。
2.配置 systick_load寄存器为重载值(如1000),每1000个时钟周期产生一个中断。
3.等待systick定时器中断,并在中断服务程序内进行任务调度或其他定时任务。
4.获取systick_calib的值,例如0x0320,表明每个时钟周期大约为30.5us。
5.要延时100ms,计算需要的时钟周期数:100ms / 30.5us = 3276。写入systick_load,使能定时器。
6.等待systick定时器中断,表示延时完成。
所以,systick模块为cortex-m3内核提供了一个简单而高效的定时器,可用于rtos的任务调度、软件延时和其他定时事件。它的24位计数器和微秒级精度可以满足大多数应用的需要。
和其它的定时器外设比较有什么区别?
systick定时器有以下主要用途:
1.提供系统节拍定时器,用于rtos的任务调度。rtos可以配置systick产生中断,并在中断处理程序中进行任务切换。
2.实现软件延时。我们可以根据systick的定时周期计算需要的计数值来生成所需延时。
3.其他定时事件。systick定时器可以用于系统的各种定时任务,如定时监测、看门狗喂狗等。
与其他定时器外设相比,systick定时器有以下区别:
1.systick定时器是cortex-m内核的一部分,而其他定时器属于mcu的外设。所以systick定时器更轻量,通用性更强。
2.systick定时器的时钟源只能选择内核时钟或外部参考时钟,而其他定时器通常有更多时钟源选择。
3.systick定时器的计数器只有24位,范围更小。其他定时器的计数器可以达32位或更高。
4.systick定时器的中断优先级固定为最低,无法配置。其他定时器的中断通常可以配置优先级。
5.systick定时器只有比较基本的控制寄存器,更简单。其他定时器通常具有更丰富的控制与配置选项。
6.systick定时器的溢出事件只能产生中断,无法产生dma请求等。部分定时器可以通过多种方式响应溢出事件。
让我来说下这个计数模式:
递增计数模式和递减计数模式是定时器的两种不同的计数方式:
递增计数模式:定时器的计数器从初始值(通常为0)开始递增,当计数器达到重载值时,定时器溢出。然后计数器重载为初始值,重新开始递增。如果配置为产生中断,则在计数器达到重载值时触发中断。
例如,如果初始值为0,重载值为100,则计数序列为:
0, 1, 2, 3, ... 98, 99, 100 - 触发中断 - 0, 1, 2, 3 ...
递减计数模式:
定时器的计数器从重载值开始递减,当计数器达到0时,定时器溢出。然后计数器重载为重载值,重新开始递减。如果配置为产生中断,则在计数器达到0时触发中断。
例如,如果重载值为100,则计数序列为:
100, 99, 98, 97 ... 3, 2, 1, 0 - 触发中断 - 100, 99, 98 ...
所以,主要差异在于计数器的初始值和溢出条件不同:
递增模式:
初始值:通常为0
溢出条件:计数器达到重载值
递减模式:
初始值:等于重载值
溢出条件:计数器达到0
让我们来探究一下这个设计意图,就是定时器的设计意图。
1.适应开发者的习惯。有的开发者更习惯从0开始递增计数,有的更习惯从最大值开始递减计数,所以提供两种模式以满足不同习惯。
2.方便实现定时器的溢出中断。无论是递增模式从0溢出到重载值,还是递减模式从重载值溢出到0,都可以很简单地通过比较计数器与重载值/0来检测溢出事件并产生中断。
3.扩展定时范围。24位的定时器,递增模式下最大延时为2^24个周期,若选择递减模式,最大延时可扩展为2^24 + 重载值个周期,所以可获得较大的定时范围。
4. 不同模式下的溢出事件可用于不同用途。例如,可以选择递增模式用于周期性中断,而选择递减模式用于超时检测。两种事件可以同时使用,扩展定时器的应用。
5. 简化硬件设计。提供两种模式而非只有一种,可以在软件中通过配置来选择模式,而不需要硬件支持两套完全不同的定时与计数逻辑,简化了定时器模块的设计。
接下来说这个设计上面的简便性,这个就比较深奥了,之后我如果把玩fpga我会写详细的。
如果systick定时器仅支持递增模式或递减模式中的一种,则其硬件结构可以简单设计为:
- 24位计数器寄存器
- 24位重载寄存器
- 比较逻辑,比较计数器与重载寄存器,产生溢出事件
但是,为了支持两种模式,systick定时器的硬件结构可以设计为:
- 24位计数器寄存器
- 24位重载寄存器
- 1位递增/递减模式选择位
- 比较逻辑,当模式选择位选择递增模式时,比较计数器与重载寄存,当选择递减模式时, 比较计数器与0,以产生溢出事件。
可以看到,仅添加一个1位的模式选择逻辑,systick定时器就可以支持两种模式,而不需要实现两套完全独立的计数/比较逻辑。在软件层面,我们只需要设置mode位为0选择递增模式,设置为1选择递减模式,然后处理溢出事件中断即可。
硬件层面已经为两种模式实现了统一的定时逻辑。可以想象,如果定时器需要同时支持4种或更多种模式,仅靠硬件实现各自独立的定时机制会变得非常复杂。
而采用类似systick的方式,通过软件配置选择定时模式,硬件只需实现一套相对通用的定时机制,这无疑可以大大简化定时器模块的设计。
虹科技术丨头脑风暴 (下)
逆变器对于提升电网品质的帮助
硕博电子工程机械控制器在泵车上的应用
英特尔的折叠屏笔记本计划搁浅,操作系统还不够成熟
南疆首例飞秒激光近视手术成功_飞秒激光治疗近视手术进入了“无刀时代”
Cortex-M核心寄存器和位域
美国最大射电望远镜阿雷西博严重受损:予以拆除
coverpoint是什么意思
紫光展锐“换帅”!赵伟国退出,新董事长是他
STM32入门学习笔记之温湿度采集实验4
5G时代正在路上我们应该怎么做
基于AT89S52和K9F6408UOA的语音数字系统设计
上能电气15GW储能变流器及储能系统集成研发与产业化项目开工
带你深入了解:三星Galaxy S经典之路发展史
fpga是什么 fpga用什么编程语言
近半年来半导体十大烂尾项目盘点
新型远程反舰导弹LRASM连续6次飞行测试成功
华为Mate10评测 更快更智慧的全能旗舰名副其实
超声波传感器应用AGV移动小车测距应用解决方案
寒冬没能冻住的中国面板