嵌入式基础篇 - 第2章 Systick系统定时器

2.1 STM32 的时钟系统

STM32 芯片为了实现低功耗,设计了一个功能完善但却非常复杂的时钟系统。普通的MCU 一般只要配置好 GPIO 的寄存器就可以使用了,但 STM32 还有一个步骤,就是开启外设时钟。 

这里写图片描述

 

图2-1 STM32的时钟树


在 STM32 中,有五个时钟源,为 HSI、 HSE、 LSI、 LSE、 PLL。 从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS, HSE 以及 PLL 是高速时钟, LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。下面我们看看 STM32 的 5 个时钟源,我们讲解顺序是按图中红圈标示的顺序: 
①HSI 是高速内部时钟, RC 振荡器,频率为 8MHz。 
②HSE 是高速外部时钟,可接石英 /陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 我们的开发板接的是 8M 的晶振。 
③LSI 是低速内部时钟,RC 振荡器,频率为 40kHz。独立看门狗的时钟源只能是 LSI,同时 LSI 还可以作为 RTC 的时钟源。 
④LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。这个主要是 RTC 的时钟源。 
⑤PLL 为锁相环倍频输出,其时钟输入源可选择为 HSI/2、HSE 或者 HSE/2。倍频可选择为2~16 倍,但是其输出频率最大不得超过 72MHz。 
图中我们用 A~E 标示我们要讲解的地方。 
A. MCO 是 STM32 的一个时钟输出 IO(PA8),它可以选择一个时钟信号输出, 可以选择为 PLL 输出的 2 分频、 HSI、 HSE、或者系统时钟。这个时钟可以用来给外部其他系统提供时钟源。 
B. 这里是 RTC 时钟源,从图上可以看出, RTC 的时钟源可以选择 LSI, LSE,以及HSE 的 128 分频。 
C. 从图中可以看出 C 处 USB 的时钟是来自 PLL 时钟源。 STM32 中有一个全速功能的 USB 模块,其串行接口引擎需要一个频率为 48MHz 的时钟源。该时钟源只能从 PLL 输出端获取,可以选择为 1.5 分频或者 1 分频,也就是,当需要使用 USB模块时, PLL 必须使能,并且时钟频率配置为 48MHz 或 72MHz。 
D. D 处就是 STM32 的系统时钟 SYSCLK,它是供 STM32 中绝大部分部件工作的时钟源。系统时钟可选择为 PLL 输出、 HSI 或者 HSE。系统时钟最大频率为 72MHz,当然你也可以超频,不过一般情况为了系统稳定性是没有必要冒风险去超频的。 
E. 这里的 E 处是指其他所有外设了。从时钟图上可以看出,其他所有外设的时钟最终来源都是 SYSCLK。 SYSCLK 通过 AHB 分频器分频后送给各模块使用。这些模块包括: 
①AHB 总线、内核、内存和 DMA 使用的 HCLK 时钟。 
②通过 8 分频后送给 Cortex 的系统定时器时钟,也就是 systick 了。 
③直接送给 Cortex 的空闲运行时钟 FCLK。 
④送给 APB1 分频器。 APB1 分频器输出一路供 APB1 外设使用(PCLK1,最大频率 36MHz),另一路送给定时器(Timer)2、 3、 4 倍频器使用。 
⑤送给 APB2 分频器。 APB2 分频器分频输出一路供 APB2 外设使用(PCLK2,最大频率 72MHz),另一路送给定时器(Timer)1 倍频器使用。 
其中需要理解的是 APB1 和 APB2 的区别, APB1 上面连接的是低速外设,包括电源接口、备份接口、 CAN、 USB、 I2C1、 I2C2、 UART2、 UART3 等等, APB2 上面连接的是高速外设包括 UART1、 SPI1、 Timer1、 ADC1、 ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等。 
SystemInit()函数中设置的系统时钟大小: 
 SYSCLK(系统时钟) =72MHz 
 AHB 总线时钟(使用 SYSCLK) =72MHz 
 APB1 总线时钟(PCLK1) =36MHz 
 APB2 总线时钟(PCLK2) =72MHz 
 PLL 时钟 =72MHz 
具体代码清读者查看工程文件的system_stm32f10x.c文件。

 

2.2 Systick系统定时器工作原理分析

SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号 :15)。在以前,操作系统和所有使用了时基的系统都必须有一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务分配不同数目的时间片,确保没有一个任务能霸占系统 ;或者将每个定时器周期的某个时间范围赐予特定的任务等,操作系统提供的各种定时功能都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 
Cortex-M3 在内核部分包含了一个简单的定时器——SysTick。因为所有的 CM3 芯片都带有这个定时器,软件在不同芯片生产厂商的 CM3 器件间的移植工作就得以简化。该定时器的时钟源可以是内部时钟(FCLK,CM3 上的自由运行时钟),或者是外部时钟( CM3 处理器上的 STCLK 信号)。不过,STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能大不相同。因此,需要阅读芯片的使用手册来确定选择什么作为时钟源。在 STM32 中 SysTick 以 HCLK(AHB 时钟)或 HCLK/8 作为运行时钟,见图 1- 1。 
SysTick 定时器能产生中断,CM3 为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其他系统软件在 CM3 器件间的移植变得简单多了,因为在所有 CM3 产品间,SysTick 的处理方式都是相同的。SysTick 定时器除了能服务于操作系统之外,还能用于其他目的,如作为一个闹铃、用于测量时间等。Systick 定时器属于Cortex 内核部件,可以参考《ARM Cortex-M3 权威指南》((英)JosephYiu 著,宋岩译,北京航空航天大学出版社出版)或“STM32xxx-Cortex-M3programmingmanual”(这是 ST 官方提供的电子版编程手册,可以在 ST 官网下载)来了解。

2.3 Systick系统定时器寄存器分析

在传统的嵌入式系统软件按中通常实现 Delay(N) 函数的方法为:

for(i = 0; i <= x; i ++); x --- ;

 

对于STM32系列微处理器来说,执行一条指令只有几十个 ns,进行 for 循环时,要实现 N 毫秒的 x 值非常大,而且由于系统频率的宽广,很难计算出延时 N 毫秒的精确值。针对 STM32 微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用 Delay(N)。 
Cortex-M3 的内核中包含一个 SysTick 时钟。SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的 COUNTFLAG 标志会置位,触发中断 (如果中断使能情况下)。 
在 STM32 的应用中,使用 Cortex-M3 内核的 SysTick 作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对 N 减一,在Delay(N) 函数中循环检测 N 是否为 0,不为 0 则进行循环等待;若为 0 则关闭 SysTick 时钟,退出函数。 
注: 全局变量 TimingDelay , 必须定义为 volatile 类型 , 延迟时间将不随系统时钟频率改变。 
STM32中的Systick 部分内容属于NVIC控制部分,一共有4个寄存器,名称和地址分别是: 
 STK_CTRL, 0xE000E010 – 控制寄存器 

表2-1 SysTick控制及状态寄存器

 

这里写图片描述


第0位:ENABLE,Systick 使能位 
(0:关闭Systick功能;1:开启Systick功能) 
第1位:TICKINT,Systick 中断使能位 
(0:关闭Systick中断;1:开启Systick中断) 
第2位:CLKSOURCE,Systick时钟源选择 
(0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟) 
第16位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位,该位将自动清零 
 STK_LOAD, 0xE000E014 – 重载寄存器 

表2-2 SysTick重装载数值寄存器

 

这里写图片描述


Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD 重载寄存器是个24位的寄存器最大计数0xFFFFFF。 
 STK_VAL, 0xE000E018 – 当前值寄存器 

表2-3 SysTick当前数值寄存器

 

这里写图片描述


也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志。 
 STK_CALRB, 0xE000E01C – 校准值寄存器 

表2-4 SysTick校准数值寄存器

 

这里写图片描述


校准值寄存器提供了这样一个解决方案:它使系统即使在不同的CM3产品上运行,也能产生恒定的SysTick中断频率。最简单的作法就是:直接把TENMS的值写入重装载寄存器,这样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下, CM3芯片可能无法准确地提供TENMS的值(如, CM3的校准输入信号被拉低),所以为保险起见,最好在使用TENMS前检查器件的参考手册。 
SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停( halt)时,则SysTick定时器亦将暂停运作。

 

2.4 Systick系统定时器具体代码分析

