哈哈哈哈 发表于 2024-8-19 21:28:39

AI8051U 伪多任务 极简框架

AI8051U单片机的 伪多任务 极简框架


static/image/hrline/1.gif


实现功能

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


static/image/hrline/1.gif




先看框架
// 定义任务函数
void task1();
void task2();
void task3();

// 定义任务周期(单位:毫秒)
#define TASK1_PERIOD 100
#define TASK2_PERIOD 50
#define TASK3_PERIOD 200

// 定义任务计数器
volatile unsigned int task1_counter = 0;
volatile unsigned int task2_counter = 0;
volatile unsigned int task3_counter = 0;

// 主循环
void main() {
    // 初始化计数器
    task1_counter = TASK1_PERIOD;
    task2_counter = TASK2_PERIOD;
    task3_counter = TASK3_PERIOD;

    // 主循环
    while (1) {
      // 模拟一个循环中的任务调度
      taskScheduler();
    }
}

// 任务调度函数
void taskScheduler() {
    static unsigned int system_tick = 0;// 系统计数器

    // 更新系统计数器
    system_tick++;

    // 检查任务1是否准备好执行
    if (system_tick >= task1_counter) {
      task1_counter += TASK1_PERIOD;
      task1();
    }

    // 检查任务2是否准备好执行
    if (system_tick >= task2_counter) {
      task2_counter += TASK2_PERIOD;
      task2();
    }

    // 检查任务3是否准备好执行
    if (system_tick >= task3_counter) {
      task3_counter += TASK3_PERIOD;
      task3();
    }
}

// 任务1
void task1() {
    // 执行任务1的代码
    // 例如控制LED闪烁
    // ...
}

// 任务2
void task2() {
    // 执行任务2的代码
    // 例如读取传感器数据
    // ...
}

// 任务3
void task3() {
    // 执行任务3的代码
    // 例如更新显示屏显示
    // ...
}
再看实测演示


244

测试代码
#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 //ISP 下载时需将工作频率设置为 24MHz
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#"; //不停电自动 ISP 下载命令

#define POWER_IO P10

int num_A = 0;
int num_M = 0;
int num_B = 0;

char buf = {0};

volatile float tem;
volatile float hum;

#define POWER_ON POWER_IO = 1;
#define POWER_OFF POWER_IO = 0;

// 任务调度函数
void taskScheduler();

// 定义任务函数
void task1();//按键检测
void task2();//读温湿度
void task3();//更新显示

// 定义任务周期(单位:毫秒)
#define TASK1_PERIOD 50
#define TASK2_PERIOD 500
#define TASK3_PERIOD 200

// 定义任务计数器
volatile unsigned int task1_counter = 0;
volatile unsigned int task2_counter = 0;
volatile unsigned int task3_counter = 0;

void main()
{
    EAXFR = 1;
    WTST = 0X00;
    CKCON = 0X00;

    //POWER_IO0: 关机1:开机 推挽输出
    P1M0 |= 0x01;
    P1M1 &= ~0x01;

    POWER_ON

    //POWER_KEY 0:按键没按下,即充电开机1:按开机 下拉输入
    P4M0 &= ~0x04;
    P4M1 &= ~0x04;
    P4PD |= 0x04;


    //tft 推挽输出
    P3M0 |= 0xc0;
    P3M1 &= ~0xc0;
    P1M0 |= 0xa0;
    P1M1 &= ~0xa0;

    //KEY_A KEY_M KEY_B 下拉输入
    P1M0 &= ~0x1c;
    P1M1 |= 0x1c;
    P1PD |= 0x1c;

    //SCL 推挽输出
    P2M0 |= 0x10;
    P2M1 &= ~0x10;
    //SDA 准双向IO口
    P2M0 &= ~0x08;
    P2M1 &= ~0x08;

    //USB_CDC
    P3M0 &= ~0x03; //P3.0/P3.1 和 USB 的 D-/D+共用 PIN 脚,
    P3M1 |= 0x03; //需要将 P3.0/P3.1 设置为高阻输入模式
    IRC48MCR = 0x80; //使能内部 48M 的 USB 专用 IRC
    while (!(IRC48MCR & 0x01));
    USBCLK = 0x00; //设置 USB 时钟源为内部 48M 的 USB 专用 IRC
    USBCON = 0x90; //使能 USB 功能
    usb_init(); //调用 USB CDC 初始化库函数
    IE2 |= 0x80; //使能 USB 中断
    EA = 1;

    ST7735_Init();

    // 初始化计数器
    task1_counter = TASK1_PERIOD;
    task2_counter = TASK2_PERIOD;
    task3_counter = TASK3_PERIOD;

    while(1)
    {
      taskScheduler();
      m_delay_ms(1);
    }
}


