GD32开发实战指南(基础篇) 第7章 定时器

发布者:innovator7最新更新时间:2024-11-06 来源: elecfans关键字:GD32  开发实战  定时器 手机看文章 扫描二维码
随时随地手机看文章

开发环境:

MDK:Keil 5.30

开发板:GD32F207I-EVAL

MCU:GD32F207IK

1 定时器的工作原理概述

系统滴答定时器一般用来提供“心跳”作用,而GD32定时器最基本功能也是定时,可以设置不同时间长度的定时。定时器除了最基本的定时功能外,定时器与GPIO有挂钩使得它可以发挥强大的作用,比如可以输出不同频率、不同占空比的方波信号、PWM信号,同时做为输入捕获功能时,可以测量脉冲宽度、实现电容按键检测等等。

GD32有三类定时器,基本定时器就是单纯的定时计数器,通用定时器多了四个通道,相对应的增加了功能,高级定时器具有基本,通用定时器的所有的功能,并且添加了其他功能。定时器的对比特性如下表所示。

定时器定时器****0/7定时器****1/2/3/4定时器****8/11定时器****9/10/12/13定时器****5/6
类型高级通用(L0)通用(L1)通用(L2)基本
预分频器16位16位16位16位16位
计数器16位16位16位16位16位
计数模式向上, 向下, 中央对齐向上, 向下, 中央对齐向上, 向下, 中央对齐向上, 向下, 中央对齐向上

1.1 基本定时器

TIMER5和TIMER6定时器的主要功能包括:

● 16位自动重装载累加计数器

● 16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1 ~ 65536之间的任意数值分频

● 时钟源只有内部时钟

● 在更新事件(计数器溢出)时产生中断/DMA请求

总的说来,基本定时器 TIMER5和TIMER6只具备最基本的定时功能,就是累加的时钟脉冲数超过预定值时,能触发中断或触发 DMA 请求。由于在芯片内部与 DAC 外设相连,可通过触发输出驱动 DAC,也可以作为其他通用定时器的时钟基准。

这两个基本定时器使用的时钟源都是CK_TIMER驱动,时钟源经过 TIMERx_PSC预分频器输入至脉冲计数器TIMERx_CNT,基本定时器只能工作在向上计数模式,在重载寄存器TIMERx_CAR中保存的是定时器的溢出值。

工作时,脉冲计数器TIMERx_CNT由时钟触发进行计数,当 TIMx_CNT 的计数值 X 等于重载寄存器TIMERx_CAR中保存的数值 N 时,产生溢出事件,可触发中断或 DMA 请求。然后TIMERx_CNT的值重新被置为 0,重新向上计数。

1683729210717qoj86wq8k1

1.2 通用定时器

通用TIMERx(TIMER1/ TIMER2/ TIMER3/ TIMER4/ TIMER8/ TIMER11/ TIMER9/ TIMER10/ TIMER12/ TIMER13)定时器功能包括:

● 16位向上、向下、向上/向下自动装载计数器;

● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值;

● 4个独立通道:输入捕获,输出比较,PWM生成(边缘或中间对齐模式),单脉冲模式输出;

● 使用外部信号控制定时器和定时器互连的同步电路;

● 如下事件发生时产生中断/DMA:更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发), 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数),输入捕获,输出比较;

● 支持针对定位的增量(正交)编码器和霍尔传感器电路;

● 时钟源可选:内部时钟,内部触发,外部输入,外部触发;

相比之下,通用定时器就比基本定时器复杂得多了。除了基本的定时,它主要用在测量输入脉冲的频率、脉冲宽与输出 PWM 脉冲的场合,还具有编码器的接口。

16837292112783m1yhn9uky

从时钟源方面来说,通用定时器比基本定时器多了一个选择,它可以使用外部脉冲作为定时器的时钟源。使用外部时钟源时,要使用寄存器进行触发边沿、滤波器带宽的配置。如果选择内部时钟源的话则与基本定时器一样,也为CK_TIMER。但要注意的是,所有定时器(包括基本、通用和高级)使用内部时钟时,定时器的时钟源都被称为CK_TIMER,但CK_TIMER的时钟来源并不是完全一样的,见下图。

1683729211828lvanongcnk

