RTC和看门狗基于GD32F407VE的天空星的配置

GD32F407VE天空星开发板RTC时钟与看门狗配置完全指南

一、RTC实时时钟配置

1.1 RTC概述

RTC(Real-Time Clock)是用于提供精确日期和时间信息的硬件模块。在GD32F407上,RTC支持完整的日历功能,包括日期(年/月/日)和时间(时/分/秒/亚秒)。

关键特性:

  • 日期和时间以BCD码格式显示(亚秒除外)
  • 核心是一个以1秒为单位的计数器
  • 需要1Hz的精确时钟源驱动
  • 具备备份电源域,掉电后仍可工作

1.2 RTC初始化完整流程

c 复制代码
void RTC_config() {
    /* 1. 使能PMU时钟 */
    rcu_periph_clock_enable(RCU_PMU);
    
    /* 2. 解除备份域写保护 */
    pmu_backup_write_enable();
    
    /* 3. 重置备份域 */
//    rcu_bkp_reset_enable();  // 使用备份寄存器,不能重置
    rcu_bkp_reset_disable();
    
    /* 4. 配置RTC时钟源为 外部高速晶振 8M */
    rcu_osci_on(RCU_HXTAL);
    while(SUCCESS != rcu_osci_stab_wait(RCU_HXTAL));
    rcu_rtc_clock_config(RCU_RTCSRC_HXTAL_DIV_RTCDIV);
	rcu_rtc_div_config(RCU_RTC_HXTAL_DIV25); // =======++ 分频配置  8M/25 = 320K
    
    /* 5. 使能RTC时钟 */
    rcu_periph_clock_enable(RCU_RTC);
    while(SUCCESS != rtc_register_sync_wait());
}

1.3 时钟源选择与配置

LXTAL(32.768kHz)- 推荐选择
c 复制代码
	// config
	// 低速外部晶振  32.768 hz
	// 3.1 设置时钟的晶振 rcu_osci_on
	rcu_osci_on(RCU_LXTAL);
	// 3.2 等待晶振稳定 rcu_osci_stab_wait
	rcu_osci_stab_wait(RCU_LXTAL);
	// 3.3 给rtc配置晶振 rcu_rtc_clock_config
	rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
	// write
    // 配置异步和同步分频器数值
    ris.factor_asyn = 0x7F;   // 7位异步预分频器, 0x0 - 0x7F
    ris.factor_syn  = 0xFF;   // 15位同步预分频器。0x0 - 0x7FFF
LXTAL(8MHz)
c 复制代码
	// 3.1 设置时钟的晶振 HXTAL -> 8M
    rcu_osci_on(RCU_HXTAL);
    // 3.2 等待晶振稳定
    rcu_osci_stab_wait(RCU_HXTAL);
    // 3.3 给rtc配置晶振
    rcu_rtc_clock_config(RCU_RTCSRC_HXTAL_DIV_RTCDIV);
    // 3.4 分频系数(HXTAL时,需要配置,建议选一个能除尽的数) // DIV25 -> 320K
    rcu_rtc_div_config(RCU_RTC_HXTAL_DIV25);

	// write
    rps.factor_asyn = 127;   // 7位异步预分频器, 0x0 - 0x7F
    rps.factor_syn  = 2499;   // 15位同步预分频器。0x0 - 0x7FFF
IRC32K(内部32kHz)
c 复制代码
	// config
	// 3.1 设置时钟的晶振 IRC32K
	rcu_osci_on(RCU_IRC32K);
	// 3.2 等待晶振稳定
	rcu_osci_stab_wait(RCU_IRC32K);
	// 3.3 给rtc配置晶振 
	rcu_rtc_clock_config(RCU_RTCSRC_IRC32K);

	// write
    // 配置异步和同步分频器数值
    rps.factor_asyn = 0x7F;   // 7位异步预分频器, 0x0 - 0x7F
    rps.factor_syn  = 0xF9;   // 15位同步预分频器。0x0 - 0x7FFF

1.4 时间读写操作

