多定时器处理1(30天自制操作系统--读书笔记)

自认为写过很多MCU程序,但总是回头想想,我所了解的MCU编程思想大体有两种,其中具体的想法我得再找时间写下来。

总想总结出一个可扩展的,易移植的写法,但能力还没到这个层次。但《30天自制操作系统》这本书确实给我了一个思路,就像我已经写过的两篇读书笔记。

将两个独立的内容--FIFO和内存动态管理做到高度模块化,尤其是其中数据结构模型的设计更是我学习的好例子。

今天要学习的设计内容是多定时器处理。原书对这部分的处理讲的很详细,由浅入深,看得我由衷佩服作者,也可能是因为我水平低,稍稍看出点门道来就高兴得不得了。

呵呵,进入正题。

1、数据结构的抽象

#define MAX_TIMER 500

#define TIMER_FLAG_NOUSE 0    //没使用
#define TIMER_FLAG_ALLOC 1    //已配置状态
#define TIMER_FLAG_USING 2    //已使用状态

struct TIMER
{
    unsigned int timeout,flag;     //设定的定时时间,定时器的状态
    struct FIFO8 *fifo;            //定时器关联的fifo
    unsigned char data;            //当定时时间到时,向fifo中写入的数值
}

struct TIMERCTL
{
    unsigned int count;            //定时器计数基数
    struct TIMER timer[MAX_TIMER]; //设定系统最多使用的定时器个数
}

TIMERCTL timerctl;     //定义一个定时器控制变量

2、定时器控制管理变量的初始化

void TIMERCTL_Initial(void)
{
    char i=0;
    timer.count = 0;               //基数清零
    for(i=0;i<MAX_TIMER;i++)
    {
        timerctl.timer[i].flag = TIMER_FLAG_NOUSE;   /*标记为未使用*/
    }
}

3、申请一个定时器

struct TIMER* timer_alloc(void)    //分配一个可以使用的定时器
{
    int i=0;
    for(i=0;i<MAX_TIMER;i++)
    {
        if(timerctl.timer[i].flag == TIMER_FLAG_NOUSE)
        {
            timerctl.timer[i].flag = TIMER_FLAG_ALLOC;   //标记为已分配
            return &timer[i];
        }
    }

    return NULL;       //没有可用的了
}

4、释放一个定时器

void timer_free(struct TIMER* timer)  //释放一个定时器
{
    timer.flag = TIMER_FLAG_NOUSE;
    return ;
}

5、要使用一个定时器时,先初始化定时器

//初始化一个定时器,timer应该先去调用timer_alloc申请,fifo也应该先创立,data表示当定时时间到了之后
//向关联fifo中写入的数据
void timer_init(struct TIMER* timer,struct FIFO8* fifo,unsigned char data)
{
    timer.fifo = fifo;
    timer.data = data;

    return ;
}

6、设定定时器的定时时间,同时也启动了定时器

//设定timer定时器的定时时间为timeout
void timer_settime(struct TIMER* timer,unsigned int timeout)
{
    timer.timeout = timeout;
    timer.flag = TIMER_FLAG_USING;  //这条语句相当于启动了定时器

    return ;
}

7、定时器中断处理函数

//定时器中断函数
void Timer_Interrupt(void)
{
    int i=0;
    timerctl.count ++;
    for(i=0;i<MAX_TIMER;i++)        //扫描所有的定时器
    {
        if(timerctl.timer[i].flag == TIMER_FLAG_USING)
        {
            timerctl.count--;
            if(timerctl.count == 0) //减得时间到了
            {
                fifo8_put(timerctl.timer[i].fifo,timerctl.timer[i].data);  //向关联fifo中写入数据
                timerctl.timer[i].flag = TIMER_FLAG_ALLOC;      //改变标志位
            }
        }
    }

    return ;
}

如何使用以上代码:

1、初始化一个fifo,包括以下内容

struct FIFO8 timer0fifo;

char timer0buf[8];

fifo8_init(&timer0fifo,8,timer0buf);     //这句话就是初始化一个fifo,8是缓存大小,timer0buf是实际缓存地址。

2、定义一个timer,先申请再初始化它

struct TIMER* timer0;

timer0 = timer_alloc();                   //申请一个定时器对象

timer_init(timer0,timer0fifo,1);        //这里也就是将timer0fifo与timer0关联,1是定时器到达时,向关联fifo中写入的值

3、设定定时时间,启动定时器

timer_settime(timer0,1000);          //这里设定的定时时间t=1000*T T为定时器硬件设定的时间间隔,比如1ms,那么这里就设定了一个1s的定时器

4、通过在主程序中查询定时器关联fifo的状态,判断定时时间是否到了,并处理相关事情

    while(1)
   {
          ...(其他省略)
          if(fifo8_status(&timer0fifo) != 0)      //定时时间到了,定时器向关联fifo中写入了数据
         {
               i = fifo8_get(&timer0fifo);
               if(i == 1)
               {
                   //do_something
               }
         }
   }

这样可以完成类似LED灯闪烁的任务了。当然这个定时器定时时间到了之后,还可以再初始化这个定时器,比如改变定时到时向fifo中写入的数值,然后再启动定时器,这样

判断fifo8_get的值就有意义了。这样可以完成文本输入中光标闪烁的任务(定时亮,定时灭,定时时间一样,处理不一样)。

今天的内容就到此为止了,实际原作者比这写得更好,明天继续深入。