// 任务调度函数
void taskScheduler() {
   
    static unsigned long int system_tick = 0;// 系统计数器 32位 49.7天溢出

    // 更新系统计数器
    system_tick++;

    // 检查任务1是否准备好执行
    if (system_tick >= task1_counter) {
      task1_counter += TASK1_PERIOD;
      task1();
    }

    // 检查任务2是否准备好执行
    if (system_tick >= task2_counter) {
      task2_counter += TASK2_PERIOD;
      task2();
    }

    // 检查任务3是否准备好执行
    if (system_tick >= task3_counter) {
      task3_counter += TASK3_PERIOD;
      task3();
    }
   
}

// 任务1
void task1() {
    // 执行任务1的代码
    static unsigned char key_value;
    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() {
    // 执行任务2的代码
    AHT10_Read(tem,hum);
}

// 任务3
void task3() {
    // 执行任务3的代码
    sprintf(buf,"T:%.2f %d",tem,num_A);
    ST7735_WriteString(10,10,buf, Font_11x18,ST7735_GREEN,ST7735_BLACK);
    sprintf(buf,"H:%.2f %d",hum,num_B);
    ST7735_WriteString(10,40,buf, Font_11x18,ST7735_RED,ST7735_BLACK);
}


static/image/hrline/1.gif

实验结果

[*]能运行
[*]满足项目需求


static/image/hrline/1.gif
待优化


[*]使用定时器中断来更新系统计数器




soma 发表于 2024-8-19 22:04:00

没有使用定时器中断,还是有点不足

哈哈哈哈 发表于 2024-8-19 22:31:22

soma 发表于 2024-8-19 22:04
没有使用定时器中断,还是有点不足

定时器还没学{:4_198:}

嵌入式之路 发表于 2024-8-19 23:02:25

想法挺不错的

lezjin 发表于 2024-8-20 07:58:10

中断计时设定1ms,可以参考下


typedef struct
{
      uint8_t taskstate;            //任务状态
      uint16_t tasktime;             //任务时间
      uint16_t tasktimer;             //任务时间重装值
    void (*pTaskFunCb)(void);            //任务函数
}Task_t;


static Task_t g_task[] =
{
//状态计数周期函数
0
//      {0,   5,   5,button_app_tset},
//      {0,   2000,   2000,      LedCtrltwo},
          /* Add new task here */

};

#define TASK_MAX (sizeof(g_task) / sizeof(g_task))

/*--------------------------------------------------------------------------
@brief:时间片轮转调用结构体函数
@param: 无
@retval: 无
--------------------------------------------------------------------------*/
static void TaskHandle(void)
{
      uint8_t i;
      for(i = 0; i < TASK_MAX; i++)
      {
                if (g_task.taskstate)
                {
                        g_task.taskstate = 0;
                        g_task.pTaskFunCb();
                }
      }
}

/*-------------------------------------------------------------------------
@brief: 结构体函数状态刷新函数
@param: 无
@retval: 无
-------------------------------------------------------------------------*/
static void TaskCbState(void)
{
      uint8_t i;
      for( i = 0; i < TASK_MAX; i++)
      {
                if (g_task.tasktime)
                {
                        g_task.tasktime--;
                        if(0 == g_task.tasktime)
                        {
                              g_task.taskstate = 1;
                              g_task.tasktime= g_task.tasktimer;
                        }
                }
      }
}


static void DrvInit(void)
{
    Timer0_Init();
    GpioInit();
    Uart2Init();   
}


static void AppInit(void)
{

}

void main(void)
{
    DrvInit();
    AppInit();

    EA = 1;
   
    printf("uart2printf test\n");

    while(1)
    {
      TaskHandle();
    }
}

void Time0_ISR() interrupt   TMR0_VECTOR   //定时器0中断函数
{
    TaskCbState();   
}

jackfangxq 发表于 2024-8-23 13:37:22

学习{:4_165:}
页: [1]
查看完整版本: AI8051U 伪多任务 极简框架