[自制简单操作系统] 6、多任务(一)
#前言#
>_<" 这里主要是多任务的初探~比较简单,主要是尝试保存当前任务、任务切换、恢复当前任务,而真正的多任务要比这个复杂的多,因为包含互不干扰,甚至是高度优化的并行技术!
一、保存当前任务:
>_<" 当向CPU发出切换命令的时候,CPU会先把寄存器中的值全部写入内存中,这样当切换回来时,可以从中断的地方继续执行。接下来,为了运行下一个程序,CPU会把所有的寄存器中的值从内存中读取出来,这就完成了一次切换。
>_<" 这里的结构TSS32是task status segment,是32位任务状态段,其也是内存段的一种,需要再GDT中进行定以后使用。
1 struct TSS32 {//task status segment 任务状态段 2 int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入) 3 int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器 4 int es, cs, ss, ds, fs, gs;//16位寄存器 5 int ldtr, iomap;//有关任务设置部分 6 };
二、任务切换:从任务A到任务B[12a]
>_<" 接下来要在main函数中创建两个TSS:任务A的TSS和任务B的TSS,然后对其初始化,接着再在GDT中定义...见下面的main函数(有删减,这里只展示核心部分):
18 void HariMain(void) 19 { 25 int mx, my, i ,cursor_x, cursor_c, task_b_esp;//cursor_x是记录光标位置的变量,cursor_c表示光标现在的颜色,每隔0.5秒变化一次,任务B的栈 41 struct TSS32 tss_a, tss_b;//首先建立2个TSS,任务a的TSS和任务b的TSS
110 tss_a.ldtr = 0;//先这样设置好 111 tss_a.iomap = 0x40000000; 112 tss_b.ldtr = 0; 113 tss_b.iomap = 0x40000000; 114 set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);//定义在gdt的3号,段长限制为103字节 115 set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32); 116 //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务 117 //每当进行任务切换时,TR寄存器的值也会自动变换,task register 118 //每次给TR赋值的时候,必须把GDT的编号乘以8 119 load_tr(3 * 8); 120 task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;//要为任务B专门分配栈,直接用任务A的栈就会乱成一团糟 121 tss_b.eip = (int) &task_b_main;//任务b的开始地址 122 tss_b.eflags = 0x00000202; /* IF = 1; */ 123 tss_b.eax = 0; 124 tss_b.ecx = 0; 125 tss_b.edx = 0; 126 tss_b.ebx = 0; 127 tss_b.esp = task_b_esp; 128 tss_b.ebp = 0; 129 tss_b.esi = 0; 130 tss_b.edi = 0; 131 tss_b.es = 1 * 8; 132 tss_b.cs = 2 * 8; 133 tss_b.ss = 1 * 8; 134 tss_b.ds = 1 * 8; 135 tss_b.fs = 1 * 8; 136 tss_b.gs = 1 * 8; 137 138 for (;;) {140 if (fifo32_status(&fifo) == 0) {142 } else {145 if (256 <= i && i <= 511) {//键盘数据165 }else if (512 <= i && i <= 767) {//鼠标数据202 }else if(i==10){//10s定时 204 taskswitch4();//程序10s以后进行任务切换 205 }else if (i == 3){}219 } 220 } 221 }300 ///////////////////////////////////////////////////////////////////////////////////// 301 //功能:任务b的函数 302 //参数: 303 void task_b_main(void) 304 { 305 for (;;) { io_hlt(); } 306 }
1 /* bootpack */ 2 3 #include "bootpack.h" 4 #include <stdio.h> 5 6 void make_window8(unsigned char *buf, int xsize, int ysize, char *title); 7 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l);//字符串显示 8 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); 9 10 struct TSS32 {//task status segment 任务状态段 11 int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入) 12 int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器 13 int es, cs, ss, ds, fs, gs;//16位寄存器 14 int ldtr, iomap;//有关任务设置部分 15 }; 16 void task_b_main(void); 17 18 void HariMain(void) 19 { 20 struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; 21 struct FIFO32 fifo;//定时器FIFO 22 char s[40]; 23 int fifobuf[128]; 24 struct TIMER *timer,*timer2,*timer3;//3个定时器 25 int mx, my, i ,cursor_x, cursor_c, task_b_esp;//cursor_x是记录光标位置的变量,cursor_c表示光标现在的颜色,每隔0.5秒变化一次,任务B的栈 26 unsigned int memtotal; 27 struct MOUSE_DEC mdec; 28 struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; 29 struct SHTCTL *shtctl; 30 struct SHEET *sht_back, *sht_mouse, *sht_win; 31 unsigned char *buf_back, buf_mouse[256], *buf_win; 32 static char keytable[0x54] = {//键盘映射表 33 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, 34 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', 35 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', 36 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 37 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', 38 '2', '3', '0', '.' 39 }; 40 41 struct TSS32 tss_a, tss_b;//首先建立2个TSS,任务a的TSS和任务b的TSS 42 struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; 43 44 init_gdtidt();//在dsctbl.c中,负责分区和中断分区初始化[包括键盘和鼠标中断设定] 45 init_pic();//在int.c中,负责中断初始化(硬件) 46 io_sti();//在naskfunc.nas中,仅仅执行STI指令,是CLI的逆指令,前者是开中断,后者是禁止中断 47 /* 48 同一占用一个fifo,这里: 49 0~1 光标闪烁用定时器 50 3 3秒定时器 51 10 10秒定时器 52 256~511 键盘输入(从键盘控制器读入的值再加上256) 53 512~767 鼠标输入(从键盘控制器读入的值再加上512) 54 */ 55 fifo32_init(&fifo, 128, fifobuf);//初始化fifo 56 init_pit();//负责计时器初始化100hz 57 init_keyboard(&fifo, 256);//初始化键盘控制电路//在fifo.c中,负责缓冲区初始化(缓冲区结构体,大小,缓冲区首址) 58 enable_mouse(&fifo, 512, &mdec);//使能鼠标 59 /*这里IMR是(interrupt mask register),意思是“中断屏蔽寄存器”,是8位寄存器,分别对应8路IRQ信号,如果一路是1则该路被屏蔽,因为键盘中断是IRQ1,鼠标中断是IRQ12,且PIC分主从2个,从PIC连接主PIC的IRQ2,所以想要有鼠标和键盘中断,要PIC0的IRQ1和IRQ2,和PIC1的IRQ4*/ 60 io_out8(PIC0_IMR, 0xf8); /* (11111000) *///PIT,PIC1,键盘许可 61 io_out8(PIC1_IMR, 0xef); /* (11101111) */ 62 63 timer = timer_alloc();//3个定时器 64 timer_init(timer, &fifo, 10); 65 timer_settime(timer, 1000); 66 timer2 = timer_alloc(); 67 timer_init(timer2, &fifo, 3); 68 timer_settime(timer2, 300); 69 timer3 = timer_alloc(); 70 timer_init(timer3, &fifo, 1); 71 timer_settime(timer3, 50); 72 73 //memman需要32KB内存 74 memtotal = memtest(0x00400000, 0xbfffffff);//计算总量memtatal 75 memman_init(memman); 76 memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff 将现在不用的字节以0x1000个字节为单位注册到memman里*/ 77 memman_free(memman, 0x00400000, memtotal - 0x00400000); 78 79 init_palette();//调色板 80 shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);//图层初始化函数 81 sht_back = sheet_alloc(shtctl);//分配一个背景窗口 82 sht_mouse = sheet_alloc(shtctl);//分配一个鼠标窗口 83 sht_win = sheet_alloc(shtctl);//分配一个小窗口 84 buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);//为背景窗口和普通小窗口分配缓存空间 85 buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); 86 sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 87 sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); 88 sheet_setbuf(sht_win, buf_win, 160, 52, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 89 init_screen8(buf_back, binfo->scrnx, binfo->scrny);//初始化屏幕,画矩形,形成最初的窗口界面 90 init_mouse_cursor8(buf_mouse, 99);//准备鼠标指针(16*16),99是窗口背景颜色 91 make_window8(buf_win, 160, 52, "WINDOW");//就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 92 make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);//窗口上的文件编辑部分 93 cursor_x = 8; 94 cursor_c = COL8_FFFFFF; 95 sheet_slide(sht_back, 0, 0);//上下左右移动窗口,即移动窗口至0,0 96 mx = (binfo->scrnx - 16) / 2; /* 计算鼠标初始位置 */ 97 my = (binfo->scrny - 28 - 16) / 2; 98 sheet_slide(sht_mouse, mx, my);//移动鼠标窗口 99 sheet_slide(sht_win, 80, 72);//移动消息窗口 100 sheet_updown(sht_back, 0);//设置窗口对的高度,背景在最下面 101 sheet_updown(sht_win, 1); 102 sheet_updown(sht_mouse, 2); 103 sprintf(s, "(%3d, %3d)", mx, my);//显示鼠标位置 104 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10); 105 sprintf(s, "memory %dMB free : %dKB", 106 memtotal / (1024 * 1024), memman_total(memman) / 1024); 107 putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40); 108 sheet_refresh(sht_back, 0, 0, binfo->scrnx, 48); 109 110 tss_a.ldtr = 0;//先这样设置好 111 tss_a.iomap = 0x40000000; 112 tss_b.ldtr = 0; 113 tss_b.iomap = 0x40000000; 114 set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);//定义在gdt的3号,段长限制为103字节 115 set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32); 116 //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务 117 //每当进行任务切换时,TR寄存器的值也会自动变换,task register 118 //每次给TR赋值的时候,必须把GDT的编号乘以8 119 load_tr(3 * 8); 120 task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;//要为任务B专门分配栈,直接用任务A的栈就会乱成一团糟 121 tss_b.eip = (int) &task_b_main;//任务b的开始地址 122 tss_b.eflags = 0x00000202; /* IF = 1; */ 123 tss_b.eax = 0; 124 tss_b.ecx = 0; 125 tss_b.edx = 0; 126 tss_b.ebx = 0; 127 tss_b.esp = task_b_esp; 128 tss_b.ebp = 0; 129 tss_b.esi = 0; 130 tss_b.edi = 0; 131 tss_b.es = 1 * 8; 132 tss_b.cs = 2 * 8; 133 tss_b.ss = 1 * 8; 134 tss_b.ds = 1 * 8; 135 tss_b.fs = 1 * 8; 136 tss_b.gs = 1 * 8; 137 138 for (;;) { 139 io_cli(); 140 if (fifo32_status(&fifo) == 0) { 141 io_sti(); 142 } else { 143 i = fifo32_get(&fifo); 144 io_sti(); 145 if (256 <= i && i <= 511) {//键盘数据 146 sprintf(s, "%02X", i - 256);//减去256 147 putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);//清,显,刷 148 if (i < 0x54 + 256) { 149 if (keytable[i - 256] != 0 && cursor_x < 144) {//一般字符 150 /* 显示一次就前移一次光标 */ 151 s[0] = keytable[i - 256]; 152 s[1] = 0; 153 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); 154 cursor_x += 8;//记录光标位置 155 } 156 } 157 if (i == 256 + 0x0e && cursor_x > 8) { /* 退格键 */ 158 /* 用空格键把光标消去后,后移1次光标 */ 159 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); 160 cursor_x -= 8; 161 } 162 /* 光标再显示 */ 163 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 164 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 165 }else if (512 <= i && i <= 767) {//鼠标数据 166 //已经收集了3字节的数据,所以显示出来 167 if (mouse_decode(&mdec, i - 512) != 0) { 168 sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y); 169 if ((mdec.btn & 0x01) != 0) { 170 s[1] = 'L'; 171 } 172 if ((mdec.btn & 0x02) != 0) { 173 s[3] = 'R'; 174 } 175 if ((mdec.btn & 0x04) != 0) { 176 s[2] = 'C'; 177 } 178 putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);//清,显,刷 179 /* 移动鼠标 */ 180 mx += mdec.x; 181 my += mdec.y; 182 if (mx < 0) { 183 mx = 0; 184 } 185 if (my < 0) { 186 my = 0; 187 } 188 if (mx > binfo->scrnx - 1) { 189 mx = binfo->scrnx - 1; 190 } 191 if (my > binfo->scrny - 1) { 192 my = binfo->scrny - 1; 193 } 194 sprintf(s, "(%3d, %3d)", mx, my); 195 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);//清,显,刷 196 sheet_slide(sht_mouse, mx, my); 197 //移动窗口计算 198 if((mdec.btn & 0x01)!=0){ 199 sheet_slide(sht_win,mx-80,my-80); 200 }//按下左键移动sht_win 201 } 202 }else if(i==10){//10s定时 203 putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);//清,显,刷、 204 taskswitch4();//程序10s以后进行任务切换 205 }else if (i == 3) { //3秒定时器 206 putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6); 207 }else if (i<=1) { //光标用定时器 208 if (i != 0) { 209 timer_init(timer3, &fifo, 0); /* 師偼0傪 */ 210 cursor_c = COL8_000000; 211 } else { 212 timer_init(timer3, &fifo, 1); /* 師偼1傪 */ 213 cursor_c = COL8_FFFFFF; 214 } 215 timer_settime(timer3, 50); 216 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 217 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 218 } 219 } 220 } 221 } 222 ///////////////////////////////////////////////////////////////////////////////////// 223 //功能:就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 224 //参数: 225 void make_window8(unsigned char *buf, int xsize, int ysize, char *title) 226 { 227 static char closebtn[14][16] = { 228 "OOOOOOOOOOOOOOO@", 229 "OQQQQQQQQQQQQQ$@", 230 "OQQQQQQQQQQQQQ$@", 231 "OQQQ@@QQQQ@@QQ$@", 232 "OQQQQ@@QQ@@QQQ$@", 233 "OQQQQQ@@@@QQQQ$@", 234 "OQQQQQQ@@QQQQQ$@", 235 "OQQQQQ@@@@QQQQ$@", 236 "OQQQQ@@QQ@@QQQ$@", 237 "OQQQ@@QQQQ@@QQ$@", 238 "OQQQQQQQQQQQQQ$@", 239 "OQQQQQQQQQQQQQ$@", 240 "O$$$$$$$$$$$$$$@", 241 "@@@@@@@@@@@@@@@@" 242 }; 243 int x, y; 244 char c; 245 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); 246 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); 247 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); 248 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); 249 boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); 250 boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); 251 boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); 252 boxfill8(buf, xsize, COL8_000084, 3, 3, xsize - 4, 20 ); 253 boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); 254 boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); 255 putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title); 256 for (y = 0; y < 14; y++) { 257 for (x = 0; x < 16; x++) { 258 c = closebtn[y][x]; 259 if (c == '@') { 260 c = COL8_000000; 261 } else if (c == '$') { 262 c = COL8_848484; 263 } else if (c == 'Q') { 264 c = COL8_C6C6C6; 265 } else { 266 c = COL8_FFFFFF; 267 } 268 buf[(5 + y) * xsize + (xsize - 21 + x)] = c; 269 } 270 } 271 return; 272 } 273 ///////////////////////////////////////////////////////////////////////////////////// 274 //功能:先图上背景颜色,再显示字符,最后完成刷新 275 //参数:图层,位置,字体颜色,背景颜色,字符串,字符串长度 276 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) 277 { 278 boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); 279 putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); 280 sheet_refresh(sht, x, y, x + l * 8, y + 16); 281 return; 282 } 283 ///////////////////////////////////////////////////////////////////////////////////// 284 //功能:描绘文字输入背景的 285 //参数: 286 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) 287 { 288 int x1 = x0 + sx, y1 = y0 + sy; 289 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); 290 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); 291 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); 292 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); 293 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); 294 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); 295 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); 296 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); 297 boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); 298 return; 299 } 300 ///////////////////////////////////////////////////////////////////////////////////// 301 //功能:任务b的函数 302 //参数: 303 void task_b_main(void) 304 { 305 for (;;) { io_hlt(); } 306 }
-
第41行是建立2个TSS,分别是任务A和任务B的
-
第110~113是对A和B的TSS任务的成员变量的初始化,这里不能乱赋值否则不能正常切换
-
第114和第115两行是定义两个TSS的GDT,分别是段3和段4
-
第119行load_tr(3 * 8);是用汇编写的函数,目的是给TR寄存器赋值,因为刚才设置任务a的GDT为3,而TR寄存器是让CPU记住当前执行那一条任务,所以,要给TR重新设置值,这里*8是和硬件有关~
-
第120行是给任务B分配栈,否则和任务A混在一起就会出现混乱
-
第121~136是对B的TSS的初始化设置,其中第一行指定任务B的入口地址,当任务切换到任务B时,就会转到第303行任务B的函数执行~
-
第204行是任务切换,同样这里的函数也是用汇编写的,里面就是一个JMP语句:JMP 4*8:0 用来转到任务B所对应的段地址,我们可以看到这是在10s定时器中写的,所以每隔10s就进行任务切换了
-
@总的来说,这段代码的任务就是做一个10s后的任务切换工作,先运行A任务,然后任务切换进入B,一直处于进行hlt()~
三、任务切换:任务A和B的互相切换[12b]
>_<" 上面只是实现了从任务A切换到任务B,然后就一直处于hlt()了~这里我们只要简单的改一下任务B的函数就能实现任务的切回了:
1 void task_b_main(void) 2 { 3 struct FIFO32 fifo; 4 struct TIMER *timer; 5 int i,fifobuf[128]; 6 7 fifo32_init(&fifo,128,fifobuf); 8 timer=timer_alloc(); 9 timer_init(timer,&fifo,1); 10 timer_settime(timer,500); 11 12 for(;;){ 13 io_cli(); 14 if(fifo32_status(&fifo)==0){ 15 io_stihlt(); 16 }else{ 17 i=fifo32_get(&fifo); 18 io_sti(); 19 if(i==1){//超时时间为5s 20 taskswitch3();//返回任务A 21 } 22 } 23 } 24 }
PS: 这里在任务B的函数里写了和任务A中相同的变量名,其实是互不影响的~
四、多任务:每隔0.02s切换任务 & 变量传递[这里是窗口sht_back][12e]
>_<" 这里把汇编写的taskswitch3();和taskswitch4();合并为一个可以带参数的任务切换函数farjmp(),并声明一个定时器0.02s中断一次用于任务切换,注意这里每次切换后要重新设置定时器,以便下次仍然是0.02s切换一次~,对于参数传递采用的思路是:把sht_back在任务A的时候找一个内存存进去(*((int*)0x0fec)=(int) sht_back;),然后在任务B的时候再从这个内存中读出sht_back的值(sht_back=(struct SHEET *)*((int*)0x0fec);)
1 if (i==2){//每隔0.02s执行一次任务切换 2 farjmp(0,4*8); 3 timer_settime(timer_ts,2); 4 }
1 /* bootpack */ 2 3 #include "bootpack.h" 4 #include <stdio.h> 5 6 void make_window8(unsigned char *buf, int xsize, int ysize, char *title); 7 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l);//字符串显示 8 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); 9 10 struct TSS32 {//task status segment 任务状态段 11 int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入) 12 int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器 13 int es, cs, ss, ds, fs, gs;//16位寄存器 14 int ldtr, iomap;//有关任务设置部分 15 }; 16 void task_b_main(void); 17 18 void HariMain(void) 19 { 20 struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; 21 struct FIFO32 fifo;//定时器FIFO 22 char s[40]; 23 int fifobuf[128]; 24 struct TIMER *timer,*timer2,*timer3,*timer_ts;//4个定时器 25 int mx, my, i ,cursor_x, cursor_c, task_b_esp;//cursor_x是记录光标位置的变量,cursor_c表示光标现在的颜色,每隔0.5秒变化一次,任务B的栈 26 unsigned int memtotal; 27 struct MOUSE_DEC mdec; 28 struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; 29 struct SHTCTL *shtctl;//图层管理 30 struct SHEET *sht_back, *sht_mouse, *sht_win;//3个图层 31 unsigned char *buf_back, buf_mouse[256], *buf_win; 32 static char keytable[0x54] = {//键盘映射表 33 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, 34 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', 35 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', 36 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 37 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', 38 '2', '3', '0', '.' 39 }; 40 41 struct TSS32 tss_a, tss_b;//首先建立2个TSS,任务a的TSS和任务b的TSS 42 struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; 43 44 init_gdtidt();//在dsctbl.c中,负责分区和中断分区初始化[包括键盘和鼠标中断设定] 45 init_pic();//在int.c中,负责中断初始化(硬件) 46 io_sti();//在naskfunc.nas中,仅仅执行STI指令,是CLI的逆指令,前者是开中断,后者是禁止中断 47 /* 48 同一占用一个fifo,这里: 49 0~1 光标闪烁用定时器 50 3 3秒定时器 51 10 10秒定时器 52 256~511 键盘输入(从键盘控制器读入的值再加上256) 53 512~767 鼠标输入(从键盘控制器读入的值再加上512) 54 */ 55 fifo32_init(&fifo, 128, fifobuf);//初始化fifo 56 init_pit();//负责计时器初始化100hz 57 init_keyboard(&fifo, 256);//初始化键盘控制电路//在fifo.c中,负责缓冲区初始化(缓冲区结构体,大小,缓冲区首址) 58 enable_mouse(&fifo, 512, &mdec);//使能鼠标 59 /*这里IMR是(interrupt mask register),意思是“中断屏蔽寄存器”,是8位寄存器,分别对应8路IRQ信号,如果一路是1则该路被屏蔽,因为键盘中断是IRQ1,鼠标中断是IRQ12,且PIC分主从2个,从PIC连接主PIC的IRQ2,所以想要有鼠标和键盘中断,要PIC0的IRQ1和IRQ2,和PIC1的IRQ4*/ 60 io_out8(PIC0_IMR, 0xf8); /* (11111000) *///PIT,PIC1,键盘许可 61 io_out8(PIC1_IMR, 0xef); /* (11101111) */ 62 63 timer = timer_alloc();//4个定时器 64 timer_init(timer, &fifo, 10); 65 timer_settime(timer, 1000); 66 timer2 = timer_alloc(); 67 timer_init(timer2, &fifo, 3); 68 timer_settime(timer2, 300); 69 timer3 = timer_alloc(); 70 timer_init(timer3, &fifo, 1); 71 timer_settime(timer3, 50); 72 timer_ts = timer_alloc(); 73 timer_init(timer_ts, &fifo, 2); 74 timer_settime(timer_ts, 2); 75 76 //memman需要32KB内存 77 memtotal = memtest(0x00400000, 0xbfffffff);//计算总量memtatal 78 memman_init(memman); 79 memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff 将现在不用的字节以0x1000个字节为单位注册到memman里*/ 80 memman_free(memman, 0x00400000, memtotal - 0x00400000); 81 82 init_palette();//调色板 83 shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);//图层初始化函数 84 sht_back = sheet_alloc(shtctl);//分配一个背景窗口 85 sht_mouse = sheet_alloc(shtctl);//分配一个鼠标窗口 86 sht_win = sheet_alloc(shtctl);//分配一个小窗口 87 buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);//为背景窗口和普通小窗口分配缓存空间 88 buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); 89 sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 90 sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); 91 sheet_setbuf(sht_win, buf_win, 160, 52, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 92 init_screen8(buf_back, binfo->scrnx, binfo->scrny);//初始化屏幕,画矩形,形成最初的窗口界面 93 init_mouse_cursor8(buf_mouse, 99);//准备鼠标指针(16*16),99是窗口背景颜色 94 make_window8(buf_win, 160, 52, "WINDOW");//就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 95 make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);//窗口上的文件编辑部分 96 cursor_x = 8; 97 cursor_c = COL8_FFFFFF; 98 sheet_slide(sht_back, 0, 0);//上下左右移动窗口,即移动窗口至0,0 99 mx = (binfo->scrnx - 16) / 2; /* 计算鼠标初始位置 */ 100 my = (binfo->scrny - 28 - 16) / 2; 101 sheet_slide(sht_mouse, mx, my);//移动鼠标窗口 102 sheet_slide(sht_win, 80, 72);//移动消息窗口 103 sheet_updown(sht_back, 0);//设置窗口对的高度,背景在最下面 104 sheet_updown(sht_win, 1); 105 sheet_updown(sht_mouse, 2); 106 sprintf(s, "(%3d, %3d)", mx, my);//显示鼠标位置 107 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10); 108 sprintf(s, "memory %dMB free : %dKB", 109 memtotal / (1024 * 1024), memman_total(memman) / 1024); 110 putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40); 111 // sheet_refresh(sht_back, 0, 0, binfo->scrnx, 48); 112 113 tss_a.ldtr = 0;//先这样设置好 114 tss_a.iomap = 0x40000000; 115 tss_b.ldtr = 0; 116 tss_b.iomap = 0x40000000; 117 set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);//定义在gdt的3号,段长限制为103字节 118 set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32); 119 //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务 120 //每当进行任务切换时,TR寄存器的值也会自动变换,task register 121 //每次给TR赋值的时候,必须把GDT的编号乘以8 122 load_tr(3 * 8); 123 task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;//要为任务B专门分配栈,直接用任务A的栈就会乱成一团糟 124 tss_b.eip = (int) &task_b_main;//任务b的开始地址 125 tss_b.eflags = 0x00000202; /* IF = 1; */ 126 tss_b.eax = 0; 127 tss_b.ecx = 0; 128 tss_b.edx = 0; 129 tss_b.ebx = 0; 130 tss_b.esp = task_b_esp; 131 tss_b.ebp = 0; 132 tss_b.esi = 0; 133 tss_b.edi = 0; 134 tss_b.es = 1 * 8; 135 tss_b.cs = 2 * 8; 136 tss_b.ss = 1 * 8; 137 tss_b.ds = 1 * 8; 138 tss_b.fs = 1 * 8; 139 tss_b.gs = 1 * 8; 140 *((int*)0x0fec)=(int) sht_back;//将这个变量从任务A传给任务B 141 142 for (;;) { 143 io_cli(); 144 if (fifo32_status(&fifo) == 0) { 145 io_sti(); 146 } else { 147 i = fifo32_get(&fifo); 148 io_sti(); 149 if (i==2){//每隔0.02s执行一次任务切换 150 farjmp(0,4*8); 151 timer_settime(timer_ts,2); 152 }if (256 <= i && i <= 511) {//键盘数据 153 sprintf(s, "%02X", i - 256);//减去256 154 putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);//清,显,刷 155 if (i < 0x54 + 256) { 156 if (keytable[i - 256] != 0 && cursor_x < 144) {//一般字符 157 /* 显示一次就前移一次光标 */ 158 s[0] = keytable[i - 256]; 159 s[1] = 0; 160 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); 161 cursor_x += 8;//记录光标位置 162 } 163 } 164 if (i == 256 + 0x0e && cursor_x > 8) { /* 退格键 */ 165 /* 用空格键把光标消去后,后移1次光标 */ 166 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); 167 cursor_x -= 8; 168 } 169 /* 光标再显示 */ 170 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 171 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 172 }else if (512 <= i && i <= 767) {//鼠标数据 173 //已经收集了3字节的数据,所以显示出来 174 if (mouse_decode(&mdec, i - 512) != 0) { 175 sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y); 176 if ((mdec.btn & 0x01) != 0) { 177 s[1] = 'L'; 178 } 179 if ((mdec.btn & 0x02) != 0) { 180 s[3] = 'R'; 181 } 182 if ((mdec.btn & 0x04) != 0) { 183 s[2] = 'C'; 184 } 185 putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);//清,显,刷 186 /* 移动鼠标 */ 187 mx += mdec.x; 188 my += mdec.y; 189 if (mx < 0) { 190 mx = 0; 191 } 192 if (my < 0) { 193 my = 0; 194 } 195 if (mx > binfo->scrnx - 1) { 196 mx = binfo->scrnx - 1; 197 } 198 if (my > binfo->scrny - 1) { 199 my = binfo->scrny - 1; 200 } 201 sprintf(s, "(%3d, %3d)", mx, my); 202 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);//清,显,刷 203 sheet_slide(sht_mouse, mx, my); 204 //移动窗口计算 205 if((mdec.btn & 0x01)!=0){ 206 sheet_slide(sht_win,mx-80,my-80); 207 }//按下左键移动sht_win 208 } 209 }else if(i==10){//10s定时 210 putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);//清,显,刷、 211 }else if (i == 3) { //3秒定时器 212 putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6); 213 }else if (i<=1) { //光标用定时器 214 if (i != 0) { 215 timer_init(timer3, &fifo, 0); /* 師偼0傪 */ 216 cursor_c = COL8_000000; 217 } else { 218 timer_init(timer3, &fifo, 1); /* 師偼1傪 */ 219 cursor_c = COL8_FFFFFF; 220 } 221 timer_settime(timer3, 50); 222 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 223 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 224 } 225 } 226 } 227 } 228 ///////////////////////////////////////////////////////////////////////////////////// 229 //功能:就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 230 //参数: 231 void make_window8(unsigned char *buf, int xsize, int ysize, char *title) 232 { 233 static char closebtn[14][16] = { 234 "OOOOOOOOOOOOOOO@", 235 "OQQQQQQQQQQQQQ$@", 236 "OQQQQQQQQQQQQQ$@", 237 "OQQQ@@QQQQ@@QQ$@", 238 "OQQQQ@@QQ@@QQQ$@", 239 "OQQQQQ@@@@QQQQ$@", 240 "OQQQQQQ@@QQQQQ$@", 241 "OQQQQQ@@@@QQQQ$@", 242 "OQQQQ@@QQ@@QQQ$@", 243 "OQQQ@@QQQQ@@QQ$@", 244 "OQQQQQQQQQQQQQ$@", 245 "OQQQQQQQQQQQQQ$@", 246 "O$$$$$$$$$$$$$$@", 247 "@@@@@@@@@@@@@@@@" 248 }; 249 int x, y; 250 char c; 251 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); 252 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); 253 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); 254 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); 255 boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); 256 boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); 257 boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); 258 boxfill8(buf, xsize, COL8_000084, 3, 3, xsize - 4, 20 ); 259 boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); 260 boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); 261 putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title); 262 for (y = 0; y < 14; y++) { 263 for (x = 0; x < 16; x++) { 264 c = closebtn[y][x]; 265 if (c == '@') { 266 c = COL8_000000; 267 } else if (c == '$') { 268 c = COL8_848484; 269 } else if (c == 'Q') { 270 c = COL8_C6C6C6; 271 } else { 272 c = COL8_FFFFFF; 273 } 274 buf[(5 + y) * xsize + (xsize - 21 + x)] = c; 275 } 276 } 277 return; 278 } 279 ///////////////////////////////////////////////////////////////////////////////////// 280 //功能:先图上背景颜色,再显示字符,最后完成刷新 281 //参数:图层,位置,字体颜色,背景颜色,字符串,字符串长度 282 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) 283 { 284 boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); 285 putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); 286 sheet_refresh(sht, x, y, x + l * 8, y + 16); 287 return; 288 } 289 ///////////////////////////////////////////////////////////////////////////////////// 290 //功能:描绘文字输入背景的 291 //参数: 292 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) 293 { 294 int x1 = x0 + sx, y1 = y0 + sy; 295 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); 296 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); 297 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); 298 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); 299 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); 300 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); 301 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); 302 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); 303 boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); 304 return; 305 } 306 ///////////////////////////////////////////////////////////////////////////////////// 307 //功能:任务b的函数 308 //参数: 309 //附加:这里所使用的变量名和HariMain里面一样的,不过别担心,计算机会把他们当成不同的变量来处理 310 //这里,在每个任务重,当farjmp返回的时候,我们都将定时器设定到0.02s之后,以便让程序在返回0.02s之后再次执行任务切换 311 void task_b_main(void) 312 { 313 struct FIFO32 fifo; 314 struct TIMER *timer_ts; 315 int i,fifobuf[128],count=0; 316 char s[11]; 317 struct SHEET *sht_back; 318 sht_back=(struct SHEET *)*((int*)0x0fec); 319 320 fifo32_init(&fifo,128,fifobuf); 321 timer_ts=timer_alloc(); 322 timer_init(timer_ts,&fifo,1); 323 timer_settime(timer_ts,2); 324 325 for(;;){ 326 count++; 327 sprintf(s,"%10d",count); 328 putfonts8_asc_sht(sht_back,0,144,COL8_FFFFFF,COL8_008484,s,10); 329 io_cli(); 330 if(fifo32_status(&fifo)==0){ 331 io_stihlt(); 332 }else{ 333 i=fifo32_get(&fifo); 334 io_sti(); 335 if(i==1){//超时时间为5s 336 farjmp(0,3*8);//返回任务A 337 timer_settime(timer_ts,2); 338 } 339 } 340 } 341 }
五、任务自动切换[12g]
>_<" 真正的多任务是程序本身不知道的情况下进行任务切换!这里直接创建一个mtask.c专门用来处理多任务
1 /* 任务管理相关程序 */ 2 3 #include "bootpack.h" 4 5 struct TIMER *mt_timer; 6 int mt_tr; 7 8 ///////////////////////////////////////////////////////////////////////////////////// 9 //功能:初始化mt_timer和mt_tr的值,并将计数器设定为0.02s,仅此而已 10 //参数: 11 //附加:变量mt_tr实际上代表了TR寄存器,而不需要timer_init是因为在超时的时候不需要向FIFO缓冲区写入数据 12 //接下来,mt_taskswitch函数的功能是按照当前的mt_tr变量的值计算下一个mt_tr的值,将计时器重新设定为0.02s之后并进行任务切换 13 void mt_init(void) 14 { 15 mt_timer = timer_alloc(); 16 /* 这里没有必要使用timer_init */ 17 timer_settime(mt_timer, 2); 18 mt_tr = 3 * 8; 19 return; 20 } 21 ///////////////////////////////////////////////////////////////////////////////////// 22 //功能:按照当前的mt_tr变量的值计算下一个mt_tr的值,将计时器重新设定为0.02s之后并进行任务切换 23 //参数: 24 void mt_taskswitch(void) 25 { 26 if (mt_tr == 3 * 8) { 27 mt_tr = 4 * 8; 28 } else { 29 mt_tr = 3 * 8; 30 } 31 timer_settime(mt_timer, 2); 32 farjmp(0, mt_tr); 33 return; 34 }
-
mt_init函数是初始化mt_timer和mt_tr的值,并将计数器设置为0.02s之后,mt_tr代表TR寄存器,而不需要使用timer_init()是因为发生超时时不需要向FIFO写数据~
-
mt_taskswitch是按照当前的mt_tr变量的值计算出下一个mt_tr的值,并设置计时器为0.02s,然后任务切换~
>_<" 这里就必须对timer.c里的定时器中断响应函数inthandler20进行响应的修改了:
1 void inthandler20(int *esp) 2 { 3 char ts=0;//标记mt_timer任务切换计时器是否超时,如果直接在else语句直接调用任务切换会出现错误,因为这个中断处理还没完成 4 struct TIMER *timer; 5 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接受完了的信息通知给PIC */ 6 timerctl.count++; 7 if (timerctl.next > timerctl.count) {//如果下一个还没计数完毕就直接返回 8 return; 9 } 10 timer = timerctl.t0; //把最前面的地址赋址给timer 11 for (;;) { 12 if (timer->timeout > timerctl.count) { 13 break; 14 }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环 15 /*除了上面的情况,都是定时已达的定时器*/ 16 timer->flags = TIMER_FLAGS_ALLOC; 17 if(timer!=mt_timer){ 18 fifo32_put(timer->fifo, timer->data); 19 }else{ 20 ts=1;/* mt_timer超时 */ 21 } 22 timer = timer->next;//下一个定时器的地址赋址给timer 23 } 24 timerctl.t0 = timer;//新移位 25 timerctl.next = timer->timeout;//timectl.next设定 26 if(ts!=0){ 27 mt_taskswitch(); 28 } 29 return; 30 }
-
如果发生超时的是mt_timer的话,不向FIFO写数据,而是置ts为1,最后根据这个标志看是否要进行任务切换~(这里一定不能直接在第20行进行任务切换,因为中断还没进行完毕~)
六、效果展示:
>_<" 这里每隔1s就显示一下累计的数据:7370035,下面一行是总的数据~
七、代码链接:
- 任务切换A->B链接12a:http://pan.baidu.com/s/1eQlDQ2u
- 任务切换AB互转链接12b:http://pan.baidu.com/s/1qWlZ4Qg
- 简单的多任务B数数链接12d:http://pan.baidu.com/s/1Gongy
- 简单的多任务优化提速链接12e:http://pan.baidu.com/s/1pJFhI8j
- 任务自动切换链接12g:http://pan.baidu.com/s/1ntHTGsp