ARM实验板移植Linux操作系统,LCD显示汉字(名字)

一、实验目的
1.熟悉点阵字库的使用
2.熟悉Linux操作系统的使用
3.熟悉ARM嵌入式系统开发的过程

二、实验内容
1.pc端编写用×和空格显示自己名字的c程序
2.安装交叉编译工具,修改程序,交叉编译
3.制作新的文件系统镜像,烧写。

三、实验设备及工具
硬件:MX1ADS嵌入式实验平台、PC机
软件:Linux操作系统、交叉编译工具

四、实验原理
1.16×16点阵字库HZK16的使用
GB2312规定对收录的每个字符采用两个字节表示,第一个字节为“高字节”,对应94个区;第二个字节为“低字节”,对应94个位。
每个区记录94个汉字,位号为该字在该区中的位置。
区码:汉字的第一个字节 - 0xA0 (因为汉字编码是从0xA1区开始的,要算出相对区码)位码:汉字的第二个字节 - 0xA0
汉字在HZK16中的绝对偏移位置:offset =[94×(区号-1)+(位号-1)]×一个字模占用的字节数。
2.MX1 ADS液晶显示的硬件结构
MX1 ADS附带的是一块Sharp的TFT显示屏,分辨率320*240, 16位真彩色。每个像素点对应于一个16位色彩描述存储器,颜色描述方式为R5G6B5。
3.BSP-Linux的显示结构
在MX1 ADS上运行的操作系统是BSP-Linux0.3.6(Kernel 2.4.18)。该系统使用的显示驱动是FrameBuffer。
在FrameBuffer驱动模式下,系统将显示设备映射成文件描述符(/dev/fb0)。应用程序只需打开这个文件,调用mmap()将显示存储器映射为用户空间的内存后,即可在用户空间对现存直接进行读/写

五、实验步骤
1.Linux系统上编写输出自己名字的c程序
代码如下

#include <stdio.h>
#include <stdlib.h>
void LCD_ShowChar(unsigned char *word)
{
    FILE* fphzk = NULL;
    int i, j, k, p, offset;
    int flag;
    unsigned char buffer[32];
    fphzk = fopen("HZK16", "rb");
    if(fphzk == NULL){
        fprintf(stderr, "error hzk16\n");
    }
    offset = (94*(unsigned int)(*word-0xa0-1)+(*(word+1)-0xa0-1))*32;
    fseek(fphzk, offset, SEEK_SET);//SEEK_SET(对应 0):文件开头
    fread(buffer, 1, 32, fphzk);
   //const void *buffer 为指向二进制数据来源的指针;size_t size 为每个数据单元所占的字节数;
   //size_t num 为需要读取的数据单元的个数;FILE *stream 为目的文件指针
    for(j=0; j<16; j++){
	    printf("\n");
	    for(i=0; i<2; i++){
	         for(k=0; k<8; k++){
	         flag = buffer[j*2+i]&(0x80>>k);
	         printf("%s", flag?"* ":"  ");}
	    }
    }
    fclose(fphzk);
    fphzk = NULL;
}
void LCD_ShowString(unsigned char *p)
{
     while(*p>0)
     {
          LCD_ShowChar(p);
	      p=p+2;
     }
}
int main(void)
{
     LCD_ShowString((unsigned char*)"张三李四");//此处写自己的名字或者任意汉字组合
     system("pause");
     return 0;
}

2.在Linux系统中建立交叉编译环境并修改程序
(1)解压交叉编译工具
①将armLinuxXToolChain.tar.gz(arm-linux 交叉编译工具)复制到 /usr/local 目录(注意一定要用老师的低版本交叉编译器,不要自己在网上下载)
②终端"cd" 到 /usr/local (意思是所有的命令都要在对应的路径输入,否则会提示找不到文件)
③执行 “tar -xzf armLinuxXToolChain.tar.gz” 命令解压缩
(2)配置环境变量
①打开环境变量文件:sudo gedit /etc/profile
②增加路径设置,在末尾添加如下:

export PATH=$PATH:/usr/local/bin
export PATH=$PATH:/usr/local/arm/bin

③注册环境变量:source /etc/profile
④测试是否安装成功:在终端里输入arm-linux-gcc -v
在这里插入图片描述
(3)修改代码(先编译执行之前的c代码之后再进行这一步,编译执行的命令请看下一步)
要在LCD上显示需要将printf语句改成在对应地址写寄存器值。首先打开FrameBuffer驱动:fd_fb = open("/dev/fb0", O_RDWR),然后使用mmap()函数映射显示寄存器,返回首地址。
具体代码如下:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>
#include<stdlib.h>
//画笔颜色
#define BLACK        	 0xFFFF
#define WHITE         	 0x0000	  