SysTick 库函数 
 SysTick_CLKSourceConfig 设置 SysTick 时钟源; 
 SysTick_SetReload 设置 SysTick 重装载值; 
 SysTick_CounterCmd 使能或者失能 SysTick 计数器; 
 SysTick_ITConfig 使能或者失能 SysTick 中断; 
 SysTick_GetCounter 获取 SysTick 计数器的值; 
 SysTick_GetFlagStatus 检查指定的 SysTick 标志位设置与否。

2.4.1main文件分析

int main(void)
{   /* LED 端口初始化 */LED_GPIO_Config();/* 配置SysTick 为10us中断一次 */SysTick_Init(); for(;;) { LED1( ON ); Delay_us(10000); // 10000 * 10us = 100ms //Delay_ms(100); LED1( OFF ); LED2( ON ); Delay_us(10000); // 10000 * 10us = 100ms //Delay_ms(100); LED2( OFF ); LED3( ON ); Delay_us(10000); // 10000 * 10us = 100ms //Delay_ms(100); LED3( OFF ); } }

在 main 函数中,SysTick_Init() 和 Delay_us() 这两个函数比较陌生,它们的功能分别是配置好 SysTick 定时器和进行精确延时。整个 main 函数的流程就是初始化 LED 及SysTick 定时器之后,就进入死循环,轮流点亮 LED1、LED2、LED3,点亮的时间为精确的 100 ms。

2.4.2 stm32f103_SysTick.c文件分析

 配置并启动 SysTick 
我们看一下 SysTick_Init() 这个函数,其功能是启动系统滴答定时器 SysTick ,并将 SysTick 配置为 10 μs 中断一次。

void SysTick_Init(void)
{/* SystemFrequency / 100000 10us中断一次* SystemFrequency / 1000000 1us中断一次*/
//  if (SysTick_Config(SystemFrequency / 100000))   // ST3.0.0库版本if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5.0库版本 { /* Capture error */ while (1); } // 关闭滴答定时器 SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; }

}

本函数实际上只是调用了 SysTick_Confi g() 函数,它是属于内核层的 Cortex-M3 通用函数,位于 core_cm3.h 文件中。若调用 SysTick_Confi g() 配置 SysTick 不成功,则进入死循环,初始化 SysTick 成功后,先关闭定时器,在需要的时候再开启。SysTick_Confi g() 函数无法在STM32 外设固件库文件中找到其使用方法。所以我们在 Keil 环境下直接跟踪这个函数到 core_cm3.h 文件,查看函数的定义。

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1); /* Reload value impossible */ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0); /* Function successful */ }

 

在这个函数定义的前面有关于它的注释,如果我们不想去研究它的具体实现,可以根据这段注释了解函数的功能 :这个函数启动了 SysTick ;并把它配置为计数至 0 时引起中断 ;输入的参数 ticks 为两个中断之间的脉冲数,即相隔 ticks 个时钟周期会引起一次中断 ;配置 SysTick 成功时返回 0,出错时返回 1。但是,这段注释并没有告诉我们它把 SysTick 的时钟设置为 AHB 时钟还是 AHB/8,这是一个十分关键的问题,于是,我们将对这个函数的具体实现进行分析,与大家再分享一下如何分析底层库函数。分析底层库函数,要有 SysTick 定时器工作分析的知识准备。 
 检查输入参数 
SysTick_Confi g() 第 3 行代码是检查输入参数 ticks,因为 ticks 是脉冲计数值,要被保存到重载寄存器 STK_LOAD 寄存器中,再由硬件把 STK_LOAD 值加载到当前计数值寄存器 STK_VAL 中使用,STK_LOAD 和 STK_VAL 都是 24 位的,所以当输入参数 ticks 大于其可存储的最大值时,将由这行代码检查出错误并返回。 
 位指示宏及位屏蔽宏 
检查 ticks 参数没有错误后,就稍稍处理一下把 ticks-1 赋值给 STK_LOAD 寄存器,要注意的是减 1,若 STK_VAL 从 ticks−1 向下计数至 0,实际上就经过了 ticks 个脉冲。这句赋值代码使用了宏 SysTick_LOAD_RELOAD_Msk,与其他库函数类似,这个宏是用来指示寄存器的特定位置或进行位屏蔽的。

