文章目录

  • 一、delay 文件夹代码介绍
    • 1.delay_init 函数
    • 2.delay_us 函数
    • 3.delay_ms函数
  • 二、sys 文件夹代码介绍
    • 1.IO 口的位操作实现
  • 三、usart 文件夹代码介绍
    • 1.printf 函数支持

  在 新建工程模板——库函数版本中,我们用到了一个 SYSTEM 文件夹里面的代码,此文件夹里面的代码由 ALIENTEK 提供,是 STM32F4xx 系列的底层核心驱动函数,可以用在 STM32F4xx 系列的各个型号上面,方便大家快速构建自己的工程。 SYSTEM 文件夹下包含了 delaysysusart 等三个文件夹。分别包含了 delay.csys.cusart.c及其头文件。

一、delay 文件夹代码介绍

  delay 文件夹内包含了 delay.cdelay.h 两个文件,这两个文件用来实现系统的延时功能,其中包含 7 个函数:

  • void delay_osschedlock(void);
  • void delay_osschedunlock(void);
  • void delay_ostimedly(u32 ticks);
  • void SysTick_Handler(void);
  • void delay_init(u8 SYSCLK);
  • void delay_ms(u16 nms);
  • void delay_us(u32 nus);

  在介绍这些函数之前,我们先了解一下编程思想:CM4 内核的处理和 CM3 一样,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。我们就是利用 STM32的内部 SysTick来实现延时的,这样既不占用中断,也不占用系统定时器。
  这里,我们以 UCOSII 为例,介绍如何实现操作系统和我们的 delay 函数共用 SysTick 定时器。首先,我们简单介绍下 UCOSII 的时钟:ucos 运行需要一个系统时钟节拍(类似 “心跳”),而这个节拍是固定的(由 OS_TICKS_PER_SEC 宏定义设置),比如要求 5ms 一次(即可设置:OS_TICKS_PER_SEC=200),在 STM32 上面,一般是由 SysTick 来提供这个节拍,也就是 SysTick要设置为 5ms 中断一次,为 ucos 提供时钟节拍,而且这个时钟一般是不能被打断的(否则就不准了)。
  因为在 ucossystick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者delay_ms 的延时,就必须想点办法了,这里我们利用的是时钟摘取法。以 delay_us 为例,比如:delay_us(50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里为 50*180(假设系统时钟为 180Mhz,因为我们设置 systick 的频率为系统时钟频率,那么 systick每增加 1,就是 1/180us),然后我们就一直统计 systick 的计数变化,直到这个值变化了 50*180,一旦检测到变化达到或者超过这个值,就说明延时 50us 时间到了。这样,我们只是抓取 SysTick计数器的变化,并不需要修改 SysTick 的任何状态,完全不影响 SysTick 作为 UCOS 时钟节拍的功能,这就是实现 delay 和操作系统共用 SysTick 定时器的原理。

1.delay_init 函数

  该函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值为 1 即可,然后,该函数会根据delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并开启 SysTick中断。具体代码如下:

//初始化延迟函数
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
//SYSTICK的时钟固定为AHB时钟
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{#if SYSTEM_SUPPORT_OS                       //如果需要支持OS.u32 reload;
#endifHAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLKfac_us=SYSCLK;                       //不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS                       //如果需要支持OS.reload=SYSCLK;                      //每秒钟的计数次数 单位为K    reload*=1000000/delay_ostickspersec;    //根据delay_ostickspersec设定溢出时间//reload为24位寄存器,最大值:16777216,在180M下,约合0.745s左右 fac_ms=1000/delay_ostickspersec;       //代表OS可以延时的最少单位    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断SysTick->LOAD=reload;                   //每1/OS_TICKS_PER_SEC秒中断一次  SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
#endif
}

可以看到,delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 OS 的时候,只是设置一下 SysTick 的时钟源以及确定 fac_us 值。而如果使用 OS 的时候,则会进行一些不同的配置,这里的条件编译是根据SYSTEM_SUPPORT_OS这个宏来确定的,该宏在sys.h里面定义。SysTickMDK 定义了的一个结构体,里面包含 CTRLLOADVALCALIB 等 4 个寄存器,

/**\brief  Structure type to access the System Timer (SysTick).*/
typedef struct
{__IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */__IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */__IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */__IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;

  CTRLSysTick控制和状态寄存器。SysTick->CTRL 的各位定义如图所示:

  LOADSysTick自动重装载除值寄存器。SysTick-> LOAD 的定义如图所示:

  VALSysTick当前值寄存器。SysTick-> VAL 的定义如图所示:

  CALIBSysTick校准值寄存器。SysTick-> CALIB 不常用,在这里我们也用不到,故不介绍了。
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);这句代码把 SysTick 的时钟选择为内核时钟,这里需要注意的是:SysTick 的时钟源自 HCLK,假设我们外部晶振为 25M,然后倍频到 180MHZ,那么 SysTick 的时钟即为 180Mhz,也就是 SysTick 的计数器 VAL 每减 1,就代表时间过了 1/180us。所以fac_us=SYSCLK;这句话就是计算在 SYSCLK 时钟频率下延时 1us需要多少个 SysTick 时钟周期。
  在不使用 OS 的时候:fac_usus 延时的基数,也就是延时 1usSystick 定时器需要走过的时钟周期数。 当使用 OS 的时候,fac_us,还是 us 延时的基数,不过这个值不会被写到SysTick->LOAD 寄存器来实现延时,而是通过时钟摘取的办法实现的。而fac_ms 则代表 ucos 自带的延时函数所能实现的最小延时时间(如 delay_ostickspersec=200,那么 fac_ms 就是 5ms)。

2.delay_us 函数

  该函数用来延时指定的 us,其参数 nus 为要延时的微秒数。该函数有使用 OS 和不使用 OS两个版本,这里我们首先介绍不使用 OS 的时候,实现函数如下:

//延时nus
//nus为要延时的us数.
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
void delay_us(u32 nus)
{       u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD;               //LOAD的值             ticks=nus*fac_us;                         //需要的节拍数 told=SysTick->VAL;                     //刚进入时的计数器值while(1){tnow=SysTick->VAL;  if(tnow!=told){        if(tnow<told)tcnt+=told-tnow;  //这里注意一下SYSTICK是一个递减的计数器就可以了.else tcnt+=reload-tnow+told;        told=tnow;if(tcnt>=ticks)break;            //时间超过/等于要延迟的时间,则退出.}  }
}

这里就正是利用了我们前面提到的时钟摘取法,ticks 是延时 nus 需要等待的 SysTick 计数次数(也就是延时时间),told 用于记录最近一次的 SysTick->VAL 值,然后 tnow 则是当前的SysTick->VAL 值,通过他们的对比累加,实现 SysTick 计数次数的统计,统计值存放在 tcnt 里面,然后通过对比 tcntticks,来判断延时是否到达,从而达到不修改 SysTick 实现 nus 的延时。
  对于使用 OS 的时候,delay_us 的实现函数和不使用 OS 的时候方法类似,都是使用的时钟摘取法,只不过使用 delay_osschedlockdelay_osschedunlock 两个函数,用于调度上锁和解锁,这是为了防止 OSdelay_us 的时候打断延时,可能导致的延时不准,所以我们利用这两个函数来实现免打断,从而保证延时精度。

//延时nus
//nus:要延时的us数.
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)
void delay_us(u32 nus)
{       u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD;               //LOAD的值             ticks=nus*fac_us;                         //需要的节拍数 delay_osschedlock();                   //阻止OS调度,防止打断us延时told=SysTick->VAL;                      //刚进入时的计数器值while(1){tnow=SysTick->VAL;  if(tnow!=told){        if(tnow<told)tcnt+=told-tnow;  //这里注意一下SYSTICK是一个递减的计数器就可以了.else tcnt+=reload-tnow+told;        told=tnow;if(tcnt>=ticks)break;            //时间超过/等于要延迟的时间,则退出.}  };delay_osschedunlock();                 //恢复OS调度
}

