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
没有使用定时器中断,还是有点不足
定时器还没学{:4_198:} 想法挺不错的 中断计时设定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();
}
学习{:4_165:}
页:
[1]