赞
踩
开发环境: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开发板上运行
连接开发板步骤
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屏幕的分辨率: 800480
分辨率:单位面积内的像素点的个数
800480 --》 一行有800个像素点, 总共有480行
像素点 pixel
像素点能够显示某种颜色的点
在屏幕上显示一个颜色,就是给对应的像素点 一个颜色值即可
LCD屏幕的每一个像素点 占4个字节 --》 a r g b a:透明度
int color;
color = 0xFF0000; //红色
是底层专门用来操作屏幕的,开发板上屏幕对应的设备文件路径名为 /dev/fb0
只需要把颜色值 写入到 /dev/fb0 文件中,底层驱动就会把屏幕上对应的像素点显示对应的颜色
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);
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 --> 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 按键松开 };
传感器和开发板的通信方式: 串口
//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); }
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);
}
}
}
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; } } }
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); }
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() 传参过程中的宽和高颠倒了,导致输出汉字字符和数字时都显示为了乱码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。