【基于6818的智能家居系统】

开发环境:Ubuntu、SourceInsight、SecureCRT
文章中的不是完整代码,仅是部分摘录
源码放最后了,需要自取

交叉编译:

在一个环境下编译生成 适用于 另一个环境下运行的可执行文件 的过程
Linux -----> ARM

为交叉编译工具创建软连接:
sudo ln -s /usr/lib/x86_64-linux-gnu/libmpfr.so.6/usr/lib/x86_64-linux-gnu/libmpfr.so.4
使用 arm-linux-gcc 来进行编译

arm-linux-gcc xxx.c ---> 默认生成的可执行文件 名为 a.out
arm-linux-gcc yyy.c -o yy ---> 生成指定名为 yy 的可执行文件
此时 a.out和yy 只能在ARM开发板上运行

串口终端软件 SecureCRT

连接开发板步骤
1)打开设备管理器 查看端口号(COM X)
2)打开SecureCRT 点击快速连接
协议:Serial
端口: 端口号选择自己查看到的端口号
波特率:115200
数据位:8
奇偶校验位:none
停止位:1
把流控选项的所有√去掉
点击连接 出现绿色的√则表示连接成功
若CRT没有数据 则重启开发板
重启后 终端上会出现启动信息 并且会出现命令行[root@GEC6818 /]#
若没有出现而是出现err = 0 则回车按ctrl+C 出现[root@GEC6818 /]#即可
3)下载可执行文件到开发板上
rx 文件名 --》 回车 --》 点击 传输 --》 选择 发送Xmodem --》
–》 选择要下载的文件 --》 发送
给可执行文件加权限
r 读
w 写
x 执行
加执行的权限:
chmod +x 文件名 或者 chmod 0777 文件名

LCD显示屏

原理:
LCD屏幕的分辨率: 800480
分辨率:单位面积内的像素点的个数
800
480 --》 一行有800个像素点, 总共有480行
像素点 pixel
像素点能够显示某种颜色的点
在屏幕上显示一个颜色,就是给对应的像素点 一个颜色值即可
LCD屏幕的每一个像素点 占4个字节 --》 a r g b a:透明度

           int color;  
			color = 0xFF0000;     //红色 

帧缓冲

是底层专门用来操作屏幕的,开发板上屏幕对应的设备文件路径名为 /dev/fb0
只需要把颜色值 写入到 /dev/fb0 文件中,底层驱动就会把屏幕上对应的像素点显示对应的颜色

文件IO

IO: input / output
文件IO:对于文件的读/写操作
Linux的核心:
Everything is a file, in Linux. 在Linux下,一切皆文件
所有的东西的操作 都是对文件的操作,或者说 操作任何的东西 都是通过文件的接口来实现的

文件操作的步骤:

    打开文件 open() 
    操作文件 read() / write() / .... 
    关闭文件 close()

1)打开文件 open
int open(const char *pathname, int flags);
功能: 打开或者创建一个文件
参数:
pathname:指定要打开的文件的路径名(不带路径 则默认当前路径)
flags:打开文件的标志
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
返回值:
int类型 文件描述符fd
如果一个文件被成功打开,那么就可以用一个int类型的整数来表示整个文件 ,后续对于该文件的所有操作 都是去操作这个整数
失败 返回-1
2)操作文件
2.1)写 write
ssize_t write(int fd, const void *buf, size_t count);
功能: 往一个文件描述符中去写入数据
参数:
fd:指定要写入的那个文件的文件描述符
buf:void * 通用指针 ,指定的空间 保存要写入的数据
count: 指定你要写入多少个字节数
返回值:
成功,返回实际写入的字节数
失败,返回-1
3)关闭文件 close
int close(int fd);

  • 功能:关闭一个文件描述符
  • 参数:
    • fd:指定要关闭的文件的文件描述符
    • 返回值:
      • 成功,返回0
      • 失败,返回-1
    • IO效率不高:
      • 拷贝内存耗时间
      • write是系统调用的函数,函数调用本身会有开销
      • 且 系统状态(用户态和内核态)的切换也会有开销

内存映射

Frame Buffer 本身就是一块内存,在C语言中只要知道一个内存地址,            就可以通过指针去操作这个内存 
Linux操作系统提供了一个接口: 
内存映射 Memory Map 