基本定时器和部分通用定时器的时钟来源是 APB1 预分频器的输出。当 APB1 的分频系数为 1 时,则CK_TIMER直接等于该APB1 预分频器的输出,而 APB1 的分频系数 不 为 1 时,CK_TIMER则为APB1 预分频器输出的 2 倍。

如在常见的配置中,AHB=120MHz,而 APB1 预分频器的分频系数被配置为2,则PCLK1 刚好达到最大值60MHz,而此时APB1的分频系数不为 1,则CK_TIMER = (AHB/2) x 2 = 120MHz。

而对于部分通用定时器和高级定时器的时钟来源则是 APB2 预分频器的输出,同样它也根据分频系数分为两种情况。

常见的配置中 AHB=120MHz,APB2 预分频器的分频系数被配置为1,此时PCLK2刚好达到最大值120MHz,而CK_TIMER则直接等于APB2分频器的输出,即CK_TIMER的时钟 CK_TIMER =AHB=120MHz。

虽然这种配置下最终CK_TIMER的时钟频率相等,但必须清楚实质上它们的时钟来源是有区别的。还要强调的是:CK_TIMER是定时器内部的时钟源,但在时钟输出到脉冲计数器 TIMERx_CNT 前,还经过一个预分频器TIMERx_PSC,最终用于驱动脉冲计数器 TIMERx_CNT 的时钟频率根据预分频器 TIMERx_PSC 的配置而定。

1.3 高级定时器

TIMER0和TIMER7定时器的功能包括:

● 16位向上、向下、向上/下自动装载计数器;

● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1 ~ 65535之间的任意数值;

● 多达4个独立通道:输入捕获,输出比较,PWM生成(边缘或中间对齐模式),单脉冲模式输出;

● 死区时间可编程的互补输出;

● 使用外部信号控制定时器和定时器互联的同步电路;

● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器;

● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态;

● 如下事件发生时产生中断/DMA:更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发),触发事件(计数器启动、停止、初始化或者由内部/外部触发计数),输入捕获,输出比较,刹车信号输入;

● 支持针对定位的增量(正交)编码器和霍尔传感器电路;

● 时钟源可选:内部时钟,内部触发,外部输入,外部触发;

总的来说,TIMER0和TIMER7是两个高级定时器,它们具有基本、通用定时器的所有功能,还具有三相 6 步电机的接口、刹车功能(break function)及用于 PWM 驱动电路的死区时间控制等,使得它非常适合于电机的控制。如图4 所示为高级定时器结构。

168372921242248hf2ofiaj

相比于通用定时器,主要多出了BRK、DTG 两个结构,因而具有了死区时间的控制功能。首先,死区时间是什么呢?在 H 桥、三相桥的 PWM 驱动电路中,上下两个桥臂的PWM 驱动信号是互补的,即上下桥臂轮流导通,但实际上为了防止出现上下两个臂同时导通(会造成短路),在上下两臂切换时留一小段时间,上下臂都施加关断信号,这个上下臂都关断的时间称为死区时间。

高级定时器可以配置出输出互补的 PWM 信号,并且在这个 PWM 信号中加入死区时间,为电机的控制提供了极大的便利。下图中的 OCxREF 为参考信号(可理解为原信号),OCx_O和 OCx_ON 为定时器通过 GPIO 引脚输出的 PWM 互补信号。

1683729212884y29ee17c9u

若不加入死区时间,当OxCPRE出现下降沿,OCx_O同时输出下降沿,OCx_ON 则同时输出相反的上升沿,即这三个信号的跳变是同时的。

加入死区时间后,当 OxCPRE出现下降沿,OCx_O同时输出下降沿,但 OCx_ON 则过了一小段延迟再输出上升沿,OxCPRE出现上升沿后,OCx_O要经过一段延时再输出上升沿。假如 OCx_O、 OCx_ON 分别控制上、下桥臂,有了延迟后,就不容易出现上、下桥臂同时导通的情况。这个延迟时间与 PWM 信号驱动的电子器件特性相关,从事工控领域的朋友对此应该比较熟悉。

2 定时器计数模式