unsigned short *fb=0;

void LCD_ShowChar(int x,int y,unsigned char *word)
{
    FILE* fphzk = NULL;
    int i, j, k, p, offset;
    int flag;
    unsigned char buffer[32];
    fphzk = fopen("HZK16", "rb");
    if(fphzk == NULL){
         fprintf(stderr, "error hzk16\n");
    }
    offset = (94*(unsigned int)(*word-0xa0-1)+(*(word+1)-0xa0-1))*32;
    fseek(fphzk, offset, SEEK_SET);//SEEK_SET(对应 0):文件开头
    fread(buffer, 1, 32, fphzk); 
    for(j=0; j<16; j++){
       printf("\n");
	   for(i=0; i<2; i++){
	        for(k=0; k<8; k++){
	      	   flag = buffer[j*2+i]&(0x80>>k);
	      	   printf("%s",flag?"* ":"  ");
	      	   if(flag==1){
		     	  *(fb+(j+y)*240+x+i*8+k) = WHITE;}
	        }
	   }
    }
     fclose(fphzk);
     fphzk = NULL;
}
void LCD_ShowString(int x,int y,unsigned char *p)
{
     while(*p>0)
     {
          LCD_ShowChar(x,y,p);
	      p=p+2;
	      x=x+20;
     }
}
int main(void)
{
     int fd_fb=0;
     int x,y;
     fd_fb=open("/dev/fb0",O_RDWR);
     fb=(unsigned short*)mmap(0,240*320*2,PROT_READ|PROT_WRITE,MAP_SHARED,fd_fb,0);
     for(y=0;y<320;y++){
		for(x=0;x<240;x++)
		{*(fb+y*240+x) = BLACK;}
     }
     LCD_ShowString(30,30,(unsigned char*)"张三李四");}

(4)交叉编译
(所有命令行均在该文件夹路径下执行)
对于修改前的代码:
①使用gcc编译:gcc -o display display.c 报错则修改,不报错则继续执行下一步
②执行编译文件:./display
对于修改后的代码:
①使用gcc编译:gcc -o display1 display1.c 报错则修改,不报错则继续执行下一步
②使用arm-linux-gcc编译:arm-linux-gcc -o display1 display1.c
3.制作新的文件系统镜像并烧写
(1)生成root文件系统
①将root文件系统镜像Mount(挂载)到一个空目录(disk),使用如下命令:mount –t cramfs –o loop root.cramfs disk
②将disk目录内的整个root文件系统复制到一个新文件夹newdisk:将挂载后的文件夹在终端打开,输入sudo nautilus获得最高管理员权限,在弹出的文件窗口中操作即可(否则将没有复制权限)
③确定完整无误地复制了root文件系统后,Unmount(卸载)disk 内的文件系统,使用命令如下:
umount disk
④修改newdisk文件夹下所有文件的权限:
chmod -R 777 newdisk/
⑤将经过交叉编译的目标文件display及HZK16字库文件复制到newdisk的bin文件夹中(确保复制后两文件权限为可读写)
⑥使用如下命令生成一个新的 root 文件系统镜像:
mkcramfs newdisk newroot.cramfs
⑦修改newroot的权限:
chmod 777 newroot.cramfs
(2)烧写
将newroot.cramfs文件拷贝至老师电脑某文件夹下,按照第一个实验的第三步(文件系统镜像烧写)进行烧写
①新建超级终端,恢复默认值,码率选择115200,上电
②输入2(文件系统镜像烧写)
③插拔usb激活
④将文件系统镜像文件拷贝到u盘里
⑤弹出u盘(文件拷贝结束的标志)
⑥按任意键开始烧写
⑦烧写结束后按复位键进入文件系统

最终结果
并没有显示成功,显示的位置和大小都对,但是没有显示全,不知道问题出在哪里

还有一个我写的比较高大上的代码,但是也出错了(段错误 访问的内存超出了系统所给这个程序的内存空间)

#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>
#include <stdlib.h>

