AI8051U单片机的 伪多任务 极简框架,ST7735-TFT显示

实现功能
- 每个任务都有一个预定的周期
- 每个任务都有一个与之关联的计数器
- 递增的计数器作为系统时间
- 比较式任务调度
- 伪非阻塞式任务运行

先看框架
- #include <stdint.h>
-
- // 1. 任务函数声明
- void task1(void);
- void task2(void);
- void task3(void);
-
- // 2. 定义任务周期(单位:毫秒,假设 tick 每 1ms 增加一次)
- #define TASK1_PERIOD 100
- #define TASK2_PERIOD 50
- #define TASK3_PERIOD 200
-
- // 3. 记录上一次执行的时间戳(初始化为 0)
- static uint32_t last_tick_task1 = 0;
- static uint32_t last_tick_task2 = 0;
- static uint32_t last_tick_task3 = 0;
-
- // 模拟系统时钟(实际应用中通常在定时器中断中自增)
- volatile uint32_t system_tick = 0;
-
- // 4. 任务调度器
- void taskScheduler(void) {
- // 获取当前时刻的快照,防止在判断过程中 tick 发生变化
- uint32_t current_tick = system_tick;
-
- /* * 核心逻辑:使用 [当前时间 - 上次时间]
- * 即使 current_tick 溢出回 0,无符号减法的结果依然是正确的差值。
- * 例如:8位机下 current=2, last=250, 则 2 - 250 = 8 (正确经过了8个tick)
- */
-
- // 检查任务1
- if (current_tick - last_tick_task1 >= TASK1_PERIOD) {
- last_tick_task1 = current_tick; // 更新记录点
- task1();
- }
-
- // 检查任务2
- if (current_tick - last_tick_task2 >= TASK2_PERIOD) {
- last_tick_task2 = current_tick;
- task2();
- }
-
- // 检查任务3
- if (current_tick - last_tick_task3 >= TASK3_PERIOD) {
- last_tick_task3 = current_tick;
- task3();
- }
- }
-
- // 5. 主循环
- int main(void) {
- // 硬件初始化代码...
-
- while (1) {
- // 模拟系统心跳增加(实际开发中请将此行移至 Timer 中断)
- // 如果在 while(1) 中自增,任务周期将取决于指令执行速度而非真实时间
- system_tick++;
-
- taskScheduler();
-
- // 实际应用中通常配合低功耗睡眠或喂狗
- }
- return 0;
- }
-
- // --- 任务实现 ---
-
- void task1(void) {
- // LED 翻转或其他逻辑
- }
-
- void task2(void) {
- // 传感器采样
- }
-
- void task3(void) {
- // 数据通讯或显示更新
- }
复制代码
再看实测演示
测试代码
- #include <STC8051U.H>
- #include "intrins.h"
- #include "stc32_stc8_usb.h"
- #include "ST7735.h"
- #include <stdio.h>
- #include "AHT25.h"
- #include "key.h"
- #include "delay.h"
-
- #define FOSC 24000000UL
-
- // --- 任务周期定义 ---
- #define TASK1_PERIOD 50 // 按键检测
- #define TASK2_PERIOD 500 // 读温湿度
- #define TASK3_PERIOD 200 // 更新显示
-
- // --- 全局变量 ---
- volatile unsigned long system_tick = 0; // 由中断每1ms加1
- float tem = 0;
- float hum = 0;
- int num_A = 0, num_M = 0, num_B = 0;
- char buf[30] = {0};
-
- #define POWER_IO P10
- #define POWER_ON POWER_IO = 1;
- #define POWER_OFF POWER_IO = 0;
-
- // --- 函数声明 ---
- void Timer0_Init(void);
- void taskScheduler(void);
- void task1(void);
- void task2(void);
- void task3(void);
-
- void main() {
- // 系统初始化
- EAXFR = 1;
- WTST = 0X00;
- CKCON = 0X00;
-
- // GPIO 配置 (参考原代码)
- P1M0 |= 0x01; P1M1 &= ~0x01; // POWER_IO 推挽
- POWER_ON;
-
- P4M0 &= ~0x04; P4M1 &= ~0x04; P4PD |= 0x04; // POWER_KEY 下拉输入
- P3M0 |= 0xc0; P3M1 &= ~0xc0; // TFT P3.6 P3.7
- P1M0 |= 0xa0; P1M1 &= ~0xa0; // TFT P1.5 P1.7
- P1M0 &= ~0x1c; P1M1 |= 0x1c; P1PD |= 0x1c; // KEY_A/M/B 下拉输入
- P2M0 |= 0x10; P2M1 &= ~0x10; // SCL 推挽
- P2M0 &= ~0x08; P2M1 &= ~0x08; // SDA 准双向
-
- // USB 初始化
- P3M0 &= ~0x03; P3M1 |= 0x03;
- IRC48MCR = 0x80;
- while (!(IRC48MCR & 0x01));
- USBCLK = 0x00;
- USBCON = 0x90;
- usb_init();
- IE2 |= 0x80;
-
- // 外设初始化
- ST7735_Init();
- Timer0_Init(); // 开启 1ms 硬件定时器
- EA = 1;
-
- while (1) {
- taskScheduler(); // 调度器循环执行
- }
- }
-
- // --- 定时器0初始化 (1ms @ 24MHz) ---
- void Timer0_Init(void) {
- AUXR |= 0x80; // 定时器时钟1T模式
- TMOD &= 0xF0; // 设置定时器模式
- TL0 = 0x40; // 设置定时初始值 (24000000/1000 = 24000)
- TH0 = 0x5D; // 24000 = 0x5DC0
- TF0 = 0; // 清除TF0标志
- TR0 = 1; // 定时器0开始计时
- ET0 = 1; // 使能定时器0中断
- }
-
- // --- 定时器0中断服务函数 ---
- void Timer0_ISR(void) interrupt 1 {
- system_tick++;
- }
-
- // --- 任务调度器 (溢出安全版) ---
- void taskScheduler(void) {
- static unsigned long last_task1 = 0;
- static unsigned long last_task2 = 0;
- static unsigned long last_task3 = 0;
-
- unsigned long current_tick;
-
- // 屏蔽中断读取,保证 32 位变量读取的原子性
- ET0 = 0;
- current_tick = system_tick;
- ET0 = 1;
-
- // 检查任务1: 按键检测
- if (current_tick - last_task1 >= TASK1_PERIOD) {
- last_task1 = current_tick;
- task1();
- }
-
- // 检查任务2: 温湿度读取
- if (current_tick - last_task2 >= TASK2_PERIOD) {
- last_task2 = current_tick;
- task2();
- }
-
- // 检查任务3: 刷新显示
- if (current_tick - last_task3 >= TASK3_PERIOD) {
- last_task3 = current_tick;
- task3();
- }
- }
-
- // --- 任务1: 按键处理 ---
- void task1() {
- unsigned char key_value = KEY_Scan(0);
- switch(key_value) {
- case A_PRES: num_A++; break;
- case M_PRES: num_M++; break;
- case B_PRES: num_B++; break;
- case POWER_PRES: POWER_OFF; break; // 修正了分号
- default: break;
- }
- }
-
- // --- 任务2: 读取传感器 ---
- void task2() {
- // 注意:AHT10_Read 内部通常需要传入变量地址以更新 tem 和 hum
- // 这里根据你的定义调用,如果 AHT10_Read(float, float) 是空函数则需修改驱动
- AHT10_Read(&tem, &hum);
- }
-
- // --- 任务3: 刷新屏显示 ---
- void task3() {
- sprintf(buf, "T:%.2f A:%d", tem, num_A);
- ST7735_WriteString(10, 10, buf, Font_11x18, ST7735_GREEN, ST7735_BLACK);
-
- sprintf(buf, "H:%.2f B:%d", hum, num_B);
- ST7735_WriteString(10, 40, buf, Font_11x18, ST7735_RED, ST7735_BLACK);
- }
复制代码

实验结果

待优化
|