This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/lib/flow
许晟昊 b4f7c45b13 更新驱动 2024-02-21 14:52:16 +08:00
..
.vscode 杭电提交 2024-01-22 09:06:18 +08:00
README.md 杭电提交 2024-01-22 09:06:18 +08:00
example.c 杭电提交 2024-01-22 09:06:18 +08:00
flow.h 更新驱动 2024-02-21 14:52:16 +08:00
flow_core.c 杭电提交 2024-01-22 09:06:18 +08:00
flow_core.h 杭电提交 2024-01-22 09:06:18 +08:00
flow_def.h 杭电提交 2024-01-22 09:06:18 +08:00
flow_sem.h 更新驱动 2024-02-21 14:52:16 +08:00

README.md

flow_lib

介绍

适用于嵌入式单片机的裸机程序微库只占用你的rom 6个字节是的6个字节。颠覆式的设计思维让你写代码的时候像flow(流水)一样丝滑让你永远不用在为delay时cpu空转而烦恼附加的超轻便的软件定时器让你轻松实现各种定时需求另还有信号量的配方让你任务间的同步像诗一样写意并且能让你裸机程序效率提升百倍以上。

移植说明

移植特别简单flow_def.h有一个全局变量

extern unsigned long flow_tick;

把这个变量放在你的某个硬件中断里去这个硬件中断一定要是一直运行的推荐RTC半秒中断或者systick中断都可以。

然后在flow.h里的第一行有个宏

#define FL_HARD_TICK        (500)                 /* 系统硬件中断一次所需要的时间单位ms */

把这里的值改成你的硬件中断一次所需的时间单位是毫秒比如你的flow_tick放在了一个500ms中断一次的rtc里那么这里的宏FL_HARD_TICK的值就是500具体中断设为多少取决于你的系统最短一次的延时的时间。

假如我的最短延时需求是100ms那么我就得给个100ms中断一次的硬件中断源宏FL_HARD_TICK的值就是100我就可以这样使用

FL_LOCK_DELAY(fl, FL_CLOCK_SEC /10);

来延时100ms。

使用说明

核心文件时flow.h看这里的注释基本就会使用大部分功能。

#ifndef __FLOW_
#define __FLOW_

#include <flow_def.h>
#include <flow_core.h>
#include <flow_sem.h>

#define FL_HARD_TICK        (500)                 /* 系统硬件中断一次所需要的时间单位ms */
#define FL_CLOCK_SEC        (1000/FL_HARD_TICK)   /* 一秒钟需要的tick可以除也可以自行添加其它宏 */

/**
 * 初始化一个flow进程
 */
#define FL_INIT(fl)                                     FLOW_INIT(fl)

/**
 * flow头必须放在函数内的最前面
 */
#define FL_HEAD(fl)                                     FLOW_HEAD(fl)

/**
 * flow尾必须放在函数内的最后面
 */
#define FL_TAIL(fl)                                     FLOW_TAIL(fl)

/**
 * 给进程加锁直到judge为真加锁期间一直放开cpu给其他进程使用
 */
#define FL_LOCK_WAIT(fl, judge)                         FLOW_LOCK_WAIT(fl, judge)

/**
 * 如果judge为真就一直给进程加锁加锁期间一直放开cpu给其他进程使用
 */
#define FL_LOCK_WHILE(fl, judge)                        FLOW_LOCK_WHILE(fl, judge)

/**
 * 退出该进程
 */
#define FL_EXIT(fl)                                     FLOW_EXIT(fl)

/**
 * 无条件锁住进程一次,下次进来再接着往下运行
 */
#define FL_LOCK_ONCE(fl)                                FLOW_LOCK_ONCE(fl)

/**
 * 等待一个flow进程结束
 */
#define FL_WAIT_PROCESS_END(fl, process)                FLOW_WAIT_PROCESS_END(fl, process)

/**
 * 等待一个flow子进程结束
 */
#define FL_WAIT_CHILD(fl, cfl, process)                 FLOW_WAIT_CHILD_PROCESS_END(fl, cfl, process)

/**
 * 给进程加锁时长为time加锁期间一直放开cpu给其他进程使用time如果用FL_CLOCK_SEC来乘那么time的单位就是s
 * 此处time必须是常数
 */
#define FL_LOCK_DELAY(fl,time)                          FLOW_LOCK_DELAY(fl,time)

/**
 * 给进程加锁时长为time延时期间如果judge为真就直接解锁进程
 * 此处time必须是常数
 */
#define FL_LOCK_DELAY_OR_WAIT(fl,judge,time)            FLOW_LOCK_DELAY_OR_WAIT(fl,judge,time)

