找回密码
 立即注册
查看: 2088|回复: 9

AI8051U 伪多任务 极简框架,ST7735-TFT显示

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:121
  • 最近打卡:2026-04-01 08:20:19

15

主题

97

回帖

128

积分

注册会员

积分
128
发表于 2024-8-19 21:28:39 | 显示全部楼层 |阅读模式
AI8051U单片机的 伪多任务 极简框架,ST7735-TFT显示





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







先看框架
  1. #include <stdint.h>
  2. // 1. 任务函数声明
  3. void task1(void);
  4. void task2(void);
  5. void task3(void);
  6. // 2. 定义任务周期(单位:毫秒,假设 tick 每 1ms 增加一次)
  7. #define TASK1_PERIOD 100
  8. #define TASK2_PERIOD 50
  9. #define TASK3_PERIOD 200
  10. // 3. 记录上一次执行的时间戳(初始化为 0)
  11. static uint32_t last_tick_task1 = 0;
  12. static uint32_t last_tick_task2 = 0;
  13. static uint32_t last_tick_task3 = 0;
  14. // 模拟系统时钟(实际应用中通常在定时器中断中自增)
  15. volatile uint32_t system_tick = 0;
  16. // 4. 任务调度器
  17. void taskScheduler(void) {
  18.     // 获取当前时刻的快照,防止在判断过程中 tick 发生变化
  19.     uint32_t current_tick = system_tick;
  20.     /* * 核心逻辑:使用 [当前时间 - 上次时间]
  21.      * 即使 current_tick 溢出回 0,无符号减法的结果依然是正确的差值。
  22.      * 例如:8位机下 current=2, last=250, 则 2 - 250 = 8 (正确经过了8个tick)
  23.      */
  24.     // 检查任务1
  25.     if (current_tick - last_tick_task1 >= TASK1_PERIOD) {
  26.         last_tick_task1 = current_tick; // 更新记录点
  27.         task1();
  28.     }
  29.     // 检查任务2
  30.     if (current_tick - last_tick_task2 >= TASK2_PERIOD) {
  31.         last_tick_task2 = current_tick;
  32.         task2();
  33.     }
  34.     // 检查任务3
  35.     if (current_tick - last_tick_task3 >= TASK3_PERIOD) {
  36.         last_tick_task3 = current_tick;
  37.         task3();
  38.     }
  39. }
  40. // 5. 主循环
  41. int main(void) {
  42.     // 硬件初始化代码...
  43.     while (1) {
  44.         // 模拟系统心跳增加(实际开发中请将此行移至 Timer 中断)
  45.         // 如果在 while(1) 中自增,任务周期将取决于指令执行速度而非真实时间
  46.         system_tick++;
  47.         taskScheduler();
  48.         
  49.         // 实际应用中通常配合低功耗睡眠或喂狗
  50.     }
  51.     return 0;
  52. }
  53. // --- 任务实现 ---
  54. void task1(void) {
  55.     // LED 翻转或其他逻辑
  56. }
  57. void task2(void) {
  58.     // 传感器采样
  59. }
  60. void task3(void) {
  61.     // 数据通讯或显示更新
  62. }
复制代码


再看实测演示