3.delay_ms函数

  该函数是用来延时指定的 ms 的,其参数 nms 为要延时的毫秒数。该函数有使用 OS 和不使用 OS 两个版本,这里我们分别介绍,首先是不使用 OS 的时候,实现函数如下:

//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{u32 i;for(i=0;i<nms;i++) delay_us(1000);
}

该函数其实就是多次调用前面所讲的 delay_us 函数,来实现毫秒级延时的。
  再来看看使用 OS 的时候,delay_ms 的实现函数如下:

//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u16 nms)
{   if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)       {        if(nms>=fac_ms)                        //延时的时间大于OS的最少时间周期 { delay_ostimedly(nms/fac_ms);   //OS延时}nms%=fac_ms;                        //OS已经无法提供这么小的延时了,采用普通方式延时    }delay_us((u32)(nms*1000));               //普通方式延时
}

  该函数中,delay_osrunningOS 正在运行的标志,delay_osintnesting 则是 OS 中断嵌套次数,必须 delay_osrunning 为真,且 delay_osintnesting 为 0 的时候,才可以调用 OS 自带的延时函数进行延时(可以进行任务调度),delay_ostimedly 函数就是利用 OS 自带的延时函数,实现任务级延时的,其参数代表延时的时钟节拍数(假设 delay_ostickspersec=200 ,那么delay_ostimedly (1),就代表延时 5ms)。
  当 OS 还未运行的时候,我们的 delay_ms 就是直接由 delay_us 实现的,OS 下的 delay_us可以实现很长的延时(达到 204 秒)而不溢出!,所以放心的使用 delay_us 来实现 delay_ms,不过由于 delay_us 的时候,任务调度被上锁了,所以还是建议不要用 delay_us 来延时很长的时间,否则影响整个系统的性能。
  当 OS 运行的时候,我们的 delay_ms 函数将先判断延时时长是否大于等于 1 个 OS 时钟节拍fac_ms,当大于这个值的时候,我们就通过调用 OS 的延时函数来实现(此时任务可以调度),不足 1 个时钟节拍的时候,直接调用 delay_us 函数实现(此时任务无法调度)。