/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos         16                                             /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ #define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */ #define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ #define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */ #define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ #define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */ #define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */ /* SysTick Reload Register Definitions */ #define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */ #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */ /* SysTick Current Register Definitions */ #define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */ #define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */ /* SysTick Calibration Register Definitions */ #define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */ #define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ #define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */ #define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ #define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */ #define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */ /*@}*/ /* end of group CMSIS_CM3_SysTick */

 

其中寄存器位指示宏 :SysTick_xxx_Pos ,宏展开后即为 xxx 在相应寄存器中的位置,如控制 SysTick 时钟源的 SysTick_CTRL_CLKSOURCE_Pos ,宏展开为 2,这个寄存器位正是寄存器 STK_CTRL 中的 Bit2。 
而寄存器位屏蔽宏 :SysTick_xxx_Msk,宏展开是 xxx 的位全部置 1 后,左移SysTick_xxx_Pos 位。如控制 SysTick 时钟源的 SysTick_CTRL_CLKSOURCE_Msk,宏展开为“1ul << SysTick_CTRL_CLKSOURCE_Pos”, 把 无 符 号 长 整 型 数 值(ul) 1 左移 2 位, 得 到 了 一 个 只 有 Bit2 :CLKSOURCE 位被置 1,其他位为 0 的数值,这样的数值配合位操作 &(按位与)、| (按位或)可以很方便地修改寄存器的某些位。假如控制 CLKSOURCE 需 要 4 个 寄 存 器 位 , 这 个 宏 就 应 该 被 改 为 ( 0xf ul <

SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 使能滴答定时器
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; // 关闭滴答定时器

 

 定时时间的计算 
在调用SysTick_Config()函数时,向它输入的参数为SystemCoreClock / 100000,SystemCoreClock为定义了系统时钟(SYSCLK)频率的 宏,即等于 AHB的时钟频率。在本书的所有例程中AHB 都是被配置为 72 MHz 的,也就是这个 SystemCoreClock 宏展开为数值 7200 0000。 
根据前面对 SysTick_Confi g() 函数的介绍,它的输入参数为 SysTick 将要计时的脉冲数,经过 ticks 个脉冲(经过 ticks 个时钟周期)后将触发中断,触发中断后又重新开始计数。由此我们可以算出定时的时间,下面为计算公式 : 
T=ticks×(1/f) 
其中,T 为要定时的总时间 ;ticks 为 SysTick_Confi g() 的输入参数 ;1/ f 即为SysTick 使用的时钟源的时钟周期,f 为该时钟源的时钟频率,当时钟源确定后为常数。 
例如 :本实验例子中,使用时钟源为 AHB 时钟,其频率被配置为 72 MHz。调用函数时,把 ticks 赋值为 ticks=SystemFrequency / 10 000 =720,表示 720 个时钟周期中断一次 ;1/f 是时钟周期的时间,此时(1/f =1/72 μs),所以最终定时总时间 T=720×(1/72),为720 个时钟周期,正好是 10 μs。 
SysTick 定时器的定时时间(配置为触发中断,即为中断周期)由 ticks 参数决定,最大定时周期不能超过 224 个。 
 编写中断服务函数 
一旦我们调用了 Delay_us() 函数,SysTick 定时器就被开启,按照设定好的定时周期递减计数,当 SysTick 的计数寄存器的值减为 0 时,就进入中断函数,当中断函数执行完毕之后重新计时,如此循环,除非它被关闭。

void Delay_us(__IO u32 nTime)
{ TimingDelay = nTime;    // 使能滴答定时器  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; while(TimingDelay != 0); }

 

使能了 SysTick 之后,就使用 while(TimingDelay != 0)语句等待 TimingDelay 变量变为 0,这个变量是在中断服务函数中被修改的。因此,我们需要编写相应的中断服务程序,在本实验室中我们配置为 10μs 中断一次,每次中断把 TimingDelay 减 1。中断程序在 stm32f10x_it.c 中实现。

void SysTick_Handler(void)
{TimingDelay_Decrement();    
}

 

SysTick中断属于系统异常向量,在stm32f10x_it.c文件中已经默认有了它的中断服务函数SysTick_Handler(),但内容为空。我们找到这个函数,其调用了用户函数TimingDelay_Decrement()。后者是由用户编写的一个应用程序。

void TimingDelay_Decrement(void)
{if (TimingDelay != 0x00){ TimingDelay--;}
}

 

每次进入 SysTick 中断就调用一次 TimingDelay_Decrement()函数,使全局变量TimingDelay 自减一次。用户函数 Delay_us ()在TimingDelay 被减至0时,才退出延时循环,即我们对 TimingDelay 赋的值为要中断的次数。所以总的延时时间 : 
T 延时 = T 中断周期 ×TimingDelay 
至此,SysTick 的精确延时功能讲解完毕。

参考资料:http://www.makeru.com.cn/               创客学院嵌入式学习交流群:561213221

转载于:https://www.cnblogs.com/huan-huan/p/8967055.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kill所有java进程

kill所有java进程 ps -ef | grep java | grep -v grep |awk {print $2} | xargs -p kill -9如果不需要询问&#xff0c;把xargs后面 -p 参数去掉Aix 通过shell脚本kill杀指定进程&#xff0c;比如杀所有java进程 2012-11-16 15:31, Tags: 127人阅读----脚本杀进程-------------…

SpringAOP02 自定义注解

1 自定义注解 1.1 创建自定义注解 从java5开始就可以利用 interface 来定义自定义注解 技巧01&#xff1a;注解不能直接干扰程序代码的运行&#xff08;即&#xff1a;注解的增加和删除操作后&#xff0c;代码都可以正常运行&#xff09; 技巧02&#xff1a;Retention 用来声明…

您的框架有多可扩展性?

在参加会议时&#xff0c;我们总是会见到高素质的决策者&#xff0c;他们经常问同样的问题&#xff1a; 您的框架有多可扩展性&#xff1f;如果我需要比您开箱即用的功能更多的东西怎么办&#xff1f; 。 这个问题是非常合理的&#xff0c;因为他们只是不想被卡在开发曲线的中间…

python-面向对象编程设计与开发

编程范式 1、对不同类型的任务&#xff0c;所采取不同的解决问题的思路。 2、编程范式有两种 1、面向过程编程 2、面向对象编程 面向过程编程 什么是面向过程编程&#xff1f; 过程——解决问题的步骤 要解决一个大的问题 1、先把大问题拆分成若干小问题或子过程。 2、然后子过…

MFC下列表控件的使用

MFC下列表控件的使用 2012-11-09 16:46:57| 分类&#xff1a; 程序VC相关 | 标签&#xff1a; |字号大中小 订阅 1、应该加入头文件 #include <Atlbase.h>2、示例m_list.SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX_ONECLICKACTIVATE);m_lis…

jbehave_使用JBehave,Gradle和Jenkins的行为驱动开发(BDD)

jbehave行为驱动开发 &#xff08;BDD&#xff09;是一个协作过程 &#xff0c;产品所有者&#xff0c;开发人员和测试人员可以合作交付可为业务带来价值的软件。 BDD是 测试驱动开发 &#xff08;TDD&#xff09; 的合理下一步 。 行为驱动的发展 本质上&#xff0c;BDD是一…

嵌入式 开发——DMA内存到外设

学习目标 加强理解DMA数据传输过程加强掌握DMA的初始化流程掌握DMA数据表查询理解源和目标的配置理解数据传输特点能够动态配置源数据学习内容 需求 串口发送数据 uint8_t data = 0x01; 串口发送(data); 实现串口的发送数据, 要求采用dma的方式 数据交互流程 CPU配置好DM…

XSS

1.什么是xss XSS攻击全称跨站脚本攻击&#xff0c;是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆&#xff0c;故将跨站脚本攻击缩写为XSS&#xff0c;XSS是一种在web应用中的计算机安全漏洞&#xff0c;它允许恶意web用户将代码植入到提供给其它用户使用的页面中…

Python之匿名函数

一、匿名函数&#xff1a;也叫lambda表达式 1.匿名函数的核心&#xff1a;一些简单的需要用函数去解决的问题&#xff0c;匿名函数的函数体只有一行 2.参数可以有多个&#xff0c;用逗号隔开 3.返回值和正常的函数一样可以是任意的数据类型 二、匿名函数练习 请把下面的函数转换…

vaadin_5分钟内Google App Engine上的Vaadin App

vaadin在本教程中&#xff0c;您将学习如何创建第一个Vaadin Web应用程序&#xff0c;如何在本地AppEngine开发服务器上运行它以及如何将其部署到Google App Engine基础结构。 所有这些大约需要5到10分钟。 是的&#xff0c;如果您已经安装了必要的先决条件&#xff0c;则可以立…

【分形】【洛谷P1498】

https://www.luogu.org/problemnew/show/P1498 题目描述 自从到了南蛮之地&#xff0c;孔明不仅把孟获收拾的服服帖帖&#xff0c;而且还发现了不少少数民族的智慧&#xff0c;他发现少数民族的图腾往往有着一种分形的效果&#xff0c;在得到了酋长的传授后&#xff0c;孔明掌握…

linux下杀死进程全权讲解

linux下杀死进程全权讲解 2009-10-27 08:57 佚名 linux 我要评论(0) 字号&#xff1a;T | T本文将详细讲解linux杀死进程的多种命令&#xff0c;包含他们的作用&#xff0c;kill作用&#xff1a;根据进程号杀死进程&#xff1b; killall作用&#xff1a;通过程序的名字&#xf…

Java Process中waitFor()的问题

Java Process中waitFor()的问题 http://yearsaaaa123789.iteye.com/blog/1404865在编写Java程序时&#xff0c;有时候我们需要调用其他的诸如exe,shell这样的程序或脚本。在Java中提供了两种方法来启动其他程序&#xff1a;(1) 使用Runtime的exec()方法(2) 使用ProcessBuilder…

应用程序模块和实体缓存

任何具有ADF业务组件基础知识的ADF开发人员都应该熟悉下图&#xff1a; 它代表运行时ADF业务组件的核心构建块。 有一个包含视图对象实例的根应用程序模块实例。 视图对象实例可能由存储在实体集合或换句话说就是实体缓存中的实体对象备份。 根应用程序模块可能还包含嵌套的应…

kubernetes-dashboard(1.8.3)部署与踩坑

Kubernetes Dashboard 是一个管理Kubernetes集群的全功能Web界面&#xff0c;旨在以UI的方式完全替代命令行工具&#xff08;kubectl 等&#xff09;。 目录 部署创建用户集成Heapster访问 kubectl proxyNodePortAPI ServerIngress部署 Dashboard需要用到k8s.gcr.io/kubernetes…

oracle线程阻塞_Oracle Service Bus –线程阻塞案例研究

oracle线程阻塞本案例研究描述了在AIX 6.1和IBM Java VM 1.6上运行的Oracle Service Bus 11g遇到的线程阻塞问题的完整根本原因分析过程。 本文也是您提高线程转储分析技能的绝佳机会&#xff0c;我强烈建议您学习并正确理解以下分析方法。 它还将展示正确数据收集的重要性&…

Activiti中的安全脚本如何工作

最近的Activiti 5.21.0版本的突出特点之一是“安全脚本”。 Activiti用户指南中详细介绍了启用和使用此功能的方法 。 在这篇文章中&#xff0c;我将向您展示我们如何实现其最终实现以及它在幕后所做的事情。 当然&#xff0c;由于这是我通常的签名风格&#xff0c;因此我们还将…

使用准现网的数据,使用本地的样式脚本,本地调试准现网页面(PC适用)

原理&#xff1a; 本地逻辑&#xff0c;重新渲染 步骤&#xff1a; 1.安装插件&#xff1a;Tampermonkey 度盘&#xff1a;https://pan.baidu.com/s/1bpBVVT9 2.设置&#xff1a; 点击插件-->仪表盘 添加脚本 将此文本文档中的脚本复制到脚本编辑框处&#xff0c;并CtrlS保存…

FDATOOL设计滤波器

FDATOOL设计滤波器 分类&#xff1a; 数字信号处理 2006-04-20 11:251. 在Matlab中键入fdatool运行Filter Design and Analysis Tool。具体使用请参见Matlab Help中的Signal Processing Toolbox->FDATool。 2. 在fdatool工具中应该注意的几个问题&#xff1a;(a)Fstop&#…

大例外背后的真相

异常可能是最被滥用的Java语言功能。 这就是为什么 让我们打破一些神话。 没有牙仙子。 圣诞老人不是真实的。 TODO评论。 finalfinalversion-final.pdf。 无皂肥皂。 而且…例外实际上是例外。 后者可能需要更多说服力&#xff0c;但我们可以帮助您。 在这篇文章中&#xff…