定时器可以向上计数、向下计数、向上向下双向计数模式。

  • 向上计数模式:计数器从0计数到自动加载值(TIMERx_CAR),然后重新从0开始计数并且产生一个计数器溢出事件。

  • 向下计数模式:计数器从自动装入的值(TIMERx_CAR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

  • 中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

简单地理解三种计数模式,可以通过下面的图形:

https://img-blog.csdn.net/20180417164424341

图6定时器计数模式

计数器时钟可由下列时钟源提供:

  • 内部时钟(CK_TIMER);

  • 外部时钟模式0:定时器选择外部输入引脚作为时钟源;

  • 外部时钟模式1:定时器选择外部输入引脚ETI作为时钟源;

3 定时器的寄存器分析

为了深入了解 GD32 的通用寄存器,下面我们先介绍一下与我们这章的实验密切相关的几个通用定时器的寄存器。首先是控制寄存器0(TIMERx_CTL0),该寄存器的各位描述如下图。

1683729213662cigun06hll

首先我们来看看TIMERx_CTL0的最低位,也就是计数器使能位,该位必须置1,才能让定时器开始计数。 从第 4 位 DIR 可以看出默认的计数方式是向上计数, 同时也可以向下计数,第 5,6位是设置计数对齐方式的。从第 8 和第 9 位可以看出,我们还可以设置定时器的时钟分频因子为1,2,4。

接下来介绍第二个与我们这章密切相关的寄存器:DMA/中断使能寄存器(TIMERx_DMAINTEN)。该寄存器是一个 16 位的寄存器,其各位描述如下图所示。

168372921409311u5mr8m3v

这里我们同样仅关心它的第 0 位,该位是更新中断允许位,本章用到的是定时器的更新中断,所以该位要设置为1。

接下来我们看第三个与我们这章有关的寄存器:预分频寄存器(TIMERx_PSC)。该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。该寄存器的各位描述如下图。

1683729214532vbfc5i5igg

这里顺带介绍一下TIMERx_CNT 寄存器,该寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。

接着我们介绍计数器自动重载寄存器(TIMERx_CAR),该寄存器在物理上实际对应着 2 个寄存器。一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器在《GD32F20x_User_Manual_EN_Rev2.4》里面被叫做影子寄存器。事实上真正起作用的是影子寄存器。根据TIMERx_CTL0寄存器中ARSE位的设置:ARSE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时二者是连通的;而 ARSE=1 时,在每一次更新事件时,才把预装在寄存器的内容传送到影子寄存器。自动重装载寄存器的各位描述如下图。

1683729214954twuu440c13

最后,我们要介绍的寄存器是:中断标志寄存器(TIMERx_INTF)。该寄存器用来标记当前与定时器相关的各种事件/中断是否发生。该寄存器的各位描述如下图。

16837292153226gzenqdxzh

1683729215675iqwup0kat8

关于这些位的详细描述,请参考《GD32F20x_User_Manual_EN_Rev2.4》。只要对以上几个寄存器进行简单的设置,我们就可以使用通用定时器了,并且可以产生中断。这一章,我们将使用定时器产生中断,然后在中断服务函数里面翻转 DS1 上的电平,来指示定时器中断的产生。


4 定时器代码实现

接下来我们以通用定时器TIMER1为实例,来说明要经过哪些步骤,才能达到这个要求,并产生中断。


4.1 定时器配置步骤

这里我们就对每个步骤通过库函数的实现方式来描述。首先要提到的是,定时器相关的库函数主要集中在固件库文件 gd32f20x_timer.h 和 gd32f20x_timer.c 文件中。


1) TIMER1时钟使能。


TIMER1是挂载在 APB1 之下,所以我们通过 APB1 总线下的使能使能函数来使能 TIMER1。调用的函数是:


rcu_periph_clock_enable(RCU_TIMER1);

2) 初始化定时器参数,设置自动重装值,分频系数,计数方式等。


在库函数中,定时器的初始化参数是通过初始化函数 timer_init实现的:


void timer_init(uint32_t timer_periph, timer_parameter_struct *initpara)

第一个参数是确定是哪个定时器,这个比较容易理解。


第二个参数是定时器初始化参数结构体指针,结构体类型为 timer_parameter_struct,下面我们看看这个结构体的定义:


/* TIMER init parameter structure definitions */