//画笔颜色
#define WHITE         	 0xFFFF
#define BLACK         	 0x0000	  
#define BLUE         	 0x001F  
#define BRED             0XF81F
#define GRED 		     0XFFE0
#define GBLUE		     0X07FF
#define RED           	 0xF800
#define MAGENTA       	 0xF81F
#define GREEN         	 0x07E0
#define CYAN          	 0x7FFF
#define YELLOW        	 0xFFE0
#define BROWN 		     0XBC40 //棕色
#define BRRED 		     0XFC07 //棕红色
#define GRAY  		     0X8430 //灰色
//画笔颜色
unsigned short POINT_COLOR = 0x0000;
//首地址
unsigned short *start_addr;
void LCD_DrawPoint(unsigned short x,unsigned short y,unsigned short color)
{
     *(start_addr+x+y*240) = color;
}
//清屏函数
//color:要清屏的填充色
void LCD_Clear(unsigned short color)
{
    unsigned short x,y;
    for(y=0;y<320;y++)
    {
	    for(x=0;x<240;x++)
	    {
	         LCD_DrawPoint(x,y,color);
	    }
    }
} 
void LCD_ShowChar(unsigned short x,unsigned short y,unsigned char *word,unsigned char mode)
{
    FILE* fphzk = NULL;
    int i, j, k, p, offset;
    int flag;
    unsigned char buffer[32];
    fphzk = fopen("HZK16", "rb");
    if(fphzk == NULL){
         fprintf(stderr, "error hzk16\n");
    }
    offset = (94*(unsigned int)(*word-0xa0-1)+(*(word+1)-0xa0-1))*32;
    fseek(fphzk, offset, SEEK_SET);//SEEK_SET(对应 0):文件开头
    fread(buffer, 1, 32, fphzk);//const  void *buffer 为指向二进制数据来源的指针;size_t size 为每个数据单元所占的字节数;size_t num 为需要读取的数据单元的个数;FILE *stream 为目的文件指针
    if(mode == 0)
    {
    	for(j=0; j<16; j++){
	     y++;
	     for(i=0; i<2; i++){
	      	  for(k=0; k<8; k++){
                   x++;
	               flag = buffer[j*2+i]&(0x80>>k);
	               if(flag == 1)
	               {	   
	                    LCD_DrawPoint(x,y,POINT_COLOR);
	               }  
	          }  
	      }
        }
    }
    else if(mode == 1)
    {
        for(j=0; j<16; j++){
             x--;
             for(i=0; i<2; i++){
                  for(k=0; k<8; k++){
		               y++;
                       flag = buffer[j*2+i]&(0x80>>k);
                       if(flag == 1)
                       {           
                            LCD_DrawPoint(x,y,POINT_COLOR);
		               }  
		          }  
	         }          
	     }
    }
     fclose(fphzk);
     fphzk = NULL;
}
void LCD_ShowString(unsigned short x,unsigned short y,unsigned char *p,unsigned char mode)
{
     if(mode == 0)
     {
          while(*p>0)
          {
               LCD_ShowChar(x,y,p,mode);
	           p=p+2;
	           x=x+20;
          }
     }
     if(mode == 1)
     {
          while(*p>0)
	      {
	           LCD_ShowChar(x,y,p,mode);
	           p=p+2;
               y=y+20;
	      }
     }
}

int main(void)
{
     //init();
     unsigned char x = 0;
     int fd;
     int i,a;
     int delay = 100000000;//100M 
     //使用mmap函数返回首地址
     fd = open("dev/fb0",O_RDWR);
     start_addr = (unsigned short*)mmap(0,240*320*2,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
     while(1)
     {
     	  switch(x)
		  {
			case 0:LCD_Clear(WHITE);break;
			case 1:LCD_Clear(BLACK);break;
			case 2:LCD_Clear(BLUE);break;
			case 3:LCD_Clear(RED);break;
			case 4:LCD_Clear(GREEN);break;
			case 5:LCD_Clear(YELLOW);break;
			case 6:LCD_Clear(GRAY);break;
			case 7:LCD_Clear(BROWN);break;
		  }
		  x++;
		  if(x==8)x=0;
	     	  LCD_ShowString(30,30,(unsigned char*)"张三李四",0);//横屏
		  LCD_ShowString(50,50,(unsigned char*)"张三李四",1);//竖屏
		  //延时函数
		  for(i=0;i<delay;i++)
		  {
		  	  a = a;
		  }
	 }

}

几点注意的地方

  1. 一定要修改所有文件的权限 比如disk、newdisk下所有文件、newroot.cramfs、编译文件等
    chmod 777 文件名 为单独修改某文件读写权限命令
    chmod -R 777 文件名/ 为修改该文件夹下所有文件权限的命令
  2. 交叉编译器一定要用老师的
  3. 第一行第二列位置为fb+1而非fb+2(代码中+1,实际的内存地址+2)不信可以自己在vc上写个测试代码看下地址的变化
  4. gcc -o可在pc端执行 arm-linux-gcc -o只能在arm端执行
  5. 输入sudo nautilus获得最高管理员权限,在弹出的文件窗口中操作,可以解决root解决不了的问题

有问题可以随时给我留言

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值