diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day2/day2.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day2/day2.c" new file mode 100644 index 0000000000000000000000000000000000000000..5ace8a43e97e5c4808deabe6ec99808fc7221328 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day2/day2.c" @@ -0,0 +1,67 @@ +#include +#include +#include + +#define thread_stack_size 512 +#define thread_tick 5 + +#define THREAD1_PRIORITY 10 // 高优先级 +#define THREAD2_PRIORITY 12 // 中优先级 +#define MAIN_THREAD_PRIORITY 15 // 低优先级(main 线程) + +void thread1_entry(void *param) +{ + while (1) + { + rt_kprintf(">>> this is HIGH priority thread1\n"); + rt_thread_mdelay(500); + } +} + +void thread2_entry(void *param) +{ + while (1) + { + rt_kprintf(" >>> this is MEDIUM priority thread2\n"); + rt_thread_mdelay(500); + } +} + +int main(void) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + + // 创建高优先级线程 thread1 + thread1 = rt_thread_create("th1", + thread1_entry, + RT_NULL, + thread_stack_size, + THREAD1_PRIORITY, // 优先级 10 + thread_tick); + // 创建中优先级线程 thread2 + thread2 = rt_thread_create("th2", + thread2_entry, + RT_NULL, + thread_stack_size, + THREAD2_PRIORITY, // 优先级 12 + thread_tick); + + if (thread1 != RT_NULL) + rt_thread_startup(thread1); + + if (thread2 != RT_NULL) + rt_thread_startup(thread2); + + // 主线程降低优先级以体现对比 + rt_thread_t main_thread = rt_thread_self(); + rt_thread_set_priority(main_thread, MAIN_THREAD_PRIORITY); // 设为低优先级 + + while (1) + { + rt_kprintf(" >>> this is LOW priority main thread\n"); + rt_thread_mdelay(500); + } + + return RT_EOK; +} \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/event.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/event.c" new file mode 100644 index 0000000000000000000000000000000000000000..2de6b190a238931d2f4bb4642bf6eb5d3b9b96bb --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/event.c" @@ -0,0 +1,65 @@ +// mailbox.c +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +static rt_event_t event = RT_NULL; +#define EVT_START 0x01 +#define EVT_DONE 0x02 + +// 任务线程(等待事件) +static void worker_entry(void *parameter) +{ + rt_uint32_t recved; + + while (1) + { + // 等待启动事件 + if (rt_event_recv(event, EVT_START, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, + RT_WAITING_FOREVER, &recved) == RT_EOK) + { + rt_kprintf("Worker: Task started...\n"); + rt_thread_mdelay(500); + rt_kprintf("Worker: Task done, sending EVT_DONE\n"); + rt_event_send(event, EVT_DONE); // 通知完成 + } + } +} + +// 控制线程(触发事件) +static void ctrl_entry(void *parameter) +{ + while (1) + { + rt_kprintf("Ctrl: Sending EVT_START\n"); + rt_event_send(event, EVT_START); + rt_thread_mdelay(2000); + } +} + +int event_demo(void) +{ + rt_thread_t tid1, tid2; + + event = rt_event_create("ev", RT_IPC_FLAG_FIFO); + if (event == RT_NULL) + { + rt_kprintf("Failed to create event!\n"); + return -1; + } + + tid1 = rt_thread_create("worker", worker_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + tid2 = rt_thread_create("ctrl", ctrl_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(event_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mailbox.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mailbox.c" new file mode 100644 index 0000000000000000000000000000000000000000..6bea08d7961c35b7e80d8a8df4606ed92eb4272b --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mailbox.c" @@ -0,0 +1,62 @@ +// mailbox.c +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +static rt_mb_t mb = RT_NULL; + +// 发送线程 +static void sender_entry(void *parameter) +{ + rt_uint32_t data; + while (1) + { + data = rt_tick_get(); // 用 tick 作为数据 + rt_kprintf("Sender: Sending data %d\n", data); + if (rt_mb_send(mb, (rt_uint32_t)data) != RT_EOK) + { + rt_kprintf("Sender: Mailbox full!\n"); + } + rt_thread_mdelay(1000); + } +} + +// 接收线程 +static void receiver_entry(void *parameter) +{ + rt_uint32_t data; + while (1) + { + if (rt_mb_recv(mb, &data, RT_WAITING_FOREVER) == RT_EOK) + { + rt_kprintf("Receiver: Received data %d\n", data); + } + } +} + +int mailbox_demo(void) +{ + rt_thread_t tid1, tid2; + + mb = rt_mb_create("mbx", 4, RT_IPC_FLAG_FIFO); // 邮箱容量 4 + if (mb == RT_NULL) + { + rt_kprintf("Failed to create mailbox!\n"); + return -1; + } + + tid1 = rt_thread_create("sender", sender_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + tid2 = rt_thread_create("receiver", receiver_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(mailbox_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/msgqueue.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/msgqueue.c" new file mode 100644 index 0000000000000000000000000000000000000000..24bb527075b81ffffc2d2bce79ac99a3ea614b89 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/msgqueue.c" @@ -0,0 +1,70 @@ +// msgqueue.c +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 1024 +#define THREAD_TIMESLICE 5 + +struct msg_data +{ + rt_uint32_t id; + char str[32]; +}; + +static rt_mq_t mq = RT_NULL; + +// 发送线程 +static void sender_entry(void *parameter) +{ + struct msg_data msg; + rt_uint32_t id = 0; + while (1) + { + msg.id = id++; + rt_sprintf(msg.str, "Hello-%d", msg.id); + rt_kprintf("Sender: Sending message ID=%d\n", msg.id); + if (rt_mq_send(mq, &msg, sizeof(struct msg_data)) != RT_EOK) + { + rt_kprintf("Sender: Message queue full!\n"); + } + rt_thread_mdelay(1000); + } +} + +// 接收线程 +static void receiver_entry(void *parameter) +{ + struct msg_data msg; + while (1) + { + if (rt_mq_recv(mq, &msg, sizeof(struct msg_data), RT_WAITING_FOREVER) == RT_EOK) + { + rt_kprintf("Receiver: Got ID=%d, str=%s\n", msg.id, msg.str); + } + } +} + +int msgqueue_demo(void) +{ + rt_thread_t tid1, tid2; + + mq = rt_mq_create("mq", sizeof(struct msg_data), 4, RT_IPC_FLAG_FIFO); + if (mq == RT_NULL) + { + rt_kprintf("Failed to create message queue!\n"); + return -1; + } + + tid1 = rt_thread_create("sender", sender_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + tid2 = rt_thread_create("receiver", receiver_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(msgqueue_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mutex.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mutex.c" new file mode 100644 index 0000000000000000000000000000000000000000..7d7aa7383b6f728380c9c3a2d06666bb4e819aa8 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/mutex.c" @@ -0,0 +1,53 @@ +// mutex.c +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +static rt_mutex_t mutex = RT_NULL; +static int shared_counter = 0; + +// 线程入口函数 +static void thread_entry(void *parameter) +{ + char *name = (char *)parameter; + while (1) + { + // 获取互斥量 + if (rt_mutex_take(mutex, RT_WAITING_FOREVER) == RT_EOK) + { + rt_kprintf("%s: Counter = %d\n", name, shared_counter); + shared_counter++; + rt_thread_mdelay(100); // 模拟临界区操作 + rt_mutex_release(mutex); // 释放 + } + rt_thread_mdelay(50); // 非临界区 + } +} + +int mutex_demo(void) +{ + rt_thread_t tid1, tid2; + + // 创建互斥量 + mutex = rt_mutex_create("mtx", RT_IPC_FLAG_FIFO); + if (mutex == RT_NULL) + { + rt_kprintf("Failed to create mutex!\n"); + return -1; + } + + tid1 = rt_thread_create("thread1", thread_entry, "T1", + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + tid2 = rt_thread_create("thread2", thread_entry, "T2", + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(mutex_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/sem.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/sem.c" new file mode 100644 index 0000000000000000000000000000000000000000..b17257db50c0f41dacd431961cb507e762651b36 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/sem.c" @@ -0,0 +1,60 @@ +// sem.c +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +static rt_sem_t sem = RT_NULL; // 信号量 + +// 生产者线程 +static void producer_entry(void *parameter) +{ + while (1) + { + rt_thread_mdelay(1000); + rt_kprintf("Producer: Posting semaphore\n"); + rt_sem_release(sem); // 释放信号量 + } +} + +// 消费者线程 +static void consumer_entry(void *parameter) +{ + while (1) + { + // 等待信号量 + if (rt_sem_take(sem, RT_WAITING_FOREVER) == RT_EOK) + { + rt_kprintf("Consumer: Got semaphore, processing data...\n"); + } + } +} + +int sem_demo(void) +{ + rt_thread_t tid1, tid2; + + // 创建信号量 + sem = rt_sem_create("sem1", 0, RT_IPC_FLAG_FIFO); + if (sem == RT_NULL) + { + rt_kprintf("Failed to create semaphore!\n"); + return -1; + } + + // 创建生产者线程 + tid1 = rt_thread_create("producer", producer_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + // 创建消费者线程 + tid2 = rt_thread_create("consumer", consumer_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(sem_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/signal.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/signal.c" new file mode 100644 index 0000000000000000000000000000000000000000..f90a2783e7142b8f9506f872a3e16c80867aa495 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day3/signal.c" @@ -0,0 +1,63 @@ +// signal.c +#include +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 1024 +#define THREAD_TIMESLICE 5 + +static rt_thread_t sig_thread = RT_NULL; + +// 信号处理函数 +void signal_handler(int sig) +{ + rt_kprintf("Signal %d received in thread: %s\n", sig, rt_thread_self()->name); +} + +// 信号接收线程 +static void sig_entry(void *parameter) +{ + rt_kprintf("Signal thread started, PID: %d\n", getpid()); + + // 注册信号处理函数 + signal(SIGUSR1, signal_handler); + + // 无限等待信号(实际由系统调度) + while (1) + { + rt_thread_mdelay(1000); + } +} + +// 发送信号的线程 +static void sender_entry(void *parameter) +{ + while (1) + { + rt_thread_mdelay(3000); + rt_kprintf("Sender: Sending SIGUSR1 to thread %s\n", sig_thread->name); + pthread_kill(sig_thread->tid, SIGUSR1); + } +} + +int signal_demo(void) +{ + rt_thread_t tid1, tid2; + + // 创建信号接收线程 + sig_thread = rt_thread_create("sig_recv", sig_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (sig_thread != RT_NULL) + { + rt_thread_startup(sig_thread); + } + + // 创建发送线程 + tid2 = rt_thread_create("sig_send", sender_entry, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} +INIT_APP_EXPORT(signal_demo); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.c" new file mode 100644 index 0000000000000000000000000000000000000000..a54da3969e0e57684eb0b14975abe2ecaab74ba5 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.c" @@ -0,0 +1,85 @@ +#include + +#if defined(RT_USING_VIR) + +/* 设备实例 */ +static struct vir_test vir_dev; + +/** + * @brief 打印设备信息 + * @param device 设备句柄 + * @param str 要打印的字符串 + */ +static void printfinfo(struct rt_device *device, rt_uint8_t *str) +{ + if (str != RT_NULL) + { + rt_kprintf("vir info: %s\n", str); + } +} + +/** + * @brief 设置设备值 + * @param device 设备句柄 + * @param val 要设置的值 + */ +static void vir_set_val(struct rt_device *device, rt_uint32_t val) +{ + if (device != RT_NULL) + { + struct vir_test *dev = (struct vir_test *)device; + dev->val = val; + } +} + +/** + * @brief 获取设备值 + * @param device 设备句柄 + * @param val 值输出指针 + */ +static void vir_get_val(struct rt_device *device, rt_uint32_t *val) +{ + if (device != RT_NULL && val != RT_NULL) + { + struct vir_test *dev = (struct vir_test *)device; + *val = dev->val; + } +} + +/* 虚拟设备操作函数表 */ +static const struct rt_virt_ops ops = + { + .printinfo = printfinfo, + .set_val = vir_set_val, + .get_val = vir_get_val, +}; + +/** + * @brief 虚拟设备初始化函数 + * @return 初始化结果 + */ +static int vir_init(void) +{ + rt_err_t result; + + /* 初始化设备成员 */ + vir_dev.val = 0; + vir_dev.info = "test_vir"; + + /* 注册虚拟设备 */ + result = rt_hw_virt_register(&vir_dev.parent, + "vir", + &ops, + (void *)vir_dev.info); + + if (result != RT_EOK) + { + rt_kprintf("Failed to register virtual device: %d\n", result); + return -1; + } + + return 0; +} +INIT_APP_EXPORT(vir_init); + +#endif /* RT_USING_VIR */ \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.h" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.h" new file mode 100644 index 0000000000000000000000000000000000000000..c08f9daa68d52fb2439df1ff4b8ac5616344057b --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/drv_vir.h" @@ -0,0 +1,26 @@ +#ifndef __DRV_VIR_H__ +#define __DRV_VIR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * @brief 虚拟测试设备结构体 + */ + struct vir_test + { + struct rt_virt_device parent; /**< 继承虚拟设备基类 */ + rt_uint32_t val; /**< 设备值 */ + char *info; /**< 设备信息字符串 */ + }; + +#ifdef __cplusplus +} +#endif + +#endif /* __DRV_VIR_H__ */ \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/main.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/main.c" new file mode 100644 index 0000000000000000000000000000000000000000..fed426e479d3b6ba1132f631e571185dcc0b2c7a --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/main.c" @@ -0,0 +1,29 @@ + +#include +#include +#include +#ifndef RT_USING_NANO +#include +#endif /* RT_USING_NANO */ + +int main(void) +{ + // IO + rt_device_t vir = rt_device_find("vir"); + if (vir == RT_NULL) + { + rt_kprintf("find vir dev err\n"); + return -RT_ERROR; + } + rt_uint32_t val = 1314; + rt_uint32_t ret = 0; + rt_device_open(vir, RT_DEVICE_FLAG_RDWR); + rt_device_write(vir, 0, &val, 4); + rt_device_read(vir, 0, &ret, 4); + rt_kprintf("ret :%d\n", ret); + rt_device_close(vir); + val = 333; + rt_vir_wirte((rt_vir_device_t)vir, val); + rt_vir_read((rt_vir_device_t)vir, &ret); + rt_kprintf("ret :%d\n", ret); +} \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.c" new file mode 100644 index 0000000000000000000000000000000000000000..a02443b5cd3edbd9feb44698c799b09d0f0d66de --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.c" @@ -0,0 +1,143 @@ +#include +#include + +#if defined(RT_USING_VIR) + +/* 设备操作结构体定义 */ +struct rt_vir_device_ops +{ + rt_err_t (*vir_get_val)(rt_device_t dev, rt_uint32_t *val); + rt_err_t (*vir_set_val)(rt_device_t dev, rt_uint32_t val); +}; + +/* 虚拟设备结构体 */ +struct rt_vir_device +{ + struct rt_device parent; // 继承自 rt_device + const struct rt_vir_device_ops *ops; // 操作函数指针 + const void *user_data; // 用户私有数据 +}; +typedef struct rt_vir_device *rt_vir_device_t; + +/* 内部初始化接口 */ +static rt_err_t _vir_init(rt_device_t dev) +{ + rt_kprintf("Virtual device init\n"); + return RT_EOK; +} + +/* 打开设备 */ +static rt_err_t _vir_open(rt_device_t dev, rt_uint16_t oflag) +{ + rt_kprintf("Virtual device open\n"); + return RT_EOK; +} + +/* 关闭设备 */ +static rt_err_t _vir_close(rt_device_t dev) +{ + rt_kprintf("Virtual device close\n"); + return RT_EOK; +} + +/* 读取数据 */ +static rt_ssize_t _vir_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_vir_device_t vir_dev = (rt_vir_device_t)dev; + + if (vir_dev->ops && vir_dev->ops->vir_get_val && buffer) + { + rt_uint32_t value = 0; + rt_err_t result = vir_dev->ops->vir_get_val(dev, &value); + if (result == RT_EOK) + { + *(rt_uint32_t *)buffer = value; + return sizeof(rt_uint32_t); + } + } + + return -RT_ERROR; +} + +/* 写入数据 */ +static rt_ssize_t _vir_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_vir_device_t vir_dev = (rt_vir_device_t)dev; + + if (vir_dev->ops && vir_dev->ops->vir_set_val && buffer) + { + rt_uint32_t value = *(const rt_uint32_t *)buffer; + rt_err_t result = vir_dev->ops->vir_set_val(dev, value); + if (result == RT_EOK) + { + return sizeof(rt_uint32_t); + } + } + + return -RT_ERROR; +} + +/* 控制命令处理 */ +static rt_err_t _vir_control(rt_device_t dev, int cmd, void *args) +{ + rt_kprintf("Virtual device control, cmd: %d\n", cmd); + return RT_EOK; +} + +/* 注册虚拟设备 */ +rt_err_t rt_hw_vir_register(rt_vir_device_t device, + const char *name, + const struct rt_vir_device_ops *ops, + const void *user_data) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(name != RT_NULL); + RT_ASSERT(ops != RT_NULL); + + device->ops = ops; + device->user_data = user_data; + + /* 初始化父类设备结构 */ + device->parent.type = RT_Device_Class_Miscellaneous; + device->parent.init = _vir_init; + device->parent.open = _vir_open; + device->parent.close = _vir_close; + device->parent.read = _vir_read; + device->parent.write = _vir_write; + device->parent.control = _vir_control; + + return rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); +} + +/* 提供给外部使用的读写接口 */ + +/* 读取值 */ +rt_err_t rt_vir_read(rt_vir_device_t device, rt_uint32_t *val) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(val != RT_NULL); + RT_ASSERT(device->ops != RT_NULL); + + if (device->ops->vir_get_val) + { + return device->ops->vir_get_val((rt_device_t)device, val); + } + + return -RT_ERROR; +} + +/* 写入值 */ +rt_err_t rt_vir_write(rt_vir_device_t device, rt_uint32_t val) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->ops != RT_NULL); + + if (device->ops->vir_set_val) + { + return device->ops->vir_set_val((rt_device_t)device, val); + } + + return -RT_ERROR; +} + +#endif /* RT_USING_VIR */ \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.h" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.h" new file mode 100644 index 0000000000000000000000000000000000000000..3332d9c2bb976f43a8e3dfa3c764749481c64914 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day4/vir.h" @@ -0,0 +1,46 @@ + +#ifndef __VIR_H__ +#define __VIR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined(RT_USING_VIR) + + /* 虚拟设备操作函数集合 */ + struct rt_vir_device_ops + { + rt_err_t (*vir_get_val)(rt_device_t dev, rt_uint32_t *val); /* 读取值 */ + rt_err_t (*vir_set_val)(rt_device_t dev, rt_uint32_t val); /* 设置值 */ + }; + + /* 虚拟设备结构体 */ + struct rt_vir_device + { + struct rt_device parent; /* 继承自标准设备结构 */ + const struct rt_vir_device_ops *ops; /* 设备操作函数指针 */ + const void *user_data; /* 用户私有数据 */ + }; + typedef struct rt_vir_device *rt_vir_device_t; + + rt_err_t rt_hw_vir_register(rt_vir_device_t device, + const char *name, + const struct rt_vir_device_ops *ops, + const void *user_data); + + rt_err_t rt_vir_read(rt_vir_device_t device, rt_uint32_t *val); + + rt_err_t rt_vir_write(rt_vir_device_t device, rt_uint32_t val); + +#endif /* RT_USING_VIR */ + +#ifdef __cplusplus +} +#endif + +#endif /* __device_H__ */ \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day5/\345\261\217\345\271\225\346\210\252\345\233\276 2025-08-02 144726.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day5/\345\261\217\345\271\225\346\210\252\345\233\276 2025-08-02 144726.png" new file mode 100644 index 0000000000000000000000000000000000000000..59fa06b1c09d4de34527974db49e2b115d9be094 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\344\275\234\344\270\232/day5/\345\261\217\345\271\225\346\210\252\345\233\276 2025-08-02 144726.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day1.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day1.md" new file mode 100644 index 0000000000000000000000000000000000000000..ec4bab36bc052401631e946efa22788702884fc5 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day1.md" @@ -0,0 +1,20 @@ +一:上午学了env环境配置 +env下载:https://download-redirect.rt-thread.org/download/env_release/env-windows-v2.0.0.7z + +RT-Thread源码下载:RT-Thread/rt-thread: RT-Thread is an open source IoT Real-Time Operating System (RTOS) +1.先下载好git和env,用git对RT-Thread源码进行拉取(在git中输入git clone “网址”)。 +2.对env配置 +scons -4j//对文件进行编译 pkgs --upgrade//升级软件包 menuconfig//打开图形化配置界面 +3.运行LVGL示例程序 +打开env命令行,运行menuconfig,然后选择Hardware Drivers Config -> Onboard Periperal Drivers,可以看到有Enable LVGL for LCD和Enable LVGL Demo,全部启用即可: +然后运行pkgs —update更新一下当前工程的包,运行scons -j4编译,编译完成后直接运行qemu即可启动示例demo +下午:git仓库 +git add 暂存 +git commit 提交 +git log 查看历史 +git checkout/git reset 回退 +git branch 创建分支 +git merge 合并分支 +git push/pull 推送/拉取 +git status 查看文件状态 + diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day2.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day2.md" new file mode 100644 index 0000000000000000000000000000000000000000..6bc902ca6467bc734cb02b009a3aecb45d771f6e --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day2.md" @@ -0,0 +1,44 @@ +1.资源包安装与环境配置 +安装资源包: +部署 STM32F407-ATK-Explorer 开发资源包(含驱动、BSP支持包)。 +配置 QEMU 仿真环境(用于无硬件调试)。 +2.概念: + 临界区(Critical Section)定义:进程内访问共享资源的代码段,需通过关中断/信号量保护; + 线程状态机(就绪→运行→阻塞→挂起); +RT-Thread启动流程 +struct rt_thread { + void (*entry)(void*); // 入口函数指针 + void* parameter; // 传入参数 + rt_uint8_t* stack_addr; // 栈起始地址(静态分配时需显式指定) + rt_uint32_t stack_size; // 栈大小(单位:字节) + void* sp; // 栈顶指针(由rt_hw_stack_init()初始化) + rt_uint8_t init_priority; // 初始优先级(0最高) + rt_tick_t init_tick; // 时间片长度(tick数) + // ... 其他状态字段 +}; + 内核开发指令: +LDR 从内存加载数据至寄存器 +STR 寄存器值存入内存 +ADD 寄存器算术运算 +BL 带链接跳转(保存返回地址) +PUSH 寄存器入栈 + 线程 + 线程本质:可被调度的执行流,其运行状态由线程控制块(TCB) 维护。 + 线程创建双模式: +// 静态创建(栈内存由用户预分配) +rt_err_t rt_thread_init(rt_thread_t thread, + const char* name, + void (*entry)(void*), + void* parameter, + void* stack_start, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); + +// 动态创建(内核自动分配TCB及栈) +rt_thread_t rt_thread_create(const char* name, + void (*entry)(void*), + void* parameter, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day3.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day3.md" new file mode 100644 index 0000000000000000000000000000000000000000..4efd4d76063f9c1b319db42c1dbff01b1b1f1eca --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day3.md" @@ -0,0 +1,82 @@ +定时器链表操作机制 +定时器系统通过周期性中断在固定时间间隔内轮询检查所有线程的定时器状态。每个线程维护一个独立的线程定时器结构,记录其累积运行时间。当某线程的运行时间超过预设阈值时,系统将触发超时处理函数。为高效管理这些定时器,系统采用双向链表组织所有线程定时器:链表头部指向活跃定时器的首节点,每个节点包含线程控制块指针、剩余时间计数值及链表指针。定时器检查时,从链表头开始遍历,逐个递减计数值并判断超时条件,确保检查操作的时间复杂度为O(n),同时支持动态添加或移除定时器节点。 + +线程间通信(IPC)机制 +线程间通信的核心作用在于实现线程同步与数据交换,具体包括: + +互斥操作:通过关中断或同步原语确保临界区访问的排他性。 +休眠-唤醒机制:利用等待队列实现线程阻塞与唤醒。 +关键约束: +全局变量不可直接用作IPC媒介,因其无法解决竞态条件、缓存一致性及原子性问题,易导致数据损坏或逻辑错误。必须采用内核提供的同步原语保障通信可靠性。 + +通信机制一:消息队列 +消息队列由固定数量的消息块组成,每个消息块存储固定长度的数据。初始化时需指定消息块数量及单个消息块大小。 + +写操作(发送消息): +有空闲空间:立即写入,返回成功。 +无空闲空间: +若线程选择阻塞:将线程从就绪队列移除,加入队列的发送等待链表(Send List),并启动超时定时器;唤醒条件为: +其他线程执行读操作释放空间; +定时器超时,返回错误码。 +若线程选择非阻塞:直接返回错误码。 +读操作(接收消息): +有可用数据:立即读取,返回成功。 +无可用数据: +若线程选择阻塞:将线程从就绪队列移除,加入队列的接收等待链表(Receive List),并启动超时定时器;唤醒条件为: +其他线程执行写操作填入数据; +定时器超时,返回错误码。 +若线程选择非阻塞:直接返回错误码。 +唤醒机制: +队列内部维护两个独立等待链表(Send List 和 Receive List)。当数据写入时,系统遍历Receive List唤醒首个等待线程;当数据读出时,遍历Send List唤醒首个等待线程。多线程竞争时,支持FIFO(先入先出)或优先级排序策略。数据存储遵循"写入队尾,读取队首"原则,确保有序性。 + +通信机制二:邮箱 +邮箱专为高效传递小规模数据(通常为整型值)设计,结合环形缓冲区、等待链表及超时定时器实现。 + +读操作: +有数据:直接读取缓冲区首个值,返回成功。 +无数据: +若线程选择阻塞:将线程加入邮箱的接收等待链表,并启动超时定时器;唤醒条件为: +其他线程写入数据; +定时器超时,返回错误码。 +若线程选择非阻塞:直接返回错误码。 +写操作: +有空位:直接写入环形缓冲区,返回成功。 +无空位: +若线程选择阻塞:将线程加入邮箱的发送等待链表,并启动超时定时器;唤醒条件为: +其他线程读取数据释放空间; +定时器超时,返回错误码。 +若线程选择非阻塞:直接返回错误码。 +典型实现中,邮箱缓冲区大小固定(如5个unsigned long槽位),通过环形索引管理数据存取,避免链表操作开销,提升小数据传递效率。 + +信号量(Semaphore) +信号量用于抽象化CPU或硬件资源的可用数量,其核心结构包含计数值(value)及等待线程链表。 + +获取资源(P操作): +value > 0:立即递减值,线程继续执行。 +value = 0: +若线程选择阻塞:从就绪队列移除,加入信号量等待链表,并启动超时定时器;唤醒条件为: +其他线程释放资源(value > 0); +定时器超时,返回错误码。 +若线程选择非阻塞:直接返回错误码。 +释放资源(V操作): +递增value,若等待链表非空则唤醒首个线程。 +局限性: + +任意线程均可执行V操作,存在资源误释放风险; +可能引发优先级反转问题(高优先级线程因等待低优先级线程持有的资源而阻塞)。 +互斥量(Mutex) +互斥量是专为互斥访问设计的特殊信号量,核心改进在于: + +优先级继承机制:当高优先级线程等待互斥量时,持有者线程优先级临时提升至等待者优先级,避免优先级反转;释放后恢复原优先级。 +所有权约束:仅持有互斥量的线程可执行释放操作,防止误释放。 +递归持有支持:同一线程可多次获取互斥量,内部通过持有计数(hold)跟踪嵌套深度,需等量释放。 +结构体包含关键字段:value(资源状态)、owner(持有线程指针)、original_priority(持有者原始优先级)、hold(持有计数)。 + +事件组(Event Group) +事件组用于实现"等待多个事件"的同步模式,与前述机制的区别在于: + +队列:传递任意大小数据块,适用于大数据传输。 +邮箱:传递固定长度整型数据,适用于小数据高效传输。 +信号量:表示资源实例数量,不携带数据。 +互斥量:专为互斥访问优化,具备优先级继承和所有权机制。 +事件组:通过位掩码聚合多个事件标志,线程可等待特定组合事件(如"事件A与事件B同时发生"或"事件A或事件B任一发生"),实现复杂同步场景。 \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day4.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day4.md" new file mode 100644 index 0000000000000000000000000000000000000000..4309e3171c49e33884249c6dda8b0b029d2670b9 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day4.md" @@ -0,0 +1,61 @@ +I/O 设备模型 +RT-Thread 提供了一套简单的 I/O 设备模型框架,它位于硬件和应用程序之间,共分成三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。 +应用程序通过 I/O 设备管理接口获得正确的设备驱动,然后通过这个设备驱动与底层 I/O 硬件设备进行数据(或控制)交互。 + +I/O 设备管理层实现了对设备驱动程序的封装。应用程序通过图中的"I/O设备管理层"提供的标准接口访问底层设备,设备驱动程序的升级、更替不会对上层应用产生影响。这种方式使得设备的硬件操作相关的代码能够独立于应用程序而存在,双方只需关注各自的功能实现,从而降低了代码的耦合性、复杂性,提高了系统的可靠性。 + +设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。 + +设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。它负责创建和注册 I/O 设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到 I/O 设备管理器中,使用序列图如下图所示,主要有以下 2 点: + +设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过 rt_device_register() 接口注册到 I/O 设备管理器中。 + +应用程序通过 rt_device_find() 接口查找到设备,然后使用 I/O 设备管理接口来访问硬件 + +字符设备与块设备的主要区别在于是否支持随机访问: +字符设备:提供连续数据流,通常只能顺序读取,不支持随机访问,按字节/字符进行数据传输。典型例子包括键盘、串口和调制解调器。 + +块设备:支持随机访问,应用程序可直接定位到设备的任意位置读取数据。数据读写必须以块(通常512B)为单位进行。典型例子包括硬盘、软盘、CD-ROM和闪存。 +对设备进行分类管理,使得同一类设备能够使用统一的控制方式。 + +GPIO简介 +芯片上的引脚一般分为 4 类:电源、时钟、控制与 I/O,I/O 口在使用模式上又分为 General Purpose Input Output(通用输入 / 输出),简称 GPIO,与功能复用 I/O(如 SPI/I2C/UART 等)。 + +大多数 MCU 的引脚都不止一个功能。不同引脚内部结构不一样,拥有的功能也不一样。可以通过不同的配置,切换引脚的实际功能。通用 I/O 口主要特性如下: + +可编程控制中断:中断触发模式可配置,一般有 5 种中断触发模式: +上升沿触发:当信号从低电平跳变至高电平时触发中断 +下降沿触发:当信号从高电平跳变至低电平时触发中断 +高电平触发:当信号保持高电平时持续触发中断 +低电平触发:当信号保持低电平时持续触发中断 +双边沿触发:当信号发生任何电平跳变(上升沿或下降沿)时触发中断 +I2C从机应用与驱动开发 +I2C(Inter-Integrated Circuit)由飞利浦公司于1980年代提出,用于连接低速外部设备。 + +I2C总线数据传输格式如下: + + +向从机写数据流程:开始传输后,主设备发送起始位(S),然后发送包含7位从设备地址和写标志位的8位字节数据,释放SDA线等待从设备应答(ACK)。每个字节传输后都需应答,最后以停止位(P)结束传输并释放总线。 + + +向从机读数据流程:主设备发送起始信号(S)和包含7位地址及写标志的字节,等待应答后发送寄存器地址,再次发送起始信号,发送包含读标志的地址,从设备应答后将寄存器值发送给主设备。 + + +I2C从机常用操作包括:向从机特定寄存器写入单字节或多字节数据,从特定寄存器读取单字节或多字节数据。 + +启用I2C驱动(Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable I2C)后,可使用list_device命令查看总线设备注册情况。I2C设备探测软件包(RT-Thread online packages -> peripheral libraries and drivers -> i2c-tools)可用于探测总线上的设备。 +SPI从机与应用开发 +SPI(Serial Peripheral Interface)是一种高速、全双工、同步通信总线,常用于短距离通信,主要应用于EEPROM、FLASH、实时时钟、AD转换器等设备之间。 + +在RT-Thread中,SPI设备分为"SPI总线"和"SPI设备"两类,SPI总线对应SPI控制器,SPI设备对应不同CS连接的从设备。使用前需要先注册SPI总线,再将从设备挂载到总线上。 + +SPI开发流程:注册SPI Device设备 -> 打开SPI Device设备 -> 使用SPI框架API进行数据收发 -> 关闭SPI Device设备 +SPI设备控制API: +rt_device_find() /*根据SPI设备名称查找设备获取设备句柄*/ +rt_spi_configure() /*配置SPI设备*/ +rt_spi_transfer() /*传输一次数据,不需要手动片选,相当于调用rt_spi_transfer_message*/ +rt_spi_send() /*发送一次数据,忽略接收到的数据*/ +rt_spi_recv() /*只接受一次数据*/ +rt_spi_send_then_send() /*连续发送两个缓冲区的数据,中间片选不释放,忽略接收到的数据*/ +rt_spi_send_then_recv() /*先发送后接收,中间片选不释放*/ +rt_spi_transfer_message() /*自定义传输数据,开始发送数据时片选,返回时释放*/ \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day5.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day5.md" new file mode 100644 index 0000000000000000000000000000000000000000..ccea8ea063f53572aa63447af706bf2d9af323d7 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\344\270\201\345\223\262\347\277\224/\347\254\224\350\256\260/day5.md" @@ -0,0 +1,52 @@ +# 软件包机制 +软件包是运行于RT-Thread物联网操作系统平台上,面向不同应用领域的软件组件形成一个个软件包,由软件包描述信息,软件包源代码或库文件组成。 +## 软件包安装 +在项目文件夹中启动env并打开menuconfig,并使用`/`功能进行搜索软件包。例如搜索软件包`hello`,可以看到前缀为PKG的是软件包。选中后保存退出。 +保存退出后可以通过控制台打印的语句看到,它使用了`.config`文件,其中保存了所有的软件包索引,该文件会根据云端仓库中的软件包进行更新,添加新的软件包。 +menuconfig配置完保存退出后一般会根据配置自动拉取所需的软件包到项目的`packages`目录下,也可以使用命令`pkgs --update`手动更新拉取。 +如想要最新版本,可使用命令`pkgs --upgrade`可以更新本地的软件包索引 +packages目录下有pkgs.json是给env使用的,SConscript文件是env工具生成的用于递归添加子目录中的SCons脚本,将软件包加入编译。之后就可以直接使用`scons -j`命令进行编译。 + +# Kconfig +C语言项目的裁剪配置本质上通过条件编译和宏的展开来实现的,RT-Thread借助Kconfig这套机制更方便的实现了这一功能。以Windows下Env工具中的使用为例,简述Kconfig在RT-Thread的工作机制。 +![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20250802/d707ef8ca893f0664bed8e79ccb3588f.png.webp) +Kconfig机制包括了Kconfig文件和配置UI界面(如menuconfig,pyconfig等)。Kconfig机制有如下特点: +- Kconfig文件中的配置项会映射至rtconfig.h中 +- Kconfig文件可以随源码分散至各级子目录,便于灵活修改。 +配置生成: +配置menuconfig后,会生成.config文件保存用户选择 +将.config转换为rtconfig.h,供编译系统使用 +注意:rtconfig.h是自动生成文件,不应手动修改,修改后在编译会将被刷掉。 +# Scons +Scons是一个开放源码、以Python语言编码的自动化构建工具,可用来替代make编写复杂的makefile。并且scons是跨平台的,只要scons脚本写的好,可以在Linux和Windows下随意编译。 + +## SCons优点 +SCons 具有以下优点: +Python驱动:完全使用Python编写,构建脚本本身就是Python脚本 +依赖自动检测:智能分析文件依赖关系,避免不必要的重新编译 +跨平台支持:在Windows、Linux、macOS等平台提供一致的构建体验 +构建缓存:支持构建缓存机制,显著提升重复构建速度 +并行构建:原生支持多线程并行编译(如scons -j8命令) +## SCons构建系统结构说明 +SCons使用SConstruct和SConscript文件来组织源码结构并执行构建过程,形成层次化的构建体系: +SConstruct:作为SCons构建系统的主控制脚本,位于项目根目录。每个项目(包括BSP)仅有一个SConstruct文件,它负责初始化构建环境、定义全局构建参数,并作为构建入口点递归调用各子目录中的SConscript文件。 +SConscript:作为子目录构建脚本,通常放置在包含源代码的各个子目录中。一个项目中会有多个SConscript文件,它们继承主SConstruct的构建环境,专注于定义本目录下的具体构建任务。 +# config +定义一组新的配置选项,以下为 RT-Thread 系统中 config 语句的示例 + +```c +config BSP_USING_GPIO # 配置项 + bool "Enable GPIO" # 类型及此项名称 + select RT_USING_PIN # 依赖项,若选择本项也会选中此项。 + default y # 默认值 + help # 帮助信息,注释 + config gpio +``` + +每个 config 菜单项都要有类型定义,变量有5种类型即: +- bool 布尔类型,取值范围为:y/n +- tristate 三态类型,取值范围为y/n/m,代表在内核中有三种状态,一种是不选中,一种是选中直接编译进内核,还有一种是 m 手动添加驱动 +- string 字符串,默认值是一个字符串 +- hex 十六进制,取值范围是一个16进制数,使用方法与整形一致。 +- int 整型,取值范围是一个整形的数,可以使用`range a b`配置取值范围 +通过env选中之后最终可在 rtconfig.h 文件中生成如下两个宏,该文件会在menuconfig配置后重新生成因此不要手动修改其中的内容。而要使用Kconfig配置 \ No newline at end of file