测试代码
  1. #include <STC8051U.H>
  2. #include "intrins.h"
  3. #include "stc32_stc8_usb.h"
  4. #include "ST7735.h"
  5. #include <stdio.h>
  6. #include "AHT25.h"
  7. #include "key.h"
  8. #include "delay.h"
  9. #define FOSC 24000000UL
  10. // --- 任务周期定义 ---
  11. #define TASK1_PERIOD 50   // 按键检测
  12. #define TASK2_PERIOD 500  // 读温湿度
  13. #define TASK3_PERIOD 200  // 更新显示
  14. // --- 全局变量 ---
  15. volatile unsigned long system_tick = 0; // 由中断每1ms加1
  16. float tem = 0;
  17. float hum = 0;
  18. int num_A = 0, num_M = 0, num_B = 0;
  19. char buf[30] = {0};
  20. #define POWER_IO P10
  21. #define POWER_ON  POWER_IO = 1;
  22. #define POWER_OFF POWER_IO = 0;
  23. // --- 函数声明 ---
  24. void Timer0_Init(void);
  25. void taskScheduler(void);
  26. void task1(void);
  27. void task2(void);
  28. void task3(void);
  29. void main() {
  30.     // 系统初始化
  31.     EAXFR = 1;
  32.     WTST = 0X00;
  33.     CKCON = 0X00;
  34.     // GPIO 配置 (参考原代码)
  35.     P1M0 |= 0x01; P1M1 &= ~0x01; // POWER_IO 推挽
  36.     POWER_ON;
  37.     P4M0 &= ~0x04; P4M1 &= ~0x04; P4PD |= 0x04; // POWER_KEY 下拉输入
  38.     P3M0 |= 0xc0; P3M1 &= ~0xc0; // TFT P3.6 P3.7
  39.     P1M0 |= 0xa0; P1M1 &= ~0xa0; // TFT P1.5 P1.7
  40.     P1M0 &= ~0x1c; P1M1 |= 0x1c; P1PD |= 0x1c; // KEY_A/M/B 下拉输入
  41.     P2M0 |= 0x10; P2M1 &= ~0x10; // SCL 推挽
  42.     P2M0 &= ~0x08; P2M1 &= ~0x08; // SDA 准双向
  43.     // USB 初始化
  44.     P3M0 &= ~0x03; P3M1 |= 0x03;
  45.     IRC48MCR = 0x80;
  46.     while (!(IRC48MCR & 0x01));
  47.     USBCLK = 0x00;
  48.     USBCON = 0x90;
  49.     usb_init();
  50.     IE2 |= 0x80;
  51.     // 外设初始化
  52.     ST7735_Init();
  53.     Timer0_Init(); // 开启 1ms 硬件定时器
  54.     EA = 1;
  55.     while (1) {
  56.         taskScheduler(); // 调度器循环执行
  57.     }
  58. }
  59. // --- 定时器0初始化 (1ms @ 24MHz) ---
  60. void Timer0_Init(void) {
  61.     AUXR |= 0x80;   // 定时器时钟1T模式
  62.     TMOD &= 0xF0;   // 设置定时器模式
  63.     TL0 = 0x40;     // 设置定时初始值 (24000000/1000 = 24000)
  64.     TH0 = 0x5D;     // 24000 = 0x5DC0
  65.     TF0 = 0;        // 清除TF0标志
  66.     TR0 = 1;        // 定时器0开始计时
  67.     ET0 = 1;        // 使能定时器0中断
  68. }
  69. // --- 定时器0中断服务函数 ---
  70. void Timer0_ISR(void) interrupt 1 {
  71.     system_tick++;
  72. }
  73. // --- 任务调度器 (溢出安全版) ---
  74. void taskScheduler(void) {
  75.     static unsigned long last_task1 = 0;
  76.     static unsigned long last_task2 = 0;
  77.     static unsigned long last_task3 = 0;
  78.    
  79.     unsigned long current_tick;
  80.     // 屏蔽中断读取,保证 32 位变量读取的原子性
  81.     ET0 = 0;
  82.     current_tick = system_tick;
  83.     ET0 = 1;
  84.     // 检查任务1: 按键检测
  85.     if (current_tick - last_task1 >= TASK1_PERIOD) {
  86.         last_task1 = current_tick;
  87.         task1();
  88.     }
  89.     // 检查任务2: 温湿度读取
  90.     if (current_tick - last_task2 >= TASK2_PERIOD) {
  91.         last_task2 = current_tick;
  92.         task2();
  93.     }
  94.     // 检查任务3: 刷新显示
  95.     if (current_tick - last_task3 >= TASK3_PERIOD) {
  96.         last_task3 = current_tick;
  97.         task3();
  98.     }
  99. }
  100. // --- 任务1: 按键处理 ---
  101. void task1() {
  102.     unsigned char key_value = KEY_Scan(0);
  103.     switch(key_value) {
  104.         case A_PRES:     num_A++; break;
  105.         case M_PRES:     num_M++; break;
  106.         case B_PRES:     num_B++; break;
  107.         case POWER_PRES: POWER_OFF; break; // 修正了分号
  108.         default: break;
  109.     }
  110. }
  111. // --- 任务2: 读取传感器 ---
  112. void task2() {
  113.     // 注意:AHT10_Read 内部通常需要传入变量地址以更新 tem 和 hum
  114.     // 这里根据你的定义调用,如果 AHT10_Read(float, float) 是空函数则需修改驱动
  115.     AHT10_Read(&tem, &hum);
  116. }
  117. // --- 任务3: 刷新屏显示 ---
  118. void task3() {
  119.     sprintf(buf, "T:%.2f  A:%d", tem, num_A);
  120.     ST7735_WriteString(10, 10, buf, Font_11x18, ST7735_GREEN, ST7735_BLACK);
  121.    
  122.     sprintf(buf, "H:%.2f  B:%d", hum, num_B);
  123.     ST7735_WriteString(10, 40, buf, Font_11x18, ST7735_RED, ST7735_BLACK);
  124. }
复制代码





实验结果
  • 能运行
  • 满足项目需求



待优化

  • 使用定时器中断来更新系统计数器





回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:755
  • 最近打卡:2026-04-02 00:00:13
已绑定手机

19

主题

3351

回帖

6973

积分

论坛元老

积分
6973
发表于 2024-8-19 22:04:00 | 显示全部楼层
没有使用定时器中断,还是有点不足
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:121
  • 最近打卡:2026-04-01 08:20:19

15

主题

97

回帖

128

积分

注册会员