/**
 * 初始化一个信号量
 */
#define FL_SEM_INIT(sem, count)                         FLOW_SEM_INIT(sem, count)

/**
 * 给进程加锁,直到有信号释放
 */
#define FL_LOCK_WAIT_SEM(f, sem)                        FLOW_LOCK_WAIT_SEM(f, sem)

/**
 * 给进程加锁直到有信号或者超时此处time可以为变量其他的接口处time必须是常数
 */
#define FL_LOCK_WAIT_SEM_OR_TIMEOUT(fl, sem, time)      FLOW_LOCK_WAIT_SEM_OR_TIMEOUT(fl, sem, time)

/**
 * 释放一个信号量
 */
#define FL_SEM_RELEASE(sem)                             FLOW_SEM_RELEASE(sem)

/**
 * 初始化一个软件定时器
 */
void fl_timer_set(struct flow_timer *t, unsigned long interval);

/**
 * 复位一个软件定时器
 */
void fl_timer_reset(struct flow_timer *t);

/**
 * 重启一个软件定时器
 */
void fl_timer_restart(struct flow_timer *t);

/**
 * 检测一个软件定时器是否超时0为不超时1为超时
 */
char fl_timer_timeout(struct flow_timer *t);

/**
 * 检测一个软件定时器还剩多少时间超时单位为硬件tick比如硬件tick 500ms中断一次那么
 * 返回的时间单位就是500ms
 */
unsigned long fl_hour_much_time(struct flow_timer *t);

#endif /* __FLOW_ */

简单举个例子先从需求说起假如说你现在需要一个函数这个函数的功能是每隔1s让你的led亮一次正常设计的要么起个软件定时器或者硬件定时器甚至状态机可以实现需求但是都太low了让我们看一下如何用flow库来实现这个函数。

该函数格式如下:

char led_flash(struct flow *fl)
{}

其中char、struct flow *fl是必备的。

再来看看函数里面的内容格式:

char led_flash(struct flow *fl)
{
    FL_HEAD(fl);
    FL_TAIL(fl);
}

函数里面的FL_HEAD和FL_TAIL是使用flow库的所必须的宏FL_HEAD(fl)放到函数的最前面如果你的函数内部有变量定义的话放在变量定义的后面。而FL_TAIL(fl)是放在函数最后面一行的。

基本格式有了再来看下如何实现延时一秒呢其实只用一个语句就OK。

char led_flash(struct flow *fl)
{
    FL_HEAD(fl);
    FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
    led_open();
    FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
    led_close();
    FL_TAIL(fl);
}

是的你没看错仅仅只需要FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1)这一个语句就OK当执行到这个语句的时候该函数就会让出CPU权限当延时时间到了之后就会回来接着执行FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1)下面的语句。一直到FL_TAIL(fl),该函数就会结束任务,再也不会执行了,那么如果我们想让它一直循环执行呢?看下面:

char led_flash(struct flow *fl)
{
    FL_HEAD(fl);
    while(1)
    {
        FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
        led_open();
        FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
        led_close();
    }
    FL_TAIL(fl);
}

看起来像不像个进程?其实也有点操作系统的样子了。。。

光有这个函数也不行,还得进行一些额外的操作

比如:

static struct flow fl_led; /* 1定义一个struct flow变量给这个函数使用 */

static char led_flash(struct flow *fl)
{
    FL_HEAD(fl);
    led_init();  /* 这里还能解决你的初始化问题,这里的函数只会在开机时或者说进程第一次进来时运行一次,以后将永远不会运行。注意:如果放在                              
                    FL_HEAD(fl)前面,那么就是每次轮到这个进程运行的时侯就会运行一次,总之很灵活 */
    while(1)
    {
        FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
        led_open();
        FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
        led_close();
    }
    FL_TAIL(fl);
}

int main(void)
{
    FL_INIT(&fl_led);  /* 2初始化struct flow变量 */
    while(1)
    {
        led_flash(&fl_led); /* 3把led_flash进程放在main函数的while循环里 */
        ...
    }
    return 0;
}

经过以上3步就可以实现进程之间的切换啦。然后想根据某个条件来锁住线程释放CPU的话可以把里面的

FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);

换成

FL_LOCK_WAIT(fl, judge);

当里面的judge为假时线程就一直锁住在这一行语句当judge为真时就可以往下执行啦。同理可以完成很多其他的神奇功能让你的cpu再也不空转啦具体请看flow.h文件。。。。

这个版本暂时先写这么多先看看example.c。