映射 mmap
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
功能:映射一个文件或者设备到内存
参数:
addr:地址,指定要映射到内存的哪个地址上去 ,一般 填 NUL,表示让系统自行分配
length:指定要映射多大的内存空间,单位:字节 (8004804 )
prot: 指定映射区的权限
PROT_EXEC 可执行
PROT_READ 可读
PROT_WRITE 可写
PROT_NONE 没有权限
读写:PROT_READ | PROT_WRITE
flags: 映射标志
MAP_SHARED 共享映射,对映射区的操作会立即反馈到文件中
MAP_PRIVATE 私有映射,对映射区的操作仅对代码可见
fd:指定要映射的文件的描述符
offset:偏移量,要从文件的哪个位置开始映射,一般为 0 , 表示从文件开头的位置映射
返回值:
成功,返回映射区的首地址
失败,返回 MAP_FAILED
解除映射 munmap
int munmap(void *addr, size_t length);
功能:解除映射
参数:
addr: 指定要解除映射区的首地址,即mmap的返回值
length:指定要解除映射的空间的大小 8004804
返回值:
成功,返回0
失败,返回-1

bmp图片

bmp --> bitmap位图文件,是由Microsoft发明的一种无压缩的图片文件格式,每一个像素点的原始数据都保存图片文件中
bmp图片文件的格式
1)BITMAP文件头
保存文件的魔数、大小等数据
固定占14个字节
2)DIB头
保存图片的宽、高、色深等数据
固定占40个字节
宽度 width
偏移量: 0x12
占4个字节


             int width = 0;
             lseek( fd, 0x12, SEEK_SET );
             read( fd, &width, 4 );
             
         >0 每一行的像素点数据 从左至右存放的
         <0 每一行的像素点数据 从右至左存放的 
        高度 height 
            偏移量: 0x16 
            占4个字节 
         inr height = 0;
         >0 从下至上 保存每一行的像素点数据 
          <0 从上至下 保存每一行的像素点数据
        色深 depth 
            每个像素点所占的bit位数 
            偏移量: 0x1C 
            占2个字节 
          short depth = 0;
          depth == 24     24位bmp图片 
          depth == 32     32位bmp图片

字模软件

在屏幕上 显示字符(数字、汉字、字母等),笔画经过的地方 显示颜色, 没有经过的地方就不显示 
点阵液晶取模软件 :这个软件 把字符 转换成 一些十六进制的取模数据 

一个数据 占1个字节(8bits),对应了8个像素点
例如:宽x高 --》24x31
–》生成的取模数据的总字节数: (24/8) * 31 == 93
取模方式:
横向取模:
从上至下,从左至右
高位优先,先扫描的点 保存在数据的高位

显示字符

显示: 就是相反的操作 --》 把取模数据 还原成 字符形状
1)首先要把这些取模数据 保存起来
二维数组
unsigned char word[h][w/8]
2)显示
解析数据的每一个bit位,为1就显示颜色,为0就不显示

触摸屏

“输入设备” : 键盘、鼠标、触摸屏、 ... 

内核要监听这些“输入设备”上的事件(Event),当我们去触摸屏幕、点击鼠标、按下按键… 操作输入设备时 ,就会产生相应的输入事件
输入事件: Linux下 触摸事件、鼠标事件、按键事件等
这些输入设备 在Linux下 对应的设备文件名为
/dev/input/eventX (X=0,1,2,…)
开发板上,触摸屏对应的设备文件名为
/dev/input/event0
Linux输入设备的基本原理
经过内核驱动以及输入子系统的处理之后,会把输入设备上产生的输入事件的信息,保存在对应的设备文件中(如:/dev/input/event0 )
不同的输入设备 对应输入事件是不同的,但是 Linux操作系统用了一个标准的事件结构体来描述输入事件

   struct input_event {
        struct timeval time;    //事件发送的时间 
        __u16 type;     //事件的类型 
        #define EV_SYN  0x00        同步事件 
        #define EV_KEY  0x01        按键事件
        #define EV_REL  0x02        相对事件(鼠标事件)
        #define EV_ABS  0x03        绝对事件(触摸事件)

        __u16 code;     //事件的编码,根据type的不同 而有不同的含义 
        当 type == EV_ABS 时, code表示坐标轴
        code == ABS_X   //x轴   #define ABS_X  0x00
        code == ABS_Y   //y轴   #define ABS_Y  0x01
        code == ABS_PRESSURE    //触摸屏压力事件 
                                                                #define ABS_PRESSURE  0x18

        当 type == EV_KEY 时, code表示键值 
           KEY_A
           KEY_B
             ...
           BTN_TOUCH  --> 把整个屏幕当作是一个按键来使用 

         __s32 value;    //事件的值, 根据type的不同 而有不同的含义 
        当 type == EV_ABS 时, value坐标轴的值 
           code == ABS_X   //x轴的坐标
           code == ABS_Y   //y轴的坐标 
           code == ABS_PRESSURE    //压力值 
                               == 0    触摸屏弹起 
                               >0      触摸屏按下 

        当 type == EV_KEY 时,value表示按键的状态 
                               1   按键按下 
                               0   按键松开     
};

