写在开始
本周使用的开发板是s6818,使用c语言编程。
第一天作业:测试在windows端以及linux段的各个数据类型大小
如图所示。主要的知识点是sizeof()函数,可以获取数据类型的字节大小。
1byte = 8 bits。
题外话:面对这种数据类型不同的情况,假如需要移植系统,使用typedef;
typedef double int8_t; //给double取别名
typedef long int8_t; //给long取别名
作出声明之后,就可进行移植了,不用困扰字节数不对的情况。
第二天:如何在一个有hello world文本文件前面插入hi
思路:用字符串把源文本存起来,然后写入hi,最后用printf把字符串内容打印出来
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include<stdlib.h>
int main()
{
FILE *src_file, *dest_file;
char ch;
// 打开原始文件和目标文件
int hello = open("hello.txt",O_RDWR|O_CREAT, 0777);
int hi = open("hi.txt", O_RDWR|O_CREAT, 0777);
const char *content = "hello world";
if(write(hello, content, 12) == -1)
{
printf("输入hello world失败");
}
src_file = fopen("hello.txt" , "r");
dest_file = fopen("output.txt", "w");
// 写入需要添加的内容
fprintf(dest_file, "hi\t");
// 读取原始文件中的内容,并将其写入目标文件中
while ((ch = fgetc(src_file)) != EOF) //如果成功如果读取失败或到达文件结尾,返回EOF。while循环,加入未到达文件结尾,就一直输出字符到目标文件
{
fputc(ch, dest_file);//ch是要写入的字符
}
// 关闭文件
fclose(src_file);
fclose(dest_file);
return 0;
}
我这里是放到了另外一个文件,其实用字符串存起来更好。
open函数:
C语言中的open函数用于打开一个文件,并返回一个文件描述符(file descriptor),以便后续的读写操作。
函数原型如下:
```c
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
```
参数说明:
- `pathname`:要打开的文件路径名。
- `flags`:打开文件的方式和权限,可以是以下几个常量的按位或(`|`)组合:
- `O_RDONLY`:只读方式打开文件。
- `O_WRONLY`:只写方式打开文件。
- `O_RDWR`:读写方式打开文件。
- `O_CREAT`:如果文件不存在,则创建文件。
- `O_EXCL`:与`O_CREAT`一起使用,如果文件已经存在,则返回错误。
- `O_TRUNC`:如果文件存在,且以写方式打开,则清空文件内容。
- `O_APPEND`:以追加方式打开文件。
- `mode`:文件的权限,只有在创建文件时才有意义,可以是以下几个常量的按位或(`|`)组合:
- `S_IRUSR`:用户可读权限。
- `S_IWUSR`:用户可写权限。
- `S_IXUSR`:用户可执行权限。
- `S_IRGRP`:组可读权限。
- `S_IWGRP`:组可写权限。
- `S_IXGRP`:组可执行权限。
- `S_IROTH`:其他人可读权限。
- `S_IWOTH`:其他人可写权限。
- `S_IXOTH`:其他人可执行权限。
函数返回值:
- 如果成功,返回文件描述符(非负整数)。
- 如果失败,返回-1,并设置errno变量表示错误原因。
write函数:
C语言中的write函数是用来向文件描述符(文件、标准输入输出、网络套接字等)写入数据的函数。它的函数原型如下:
```
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
```
其中,参数fd是文件描述符,buf是要写入的数据的指针,count是要写入的数据的字节数。
函数返回值是写入的字节数,如果出现错误则返回-1
第三天:
作业:1:利用映射的方式画一个彩虹
作业:2:画一个4个格子形成的整个格子
作业:3:在屏幕中间做一个进度条(选做)
作业1
#include"stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
/*
作业:1:利用映射的方式画一个彩虹
作业:2:画一个4个格子形成的整个格子
作业:3:在屏幕中间做一个进度条(选做)
i*/
#define RED 0x00FF0000
#define ORIANGE 0x00FFA500
#define YELLOW 0x00FFFF00
#define GREEN 0x00008000
#define CYAN 0x0000FFFF
#define BLUE 0x000000FF
#define PURPLE 0x00800080
int main()
{
int x = 0;
int y = 0;
int i = 0;
//1打开文件
int fd_lcd = open("./dev/fb0",O_RDWR);
if(-1 == fd_lcd)
{
printf("打开文件失败\n");
return 0;
}
printf("打开文件成功\n");
//准备数据(用映射内存的方式)
int buf[800 * 480];
int *lcd_mp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd_lcd, 0);
int color[] = {RED, ORIANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE};
//作业:1:利用映射的方式画一个彩虹
for ( i = 0; i < 800 * 480; i++)
{
//拆开
x = i % 800;//x轴
y = i / 800;//y轴
lcd_mp [ i ] = color[ y / 68 ];
}
close(fd_lcd);
return 0;
}
作业二
#include"stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
/*
作业:1:利用映射的方式画一个彩虹
作业:2:画一个4个格子形成的整个格子
作业:3:在屏幕中间做一个进度条(选做)
*/
#define RED 0x00FF0000
#define ORIANGE 0x00FFA500
#define YELLOW 0x00FFFF00
#define GREEN 0x00008000
#define CYAN 0x0000FFFF
#define BLUE 0x000000FF
#define PURPLE 0x00800080
int main()
{
int x = 0;
int y = 0;
int i = 0;
//1打开文件
int fd_lcd = open("./dev/fb0",O_RDWR);
if(-1 == fd_lcd)
{
printf("打开文件失败\n");
return 0;
}
printf("打开文件成功\n");
//准备数据(用映射内存的方式)
int buf[800*240];
int color[] = {RED, ORIANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE};
int *lcd_mp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd_lcd, 0);
for ( i = 0; i < 800 * 480; i++)
{
x = i % 800;
y = i / 800;
if (x < 400 && y < 240)
{
lcd_mp [ i ] = color[0];
}
}
close(fd_lcd);
return 0;
}
mmap函数:
mmap函数是一种内存映射文件的方法,可以将一个文件或者设备映射到进程的地址空间中,使得进程可以像访问内存一样访问文件或设备。
mmap函数的用法如下:
```c
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
```
参数说明:
- addr:映射区的开始地址,通常设置为0,表示由系统自动分配。
- length:映射区的长度,单位是字节。
- prot:映射区的保护方式,可以是以下几种取值的组合:
- PROT_READ:可读
- PROT_WRITE:可写
- PROT_EXEC:可执行
- PROT_NONE:不可访问
- flags:映射区的标志,可以是以下几种取值的组合:
- MAP_SHARED:共享映射
- MAP_PRIVATE:私有映射
- MAP_ANONYMOUS:匿名映射
- MAP_FIXED:强制将映射区放在指定地址处
- fd:要映射的文件描述符,如果是匿名映射,则设置为-1。
- offset:文件映射的偏移量,通常设置为0。
mmap函数返回映射区的起始地址,如果出错则返回MAP_FAILED。
使用mmap函数需要注意以下几点:
- 映射区的长度必须是页大小的整数倍。
- 映射区的起始地址必须是页大小的整数倍。
- 映射区的保护方式和标志必须是合法的组合。
- 映射区的长度不能超过进程的地址空间大小。
- 映射区的起始地址不能与其他映射区重叠。
- 映射区的起始地址不能是NULL,除非设置了MAP_FIXED标志。
- 映射区的起始地址和长度必须对齐到页大小。
- 映射区的保护方式和标志不能与已有的映射区冲突
作业三
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define WHITE 0xFFFFFFFF
#define BLACK 0xFF000000
#define RED 0xFFFF0000
int main()
{
int fd_lcd = open("/dev/fb0", O_RDWR);
if (fd_lcd == -1)
{
printf("打开文件失败\n");
return -1;
}
int *lcd_mp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd_lcd, 0);
if (lcd_mp == MAP_FAILED)
{
printf("内存映射失败\n");
close(fd_lcd);
return -1;
}
// 绘制背景
int x, y;
for (y = 190; y < 290; y++)
{
for (x = 200; x < 600; x++)
{
lcd_mp[800 * y + x] = WHITE;
}
}
// 绘制进度条指示器
for (x = 200; x < 600; x++)
{
for (y = 190; y < 290; y++)
{
lcd_mp[800 * y + x] = BLACK;
}
usleep(100000);
}
munmap(lcd_mp, 800*480*4);
close(fd_lcd);
return 0;
}
其中最难的点就是两个for循环嵌套了
之前一直往横着一条一条打印,就无法实现
for ( y = 0; y < 800; y++)
{
for ( x = 0; x < 480; i++)
{
}
}
假如第一个for循环是x的话,那么就是竖着一起打印,进度条的问题就自然解决了。
第四天
打印图片
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#define BMP "./1.bmp"
int main()
{
int x,y;
int i = 0;
int color;
char r,g,b;
//打开lcd
int lcd_fd = open("/dev/fb0",O_RDWR);
if(-1 == lcd_fd)
{
perror("open() lcd failed");
return -1;
}
//进行内存映射
int *p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,lcd_fd,0);
if(NULL == p)
{
perror("mmap() failed");
return -1;
}
//1:打开一个我们的图片
int lcd_bmp = open(BMP,O_RDWR);
if(-1 == lcd_bmp)
{
printf("打开失败了吧\n");
}
printf("打开成功了吧\n");
//进行图片操作之前,光标位移54个字节
lseek(lcd_bmp,54,SEEK_SET);
//读取我们图片的一个数据
char buf_bmp[800*480*3];
read(lcd_bmp,buf_bmp,800*480*3);
for(y=479; y>=0; y--)
{
for(x=0; x<800; x++)
{
r = buf_bmp[i++]; //0
g = buf_bmp[i++]; //1
b = buf_bmp[i++]; //2
color = b <<16 | g <<8 | r ;
*(p+x+800*y) = color;
}
}
close(lcd_fd);
close(lcd_bmp);
return 0;
}
lseek函数:
lseek函数是C语言中用于移动文件指针的函数,其原型如下:
```c
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
```
其中,参数fd为文件描述符,offset为偏移量,whence为起始位置。
lseek函数的返回值为文件指针的新位置,如果出现错误则返回-1。
lseek函数的常用起始位置和偏移量如下:
- SEEK_SET:文件开头,偏移量为正数表示向后移动,为负数表示向前移动。
- SEEK_CUR:当前位置,偏移量为正数表示向后移动,为负数表示向前移动。
- SEEK_END:文件结尾,偏移量为正数表示向后移动,为负数表示向前移动
分析:
color = b <<16 | g <<8 | r ;
这里进行了位运算里面的或运算,目的就是将原本图片的RGB文件改成BRG。
for(y=479; y>=0; y--)
这里是因为假如是正序的话,图片是反过来的,因为图片是从开发板左下角开始打印。
r = buf_bmp[i++]; //0
g = buf_bmp[i++]; //1
b = buf_bmp[i++]; //2
这个实现rgb交替的一个赋值
第五天
触摸屏
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //open
#include <unistd.h> //sleep close
#include <linux/input.h>
#include <sys/mman.h>
//显示屏文件
#define BMP0 "./background.bmp"
#define BMP1 "./1.bmp"
#define BMP2 "./2.bmp"
#define BMP3 "./3.bmp"
#define BMP4 "./4.bmp"
#define BMP5 "./5.bmp"
#define BMP6 "./6.bmp"
#define BMP7 "./7.bmp"
int x, y, j = 0;//全局变量
//显示屏函数
int open_printf(char* which_bmp, int array_size, int x1, int x2)
{
int color,i = 0;
char r, g, b;
int fd_lcd = open("/dev/fb0",O_RDWR); //打开显示屏文件
int *p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd_lcd,0);
if(NULL == p)
{
perror("mmap() failed");
return -1;
}
int lcd_bmp = open(which_bmp,O_RDWR);//打开背景图
//进行图片操作之前,光标位移54个字节
lseek(lcd_bmp,54,SEEK_SET);
//读取我们图片的一个数据
char buf_bmp[array_size];
read(lcd_bmp,buf_bmp,sizeof(buf_bmp));
//打印图片
for(y=479; y>=0; y--)
{
for(x = x1; x < x2; x++)
{
r = buf_bmp[i++]; //0
g = buf_bmp[i++]; //1
b = buf_bmp[i++]; //2
color = b << 16 | g << 8 | r ;
*(p+x+800*y) = color;
}
}
}
//触摸屏函数
int axis()
{
int cnt;
//打开触摸屏文件
int fd_ts = open("/dev/input/event0",O_RDWR);
struct input_event init_eventStruct;
memset(&init_eventStruct,0,sizeof(struct input_event));
read(fd_ts,&init_eventStruct,sizeof(struct input_event));
//触摸屏默认的一个xy的大小是1024*600
if(init_eventStruct.type == EV_ABS)
{
if(init_eventStruct.code == ABS_X)
{
x = init_eventStruct.value*800/1024;
//x = (int)(800*1.0)/1024*init_eventStruct.value;
printf("x = %d\n",x);
cnt++;
}
}
return x;
}
//while循环函数
int loop()
{
char* photo[] = {BMP1, BMP2, BMP3, BMP4, BMP5, BMP6, BMP7};
while(1)
{
x = axis();
if(x > 600 && x < 800)//右滑
{
j = j + 1;
if (j == 7){j = 0;}
open_printf(photo[j], 400*480*3, 200, 600);
}
if (x > 0 && x < 200)//左滑
{
j = j - 1;
if (j == -1){j = 6;}
open_printf(photo[j], 400*480*3, 200, 600);
}
x = 0;
}
}
//主函数
int main(void)
{
open_printf(BMP0, 800*480*3, 0, 800);//背景图
open_printf(BMP1, 400*480*3 ,200, 600);//显示第一张图片
loop();
}
主要实现一个切换图片
效果如下:
粤嵌第一周项目作业