时间: 2024-10-12 09:22:55

多定时器处理1(30天自制操作系统--读书笔记)的相关文章

多定时器处理2(30天自制操作系统 -- 读书笔记)

今天的内容依然来自<30天自制操作系统>这本书. 1.中断处理程序存在的问题,中断处理程序Timer_Interrupt如下: //定时器中断函数 void Timer_Interrupt(void) { int i=0; timerctl.count ++; for(i=0;i<MAX_TIMER;i++) //扫描所有的定时器 { if(timerctl.timer[i].flag == TIMER_FLAG_USING) { timerctl.count--; if(timerct

内存管理(30天自制操作系统--读书笔记)

今天继续读书笔记,“挑战内存管理”(30天自制操作系统). 为什么对这块内容敢兴趣呢,因为曾经遇到这么一个问题.在STM32程序中想使用队列,可不是上篇讲的FIFO,而是使用了较大的内存空间,又想做队列的顺序存取管理. 在这个队列里用到了malloc,动态申请内存,一开始是直接申请不到内存,后来在启动脚本里更改了设置堆的地址值,可以申请成功,但发现申请几次后,也申请不到内存. 果然MCU级别的程序,内存这块处理起来就没有windows程序那么随心所欲了.讲了这么多,开始正题吧. 1.相关数据结构

单字节的FIFO缓存(30天自制操作系统--读书笔记)

从今天起,写一些读书笔记.最近几个月都在看<30天自制操作系统这本书>,书虽说看的是电子书,但可以花钱买的正版书,既然花费了金钱,就总得有些收获. 任何人都不能总是固步自封,想要进步就得学习别人的知识,对于程序员而言,最简单的方法即是学习别人的代码. 今天的标题是“单字节的FIFO缓存”,其实就是做一个FIFO,看名字就知道了.也就4个函数和1个相关结构体,这样的小代码在嵌入式系统中很常用,也会很好用. 1.相关数据结构体 struct FIFO8 { unsigned char *buf;

多定时器处理3(30天自制操作系统 -- 读书笔记)

继续定时器中断处理的改进. 1.定时器中断程序Timer_Interrupt是这样的. //定时器中断函数 void Timer_Interrupt(void) { int i=0; timerctl.count ++; for(i=0;i<MAX_TIMER;i++) //扫描所有的定时器 { if(timerctl.timer[i].flag == TIMER_FLAG_USING) { timerctl.count--; if(timerctl.count == 0) //减得时间到了 {

30天自制操作系统读书笔记(一)

刚开始作者叫我们用二进制编辑器,手敲01代码写了个IMG(磁盘映像文件) ,并提供了一些文件 : Run.bat, install.bat这些一个批处理文件,其实就是写好了cmd指令保存到文档里面,方便以后执行. 其中run.bat里面的指令是这样的 : copy helloos.img ..\z_tools\qemu\fdimage0.bin ..\z_tools\make.exe         -C ../z_tools/qemu (稍微解释一下:第一行:copy指令把,helloos.i

30天自制操作系统读书笔记(二)

我还以为马大哈的作者忘记解释之前那段好长的汇编代码了,留下这么多疑惑! 第二天作者就交代了:以后再讲,第二天我们先来谈谈程序核心部分的内容吧! 好吧,刚准备欢喜的等着作者解释,没想到他就扔了一大串代码(什么鬼?) ; hello-os ; TAB=4 ORG 0x7c00 ; 指明程序的装载地址,这个指令是和nask编译器说的(伪指令)告诉nask,开始执行的时候,把代码放到0x7c00的地方. ;为什么是0x7c00呢,因为规定了0x7c00-0x7dff是启动区的装载地址. ; 以下用于标准

30天自制操作系统读书笔记(五)

为了让程序灵活点,作者觉得把什么320X200这些数据直接写入程序,不如让程序自己获取. 所以就引入了结构体,指针.用指针直接在内存中获取这些数据 (如程序里的这句: Binfo_scrnx = (short *) 0xff4; ). 对于结构体和指针我就不细写了,有C语言基础的人都知道. 因为已经进入了32位模式,所以不能再用bios写好的中断程序给我们输出字符了,要手动了! 用像素点描出图形. 字符可以使用8X16的长方形像素点来表示,转变为16进制就是这样: static char fon

30天自制操作系统读书笔记(四)

想要在画面里画点什么东西,就需要往VRAM的内存区里写入点什么东西. 但是如何写入呢? 作者先用了汇编: _write_mem8:         ; void write_mem8(int addr, int data); MOV                  ECX,[ESP+4]               ; [ESP + 4]中存放的是地址,将其读入ECX MOV                  AL,[ESP+8]                 ; [ESP + 8]中存放的

《30天自制操作系统》笔记(12)——多任务入门

<30天自制操作系统>笔记(12)——多任务入门 进度回顾 上一篇介绍了设置显示器高分辨率的方法.本篇讲一下操作系统实现多任务的方法. 什么是多任务 对程序员来说,也许这是废话,不过还是说清楚比较好. 多任务就是让电脑同时运行多个程序(如一边写代码一边听音乐一边下载电影). 电脑的CPU只有固定有限的那么一个或几个,不可能真的同时运行多个程序.所以就用近似的方式,让多个程序轮换着运行.当轮换速度够快(0.01秒),给人的感觉就是"同时"运行了. 多任务之不实用版 我们首先从