GY39传感器

传感器和开发板的通信方式: 串口
//6818开发板对应的串口
#define COM2 "/dev/ttySAC1"
#define COM3 "/dev/ttySAC2"
#define COM4 "/dev/ttySAC3"

串口的初始化

            int init_serial(const char *file, int baudrate)
            { 
                int fd; 
                fd = open(file, O_RDWR);
                if (fd == -1)
                {
                    perror("open device error:");
                    return -1;
                }
                struct termios myserial;
                //清空结构体
                memset(&myserial, 0, sizeof (myserial));
                //O_RDWR               
                myserial.c_cflag |= (CLOCAL | CREAD);
                //设置控制模式状态,本地连接,接受使能
                //设置 数据位
                myserial.c_cflag &= ~CSIZE;   //清空数据位
                myserial.c_cflag &= ~CRTSCTS; //无硬件流控制
                myserial.c_cflag |= CS8;      //数据位:8
                myserial.c_cflag &= ~CSTOPB;//   //1位停止位
                myserial.c_cflag &= ~PARENB;  //不要校验
                //myserial.c_iflag |= IGNPAR;   //不要校验
                //myserial.c_oflag = 0;  //输入模式
                //myserial.c_lflag = 0;  //不激活终端模式
                switch (baudrate)
                {
                    case 9600:
                        cfsetospeed(&myserial, B9600);  //设置波特率
                        cfsetispeed(&myserial, B9600);
                        break;
                    case 115200:
                        cfsetospeed(&myserial, B115200);  //设置波特率
                        cfsetispeed(&myserial, B115200);
                        break;
                    case 19200:
                        cfsetospeed(&myserial, B19200);  //设置波特率
                        cfsetispeed(&myserial, B19200);
                        break;
                } 
                /* 刷新输出队列,清除正接受的数据 */
                tcflush(fd, TCIFLUSH);
                /* 改变配置 */
                tcsetattr(fd, TCSANOW, &myserial);
                return fd;
            }

线程

进程: 正在运行的程序,是程序的一次活动
线程:线程比进程更加小的活动单位,它进程的执行分支,线程同进程内的其他线程用整个进程的资源,进程有一个主线程,就是main()
创建一个线程
pthread_create()
在pthread中 用类型pthread_t 来表示一个线程的id ,用pthread_attr_t 来描述线程的属性
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void ), void arg);
功能:创建一个新线程
参数:
thread:地址,指向的空间用来保存新线程的id
attr:指定新线程的属性 ,一般为 NULL , 表示默认属性
start_routine:函数指针,它指向 返回值为void
且带有一个void
参数的函数,即 线程函数
线程函数的类型应该为:
void * xxx( void * arg )
{
}
arg: 线程函数的参数
返回值:
成功,返回0
失败,返回一个错误的值
注意:
Compile and link with -pthread.
编译时 需要链接库 -pthread
线程一旦创建成功,线程函数就会立即被指向

打开显示屏屏幕

int fd =-1;
int * plcd = NULL;  //帧缓冲的首地址 
int size = 800*480*4;

void lcd_init()
{ 
	 fd = open("/dev/fb0" , O_RDWR);
		if( fd == -1)
		{
			perror("open /dev/fb0  error"); // 打开文件出错
			//关闭文件
			close(fd);	
			return ;
		}
	//内存映射
	plcd = mmap(NULL, size, PROT_READ | PROT_WRITE,  MAP_SHARED, fd, 0);
	

}

关闭屏幕 
 void lcd_close()
 {
	 //解除映射 
	 munmap(plcd,size );
	 //关闭屏幕
	 close(fd);	
 }