c 复制代码
// 十位取出左移4位 + 个位 (得到BCD数)
#define WRITE_BCD(val) 	((val / 10) << 4) + (val % 10)
// 将高4位乘以10 + 低四位 (得到10进制数)
#define READ_BCD(val) 	(val >> 4) * 10 + (val & 0x0F)

void RTC_read() {
	rtc_parameter_struct ris;
	rtc_current_time_get(&ris); // 获取时间
	printf("%02d-%02d-%02d\n", READ_BCD(ris.year) + 2000, READ_BCD(ris.month), READ_BCD(ris.date));
	printf("weekday: %02d\n", READ_BCD(ris.day_of_week));
	printf("%02d:%02d:%02d\n", READ_BCD(ris.hour), READ_BCD(ris.minute), READ_BCD(ris.second));

}

void RTC_write() {
	rtc_parameter_struct ris = {0};
	ris.year = WRITE_BCD(25),  ris.month = WRITE_BCD(10), ris.date = WRITE_BCD(10);
	ris.day_of_week = WRITE_BCD(5);
	ris.hour = WRITE_BCD(23), ris.minute = WRITE_BCD(59),  ris.second = WRITE_BCD(54);
	ris.display_format = RTC_24HOUR;
	
	// write
    // 配置异步和同步分频器数值
    ris.factor_asyn = 0x7F;   // 7位异步预分频器, 0x0 - 0x7F
    ris.factor_syn  = 2499;   // 15位同步预分频器。0x0 - 0x7FFF

    /*************
    // 1s
    HXTAL_DIV25 -> 8M/25 -> 320K
    ck_spre = rtc_clk / ((FACTOR_A + 1)*( FACTOR_S + 1))
    1 = 320K / ((0x7F + 1)*( FACTOR_S + 1))
    FACTOR_S = 320K / 0x80 - 1 = 32K / 128 - 1 = 2499
    **************/
	
	rtc_init(&ris);
}

1.5 闹钟功能配置

c 复制代码
void RTC_alarm() {
    rtc_alarm_struct alarm_config = {0};
    
    // 配置闹钟日期和时间
//	alarm_config.alarm_mask = RTC_ALARM_DATE_MASK; // 不匹配日期
//	alarm_config.alarm_mask = RTC_ALARM_DATE_MASK | RTC_ALARM_HOUR_MASK; // 不匹配日期,小时
   alarm_config.alarm_mask = RTC_ALARM_NONE_MASK;// 不忽略任何字段,即精确匹配日期和时间
	alarm_config.weekday_or_date = RTC_ALARM_DATE_SELECTED;
	// 上面配置了RTC_ALARM_DATE_SELECTED, alarm_day成员代表几号
	// 上面配置了RTC_ALARM_WEEKDAY_SELECTED, alarm_day成员代表星期几
//    alarm_config.alarm_day = WRITE_BCD(10);  // 10号, 日期不起作用
//    alarm_config.alarm_hour = WRITE_BCD(23);   // 23点 小时不起作用
	alarm_config.alarm_day = WRITE_BCD(11);
	alarm_config.alarm_hour = WRITE_BCD(0);
    alarm_config.alarm_minute = WRITE_BCD(0); // 0分
    alarm_config.alarm_second = WRITE_BCD(0); // 0秒
    
    // 配置闹钟0
    rtc_alarm_config(RTC_ALARM0, &alarm_config);
    
    // 使能闹钟中断
    exti_init(EXTI_17, EXTI_INTERRUPT, EXTI_TRIG_RISING);
    exti_interrupt_enable(EXTI_17);
    nvic_irq_enable(RTC_Alarm_IRQn, 2, 2);
	rtc_interrupt_enable(RTC_INT_ALARM0);
    
    // 使能闹钟
    rtc_alarm_enable(RTC_ALARM0);
}
// 闹钟中断处理函数
void RTC_Alarm_IRQHandler(void) {
    if(RESET != exti_interrupt_flag_get(EXTI_17)) {
        exti_interrupt_flag_clear(EXTI_17); // 外部中断的标志位
		// RTC_FLAG_ALRM0  是  ALRM0  不是  ALARM0
        rtc_flag_clear(RTC_FLAG_ALRM0); // 清除RTC标志位
		printf("Alarm Triggered!\n");
		
		RTC_write(); // 重新写时间,为了重复验证闹钟
    }
}

