购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.2 printk函数

在介绍完MaQueOS的显示器驱动程序的实现后,为了提供在显示器上显示字符串的接口,MaQueOS实现了一个接口函数printk,它的作用是将传递给它的字符串参数显示在显示器上。本章实验code1的main函数如代码清单1.3所示。

代码清单1.3 main函数(第1版)

下面分析代码清单1.3。

·第3行: MaQueOS实现了一个由显示器和键盘组成的控制台。调用con_init函数对控制台进行初始化。con_init函数的实现详见代码清单1.4。

·第4行: 调用printk函数,在显示器上显示字符串“hello,world.”。显示过程详见1.2.1节。

·第5~6行: 进入死循环。

代码清单1.4 con_init函数(第1版)

第5~6行 中,MaQueOS定义了2个全局变量:x和y(具体定义见第1行),用于指示下一个显示字符在显示器上的坐标。在con_init函数中,将x和y变量初始化为0,即控制台初始化完成后,第1个显示字符在显示器上的坐标为(0,0)。

1.2.1 显示字符串

在显示器驱动程序中,printk函数用于将指定的字符串显示到显示器上,显示位置由(x,y)坐标指定。printk函数的参数为需显示字符串的起始地址。printk函数的实现详见代码清单1.5。本节以在main函数中调用printk函数显示字符串“hello,world.”为例,分析printk函数的处理过程。

代码清单1.5 printk函数

下面分析代码清单1.5。

·第14~15行: 通过while循环计算字符串的长度,计算得到字符串“hello,world.\n”的长度为14,其中字符“\n”为换行符(ASCII值为10)。

·第16行: 调用erase_char函数擦除光标,具体擦除过程详见1.2.2节。光标由字符“_”表示,用于指示下一个显示字符在显示器上的位置。因此,在显示字符前,需要先将光标清除。

·第17~34行: 循环遍历字符串中的所有字符,根据字符的ASCII值进行相应的处理。其中,第19行表示从字符串中获取待处理字符的ASCII值。

·第20~27行: 若该字符为可显示字符(ASCII值为32~126),则调用write_char函数(第22行)将字符直接显示在显示器上,显示过程详见1.1.2节。 第23行 表示将显示器上当前行已显示字符的个数保存到sum_char_x数组中,每行对应数组中的1项,总共50项,sum_char_x数组的定义详见第7行。在 第24行 中,将列数加一。在 第25~26行 中,若该字符为当前行的最后一个字符,则调用cr_lf函数进行回车换行处理,处理过程详见1.2.3节。

·第28~29行: 若该字符为换行符(ASCII值为10)或回车符(ASCII值为13),则调用cr_lf函数进行处理。当字符串“hello,world.”被处理到最后一个字符“\n”时,调用cr_lf函数进行回车换行处理。

·第30~31行: 若该字符为删除符(ASCII值为127),则调用del函数进行处理,处理过程详见1.2.5节。

·第32~33行: 若该字符不属于以上情况,则视为不可识别字符,调用panic函数显示错误信息,处理过程详见1.2.6节。

·第35行: 当字符串处理结束后,调用write_char函数在字符串末尾显示光标,并指示下一个显示字符在显示器上的位置。

1.2.2 字符擦除

字符擦除函数erase_char用于擦除显示器上给定坐标(xx,yy)处的字符。erase_char函数的实现详见代码清单1.6。所谓擦除,就是将像素绘制成背景色(黑色)。

代码清单1.6 erase_char函数

下面分析代码清单1.6。

·第12行: 获取待擦除字符的起始像素在显存中的起始地址,计算过程详见代码清单1.2的第14行。

·第13~23行: 按行循环遍历待擦除字符的像素,共遍历16行。在 第15~21行 中,每行按列循环遍历待擦除字符的像素,共遍历8个像素。将每个像素在显存中的(B,G,R)对应的字节设置为(0,0,0),表示将该像素绘制为黑色。在 第22行 中,每行遍历结束后,重新获取字符下一行像素的起始像素在显存中的起始地址。

1.2.3 回车换行

对回车换行的处理由函数cr_lf实现,cr_lf函数的实现详见代码清单1.7。

代码清单1.7 cr_lf函数

下面分析代码清单1.7。

·第7行: 将列坐标x清0,实现回车处理。

·第8~11行: 进行换行处理。在 第8~9行 中,若当前行不是显示器的最后一行,则通过将行坐标y加1,实现换行处理。在 第10~11行 中,若当前行是显示器的最后一行,则需要调用scrup函数进行卷屏处理,处理过程详见1.2.4节。

1.2.4 卷屏

当显示内容超出显示器最后一行时,需要调用scrup函数进行卷屏处理。卷屏的主要处理过程是将显示器第1~49行的内容分别复制到第0~48行中,并将第49行的内容擦除。scrup函数的实现详见代码清单1.8。

代码清单1.8 scrup函数

下面分析代码清单1.8。

·第15行: 获取显示器第0行第0列字符的起始像素在显存中的地址0x40000000。

·第16行: 获取显示器第1行第0列字符的起始像素在显存中的地址0x40000000+(16×1280×4)=0x40014000,计算过程详见代码清单1.2的第14行。

·第17~18行: 将显示器第1~49行中所有像素在显存中的内容,以字节大小为单位(每个像素对应4字节)复制到第0~48行对应的显存中,需要复制的字节总数为(800-16)×1280×4=4014080。

·第19~20行: 循环调用erase_char函数,擦除第49行中的160个字符。

·第21~22行: 将显示器第1~49行在数组sum_char_x中对应项的值分别复制到第0~48行对应的项中。

·第23行: 将显示器最后一行在数组sum_char_x中的对应项清0。

1.2.5 删除字符

对字符的删除处理由函数del实现,del函数的实现详见代码清单1.9。

代码清单1.9 del函数

下面分析代码清单1.9。

·第3~7行: 此时坐标(x,y)指向光标所在的位置,若光标不位于行首,则在 第5行 中,对列坐标x减1后,坐标(x,y)指向待删除的字符。在 第6行 中,更新sum_char_x数组。

·第8~13行: 若光标位于行首,并且不在首行,表示待删除字符是上一行的最后1个字符(由sum_char_x数组指定),则在 第10行 中将当前行的字符数清0,在 第11行 中将行坐标减1,在 第12行 中从sum_char_x数组获取待删除字符的行坐标。此时,坐标(x,y)指向待删除的字符。

·第14行: 调用erase_char函数,删除待删除字符。删除过程详见1.2.2节。此时,坐标(x,y)指向下一个显示字符在显示器上的位置。

1.2.6 panic函数

当系统发生错误需要终止运行时,调用panic函数显示出错信息,并进入死循环。panic函数的实现详见代码清单1.10。

代码清单1.10 panic函数

下面分析代码清单1.10。

·第3行: 调用printk函数显示错误信息,显示过程详见1.2.1节。

·第4~5行: 进入死循环。 1h5K0D6rPxDYvWNs6Dh+sGeGWoRwNOfZJ3i5rCiw4W2o6Qjgx0nDJ+b4nztqniaM

点击中间区域
呼出菜单
上一章
目录
下一章
×