在显示屏上画点 x 表示列 y表示行(共有800列 480行)

void display_point( int x, int y, int color )
{
    if( x>=0 && x<800 && y>=0 && y<480 )
    {
        *( plcd + y*800 + x ) = color;
    }
}

在显示屏上画矩形

void draw_Rectangle(int a1,int a2,int b1,int b2,int color )
{
	for(int i=a1;i<=a2;i++)
	{
		for(int j=b1;j<=b2;j++)
		{
			display_point(i, j, color);
		}
	}
}	

在显示屏上显示一张纯色的图片(清屏)

void show_a_color( int color )
{
	for(int j=0;j<480;j++)
	{
		for(int i=0;i<800;i++)
		{
			display_point(i, j, color);
		}
	}
}

显示BMP图片

int show_bmp(int x0,int y0,char *filename)
	{
	//打开图片
		int fd = open(filename , O_RDWR);
			if( fd == -1)
			{
				perror("open pic error");	// 打开图片
				printf("open pic error");
				return -1;
			}
		int width = 0;
		//宽度大于零,像素点从左到右存放,小于零反之
		int height = 0;
		//高度大于零,像素点从下到上存放,小于零反之
		int depth = 0;
		int line_size = 0;
		int laizi = 0;
		int color;
		unsigned b,g,r,a =0;
		int i,j;
		int num = 0;
		lseek(fd,0x12,SEEK_SET);
		read(fd,&width,4);
		lseek(fd,0x16,SEEK_SET);
		read(fd,&height,4);
		lseek(fd,0x1C,SEEK_SET);
		read(fd,&depth,2);
		laizi = 4 - (abs(width)*(depth/8))%4;
			if (laizi == 4)
				{
					laizi = 0;
				}
			line_size = abs(width)*(depth/8) + laizi;
			//把所有像素点都读取出来
			unsigned char buf[abs(height) * line_size];
			lseek(fd,0x36,SEEK_SET);
			read(fd,buf,abs(height) * line_size);//读取
			for(j = y0;j< abs(height) + y0;j++)
			{
				for (i =x0; i < abs(width) +x0; i++)
				{
					b = buf[num++];
					g = buf[num++];
					r = buf[num++];
					if (depth == 32)
					{
						a = buf[num++];
					}
					color = ((a<<24) | (r<<16) | (g<<8)| b);
					display_point(width>0 ? i :abs(width)-1-i, 
						height>0 ? abs(height)-1-j : j,
						color);
				}
				num = num+laizi;//跳过无效数据
			//关闭图片
			close(fd);
	}

字符取模后显示

void show_word(int x0,int y0,int w,int h,unsigned char word[][w/8],int color) 
{
	int i,j ,k;
	for(i=0;i<h;i++)
	{
		for(j=0;j<w/8;j++)
		{
			// 解析word[i][j] 的 8个bit位,为1就显示,为0就不显示
			for(k=7;k>=0;k--)
			{
				if(word[i][j]&(1<<k))
				{
					// 画点
					display_point(j*8+(7-k)+x0,y0+i,color);
				}
			}
		}
	}

}

数字取模后显示

void show_number(int x0,int y0,int num)
{
	int numx[10];
	int i=0;
	while(num/10!=0)
	{
		numx[i++] = num%10;
		num = num/10;
	}
	numx[i++] = num%10; // nu倒序存放
	int ci = i; // 共有i个数
	i--;
	for(int k=1;k<=ci;k++)
	{
		show_word(x0+(k-1)*20, y0, 24, 35, nu[numx[i--]], 0xff0000);
	}

}

获取触摸屏的数据并判断点击了什么开关

void get_touch(void )
{
	 fd = open("/dev/input/event0" , O_RDWR);
	 if( fd == -1)
		{
			perror("open /dev/input  error"); // 打开文件出错
			//关闭文件
			close(fd1);		
		}
	struct input_event  ev; 
	while(1)
	{
		 read(fd,&ev,sizeof(ev));
		 chu = 0;
		 if( ev.type == EV_ABS )     //触摸事件 
		 {
		 	chu = 1;
		 	printf("touch activate1...\n");
		 	if(ev.code == ABS_X) // x轴
		 	{
		 		xx = ev.value;
		 	}
		 	else if( ev.code == ABS_Y  ) //y轴 
            { 
            	yy= ev.value;
            }
            else if( ev.code == ABS_PRESSURE ) //压力事件压力为0 就结束循环
            {
                //压力为0退出 
                if(ev.value == 0)
                {
                  break;
                }
               
            }
	        // 触摸事件中判断点了哪些开关 
	        judge(); 
		 }
		 else if(  ev.type ==EV_KEY )     //按键事件 ,按键松开,就结束循环 
        {
            //value = 0 退出 
            if(ev.value == 0)
            {
                break;
            }
            xx=0;
            yy = 0;
        } 
	}
	close(fd1);
}
void judge()
{
	tempx = xx,tempy =yy;
	printf("x= %d ,y = %d\n",xx,yy);
	 printf("enter judge...\n");
	// 	碰到空调开关
	if(yy>=279&&yy<=321 &&xx>=939 &&xx<= 1005)
	{
		air_flag_hand =1; // 表示
		if(air_flag ==0)
		{
			air_change(1); // 1表示换成开着的图标
			air_flag = 1;
			led_beep_ctrl(BEEP, 1);
			sleep(1);
		led_beep_ctrl(BEEP, 0);
		show_bmp(380, -275,"ktydk.bmp");
			printf("on air\n");
		}
		else
		{ 
			air_change(0);
			air_flag = 0;
			show_bmp(380, -275,"bai.bmp");
			printf("off air\n");
			
		}
	}

	……
	//碰到 灯、窗帘、电视开关代码同上

	// 听歌开关
	if(yy>=200&&yy<=355 &&xx>=450 &&xx<= 750)
	{
		if(aniya_flag == 0)
		{
			system("madplay -Q  xiju.mp3 &");  
			show_bmp(380, -80,"maniya.bmp");
			aniya_flag = 1;
		}
		else
		{
		    system("killall madplay");  
			show_bmp(380, -80,"aniya.bmp");
			aniya_flag = 0;
		}
		
	}
	
}

初始化GY939传感器

int get_gy39()
{ 
	int fd = init_serial( COM2, 9600 );
	 int m = 2;
    char w_buf[][3] ={{0xa5, 0x81, 0x26}, {0xa5, 0x82, 0x27}, {0xa5, 0x83, 0x28}};
    int Lux = 0, T = 0, P = 0, Hum = 0, H = 0;
    int Lux0 = 0, T0 = 0, P0 = 0, Hum0 = 0, H0 = 0;
    unsigned char r_buf[24];
    int r;
   if( fd == -1)
	{
		perror("open uart error"); // 打开文件出错
		//关闭文件
		close(fd);	
	}
   		unsigned char cmd[3] = { 0xA5,0x81,0x26 };
   		int re = write(fd, w_buf[m], 3);
   		if(re == -1) 
   		{
	   		perror("write 1 error:");
   		}
   		usleep(1000);
   while( 1 )
   {
	    r = read(fd, r_buf, 24);
        if (r == 9 && r_buf[2] == 0x15)
        {
            Lux = (r_buf[4] << 24 | r_buf[5] << 16 | r_buf[6] << 8 | r_buf[7]) / 100;
        }
        else if (r == 15 && r_buf[2] == 0x45)
        {
            T = (r_buf[4] << 8 | r_buf[5]) / 100;
            P = (r_buf[6] << 24 | r_buf[7] << 16 | r_buf[8] << 8 | r_buf[9]) / 100;
            Hum = (r_buf[10] << 8 | r_buf[11]) / 100;
            H = (r_buf[12] << 8 | r_buf[13]) / 100;
        }
        else if (r == 24)
        {
            Lux = (r_buf[4] << 24 | r_buf[5] << 16 | r_buf[6] << 8 | r_buf[7]) / 100;
            T = (r_buf[13] << 8 | r_buf[14]) / 100;
            P = (r_buf[15] << 24 | r_buf[16] << 16 | r_buf[8] << 8 | r_buf[9]) / 100;
            Hum = (r_buf[10] << 8 | r_buf[11]) / 100;
            H = (r_buf[12] << 8 | r_buf[13]) / 100;
        }
printf("r = %d Lux = %d, T = %d, P = %d, Hum = %d, H = %d\n",r, Lux, T, P, Hum, H);
        if(Lux!=Lux0)
        {
printf("Lux! = Lux0\n");
show_number_init(3,Lux);
        }
        if(T!=T0)
        {
       		 show_number_init(1,T);
        }
        if(P!=P0)
        {
        		show_number_init(2,P/1000);
        }
        if(Hum!=Hum0)
        {
        		show_number_init(4,Hum);
        }
        if(H!=H0)
        {
        		show_number_init(5,H);
        }
        Lux0 = Lux;T0 = T; P0= P; Hum0 =Hum; H0 = H; 
        sleep(1);
   }
   close(fd);
}

获取GY939传感器的数据并显示

void get_datas(void)
{
r = read(fd6, r_buf, 24);
if (r == 9 && r_buf[2] == 0x15)
	 {
		 Lux = (r_buf[4] << 24 | r_buf[5] << 16 | r_buf[6] << 8 | r_buf[7]) / 100;
	 }
	 	else if (r == 15 && r_buf[2] == 0x45)
	 {
		 T = (r_buf[4] << 8 | r_buf[5]) / 100;
		 P = (r_buf[6] << 24 | r_buf[7] << 16 | r_buf[8] << 8 | r_buf[9]) / 100;
		 Hum = (r_buf[10] << 8 | r_buf[11]) / 100;
		 H = (r_buf[12] << 8 | r_buf[13]) / 100;
	 }
	 else if (r == 24)
	 {
		 Lux = (r_buf[4] << 24 | r_buf[5] << 16 | r_buf[6] << 8 | r_buf[7]) / 100;
		 T = (r_buf[13] << 8 | r_buf[14]) / 100;
		 P = (r_buf[15] << 24 | r_buf[16] << 16 | r_buf[8] << 8 | r_buf[9]) / 100;
		 Hum = (r_buf[10] << 8 | r_buf[11]) / 100;
		 H = (r_buf[12] << 8 | r_buf[13]) / 100;
	 }
}
void show_data()
{
show_number_init2(3,Lux0);
show_number_init(3,Lux);
					 
show_number_init2(1,T0);
show_number_init(1,T);
				 
show_number_init2(2,P0/1000);
show_number_init(2,P/1000);
				
show_number_init2(4,Hum0);
show_number_init(4,Hum);
				
show_number_init2(5,H0);
show_number_init(5,H);
				 
		 Lux0 = Lux;T0 = T; P0= P; Hum0 =Hum; H0 = H; 
}

主函数中创建线程

#include <stdio.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "lcd.h"
#include "bmp.h"
#include "chart.h"
#include "touch.h"
#include "chuan.h"
#include <pthread.h>
extern int tempx,tempy,xx,yy,chu;
// 创建线程
	  pthread_t task_gy39;
void start();
void login();
void start()
{
	show_a_color(0xffffff);
	show_bmp(0, 0,"start.bmp");
	get_touch();
	if(tempx != 0 || tempy !=0) 
	login();
}
void login()
{
	show_a_color(0xffffff);
	printf("xx = %d yy = %d\n",tempx,tempy);
	
			printf("enter login...\n");
			show_bmp(720,-200, "off.bmp");
			show_bmp(720,-100, "off.bmp");
			show_bmp(720,-250, "off.bmp");
			show_bmp(720,-150, "off.bmp");
			show_bmp(30,-100, "name.bmp");
			total();
			if(pthread_create(&task_gy39, NULL, (void *)get_onegy39, NULL) == -1)
			{
				perror("fail to create pthread task_rfid\n");
				return ;
			}
			while(1)
			{
				printf("enter while1..\n");
				get_touch();
		   }
}
int main()
{	
	led_beep_ctrl(LED, 0);
	// 1.打开屏幕
	lcd_init();
	// 2.清屏
	show_a_color(0xffffff);
	system("insmod  kobject_led.ko");
	start();
	login();		
	// 关闭屏幕
	lcd_close();
	return 0;
	
}

错误分析

在显示屏上出现汉字时,显示乱码,经排查后发现问题在于函数 show_word() 传参过程中的宽和高颠倒了,导致输出汉字字符和数字时都显示为了乱码。
在这里插入图片描述

结果展示

  • 在这里插入图片描述
  • 在这里插入图片描述
  • 在这里插入图片描述
  • 在这里插入图片描述

源代码

  • 百度网盘:
    • 链接:https://pan.baidu.com/s/1SwNOwp0HahM_cw8U94N8Sw
      提取码:2xld
  • 17
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值