二、sys 文件夹代码介绍

  sys 文件夹内包含了 sys.csys.h 两个文件。在 sys.h 里面定义了 STM32F4IO 口位操作输入读取宏定义和输出宏定义以及类型别名。sys.c 里面除了定义时钟系统配置函数Stm32_Clock_Init 外主要是一些汇编函数。本小节我们主要向大家介绍 sys.h 头文件里面的 IO 口位操作。

1.IO 口的位操作实现

  该部分代码在 sys.h 文件中,实现对STM32F4 各个 IO 口的位操作,包括读入和输出。当然在这些函数调用之前,必须先进行 IO 口时钟的使能和 IO 口功能定义。此部分仅仅对IO 口进行输入输出读取和控制。
  位带操作简单的说,就是把每个比特膨胀为一个 32 位的字,当访问这些字的时候就达到了访问比特的目的,比如说 GPIOODR 寄存器有 32 个位,那么可以映射到 32 个地址上,我们去访问这 32 个地址就达到访问 32 个比特的目的。这样我们往某个地址写 1 就达到往对应比特位写 1 的目的,同样往某个地址写 0 就达到往对应的比特位写 0 的目的。

  对于上图,我们往 Address0 地址写入 1,那么就可以达到往寄存器的第 0 位 Bit0 赋值1 的目的。下面我们看看 sys.h 中位带操作的定义,代码如下:

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014
#define GPIOJ_ODR_ADDr    (GPIOJ_BASE+20) //0x40022414
#define GPIOK_ODR_ADDr    (GPIOK_BASE+20) //0x40022814#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010
#define GPIOJ_IDR_Addr    (GPIOJ_BASE+16) //0x40022410
#define GPIOK_IDR_Addr    (GPIOK_BASE+16) //0x40022810 //IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入#define PJout(n)   BIT_ADDR(GPIOJ_ODR_Addr,n)  //输出
#define PJin(n)    BIT_ADDR(GPIOJ_IDR_Addr,n)  //输入#define PKout(n)   BIT_ADDR(GPIOK_ODR_Addr,n)  //输出
#define PKin(n)    BIT_ADDR(GPIOK_IDR_Addr,n)  //输入

