“屏幕“的实现_程序中如何将数据映射到硬件_C++实战
前言
程序里的数据,最后都需要将数据对象写入硬件.C/C++最大的优势体现也是在这里,他既是高级语言方便被程序员使用,又能和硬件沟通.
引入
以"屏幕"的实现,总结数据映射到硬件的代码写法
分析
软件部分
1.屏幕是数据对象---一切都是数据,一切都是对象;数据有类型,屏幕的类型是什么呢?矩阵类图形对象
2.屏幕有大小,比如4K屏,2K屏,分辨率有区别,即宽度和高度有差别,这点可以用形参大小来表达.
硬件部分
懂一点单片机的会知道,硬件是由硬件寄存器来控制的.给硬件寄存器发出脉冲信号0或者1,硬件会做对应的动作,也就是说做以下假设:
1.假设屏幕是2K显示器,分辨率为2560×1440.表示长度方向上每行有2560个点,高度方向有1440行.
2.假设每个数据点有3个16位硬件寄存器,分别表示红色,绿色和蓝色(rgb).那么他们占据的空间是2560x1440x3x2(字节)=22118400,约等于21MB.
3.假设每个点硬件寄存器地址按照红绿蓝依次排列表示,对应于在内存中的起始地址为0x60000000的连续地址.例如:第一个点的红色寄存器地址是0x60000000,第一个点的绿色寄存器地址则为0x60000002,依次类推.
----笔者几乎可以肯定,硬件寄存器也是遵照这个规律排布.
代码
思路:数据对象两个要求---对应地址,以及是矩阵类图形对象.
======================内容分割线===========================================
通常想到的写法是先生成一个对象,再遍历对象中的元素并赋值,如下:
//方案一
struct Matrix screen; //生成屏幕对象
short *p=(short *)0x60000000; //建立地址映射for(auto snd=screen.begin();snd!=screen.end();snd++)for(auto sndd=(*snd).begin();sndd!=(*snd).end();sndd++){*p=(*sndd).red;p+=2; //指针移动2*p=(*sndd).green;p+=2;*p=(*sndd).blue;p+=2;}
这种写法是将已有的screen对象的值写入硬件寄存器,没有达到直接映射的目的.
======================内容分割线===========================================
次日更新
昨天写的有点问题,原来的内容如下:
======================内容分割线↓以下内容有问题==============================
屏幕有多个尺寸,写个函数(或者对象方法)表达.
//屏幕对象的实现--草稿
Matrix& makeScreen(short length,short height){short *p=(short *)0x60000000;Matrix tmp_mx; //临时矩阵vector<Reg_point> tmp_rp; //临时行for(short i=0;i<height;i++)for(short j=0;j<length;j++){short red=*p;p+=2;short green=*p;p+=2;short blue=*p;p+=2;tmp_rp.push_back(Reg_point{red,green,blue}); //建立一行}tmp_mx.matrix.push_back(tmp_rp); //建立矩阵return tmp_mx;
}//规则点类--借用
struct Reg_point{short red;short green;short blue;
}//矩阵图形类定义--部分
struct Matrix : public Reg_pic {vector<vector<Reg_point>> matrix;
};
写完后发现了硬编码,修改如下:
//屏幕对象的实现
Matrix& makeScreen(short length,short height,long addr){short *p=(short *)addr; //建立地址映射Matrix tmp_mx; //临时矩阵vector<Reg_point> tmp_rp; //临时行for(short i=0;i<height;i++)for(short j=0;j<length;j++){short red=*p;p+=2;short green=*p;p+=2;short blue=*p;p+=2;tmp_rp.push_back(Reg_point{red,green,blue}); //建立一行}tmp_mx.matrix.push_back(tmp_rp); //建立矩阵return tmp_mx; //返回矩阵对象
}
======================内容分割线↑以上内容有问题==============================
以下是修改后的内容
//屏幕对象的实现
Matrix& makeScreen(short length,short height,long addr){short *p=(short *)addr; //建立地址映射Matrix tmp_mx; //临时矩阵vector<Reg_point> tmp_rp; //临时行for(short i=0;i<height;i++)for(short j=0;j<length;j++){short *red=p;p+=2;short *green=p;p+=2;short *blue=p;p+=2;tmp_rp.push_back(Reg_point{*red,*green,*blue}); //建立一行}tmp_mx.matrix.push_back(tmp_rp); //建立矩阵return tmp_mx; //返回矩阵对象
}
修改说明:
1>先前没想明白怎样把数据写入具体地址.代码中的写法应该是这样的:
short *red=p;
思路是:先让变量p地址指向具体某个地址a,然后给变量p赋值时,自动写入地址a中
2>因为第一次遇见这种情况,也是一个典型错误,所以留下错误代码做个对比.
错误原因:把因果关系弄混了.错误代码中写的是
short red=*p;
表示把硬件寄存器中的值写入矩阵对象的点颜色,那么当外部操作Matrix对象时, 不会改变硬件寄存器内容
以下继续
现在传入参数,生成2K屏幕对象:
//伪代码
Matrix screen_2k=makeScreen(2560,1440,addr); //addr是虚拟地址,需要操作系统提供;
代码说明
1>中间部分有些重复的代码(p+=2),因为用不了p++,所以不够优雅不过问题也不是很大
2>代码重点在于必须首先表达地址映射,再生成对象.做个类比:
//建立一个表示人的类,c语言表示
struct Person{char* name;double money;
}struct Person persons[1]={{"小张",50000},{"小王",52000}};
建立一个数据对象,可以传入参数,或者先生成对象,再给对象属性赋值,这种写法很优雅看起来舒服,也是常用的,但不适合用在硬件驱动上.如果采用方案一,他不是直接把数据映射到硬件,而是把程序员认为的一个矩阵图形类对象写入硬件中,多了一步操作,对于系统开销可能是巨大的.
还有一种方式,像是"数据倒装" 进了数据对象中,这是硬件映射使用的.
两种方式在前面帖子中有所提及,是两种数据生成的方法.
3>说到效率问题,C++用来写驱动可能效率也不够高,用C或者汇编更合适,但这不是本贴重点.不管用什么语言写,思路都一样.
4>如果代码还要写得"精致"一些,专门建立一个Screen类,矩阵图形类Matrix是其子类(派生类).感觉这样做得意义也不是很大,暂时没想到会有什么具体影响,所以有个想法就行了.
小结
1>所有的数据映射到硬件,方式都相同.
步骤:指向硬件寄存器所在地址,倒装进数据对象,通过数据对象直接修改硬件数据,实现效果.
2>代码要多写,边写边发现问题边解决.