提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
一、前期准备
二、项目内容
1.实现代码
2.上课笔记
总结
前言
最近接触了一块新的板子,是粤嵌公司自主研发的6818开发板,这块板子有很多有趣的功能,特别是有触摸屏,可以帮助我们实现用手来对其直接的操作,于是,我们开发了一款五子棋的游戏。
提示:以下是本篇文章正文内容,下面案例可供参考
一、前期准备
GEC6818开发板一块,USB转串口线一根,pc,远程控制终端SecureCRT,安装ubuntu虚拟机,Source Insight 4.0。
用USB转串口线将开发板的串口与电脑的USB口进行连接。
为电脑widows系统和虚拟机linux系统创建一个共享文件夹share,我们在widows上的Source Insight 4.0有利于进行代码的编写,把编写完成的代码放到共享文件夹中,可以在虚拟机上对其进行编译。因为最终程序要在6818开发板上运行,所以编译时用arm-linux-gcc编译器,确保在板子上可以运行。
用SecureCRT连接开发板,点击运行程序->选择菜单文件->快速连接,在弹出的窗口中,协议选择Serial,端口可按win+x打开设备管理器中的端口进行查看,波特率选择115200,其他默认,右边的√全部取消,然后点击连接即可。成功后,在家目录或者根目录下建立自己的一个文件夹,方便找到后续的文件传输位置。
二、项目内容
1.实现代码
代码如下:
#ifndef __TEST_H__
#define __TEST_H__
#include <>
#include <sys/>
#include <sys/>
#include <>
#include <>
#include <sys/>
extern unsigned int *plcd;
int Display(int color, int x, int y);
int Lcd_Init();
void Dis_wh();
int Dis_pic(char *pic);
void lineation();
void background();
void black(int a, int b);
void white(int a, int b);
#endif
#include ""
unsigned int *plcd = NULL;
/*
Display:对应像素点画规定颜色
参数:
@color:想要的颜色
@x:横坐标
@y:纵坐标
返回值:无
*/
void Display(int color, int x, int y)
{
if(x >=0 && x<=800 && y>=0 && y<=480)
{
*(plcd +(800*y +x))= color;
}
}
/*
Lcd_Init:LCD屏初始化
参数:无
返回值:
-1:初始化失败
*/
int Lcd_Init()
{
int fd = open("/dev/fb0", O_RDWR);
if(fd == -1)
{
perror("open error");
return -1;
}
plcd = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
}
/*
Dis_pic:显示图片
参数:
pic:图片路径
返回值:
-2:打开图片失败
*/
int Dis_pic(char *pic)
{
int fd = open(pic, O_RDONLY);
if(fd == -1)
{
perror("open error");
return -2;
}
int width,heigh;
short depth;
lseek(fd, 0x12, SEEK_SET);
read(fd, &width, 4);
read(fd, &heigh, 4);
lseek(fd, 0x1c, SEEK_SET);
read(fd, &depth, 2);
printf("%d %d %d\n", width,heigh,depth);
int laizi = (4 - (width * depth / 8) % 4) % 4;
unsigned char color_buf[heigh * (width * depth /8 + laizi)];//32 24
char color_a = 0, color_r, color_g, color_b;//颜色分量
unsigned int color;
char *p = color_buf;
lseek(fd, 0x36, SEEK_SET);
int r;
while(r != heigh * (width * depth /8 + laizi))
{
r = read(fd, color_buf, heigh * (width * depth /8 + laizi));
printf("%d %d\n", r,heigh * (width * depth /8 + laizi));
}
for(int i=heigh-1; i>=0; i--)
{
for(int j=0; j<width; j++)
{
color_b = *p++;
color_g = *p++;
color_r = *p++;
if(depth ==32){color_a = *p++;}
color = color_a << 24 | color_r << 16 | color_g << 8 | color_b;//屏幕需要的颜色
Display(color, j, i);
}
p += laizi;
}
}
#ifndef __EV_H__
#define __EV_H__
#include <>
#include <sys/>
#include <sys/>
#include <>
#include <>
#include <linux/>
int Get_ev(int *x,int *y);
void local_init();
void judge();
#endif
#include ""
#include ""
/*
position数组用来记录棋盘对应位置上是否落子
*/
int position[700][480];
/*
win_black:黑子胜
win_white:白子胜
win:有一方胜
*/
int win_black,win_white,win;
/*
local_init:棋盘上各点初始化(没有落子)
参数:无
返回值:无
*/
void local_init()
{
for(int i=40;i < 480; i+=40)
{
for(int j=40 ;j < 700; j+=40)
{
position[j][i]=0;
}
}
}
/*
judge:判断是否胜利
参数:无
返回值:无
*/
void judge()
{
for(int i=40;i < 480; i+=40)
{
for(int j=40 ;j < 700; j+=40)
{
/*
判断五子连珠的8种情况
*/
if(position[j][i]==1 && position[j][i+40]==1 && position[j][i+80]==1 && position[j][i+120]==1 && position[j][i+160]==1){Dis_pic("");win++;break;}
if(position[j][i]==1 && position[j+40][i]==1 && position[j+80][i]==1 && position[j+120][i]==1 && position[j+160][i]==1){Dis_pic("");win++;break;}
if(position[i][j]==1 && position[i+40][j]==1 && position[i+80][j]==1 && position[i+120][j]==1 && position[i+160][j]==1){Dis_pic("");win++;break;}
if(position[i][j]==1 && position[i][j+40]==1 && position[i][j+80]==1 && position[i][j+120]==1 && position[i][j+160]==1){Dis_pic("");win++;break;}
if(position[j][i]==2 && position[j][i+40]==2 && position[j][i+80]==2 && position[j][i+120]==2 && position[j][i+160]==2){Dis_pic("");win++;break;}
if(position[j][i]==2 && position[j+40][i]==2 && position[j+80][i]==2 && position[j+120][i]==2 && position[j+160][i]==2){Dis_pic("");win++;break;}
if(position[i][j]==2 && position[i+40][j]==2 && position[i+80][j]==2 && position[i+120][j]==2 && position[i+160][j]==2){Dis_pic("");win++;break;}
if(position[j][i]==2 && position[i][j+40]==2 && position[i][j+80]==2 && position[i][j+120]==2 && position[i][j+160]==2){Dis_pic("");win++;break;}
}
}
for(int i=40;i < 480; i+=40)
{
for(int j=40 ;j < 700; j+=40)
{
if(position[j][i]==1 && position[j+40][i+40]==1 && position[j+80][i+80]==1 && position[j+120][i+120]==1 && position[j+160][i+160]==1){Dis_pic("");win++;break;}
if(position[j][i]==2 && position[j+40][i+40]==2 && position[j+80][i+80]==2 && position[j+120][i+120]==2 && position[j+160][i+160]==2){Dis_pic("");win++;break;}
}
}
for(int i=40; i < 480; i+=40)
{
for(int j=40;j < 700; j+=40)
{
if(position[j][i]==1 && position[j-40][i+40]==1 && position[j-80][i+80]==1 && position[j-120][i+120]==1 && position[j-160][i+160]==1){Dis_pic("");win++;break;}
if(position[j][i]==2 && position[j-40][i+40]==2 && position[j-80][i+80]==2 && position[j-120][i+120]==2 && position[j-160][i+160]==2){Dis_pic("");win++;break;}
}
}
}
/*
Get_ev:打开触摸屏,获取屏幕信息
参数:
@x:记录横坐标
@y:记录纵坐标
返回值:
-1:打开屏幕失败
*/
int Get_ev(int *x,int *y)
{
int fd = open("/dev/input/event0",O_RDONLY);//打开触摸屏
if(-1 == fd)
{
perror("open error");
return -1;//打开失败返回-1
}
struct input_event ev;
/*
x1:记录横坐标
y1:记录纵坐标
num:标记五子棋进行到哪一步了
flag:决定是黑棋下还是白起下(1为白棋下,0为黑棋下)
*/
int x1,y1,num=0,flag=0;
while(1)
{
read(fd, &ev, sizeof(ev));//读一个结构体的信息
printf("ev_type = %d code = %d value = %d\n",,,); //读到的东西打印出来,打印在SecureCRT交互界面
if( == EV_ABS)//(绝对事件,如触摸屏的坐标)
{
if( == 0)//code为0表示得到的是x轴(横轴)坐标
{
x1 = * 800 /1024;
}
else//code为1表示得到的是y轴(纵轴)坐标
{
y1 = * 480 / 600;
}
}
if( == EV_KEY && == 330 && == 1)//(按键事件,触摸触摸屏)
{
*x = x1;
*y = y1;
}
if( == EV_KEY && == 330 && == 0)//(按键事件,离开触摸屏)
{
if(*x == x1 && *y == y1 )//触摸和离开位置一样,构成点击事件
{
//Dis_pic("");
if(num == 0)//如果还没进入过游戏,第一步,进入游戏阶段
{
background();
lineation();
Dis_picture("");//准备开始
sleep(1);
Dis_picture("");
num++;//进入了下一步
}
else if(num == 1)//第二步,下棋阶段
{
for(int i=40;i < 480; i+=40)
{
for(int j=40 ;j < 700; j+=40)
{
if((x1 - j) * (x1 - j) + (y1 - i) * (y1 - i) <= 18*18 && flag == 0 && position[j][i]==0)//黑棋2
{
Dis_picture("");//白方走棋
black(j, i);
flag += 1;
position[j][i]=2;
judge();
}
else if((x1 - j) * (x1 - j) + (y1 - i) * (y1 - i) <= 18*18 && flag == 1 && position[j][i]==0)//白棋1
{
Dis_picture("");//黑方走棋
white(j, i);
flag -= 1;
position[j][i]=1;
judge();
}
}
if(win != 0)//有一方胜利
{
num++;//进入下一阶段
win=0;
local_init();
flag=0;
break;
}
}
}
else if(num == 2)//第三步,重新加载界面
{
Dis_pic("");
num++;
}
else if(num == 3)//第四步,从头开始
{
Dis_pic("");
num=0;
}
}
}
}
//点击 左滑 右滑
}
#include ""
#include ""
/*
background:画棋盘背景色
参数:无
返回值:无
*/
void background()
{
for(int i=0;i < 480; i++)
{
for(int j=0 ;j < 800; j++)
{
Display(0x8B4513, j, i);
}
}
}
/*
lineation:画棋盘格
参数:无
返回值:无
*/
void lineation()
{
for(int i=0;i < 480; i++)
{
if(i%40 == 0)//隔40像素点画行线
{
for(int j=0; j<680; j++)
{
Display(0x0, j, i);
}
}
}
for(int j=0 ;j < 700; j++)
{
if(j%40 == 0)//隔40像素点画列线
{
for(int i=0; i<480; i++)
{
Display(0x0, j, i);
}
}
}
for(int j=0; j<=800; j++)
{
for(int i=0; i<=480; i++)
{
if((j - 160)*(j - 160) + (i - 80)*(i - 80) <= 18 || (j - 160)*(j - 160) + (i - 400)*(i - 400) <= 18|| (j - 520)*(j - 520) + (i - 80)*(i - 80) <= 18|| (j - 520)*(j - 520) + (i - 400)*(i - 400) <= 18)//棋盘上的小黑点(用圆的公式)
{
Display(0x0, j, i);
}
}
}
}
/*
black:落子黑棋
参数:
@a:横坐标
@b:纵坐标
返回值:无
*/
void black(int a, int b)
{
for(int j=0; j<=800; j++)
{
for(int i=0; i<=480; i++)
{
if((j - a)*(j - a) + (i - b)*(i - b) <= 18*18)
{
Display(0x0, j, i);
}
}
}
}
/*
white:落子白棋
参数:
@a:横坐标
@b:纵坐标
返回值:无
*/
void white(int a, int b)
{
for(int j=0; j<=800; j++)
{
for(int i=0; i<=480; i++)
{
if((j - a)*(j - a) + (i - b)*(i - b) <= 18*18)
{
Display(0xffffff, j, i);
}
}
}
}
int main()
{
int x,y;//Get_ev的参数,x记录横坐标,y记录纵坐标
Lcd_Init();
Dis_pic("");
local_init();
Get_ev(&x,&y);
}
2.上课笔记
一.Linux系统(一切皆文件)
文件系统的结构
树状结构
根目录:文件系统的开始 “/”
根目录下面有其他的目录,也可以有文件
目录下面也有其他的目录,也可以有文件
......
这种结构就叫做树状结构
绝对路径:从根目录“/”开始的路径
相对路径:不从根目录开始的路径
. 代表当前目录
.. 代表上级目录
的基本指令
(1) cd 改变路径
cd 路径名(绝对路径/相对路径)
~ 家目录 /home/china
cd ./ 当前目录下开始
cd ../ 上级目录下开始
(2) ls :显示当前目录下所有的文件
语法:
ls [options] [文件/目录]
options:
-a all 所有文件信息,包括隐藏文件
-l list 列举所有文件的详细信息
d rwx rwx rwx 1 root root 0 6月 27 18:06 code
第一个字符代表文件的类型
d 代表是一个文件夹
- 代表是一个普通文件
c 代表是一个字符设备
b 代表是一个块设备文件
l 代表是一个链接文件
rwx rwx rwx 文件的权限
第一组 代表当前用户
第二组 代表其他组用户
第三组 代表其他用户
1 硬链接的个数
root 第一个代表组用户名
root 第二个代表组用户的组名
0 代表软链接的个数
6月 27 18:06 最后一次修改文件的时间
: 显示当前目录的绝对路径
: 查询手册
linux下面会给命令/函数,写成一个参考文档
语法:
man -f 名字 //找出和相关的所有文档
man 页码 名字
按q退出
: 创建一个文件夹
mkdir [options]
options:
-p 代表如果上级目录没有,便一起创建出来
: 删除文件/目录
语法:
rm 文件名 删除一个文件
rm -r 文件夹名 删除一个文件夹
sudo rm -rf /*
:修改文件权限
user 用户权限 u
group 组用户权限 g
other 其他用户权限 o
语法:
chmod [用户](+/-) 权限 文件
chmod u+x
chmod g-r
权限 rwx 八进制表示
1111 1111 0xff
111 07
111 可读可写可执行 7
110
011
chmod 777
chmod 763
自动补齐
两下 显示文件
: copy 复制一个文件
语法:
cp 文件名 文件名(路径)
cp
cp /mnt/hgfs/
:移动,剪切
语法:
mv file file(路径)
当前文件夹下面相当于重命名
:创建一个文件
语法:
touch file
/vim
两种工作模式:编辑模式/命令模式
命令模式:键盘上每一个按键都被当成一个命令
i/I/o/O:切换到编辑模式
yy: 复制一行、
yny: 复制n行
dd:剪切一行
dnd:剪切n行
p :粘贴
u :撤销
退出编辑模式 先点击esc shift+:命令模式
:w 保存
:q 退出
:wq 保存退出
:q! 强制退出
二.编程规范
1.编辑代码
编辑软件:
source insight
vc++
vscode
2.代码规范
(1) 缩进 tab
if()
{
if()
}
(2) 花括号要成对打
if()
a = b;
(3) 最好一行一个语句
(4) 函数的命名 明了
(5) 注释
3.代码的编译
编译让我们人能看懂的代码,编译成机器能看懂的代码
c,jave,c++ -> 二进制文件
编译器
c语言 gcc
编译的语法
gcc -o file 生成一个叫file的可执行文件
gcc 默认生成一个
arm板 arm-linux-gcc
arm-linux-gcc -o file
4.程序的运行
./file
./
三.怎么将程序下载到开发板上
1.连接开发板
2.建立一个自己的文件夹
在家目录/根目录建一个自己的文件夹
mkdir xxx
cd xxx
3.编译可执行文件
arm-linux-gcc -o file
4,传输到开发板上
rx
rx file
5.第一个传输后需要加权限
chmod +x
6.执行
./
四.C语言复习
函数
返回类型 函数名(参数列表)
{
函数体;
}
分支结构
if else
switch
if语句有三种结构
(表达式)
{
语句块;
}
(表达式)
{
语句块1;
}
else
{
语句块2;
}
(表达式1)
{
语句块1;
}
else if(表达式2)
{
语句块2;
}
else if(表达式3)
{
}
......
else
{
语句;
}
练习:判断一组奇偶数的个数
switch语句
switch(表达式)
{
case zhi: 语句;
case 值2: 语句;break;
deflaut:
语句;
}
break; 跳出switch
用在循环中,跳出整个循环
continue 跳过本次循环
题目:输入某年某月某日,判断这一天是这一年的第几天?
1.程序分析:以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊
情况,闰年且输入月份大于3时需考虑多加一天。
循环结构
for
while
do while
for(表达式1;表达式2;表达式3)
{
语句块;
}
第一次进入执行表达式1,判断表达式2,是真,便执行语句块,是假,退出循环,然后执行表达式3,
然后判断表达式2.......
while(表达式)
{
语句块;
}
当表达式为真,便执行语句块;当表达式为假,便退出循环
do
{
语句块;
}while(表达式)
先执行一次语句块,然后判断表达式的值,表达式为真,便继续执行,如果为假,便退出循环。
一.系统IO(文件IO)
对文件进行处理的操作
:打开一个文件
NAME
open, openat, creat - open and possibly create a fileSYNOPSIS
#include <sys/>
#include <sys/>
#include <>int open(const char *pathname, int flags);
pathname:文件名 //路径
flags:文件打开的标志,代表了我们对文件的权限
O_RDONLY, //只读
O_WRONLY, //只写
O_RDWR //可读可写
返回值:成功返回一个新的文件描述符
文件描述符:程序运行过程中,打开文件的序号,操作文件,就是通过操作文件描述符
系统默认会打开三个文件:标准输入,标准输出,标准出错
失败返回-1,同时error被设置(perror())
int fd = open("",O_RDONLY);
if(-1 == fd)
{
perror("open error");
return -1;
}
colse: 关闭文件
NAME
close - close a file descriptorSYNOPSIS
#include <>int close(int fd);
fd: 文件描述符
read: 读取文件信息
NAME
read - read from a file descriptorSYNOPSIS
#include <>ssize_t read(int fd, void *buf, size_t count);
fd: 文件描述符,我们要读取的那个文件
buf:将读取的信息放在哪里
count:读取多少字节的信息(一次性读取多少字节)
返回值:成功返回读取到的字节数,如果返回0,说明文件已经读完了
失败返回-1 ,同时error被设置
char buf[1024] = {0};
read(fd,buf,1024);
write: 向文件中写入NAME
write - write to a file descriptorSYNOPSIS
#include <>ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符,写入的文件
buf:要写入的东西
count:写入的大小
返回值:成功返回写入的字节数,(0 表示没有写进去)
失败返回-1,同时error被设置
二.开发板屏幕
开发板的屏幕由像素点组成,480 * 800像素点
像素点由一个32位(4个字节)的数据来描述的
为了方便描述,我们将32位分为四组, a(透明度), r(红) ,g(绿), b(蓝)
描述一个红色
a r g b
0000 0000 1111 1111 0000 0000 0000 0000
0x00ff0000 0xff0000
描述一个白色
0000 0000 1111 1111 1111 1111 1111 1111
0xffffff
描述一个黑色
0x0
开发板屏幕属于帧缓存设备,他也是一个文件(/dev/fb0)
open()
write()写颜色
close()
800 * 480 * 4
lseek:定位光标的位置 光标定位的位置 +/- 偏移量
NAME
lseek - reposition read/write file offsetSYNOPSIS
#include <sys/>
#include <>off_t lseek(int fd, off_t offset, int whence);
从光标所在位置开始偏移offset
fd:文件描述符,写入的文件
offset:偏移量 可正可负
whence:光标所在位置
SEEK_SET //文件头
The file offset is set to offset bytes.SEEK_CUR //基于当前位置
The file offset is set to its current location plus offset
bytes.SEEK_END //文件尾
The file offset is set to the size of the file plus offset
bytes.返回值:成功返回光标所在位置(离文件头的位置)
失败返回-1,同时error被设置
mmap:建设一个映射关系
NAME
mmap, munmap - map or unmap files or devices into memorySYNOPSIS
#include <sys/>void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
addr:映射区的首地址,一般由系统分配,填NULL
length:映射区的长度
prot:映射区的权限,
PROT_EXEC Pages may be executed. //可执行PROT_READ Pages may be read. //可读
PROT_WRITE Pages may be written. //可写
PROT_NONE Pages may not be accessed. //无权限
PROT_READ | PROT_WRITE //可读可写
flags:数据共享的标志
MAP_SHARED
公有的,共享
MAP_PRIVATE 私有的
fd:文件描述符,写入的文件
offset:偏移量 映射区哪个位置开始,一般给 0
返回值:成功返回映射区的首地址,
失败返回MAP_FAILED,同时error被设置
munmap:解映射
int munmap(void *addr, size_t length);addr:映射区的首地址
length:映射区的长度
输入设备:
键盘、鼠标、触摸屏、麦克风.....
Linux下面这些输入设备也是一个文件,都包含一个头文件 #include <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;//编码,为了区分同一事件类型下,不同的输入事件
#define BTN_TOUCH 0x14a(330) 接触触摸屏或者离开触摸屏
#define ABS_X 0x00 触摸屏坐标的X轴
#define ABS_Y 0x01 触摸屏的Y轴
#define ABS_PRESSURE 0x18 触摸屏的压力值事件
__s32 value;//值,根据type,code的不同,有不同的含义
如:type = 按键类型
code = BTN_TOUCH
value = 按键的状态
type = EV_ABS
code = ABS_X
value = x坐标
}
操作一个触摸屏:
打开触摸屏文件(/dev/input/event0)
创建一个结构体,保存数据
循环读取触摸屏的数据
关闭文件
//一个点击事件
ev_typeev_type = 3 code = 0 value = 561
ev_type = 3 code = 1 value = 333
ev_type = 1 code = 330 value = 1
ev_type = 0 code = 0 value = 0
ev_type = 1 code = 330 value = 0
ev_type = 0 code = 0 value = 0
3.项目成果
五子棋
总结
至此一个五子棋项目就已经结束了,项目开发中充满着乐趣,在不断修改代码的过程中锻炼了自己的能力。