二、看门狗配置

2.1 独立看门狗(FWDGT)

独立看门狗使用内部32kHz时钟,适合基本的系统监控。

c 复制代码
//第一种独立看门狗
void fwdgt_init(uint32_t timeout_ms)
{
    // 使能IRC32K时钟
    rcu_osci_on(RCU_IRC32K);
    rcu_osci_stab_wait(RCU_IRC32K);
    
    // 计算重载值(分频32时,1ms计数1次)
    uint32_t reload_value = timeout_ms;
    
    // 配置看门狗
    fwdgt_config(reload_value, FWDGT_PSC_DIV32);
    fwdgt_enable();
    
    printf("独立看门狗初始化完成,超时时间: %ld ms\n", timeout_ms);
}
//第二种独立看门狗
void WDGT_config() {
	// 配置时钟源
	rcu_osci_on(RCU_IRC32K);
    while(SUCCESS != rcu_osci_stab_wait(RCU_IRC32K));
	
	/* 独立看门狗配置 fwdgt_config
		参数1:重载计数值(这个不是时间的值,是计数值,需要通过时间,计算出这个计数值)
			  0x0000 - 0x0FFF 12位向下递减计数器初始值, Max: 4095
		参数2:预分频系数,将32kHZ进行降频 IRC32
			  32000Hz / 32 = 1000Hz 每秒数1000次,每次1ms
			  32000Hz / 64 =  500Hz 每秒数 500次,每次2ms
		假设
		target_ms = 2000ms 超过此时间不喂狗(fwdgt_counter_reload),触发看门狗重启
		PSC       = FWDGT_PSC_DIV32

		参数1(重载计数值) = target_ms / 记一次数的时长(ms)
				 = target_ms / (1000 / Freq)ms
				 = target_ms / (1000 / (32000Hz / PSC))ms
				 = target_ms / (1000 / (32000Hz / 32))ms
				 = target_ms / (1000 / 1000)ms
				 = 2000ms / 1ms
				 = 2000
				 
		参数1(重载计数值) = target_ms / 记一次数的时长(ms)
				 = target_ms / (1000 / Freq)ms
				 = target_ms / (1000 / (32000Hz / PSC))ms
				 = target_ms / (1000 / (32000Hz / 64))ms
				 = target_ms / (1000 / 500)ms
				 = 2000ms / 2ms
				 = 1000  // ==============>  计数次数
	*/
	//            2s时间,     32K做64分频
	fwdgt_config(1000,     FWDGT_PSC_DIV64);
	
	// 开启独立看门狗计数器 fwdgt_enable
	fwdgt_enable();
}
// 喂狗函数
void fwdgt_feed(void)
{
    fwdgt_counter_reload();
}

2.2 窗口看门狗(WWDGT)

窗口看门狗提供更精确的喂狗时间窗口控制。

c 复制代码
void WDGT_config() {
	// 初始化RCU时钟 rcu_periph_clock_enable
	rcu_periph_clock_enable(RCU_WWDGT);
	// 窗口看门狗重置 wwdgt_deinit
	wwdgt_deinit();
	/*
	// 窗口看门狗配置 wwdgt_config
		参数1:  计数器值,用于设置看门狗计数器的初始值
		参数2: 窗口值,该值必须小于 counter 值
		参数3: 分频系数
			假设 WWDGT_CFG_PSC_DIV4
			 Hz = (PCLK1 / 4096) / 4      每秒钟计数值
				= 42M / 4096 / 4
				= 2563.48 Hz

		求窗口时间范围:
		1/4分频系数 -> 1次计数耗时 : 1000ms / 2563.48 Hz = 0.39ms
		窗口开始时间:(counter - window) * 1次计数耗时 = (127 - 80) * 0.39ms = 18.33ms
		窗口结束时间:(counter -   0x3F) * 1次计数耗时 = (127 - 63) * 0.39ms = 24.96ms

		需要在窗口时间内喂狗(wwdgt_counter_update),否则会触发重启
		18.33ms < duration < 24.96ms
	*/
	wwdgt_config(127, 80, WWDGT_CFG_PSC_DIV4);
	// 启动窗口看门狗 wwdgt_enable  
	wwdgt_enable();
}

// 喂狗函数(必须在窗口时间内调用)
void wwdgt_feed(void)
{
    wwdgt_counter_update(127);
}

三、实用示例代码

3.1 完整的RTC应用示例

c 复制代码
#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"

// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {
    printf("recv[%d] = %s\n", len, data);
}

// 十位取出左移4位 + 个位 (得到BCD数)
#define WRITE_BCD(val) 	((val / 10) << 4) + (val % 10)
// 将高4位乘以10 + 低四位 (得到10进制数)
#define READ_BCD(val) 	(val >> 4) * 10 + (val & 0x0F)

void RTC_config() {
    /* 1. 使能PMU时钟 */
    rcu_periph_clock_enable(RCU_PMU);
    
    /* 2. 解除备份域写保护 */
    pmu_backup_write_enable();
    
    /* 3. 重置备份域 */
    rcu_bkp_reset_enable();
    rcu_bkp_reset_disable();
    
    /* 4. 配置RTC时钟源为 外部高速晶振 8M */
    rcu_osci_on(RCU_HXTAL);
    while(SUCCESS != rcu_osci_stab_wait(RCU_HXTAL));
    rcu_rtc_clock_config(RCU_RTCSRC_HXTAL_DIV_RTCDIV);
	rcu_rtc_div_config(RCU_RTC_HXTAL_DIV25); // =======++ 分频配置  8M/25 = 320K
    
    /* 5. 使能RTC时钟 */
    rcu_periph_clock_enable(RCU_RTC);
    while(SUCCESS != rtc_register_sync_wait());
}

void RTC_read() {
	rtc_parameter_struct ris;
	rtc_current_time_get(&ris); // 获取时间
	printf("%02d-%02d-%02d\n", READ_BCD(ris.year) + 2000, READ_BCD(ris.month), READ_BCD(ris.date));
	printf("weekday: %02d\n", READ_BCD(ris.day_of_week));
	printf("%02d:%02d:%02d\n", READ_BCD(ris.hour), READ_BCD(ris.minute), READ_BCD(ris.second));

}

void RTC_write() {
	rtc_parameter_struct ris = {0};
	ris.year = WRITE_BCD(25),  ris.month = WRITE_BCD(10), ris.date = WRITE_BCD(10);
	ris.day_of_week = WRITE_BCD(5);
	ris.hour = WRITE_BCD(23), ris.minute = WRITE_BCD(59),  ris.second = WRITE_BCD(54);
	ris.display_format = RTC_24HOUR;
	
	// write
    // 配置异步和同步分频器数值
    ris.factor_asyn = 0x7F;   // 7位异步预分频器, 0x0 - 0x7F
    ris.factor_syn  = 2499;   // 15位同步预分频器。0x0 - 0x7FFF

    /*************
    // 1s
    HXTAL_DIV25 -> 8M/25 -> 320K
    ck_spre = rtc_clk / ((FACTOR_A + 1)*( FACTOR_S + 1))
    1 = 320K / ((0x7F + 1)*( FACTOR_S + 1))
    FACTOR_S = 320K / 0x80 - 1 = 32K / 128 - 1 = 2499
    **************/
	
	rtc_init(&ris);
}

void RTC_alarm() {
    rtc_alarm_struct alarm_config = {0};
    
    // 配置闹钟日期和时间
//	alarm_config.alarm_mask = RTC_ALARM_DATE_MASK; // 不匹配日期
//	alarm_config.alarm_mask = RTC_ALARM_DATE_MASK | RTC_ALARM_HOUR_MASK; // 不匹配日期,小时
   alarm_config.alarm_mask = RTC_ALARM_NONE_MASK;
	alarm_config.weekday_or_date = RTC_ALARM_DATE_SELECTED;
	// 上面配置了RTC_ALARM_DATE_SELECTED, alarm_day成员代表几号
	// 上面配置了RTC_ALARM_WEEKDAY_SELECTED, alarm_day成员代表星期几
//    alarm_config.alarm_day = WRITE_BCD(10);  // 10号, 日期不起作用
//    alarm_config.alarm_hour = WRITE_BCD(23);   // 23点 小时不起作用
	alarm_config.alarm_day = WRITE_BCD(11);
	alarm_config.alarm_hour = WRITE_BCD(0);
    alarm_config.alarm_minute = WRITE_BCD(0); // 0分
    alarm_config.alarm_second = WRITE_BCD(0); // 0秒
    
    // 配置闹钟0
    rtc_alarm_config(RTC_ALARM0, &alarm_config);
    
    // 使能闹钟中断
    exti_init(EXTI_17, EXTI_INTERRUPT, EXTI_TRIG_RISING);
    exti_interrupt_enable(EXTI_17);
    nvic_irq_enable(RTC_Alarm_IRQn, 2, 2);
	rtc_interrupt_enable(RTC_INT_ALARM0);
    
    // 使能闹钟
    rtc_alarm_enable(RTC_ALARM0);
}

// 闹钟中断处理函数
void RTC_Alarm_IRQHandler(void) {
    if(RESET != exti_interrupt_flag_get(EXTI_17)) {
        exti_interrupt_flag_clear(EXTI_17); // 外部中断的标志位
		// RTC_FLAG_ALRM0  是  ALRM0  不是  ALARM0
        rtc_flag_clear(RTC_FLAG_ALRM0); // 清除RTC标志位
		printf("Alarm Triggered!\n");
		
		RTC_write(); // 重新写时间,为了重复验证闹钟
    }
}

int main(void) {
	//            抢占  [0, 3]    响应  [0, 3]
	nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
	
	// 系统滴答定时器初始化
	systick_config();
	
	USART0_init(); // 串口初始化调用
	RTC_config(); // RTC
	RTC_write(); // 写时间
	RTC_alarm(); // 闹钟
	
	while(1) {
		RTC_read(); // 读时间
		
		delay_1ms(1000);
	}	
}

3.2 看门狗应用示例

独立看门狗:

c 复制代码
#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"

// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {
    printf("recv[%d] = %#x\n", len, data[0]);
	
	if (data[0] == 0x04) {
//		while(1);
		
		delay_1ms(3000);
	}
}

void WDGT_config() {
	// 配置时钟源
	rcu_osci_on(RCU_IRC32K);
    while(SUCCESS != rcu_osci_stab_wait(RCU_IRC32K));
	
	/* 独立看门狗配置 fwdgt_config
		参数1:重载计数值(这个不是时间的值,是计数值,需要通过时间,计算出这个计数值)
			  0x0000 - 0x0FFF 12位向下递减计数器初始值, Max: 4095
		参数2:预分频系数,将32kHZ进行降频 IRC32
			  32000Hz / 32 = 1000Hz 每秒数1000次,每次1ms
			  32000Hz / 64 =  500Hz 每秒数 500次,每次2ms
		假设
		target_ms = 2000ms 超过此时间不喂狗(fwdgt_counter_reload),触发看门狗重启
		PSC       = FWDGT_PSC_DIV32

		参数1(重载计数值) = target_ms / 记一次数的时长(ms)
				 = target_ms / (1000 / Freq)ms
				 = target_ms / (1000 / (32000Hz / PSC))ms
				 = target_ms / (1000 / (32000Hz / 32))ms
				 = target_ms / (1000 / 1000)ms
				 = 2000ms / 1ms
				 = 2000
				 
		参数1(重载计数值) = target_ms / 记一次数的时长(ms)
				 = target_ms / (1000 / Freq)ms
				 = target_ms / (1000 / (32000Hz / PSC))ms
				 = target_ms / (1000 / (32000Hz / 64))ms
				 = target_ms / (1000 / 500)ms
				 = 2000ms / 2ms
				 = 1000  // ==============>  计数次数
	*/
	//            2s时间,     32K做64分频
	fwdgt_config(1000,     FWDGT_PSC_DIV64);
	
	// 开启独立看门狗计数器 fwdgt_enable
	fwdgt_enable();
}
int main(void) {
	//            抢占  [0, 3]    响应  [0, 3]
	nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
	
	// 系统滴答定时器初始化
	systick_config();
	
	USART0_init(); // 串口初始化调用
	WDGT_config(); // 看门狗配置
	
	printf("==================reboot system=====================\n");

	uint32_t cnt = 0;
	while(1) {
		cnt++;
		if (cnt == 15) {
			cnt = 0;
			
			// 重载计数值(喂狗)
			fwdgt_counter_reload();
		}
		
		printf("cnt = %d\n", cnt);
		
		delay_1ms(100);
	}	
}

窗口看门狗:

c 复制代码
#include "gd32f4xx.h"
#include "systick.h"
#include "USART0.h"
// 收到串口0数据,回调函数
void USART0_on_recv(uint8_t* data, uint32_t len) {
    printf("recv[%d] = %#x\n", len, data[0]);
	if (data[0] == 0x04) {
//		while(1);
		
		delay_1ms(3000);
	}
}
void WDGT_config() {
	// 初始化RCU时钟 rcu_periph_clock_enable
	rcu_periph_clock_enable(RCU_WWDGT);
	// 窗口看门狗重置 wwdgt_deinit
	wwdgt_deinit();
	/*
	// 窗口看门狗配置 wwdgt_config
		参数1:  计数器值,用于设置看门狗计数器的初始值
		参数2: 窗口值,该值必须小于 counter 值
		参数3: 分频系数
			假设 WWDGT_CFG_PSC_DIV4
			 Hz = (PCLK1 / 4096) / 4      每秒钟计数值
				= 42M / 4096 / 4
				= 2563.48 Hz
		求窗口时间范围:
		1/4分频系数 -> 1次计数耗时 : 1000ms / 2563.48 Hz = 0.39ms
		窗口开始时间:(counter - window) * 1次计数耗时 = (127 - 80) * 0.39ms = 18.33ms
		窗口结束时间:(counter -   0x3F) * 1次计数耗时 = (127 - 63) * 0.39ms = 24.96ms

		需要在窗口时间内喂狗(wwdgt_counter_update),否则会触发重启
		18.33ms < duration < 24.96ms
	*/
	wwdgt_config(127, 80, WWDGT_CFG_PSC_DIV4);
	// 启动窗口看门狗 wwdgt_enable  
	wwdgt_enable();
}
int main(void) {
	//            抢占  [0, 3]    响应  [0, 3]
	nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
	// 系统滴答定时器初始化
	systick_config();
	USART0_init(); // 串口初始化调用
	printf("==================reboot system=====================\n");
	WDGT_config(); // 看门狗配置
	while(1) {
//		delay_1ms(17); // 重启, 时间太早了
		delay_1ms(20); // 时间合适
//		delay_1ms(26); // 重启, 时间太晚了
		wwdgt_counter_update(127);
		printf("wwdgt_counter_update ok\n");
	}	
}

四、关键注意事项

4.1 RTC配置要点

  1. 备份域保护:写操作前必须解除保护,操作完成后建议恢复保护
  2. 时钟稳定:配置外部晶振后必须等待稳定
  3. 备份寄存器:用于标记初始化状态,避免重复设置时间
  4. 中断清理:闹钟中断后必须及时清除标志位

4.2 看门狗使用建议

  1. 超时选择:根据任务周期合理设置看门狗超时时间
  2. 喂狗时机:在关键任务完成后喂狗,避免正常业务被误重启
  3. 窗口时间:窗口看门狗必须在指定时间窗口内喂狗
  4. 调试注意:调试时可暂时禁用看门狗,发布时务必启用
  • RTC:提供精确的时间基准,支持日历功能和闹钟提醒
  • 看门狗:确保系统在异常情况下能够自动恢复,提高系统可靠性
相关推荐
qq_401700414 小时前
STM32的HardFault错误处理技巧
stm32
WD137298015575 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔5 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头6 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子7 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
报错小能手7 小时前
linux学习笔记(32)网络编程——UDP
单片机·嵌入式硬件
XiangrongZ8 小时前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
xyx-3v9 小时前
SPI四种工作模式
stm32·单片机·嵌入式硬件·学习
qiuiuiu4139 小时前
正点原子RK3568学习日志6-驱动模块传参
linux·c语言·开发语言·单片机·学习