粤嵌GEC6818-学习笔记2-屏幕相关及音频播放

Posted 蓝净云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了粤嵌GEC6818-学习笔记2-屏幕相关及音频播放相关的知识,希望对你有一定的参考价值。

这里写目录标题

LCD屏幕

简介

  • 屏幕的分辨率是:800480,即屏幕是由800480个像素点组成的。
  • 像素点:可以组成颜色的点!
  • 每个像素点占32bit,由A R G B组成,各占8各bit
像素点A(透明度)R(red)G(green)B(blue)
color00ff0000
unsigned int color = 0x00ff0000;
  • 这种模式使得我们可以把颜色数量化 。

操作:打开屏幕

  • 屏幕的路径:“/dev/fb0”
int lcd_fd;
lcd_fd = open("/dev/fb0",O_RDWR);
if(lcd_fd == -1)

    printf("open error\\n");
    return -1;

映射

  • 帧缓冲设备是linux为显存设备提供一个接口,把显存抽象后的一种设备!他允许上次应用程序在图像模式下直接对显示缓冲区进行读写!
int *plcd;   //假设这个指针是指向lcd屏幕的首地址!

*plcd = 0x00ff0000;   //给第一个像素点写入红色
*(plcd+1) = 0x00ff0000 ; //这是给lcd屏幕第二个像素点写入红色

for(int y = 0 ; y < 480 ; y++)

    for(int x = 0 ; x < 800 ; x++)
    
        *(plcd + y * 800 + x) = 0x00ff0000;   // color
    

//写一个画点的封装函数!
void Lcd_Draw_point(int x , int y , int color)

    if(x<800&&x>=0&&y<480&&y>=0)
    
        *(plcd + y * 800 + x) = color;
    

如何让plcd指向屏幕首地址!

  • mmap
NAME
       mmap, munmap - map or unmap files or devices into memory
            映射 ,把屏幕的首地址,镜像给我们!!
SYNOPSIS
       #include <sys/mman.h>
            头文件
       void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
            void *addr  : NULL 它是由系统分配
            size_t length :映射的文件的大小   480*800*4
            int prot    : 权限 
                    PROT_READ : 可读
                    PROT_WRITE : 可写
                    PROT_EXEC : 可执行
                    PROT_READ | PROT_WRITE | PROT_EXEC 
            int flags : 属性  MAP_SHARED
            int fd  : 文件描述符
            off_t offset : 偏移量 , 0
  • 返回值:

    • 失败返回NULL
    • 成功的话就返回该屏幕映射过来的首地址!
  • 例子:

int *plcd = mmap(NULL , 480*800*4 , PROT_READ | PROT_WRITE | PROT_EXEC , MAP_SHARED , lcd_fd , 0);

int munmap(void *addr, size_t length);
    void *addr : plcd   是我们映射lcd屏幕过来的首地址
    size_t length :480*800*4

BMP图片的解析

把一张BMP格式的图片显示在我们的开发板上

  • 打开图片
int bmp_fd ;
bmp_fd = open("./1.bmp",O_RDWR);
if(bmp_fd == -1)

    printf("open bmp error\\n");
    return -1;

  • 图片的类型:bmp,jpg,png
    • bmp 图片是一种最原始的,也是windows下面最常见一种图片,也是最基础的图片。它是没有经过任何算法处理的,或者说是没有经过任何算法压缩的,所以它bmp图片所占的内存是最大的!!!
    • 没有 压缩 的图片 :意味着它保存每个像素点的值!
BITMAP头:
    0x00        2字节          保存BM

DIB:
    0x12        4字节           表示是位图的宽度
    位图的宽度:每一行有多少个像素点!
    int width;
    lseek(bmp_fd,0x12,SEEK_SET);
    int r = read(bmp_fd,&width,4);
    if(r == -1)
    
        printf("read error\\n");
        return -1;
    
    printf("width == %d\\n", width);
    width > 0  :它的像素点的保存顺序就是从左边到右边
          < 0  :则反之

    0x16        4字节           表示是位图的高度
    位图的高度:每一列有多少个像素点!

    high > 0
         < 0
    0x1C        两个字节        表示是位图的色深
    short depth;
    depth == 24    //3个字节
        保存的东西为 R G B   A:默认为0
    depth == 32    //四个字节
        保存的东西为 A R G B

    像素数组的大小:abs(width) * abs(high) * (depth/8)

    0x36        像素数组:保存每个像素点

触摸板的相关操作

  • 在开发板上任意坐标显示一张任意分辨率的bmp图片

  • 触摸屏的路径名: “/dev/input/event0”

    int touch_fd = open("/dev/input/event0",O_RDONLY);
    if(touch_fd == -1)
    
        printf("open touch error\\n");
        return -1;
    
  • NOTE:
    触摸板文件跟其他文件不同的是,它的内容吧,不是用数组保存,而是用一个结构体!

  • 在linux系统下面,所以的输入事件(鼠标,键盘,触摸板。。。)都用一个结构体来表示的

    struct input_event
    
        struct timeval time;   //输入事件的时间

        _u16 type ; //事件的类型,如下:
            type == EV_KEY   表示这是一个按键事件
            type == EV_REL      表示这是一个鼠标事件
            type == EV_ABS      表示的是一个触摸板事件
            type == EV_SYN      事件的分割标志

        
        _u16 code;      //要根据type的不同,它表示的含义也就不一样了
                 type == EV_KEY   表示这是一个按键事件
                    code 表示的是按键事件的键值 code == BTN_TOUCH
                 type == EV_REL      表示这是一个鼠标事件
                    //这个暂时我们不讲!!因为我们用不到!
                type == EV_ABS      表示的是一个触摸板事件
                    code 有几个值
                        code == ABS_X   表示这是X轴的坐标
                        code == ABS_Y   表示这是Y轴的坐标
                        code == ABS_PRESSURE   表示这是给触摸板的压力

        _u16 value;         //要根据type和code的不同,它表示的含义就不一样
                type == EV_KEY   
                    code == BTN_TOUCH
                        value == 1  或者value == 0      表示按键按下/按键弹起
                 type == EV_ABS     
                        code == ABS_X   
                                value == x轴坐标
                        code == ABS_Y  
                                value == y轴坐标
                        code == ABS_PRESSURE         
                                value == 压力值
    ;
  • NOTE:
    应用程序,通过不断从输入设备文件,读取该结构体!
int xy_read()

    int x_read = -1;
    int y_read = -1;

    struct input_event ev;
    while(1)
    
        read();
        if(ev.type   && ev.code)
        

        

    

练习:获取屏幕坐标

//获取坐标
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <unistd.h>
#include <string.h>
#define TOUCH_PATH "/dev/input/event0"
int touch_fd;
int xy_read()

    //1.打开触摸屏  
    touch_fd = open(TOUCH_PATH,O_RDONLY);//只读打开
    if(touch_fd<0)
    
        perror("open fail");
        return 0;
    

    int x_read = -1;
    int y_read = -1;

    //定义一个结构体叫ev
    struct input_event ev;

    //一直读取触摸板信息
    while(1)
    
        //读取屏幕
        read(touch_fd, &ev, sizeof(struct input_event));//第三个参数ev
        
        if(ev.type == EV_KEY && ev.code == BTN_TOUCH)
        
            if(ev.value == 1)
            
                printf("down\\n");
            
            else
            
                printf("up\\n");
            
        

        if(ev.type == EV_ABS)   //触摸事件 
        
            if(ev.code == ABS_X)
            
                x_read = ev.value;   //x轴
            
            if(ev.code == ABS_Y)		//y轴
            
                y_read = ev.value;
            
            printf("(%d,%d)\\n", x_read, y_read);
            
    


int main()

    xy_read();
    close(touch_fd);

线程进程

  • 我们的一个main就是一个进程

  • 并发:同时进行两个或者两个以上的执行任务

  • 线程就是我们主函数的一个分支,是比进程更加小的活动的单位,执行分支。

  • 线程和进程都是我们平时所说的并发的一种方式!
    指令它必须在函数的内部,线程的指令也会封装在函数的内部, 那么我们封装线程的指令函数叫做线程函数!!!

  • 线程函数的原型:

       typedef void * (*start_routine_t)(void *)
                这样子的一个指针会指向我们的线程函数!!!
                那么线程函数是该长什么样子呢??
                    参数:void *
                    返回值:void *
  • step1 :定义一个线程函数!!
            void * display_adv(void *)
            
                while(1)
                
                    //在你们的2048棋盘的旁边显示一个电子相册,用来播放小广告
                    //显示第一个广告
                    sleep(5);
                    //显示第二个广告
                    sleep(5);
                
            
  • step2: 开辟这个分支
    • 在linux中pthread的接口函数!
      它可以创建一个线程:pthread_create
      每一个线程都有自己的ID,用来唯一标识一个线程的,也就是每个线程都有一个ID身份证!!
      id的类型:pthread_t ;
      声明一个id: pthread_t id;
NAME
pthread_create - create a new thread
        创建一个新的线程
SYNOPSIS
    #include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

pthread_t *thread : 指向你保存id号的那个空间!!!
const pthread_attr_t *attr : 表示线程的属性,一般为NULL,采用的是默认的属性
void *(*start_routine) (void *)*start_routine : 指向它对应的线程函数
我们上面开创线程的目的就是为了人这个线程去执行线程函数!!
void * arg :其实它就是将要作为线程函数的实参传入!!!

Compile and link with -pthread.编译时加上-pthread
gcc xxx.c -o xxx -pthread
例子:

int main()

    pthread_t id;
    pthread_create(&id,NULL,&display_adv,NULL);
    while(1)
    
        show();
    

练习:创建广告播放的一个线程

    pthrad_t ad_th_num;   // 定义一个线程号
    pthread_create(&ad_th_num,NULL,&ad,NULL);

    //线程任务函数 --- 广告
    void * ad(void * arg)
    
        while(1)
        
            bmp_show("");
            sleep(3);
            bmp_show("");
            sleep(3);
        
    

音频播放

  • 命令:madplay
    • 查看开发板是否已经安装了madplay
      which madplay
    • 拷贝到/bin/
    • 给权限

播放的方式!!

madplay的用法:madplay 路径

madplay ./mp3/1.mp3
* system
  
NAME
    system - execute a shell command

SYNOPSIS
    #include <stdlib.h>
    
    int system(const char *command);
        const char *command : 是一个字符串,然后整个字符串就是我们要执行的那个命令!
    char cmd[100];
    sprintf(cmd,"madplay ./mp3/1.mp3");
    sprintf(cmd,"madplay %s" , p);

相关

上一篇:
粤嵌GEC6818-学习笔记1-基础篇https://blog.csdn.net/weixin_45735391/article/details/125350683
下一篇:
粤嵌GEC6818-学习笔记3-相关项目https://blog.csdn.net/weixin_45735391/article/details/125820496

进入屏幕时如何自动播放音频

【中文标题】进入屏幕时如何自动播放音频【英文标题】:How to automatically play audio when entering a screen 【发布时间】:2021-03-12 05:22:35 【问题描述】:

我正在学习 Swift,我正在通过构建一个应用程序来强迫自己学习这门语言,从而让自己陷入困境。我想要实现的是,当我从屏幕 1 传输到屏幕 2 时,无需执行任何操作即可播放音频。音频是 A-14a。下面的代码是这样设置的,当我单击方向按钮时,它会播放音频,但我不知道如何立即执行。下面的图片有助于说明我的意思。

1st Screen2nd Screen

我的代码如下:

import UIKit
import AVFoundation

class Intervention_Numerals1: UIViewController 


    @IBOutlet weak var Directions: UIButton!
    @IBOutlet weak var Done: UIButton!
    var audioPlayer = AVAudioPlayer()

    
    override func viewDidLoad() 
        super.viewDidLoad()
        setUpElements()
        //Audio Test
        do 
            audioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "A-N14a", ofType:"mp3")!))
            audioPlayer.prepareToPlay()
         catch 
            print(error)
        
    
    
    func setUpElements() 
        // Style the elements
        Utilities.styleFilledButton(Directions)
        Utilities.styleFilledButton(Done)
    

    @IBAction func Play(_ sender: Any) 
        audioPlayer.play()
    
    
    

请告诉我有关如何执行此操作的任何建议

【问题讨论】:

【参考方案1】:

使用这个方法

 override func viewDidAppear(_ animated: Bool) 
         super.viewDidAppear(animated)
         audioPlayer.play()
    

【讨论】:

【参考方案2】:

您可以重写几个方法来了解视图控制器的状态并添加代码以在该状态发生时运行。

正如阿米拉所说,您正在寻找的可能是viewDidAppearviewWillAppear

也可以帮助您实现这一目标的另一种方法

我将在下面提供大多数这些方法的代码以及它们的作用,以便您可以全部尝试并试验它们:

override func viewDidLoad() 
    //This is what you already use every time, its called when the VC's view is loaded into memory


override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    //This happens when the view is *about* to appear, it happens before users see anything from the view, great for updating UI 


override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)
    //This happens when the view actually appears on screen and when all the animations of loading the View Controller are over. 
    //not so good for updating UI since users will see a glimpse of previous view data.


override func viewWillDisappear(_ animated: Bool) 
    super.viewWillDisappear(animated)
    //This happens when the view is *about* to disappear, great example for this is when you begin swiping to go back in a navigation controller.


override func viewDidDisappear(_ animated: Bool) 
    super.viewDidDisappear(animated)
    //This happens when view is no longer on screen for user to see, like when that swiping back animation in using navigation controller is *finished*

当您的视图控制器中的视图发生变化时,还会出现更多这些情况,例如 viewWillLayoutSubviewsviewDidLayoutSubviews

使用所有这些来控制什么时候发生,希望这会有所帮助:)

【讨论】:

以上是关于粤嵌GEC6818-学习笔记2-屏幕相关及音频播放的主要内容,如果未能解决你的问题,请参考以下文章

粤嵌gec6818开发板LED屏幕上画图(数组与内存映射的采用)换图片 电子相册 实现识别触摸坐标的识别等项目

粤嵌gec6818LED屏幕上画图 太极图 图片显示 电子相册 2048小游戏 实现识别触摸坐标的识别 电子自助点餐设计等项目

粤嵌GEC6818板子TCP网络编程发送命令控制音视频

粤嵌实训(笔记)

GEC6818开发板JPG图像显示,科大讯飞离线语音识别包Linux_aitalk_exp1227_1398d7c6运行demo程序,开发板实现录音

小学期Deadline之GEC6818点奶茶系统