积分
128
发表于 2024-8-19 22:31:22 | 显示全部楼层
so*** 发表于 2024-8-19 22:04
没有使用定时器中断,还是有点不足

定时器还没学
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:517
  • 最近打卡:2026-03-20 21:44:46

17

主题

534

回帖

617

积分

高级会员

积分
617
发表于 2024-8-19 23:02:25 | 显示全部楼层
想法挺不错的
自信就会温和,温和就会坚定!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:571
  • 最近打卡:2026-04-02 09:26:20

23

主题

291

回帖

1983

积分

金牌会员

积分
1983
发表于 2024-8-20 07:58:10 | 显示全部楼层
中断计时设定1ms,可以参考下


  1. typedef struct
  2. {
  3.         uint8_t taskstate;              //任务状态  
  4.         uint16_t tasktime;             //任务时间
  5.         uint16_t tasktimer;             //任务时间重装值
  6.     void (*pTaskFunCb)(void);            //任务函数
  7.   }Task_t;
  8. static Task_t g_task[] =
  9. {
  10.   //状态  计数  周期  函数
  11.   0
  12. //        {0,   5,   5,button_app_tset},
  13. //        {0,   2000,   2000,        LedCtrltwo},
  14.           /* Add new task here */
  15. };
  16. #define TASK_MAX (sizeof(g_task) / sizeof(g_task[0]))
  17. /*--------------------------------------------------------------------------
  18. @brief:  时间片轮转调用结构体函数
  19. @param: 无
  20. @retval: 无
  21. --------------------------------------------------------------------------*/
  22. static void TaskHandle(void)
  23. {
  24.         uint8_t i;
  25.         for(i = 0; i < TASK_MAX; i++)
  26.         {
  27.                 if (g_task[i].taskstate)
  28.                 {
  29.                         g_task[i].taskstate = 0;
  30.                         g_task[i].pTaskFunCb();
  31.                 }
  32.         }
  33. }
  34. /*-------------------------------------------------------------------------
  35. @brief: 结构体函数状态刷新函数
  36. @param: 无
  37. @retval: 无
  38. -------------------------------------------------------------------------*/
  39. static void TaskCbState(void)
  40. {
  41.         uint8_t i;
  42.         for( i = 0; i < TASK_MAX; i++)
  43.         {
  44.                 if (g_task[i].tasktime)
  45.                 {
  46.                         g_task[i].tasktime--;
  47.                         if(0 == g_task[i].tasktime)
  48.                         {
  49.                                 g_task[i].taskstate = 1;
  50.                                 g_task[i].tasktime= g_task[i].tasktimer;
  51.                         }
  52.                 }
  53.         }
  54. }
  55. static void DrvInit(void)
  56. {
  57.     Timer0_Init();
  58.     GpioInit();
  59.     Uart2Init();   
  60. }
  61. static void AppInit(void)
  62. {
  63. }
  64. void main(void)
  65. {
  66.     DrvInit();
  67.     AppInit();
  68.   
  69.     EA = 1;
  70.    
  71.     printf("uart2  printf test\n");
  72.     while(1)
  73.     {
  74.         TaskHandle();
  75.     }
  76. }
  77. void Time0_ISR() interrupt     TMR0_VECTOR   //定时器0中断函数
  78. {
  79.     TaskCbState();   
  80. }
复制代码
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:820
  • 最近打卡:2026-04-01 05:38:42
已绑定手机

34

主题

459

回帖

3506

积分

论坛元老

积分
3506
发表于 2024-8-23 13:37:22 | 显示全部楼层
学习
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:213
  • 最近打卡:2026-01-05 16:54:12
已绑定手机

4

主题

44

回帖

491

积分

中级会员

积分
491
发表于 2025-10-6 12:55:40 | 显示全部楼层
如果一个任务的运行时间很长,大于了下一个任务的运行时间,该怎么解决呢?
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:199
  • 最近打卡:2026-04-02 06:24:46
已绑定手机

6

主题

55

回帖

562

积分

高级会员

积分
562
发表于 2025-10-15 17:09:12 | 显示全部楼层
这个是非常不错的主意,可以在很多程序中参考。
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:104
  • 最近打卡:2026-03-31 17:33:01
已绑定手机

11

主题

73

回帖

455

积分

中级会员

积分
455
发表于 2025-11-22 20:59:40 | 显示全部楼层
还是非常不错的
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:155
  • 最近打卡:2026-04-02 07:22:09
已绑定手机

2

主题

84

回帖

714

积分

高级会员

积分
714
发表于 2025-11-22 22:37:09 | 显示全部楼层
是三*** 发表于 2025-10-6 12:55
如果一个任务的运行时间很长,大于了下一个任务的运行时间,该怎么解决呢? ...

如果把下一个任务作为中断,插入长时间任务里面行不行?
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-4-2 19:34 , Processed in 0.506969 second(s), 90 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表