typedef struct {

    uint16_t prescaler;                         /*!< prescaler value */

    uint16_t alignedmode;                       /*!< aligned mode */

    uint16_t counterdirection;                  /*!< counter direction */

    uint32_t period;                            /*!< period value */

    uint16_t clockdivision;                     /*!< clock division value */

    uint8_t  repetitioncounter;                 /*!< the counter repetition value */

} timer_parameter_struct;

这个结构体一共有6个成员变量。


第一个参数 prescaler 是用来设置分频系数的,刚才上面有讲解。


第二个参数alignedmode是对齐模式,分为边沿对齐模式,中央对齐向下计数置1模式,中央对齐向上计数置1模式,中央对齐上下计数置1模式。


第三个参数counterdirection是计数方向,向上计数和向下计数。


第四个参数period是设置自动重载计数周期值,这在前面也已经讲解过。


第五个参数clockdivision是用来设置时钟分频因子。


第六个参数repetitioncounter是重复计数器。


针对 TIMER1初始化范例代码格式:


timer_parameter_struct timer_initpara;


/* TIMER1 configuration */

timer_initpara.prescaler         = 119;

timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;

timer_initpara.counterdirection  = TIMER_COUNTER_UP;

timer_initpara.period            = 999;

timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;

timer_initpara.repetitioncounter = 0;

timer_init(TIMER1, &timer_initpara);

3) 设置TIMERx_DMAINTEN允许更新中断。


因为我们要使用 TIMER1的更新中断, 寄存器的相应位便可使能更新中断。 在库函数里面定时器中断使能是通过 timer_interrupt_enable()函数来实现的:


void timer_interrupt_enable(uint32_t timer_periph, uint32_t interrupt)

第一个参数是选择定时器号,这个容易理解,取值为TIMERx(x=0..13)。


第二个参数非常关键,是用来指明我们使能的定时器中断的类型,定时器中断的类型有很多种,包括TIMER_INT_UP, TIMER_INT_TRG等等。


例如我们要使能 TIMER1 的更新中断,格式为:


timer_interrupt_enable(TIMER1,TIMER_INT_UP);

4) TIMER1中断优先级设置。


在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中断优先级。中断优先级配置代码如下:


//TIMER1 interrupt setting, preemptive priority 0, sub-priority 3

nvic_irq_enable(TIMER1_IRQn, 0, 3);

5) 允许 TIMER1工作,也就是使能 TIMER1。


光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,通过 TIMER_CTL0的TIMER_CTL0_CEN位来设置。在固件库里面使能定时器的函数是通过 timer_enable()函数来实现的:


void timer_enable(uint32_t timer_periph)

这个函数非常简单,比如我们要使能定时器1,方法为:


/* TIMER1 enable */

timer_enable(TIMER1);

6) 编写中断服务函数。


在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在中断标志寄存器TIMERx_INTF的最低位。在处理完中断之后应该向TIMERx_INTF最低位写 0,来清除该中断标志。


在固件库函数里面,用来读取中断状态寄存器的值判断中断类型的函数是:


FlagStatus timer_interrupt_flag_get(uint32_t timer_periph, uint32_t int_flag)

该函数的作用是,判断定时器 TIMERx 的中断类型是否发生中断。比如,我们要判断定时器1是否发生更新(溢出)中断,方法为:


if ( timer_interrupt_flag_get(TIMER1 , TIMER_INT_UP) != RESET ) {}

固件库中清除中断标志位的函数是:




该函数的作用是,清除定时器 TIMERx 的中断标志位。 使用起来非常简单,比如我们在TIMER1 的溢出中断发生后,我们要清除中断标志位,方法是:


timer_interrupt_flag_clear(TIMER1 , TIMER_INT_UP);

这里需要说明一下,固件库还提供了两个函数用来判断定时器状态以及清除定时器状态标志位的函数 timer_flag_get()和timer_flag_clear(),他们的作用和前面两个函数的作用类似。只是在 timer_interrupt_flag_get()函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而timer_flag_get()直接用来判断状态标志位。


通过以上几个步骤,我们就可以达到我们的目的了,使用通用定时器的更新中断,来控制LED的亮灭。


最后定时器核心配置代码如下:


/*

    brief      configure the TIMER peripheral

    param[in]  tim_typedef_enum TIM_id, uint16_t prescaler, uint32_t period, uint8_t prePriority, uint8_t subPriority

    param[out] none

    retval     none

  */

void timx_init(tim_typedef_enum TIM_id, uint16_t prescaler, uint32_t period, uint8_t prePriority, uint8_t subPriority)

{

    /* TIMER configuration: generate PWM signals with different duty cycles */

    timer_parameter_struct timer_initpara;


  //Enable TIMER clock

    rcu_periph_clock_enable(TIM_CLK[TIM_id]);


    timer_deinit(TIM[TIM_id]);


    /* TIMER configuration */

    timer_initpara.prescaler         = prescaler;

    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;

    timer_initpara.counterdirection  = TIMER_COUNTER_UP;

    timer_initpara.period            = period;

    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;

    timer_init(TIM[TIM_id], &timer_initpara);


    timer_interrupt_enable(TIM[TIM_id], TIMER_INT_UP); /* Enable timer interrupt */ 

    //TIMER interrupt setting, preemptive priority 0, sub-priority 3

    nvic_irq_enable(TIM_IRQn[TIM_id], prePriority, subPriority);


    /* TIMER enable */

    timer_enable(TIM[TIM_id]);


    rcu_periph_clock_disable(TIM_CLK[TIM_id]);/* disable timer clock*/ 

[1] [2]
关键字:GD32  开发实战  定时器 引用地址:GD32开发实战指南(基础篇) 第7章 定时器

上一篇:GD32断上电采样相同电压有偏差如何处理?
下一篇:GD32代码移植STM32(一)

推荐阅读最新更新时间:2026-03-25 11:10

GD32开发实战指南(基础篇) 第1章 开发环境搭建
开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 1 GD32F207I-EVAL开发板简介 笔者使用的开发板是兆易创新设计的GD32F207I-EVAL开发板。 GD32F207I-EVAL开发板使用 GD32F207IK作为主控制器,主频120MHz、集成3MB Flash、256KB SRAM、通用定时器10、Adv. TM2、Basic TM2、系统时钟1、看门狗2、RTC1、USART4、UART4、I2C3、SPI3、I2S1、SDIO1、CAN2.0B2、USB2.0 OTG FS1、以太网MAC1、TFT-LCD16、数字摄像头接口1、Crypro/
[单片机]
GD32开发实战指南(基础篇) 第17章 看门狗
开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK GD32 有两个看门狗, 一个是独立看门狗,另外一个是窗口看门狗 ,独立看门狗号称宠物狗,窗口看门狗号称警犬,本章我们主要分析这两只看门狗的功能框图和它的应用。 1 独立看门狗 1.1 独立看门狗工作原理 独立看门狗用通俗一点的话来解释就是一个 12 位的递减计数器, 当计数器的值从某个值一直减到 0 的时候,系统就会产生一个复位信号,即 IWDG_RESET 。如果在计数没减到 0 之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的__喂狗__。 看门狗功能由 VDD 电压域供电,在停止模式和
[单片机]
<font color='red'>GD32</font><font color='red'>开发</font><font color='red'>实战</font>指南(基础篇) 第17章 看门狗
GD32开发实战指南(基础篇) 第19章 程序加密
开发环境: MDK:Keil 5.30 开发板:GD32F207I-EVAL MCU:GD32F207IK 1 程序加密工作原理 GD32通过读取芯片唯一ID号来实现程序的保护,防止被抄袭。96位的产品唯一身份标识所提供的参考号码对任意一个GD32微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。按照用户不同的用法,可以以字节(8位)为单位读取,也可以以半字(16位)或者全字(32位)读取。在这里要提醒读者, 要注意大端小端模式 。 2 程序加密具体代码实现 其实读取ID很简单,如果存储ID的变量为8位。则需要读取12次,如下所示。 uint8_t Sys_ID ,i; for(i=0;i 12
[单片机]
NTN 技术如何落地物联网?Nordic 联合生态伙伴共话开发实战
挪威奥斯陆 – 2026年3月17日 – 全球领先的低功耗无线通信解决方案提供商 Nordic 今日正式宣布, 将于2026 年 3 月 23 日 13:00在深圳南山深铁皇冠假日酒店 5 楼会议室 4举办 “Nordic 长距离 NTN 线下研讨会” 。本次研讨会聚焦非地面网络(NTN)技术落地,深度解析 Nordic NTN 完整解决方案,联动卫星通信生态伙伴,分享实战开发经验与全球场测成果,为物联网行业探索长距离、广覆盖的通信新路径搭建交流与合作的核心平台。 作为物联网通信技术的核心推动者,Nordic 始终致力于突破连接边界。随着物联网应用从地面场景向全球广域覆盖延伸,NTN(非地面网络)技术凭借卫星通信等接入方式,成
[物联网]
NTN 技术如何落地物联网?Nordic 联合生态伙伴共话<font color='red'>开发</font>与<font color='red'>实战</font>
赋能欧标充电桩市场:OCPP协议实战开发指南
随着全球电动汽车产业的迅猛发展,充电基础设施的智能化与标准化已成为行业迫切需求。OCPP(Open Charge Point Protocol即开放充电点协议)作为连接充电桩与中央管理系统的 通用语言 ,正成为解决设备互联互通难题的关键技术。 一、OCPP:为何是出海欧标的必选项? OCPP是一个开放、标准的通信协议,它确保了不同制造商生产的充电桩能够与任何兼容的后台管理系统进行无缝通信。集成OCPP协议意味着为产品赋予“标准通信接口”,其核心价值在于: 打破互联壁垒:使充电桩能接入任何符合OCPP标准的第三方运营平台,提升产品适配性; 满足法规要求:满足欧盟对充电设施互操作性的强制法规,是市场准入的前提; 解
[嵌入式]
赋能欧标充电桩市场:OCPP协议<font color='red'>实战</font><font color='red'>开发</font>指南
STM32 I2C实战开发:HDC1080温湿度采集系统详解
1. 引言 本项目旨在通过STM32F1系列微控制器实现对HDC1080温湿度传感器的控制与数据采集。HDC1080是一种高精度、低功耗的温湿度传感器,支持I2C接口通信。通过本系统,用户能够实时读取环境的温湿度数据,适用于多种场景,如工业自动化、智能家居等。 2. 系统架构 2.1 硬件架构 • 主控芯片 :STM32F1系列微控制器(如STM32F103C8T6) • 传感器模块 :HDC1080温湿度传感器 • 通信接口 :I2C总线(主设备) 2.2 软件架构 • I2C驱动层 :负责I2C总线的初始化和数据传输。 • 传感器驱动层 :实现对HDC1080传感器的控制与数据读取。 • 上层应用 :根据需求调用传感器
[单片机]
STM32 I2C<font color='red'>实战</font><font color='red'>开发</font>:HDC1080温湿度采集系统详解
STM32 USB OTG开发宝典:USB OTG核心技术与开发实战指南
【下载地址】STM32USBOTG培训资料 本开源项目提供了一套详尽的STM32 USB OTG培训资料,涵盖全速和高速模块的核心内容。这份资料深入解析了STM32微控制器中USB OTG模块的工作原理,从硬件设计到软件编程均有详细阐述,并附有实际开发案例供参考。无论是嵌入式系统开发工程师,还是对USB技术感兴趣的爱好者,都能从中获得实用的知识与技能。项目旨在帮助开发者更好地理解和应用USB OTG技术,提升开发效率与项目质量。欢迎广大开发者下载学习,共同进步。 项目地址: https://gitcode.com/Open-source-documentation-tutorial/1e262 项目介绍 在嵌入式系统开发领域,US
[单片机]
S3C2440 开发实战(10):signal & async 异步通信
进程之间发送信号 这里我们使用 kill 命令,在进程与进程之间进行传输信号。 比如杀死一个进程也是通过进程之间发送信号: #kill -9 pid 相对应的如果要发送信号,则要注册信号处理函数(和注册中断服务函数类似),并且编写一个信号服务函数,然后写一个一直休眠的函数就ok了。应用程序 signal.c 代码如下: #include stdio.h #include signal.h void mysignal_fun(int signum){ static int count = 0; printf( signal = %d, %d timesn , signum, count++); } int
[单片机]
S3C2440 <font color='red'>开发</font>板<font color='red'>实战</font>(10):signal & async 异步通信
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved