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:提供精确的时间基准,支持日历功能和闹钟提醒
  • 看门狗:确保系统在异常情况下能够自动恢复,提高系统可靠性
相关推荐
BreezeJuvenile8 分钟前
外设模块学习(15)——MQ-2烟雾气体传感器(STM32)
stm32·单片机·学习·mq-2·烟雾气体传感器
Jie_jiejiayou2 小时前
定时器详解以及呼吸灯实现 — STM32(HAL库)
stm32·单片机·嵌入式硬件·定时器
逆小舟2 小时前
【STM32】定时器、PWM
stm32·单片机·嵌入式硬件
XH1.2 小时前
学习RT-thread(RT-thread定时器)
stm32·单片机·学习
QT 小鲜肉2 小时前
【个人成长笔记】在 Linux 系统下撰写老化测试脚本以实现自动压测效果(亲测有效)
linux·开发语言·笔记·单片机·压力测试
申克Lab3 小时前
STM32 串口概念 UART协议
stm32·单片机·嵌入式硬件
小莞尔3 小时前
【51单片机】【protues仿真】基于51单片机自动浇花系统
单片机·嵌入式硬件
沐欣工作室_lvyiyi4 小时前
基于51单片机的宠物喂食器的设计与实现(论文+源码)
单片机·嵌入式硬件·毕业设计·51单片机·宠物
hazy1k7 小时前
51单片机基础-最小系统设计
stm32·单片机·嵌入式硬件·mcu·51单片机·proteus
奋斗的牛马8 小时前
FPGA—ZYNQ学习spi(六)
单片机·嵌入式硬件·学习·fpga开发·信息与通信