以上代码的便是 GPIO 位带操作的具体实现。比如说,我们调用 PAout(1)=1是设置了 GPIOA 的第一个管脚 GPIOA.1 为 1,实际是设置了寄存器的某个位,但是我们的定义中可以跟踪过去看到却是通过计算访问了一个地址。上面一系列公式也就是计算GPIO 的某个 IO 口对应的位带区的地址了。
  有了上面的代码,我们就可以像51一样操作STM32IO口了。比如,我要PORTA的第七个 IO 口输出 1,则可以使用 PAout(6)=1;即可实现。我要判断 PORTA 的第 15个位是否等于 1,则可以使用 if(PAin(14)==1)…;就可以了。
  这里顺便说一下,在 sys.h 中的还有个全局宏定义:

//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS       0       //定义系统文件夹是否支持OS

SYSTEM_SUPPORT_OS,这个宏定义用来定义 SYSTEM 文件夹是否支持 ucos,如果在 ucos 下面使用 SYSTEM 文件夹,那么设置这个值为 1 即可,否则设置为 0(默认)。

三、usart 文件夹代码介绍

  该文件夹下面有 usart.cusarts.h 两个文件。串口相关知识将在串口实验中讲解。

1.printf 函数支持

  printf 函数支持的代码在 usart.c 文件的最上方,在我们初始化和使能串口 1 之后,然后把这段代码加入到工程,便可以通过 printf 函数向串口 1 发送我们需要的内容,方便开发过程中查看代码执行情况以及一些变量值。这段代码如果要修改一般也只是用来改变printf 函数针对的串口号,大多情况我们都不需要修改。代码如下:

//加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{ int handle;
}; FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{ x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{   while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   USART1->DR = (u8) ch;      return ch;
}
#endif

STM32F4 | SYSTEM文件夹介绍 | delay文件夹 | sys文件夹 | usart文件夹相关推荐

  1. 【正点原子sys、delay、usart文件夹介绍】

    正点原子sys.delay.usart文件夹介绍 文章目录 正点原子sys.delay.usart文件夹介绍 一.sys文件夹函数 二.delay文件夹函数 2.1文件夹函数介绍 2.2 测试程序运行 ...

  2. 批处理命令html文件合并,cmd命令行无损合并批处理TS视频文件

    有时,当我们从Internet下载一些视频文件时,我们发现某些视频格式为.ts格式,并且被分成N个以上的小文件. 特别是,某些视频以.ts格式(MPEG2-TS流)播放. 因此,如果要下载此视频,则需 ...

  3. 【STM32】SYSTEM文件夹介绍,delay,sys,usart

    文章目录 delay 文件夹 sys 文件夹 usart 文件夹 uart_init() USART1_IRQHandler 函数 usart.h 对串口 printf 的支持代码 delay 文件夹 ...

  4. Android 文件夹介绍

    目录列表详细对照表:1..android_secure 是官方app2sd的产物,删了之后装到sd卡中的软件就无法使用了.2..Bluetooth 顾名思义,用蓝牙之后就会有这个.3..mobo 顾名 ...

  5. postman怎么导出测试用例_postman---postman文件夹介绍以及批量执行用例

    我们在做测试的过程中,都会多次请求接口,都会把接口保存下来,方便下次直接请求,节省时间不用每次都重新输入,我们一起看下Postman如何保存接口会话 保存请求作用 Postman可以将各个请求组合保存 ...

  6. win10电脑服务器在哪个文件夹下,Win10桌面背景在哪个文件夹?Win10桌面背景所在文件夹介绍...

    最近有Win10用户反映,之前电脑有设了张很好看的桌面背景,但后来不小心给换成了别的,现在想换回来,却不知道要在哪个文件夹找那张桌面背景,用户为此非常困恼.那么,Win10桌面背景在哪个文件夹呢?下面 ...

  7. linux复制文件夹 实例,linux复制文件夹与文件实例介绍linux操作系统 -电脑资料

    本文章来介绍一下关于linux复制文件夹与文件的一些基础用法,有需要学习的朋友可参考一下本文章, CP命令 格式: CP [选项] 源文件或目录  目的文件或目录 选项说明:-b 同名,备分原来的文件 ...

  8. php遍历目录与文件夹,介绍几种php遍历目录与文件夹的方法

    介绍几个php遍历目录的方法,可以遍历目录及目录中的文件,供大家参考 遍历目录或遍历目录下指定类型的文件,这是每一个童鞋在写程序的时候难免会用到的.PHP本身也提供了很多灰常有用的函数,正确地使用它们 ...

  9. linux的重要文件,Linux中重要文件夹介绍

    Linux中重要的文件夹介绍 嵌入式助教苗沛2014 01 08 知识讲解 对于linux新手来说 最感到迷惑的问题之一就是文件都存在哪里呢 特别是对于那些从windows转过来的新手来说 linux ...

最新文章

  1. 计算机名称改变之后,HOUDINI Server 连接不上的解决办法
  2. sap 教学视频网址
  3. PHP-Curl模拟HTTP请求
  4. CSS基础「六」元素的显示与隐藏
  5. linux 内核同步--理解原子操作、自旋锁、信号量(可睡眠)、读写锁、RCU锁、PER_CPU变量、内存屏障
  6. Linux中让普通用户拥有超级用户的权限
  7. CUDA编程之:Stream(流)
  8. mysql cnf参数_系统运维|MySQL my.cnf参数配置优化详解
  9. 趣学 C 语言(六)—— 结构和联合
  10. 白化(Whitening): PCA白化 ZCA白化
  11. 空气投影+生物识别,支付宝的“如影计划”还有多少硬仗要打?
  12. 页面编码和js文件不同导致的IE6下脚本错误
  13. does not point to a valid jvm installation
  14. magicbook的linux是哪个版本,MagicBook 2019 linux版来了!
  15. 大学英语精读第二版(第五册)复习笔记——文章内容摘要
  16. 正雅齿科运用新数字技术为正畸行业开辟新空间
  17. excel 锁定第一行
  18. 【软件测试】稳定性和可靠性测试在软件开发中的重要性
  19. OpenCV图像特征提取学习三,LBP图像特征检测算法
  20. C++工程编译链接错误汇总VisualStudio

热门文章

  1. flowable会签时, act_run_task 表内有数据但是 assignee字段没值
  2. 31岁程序员的苦恼:妻子总让我想办法考体制,铁饭碗总比码农强
  3. 【TouchDesigner】生成艺术
  4. html5微信拍照后自动刷新,html5 调用微信jssdk 没有调用相机,只显示最近的图片文件。...
  5. 爬虫:JSON文件存储
  6. 面试题--cpu高解决方案以及火焰图学习
  7. windbg输出SXS.DLL的调试信息
  8. 一个事件订阅和发布的库(onfire.js)的源码浅析
  9. 微信小程序开发支付流程
  10. 电视剧 | 黑镜S5E2 碎片