当前位置:   article > 正文

基于GEC6818开发板的华为云物联网数据监控项目整理_gec6818开发板 摄像头

gec6818开发板 摄像头

点击下载设备演示包,就会下载一个华为云为你写好的SDK

到此,我们需要回头改一些我们匆匆创建好的设备信息,先修改一下设备的密码:

修改完后点确定

修改完密码后我们需要修改一下设备的属性,把它改成我们需要的属性:

命令可以像这样子设置,也可以发送不同的数据类型,笔者是发的bool型数据用于开关灯,如果命令有多种情况,就需要发送别的数据类型。

这个是笔者已经弄好的设备,可以作为对照

好了,到了这一步,我们在云端的工作就已经做好了。

5、打通SDK和华为云的通信,激活云端设备

既然我们已经在云端创建了一个设备,也就是一个云设备,并不是真实的设备,我们需要利用华为云给我们提供的SDK,并修改一下代码,然后放到Ubuntu运行,建立与云端的通信,才能激活我们刚刚在华为云创建的设备。首先,我们把文件放到vscode上:

文件总体是这样子的,这里我们主要对AgentLiteDemo.c还有ClientConf.json进行修改:

先改ClientConf.json:

按照自己的设备id,密码修改

把后面的端口号删除,还有那两个冒号,因为如果固定端口的话,可能出现连不上的情况。

网址跟这个一样:

设备ID在这:

然后再修改AgentLiteDemo.c:

#include "stdio.h"
#include "signal.h"

#if defined(WIN32) || defined(WIN64)
#include "windows.h"
#endif

#include "pthread.h"

#include <math.h>
#include "hw_type.h"
#include "iota_init.h"
#include "iota_cfg.h"
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include "LogUtil.h"
#include "JsonUtil.h"
#include "StringUtil.h"
#include "iota_login.h"
#include "iota_datatrans.h"
#include "string.h"
#include "cJSON.h"
#include "sys/types.h"
#include "unistd.h"
#include "iota_error_type.h"

/* if you want to use syslog,you should do this:
 *
 * #include "syslog.h"
 * #define _SYS_LOG
 *
 * */

char* workPath = ".";
char* gatewayId = NULL;

int alarmValue = 0;

char* serverIp_ = "";
int port_ = 1883;//原本是8883,需要把端口改成1883,不然与华为云的tcp会连接失败

char* username_ = "64f82801a266cb7f6e6abfd1_gec6818";//deviceId,这个需要根据自己的情况做修改
char* password_ = "12345678";//这也也需要根据自己的情况做修改

int disconnected_ = 0;

char *subDeviceId = "f6cd4bbb1a8ab53acbb595efd0e90199_ABC123456789";//这个一般不用改

int sleepTime = 5000;

void timeSleep(int ms)
{
#if defined(WIN32) || defined(WIN64)
    Sleep(ms);
#else
    usleep(ms * 1000);
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

上面的代码中我已经加入了许多我需要用到的头文件,如果编译出现缺少头文件的情况,需要你加上对应的头文件。

void Test_propertiesReport()
{
    int serviceNum = 1;//此处是上报的服务个数
    ST_IOTA_SERVICE_DATA_INFO services[serviceNum];

    
    cJSON *root;
    root = cJSON_CreateObject();

    //设置一个p操作,如果没有资源会在此处阻塞等待
    sem_wait(&s);
    
    //需要根据自己的设备进行修改,中间的是你的云端设备属性,第三个是值,这里笔者已经用变量代替,原本的只是一个随机数,后面你需要用变量替换
    cJSON_AddNumberToObject(root, "led", LED_value);
    cJSON_AddNumberToObject(root, "adc", ADC_value);
    cJSON_AddNumberToObject(root, "pwm", BEEP_value);
    
    char *payload;
    payload = cJSON_Print(root);
    cJSON_Delete(root);

    services[0].event_time = getEventTimeStamp(); //if event_time is set to NULL, the time will be the iot-platform's time.
    services[0].service_id = "开发板数据监控系统";//这里是一开始弄的那个产品名称,需要根据自己的情况修改
    services[0].properties = payload;

    int messageId = IOTA_PropertiesReport(services, serviceNum);
    if(messageId != 0)
    {
        printfLog(EN_LOG_LEVEL_ERROR, "AgentLiteDemo: Test_batchPropertiesReport() failed, messageId %d\n", messageId);
    }
    free(payload);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
void setConnectConfig(){

    FILE *file;
    long length;
    char *content;
    cJSON *json;

    file=fopen("./ClientConf.json","rb");
    fseek(file,0,SEEK_END);
    length = ftell(file);
    fseek(file,0,SEEK_SET);
    content = (char*)malloc(length+1);
    fread(content,1,length,file);
    fclose(file);

    json = cJSON_Parse(content);

    username_ = JSON_GetStringFromObject(json, "deviceId", NULL);
    password_ = JSON_GetStringFromObject(json, "secret", NULL);
    char *url = JSON_GetStringFromObject(json, "serverUri", NULL);

    deleteSubStr(url,"ssl://");
    deleteSubStr(url,":1883");//把这个地方的端口改成1883

    serverIp_ = url;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

把上面的端口改一改

如果你需要弄云端下发命令,那么还需要修改一处:

这是原本的代码:

void handleCommandRequest(void* context, int messageId, int code, char *message, char *requestId)
{
    printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), messageId %d, code %d, messsage %s, requestId %s\n", messageId, code, message, requestId);

    JSON * root =  JSON_Parse(message);  //Convert string to JSON

    char* object_device_id = JSON_GetStringFromObject(root, "object_device_id", "-1");     //get value of object_device_id
    printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), object_device_id %s\n", object_device_id);

    char* service_id = JSON_GetStringFromObject(root, "service_id", "-1");     //get value of service_id
    printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), content %s\n", service_id);

    char* command_name = JSON_GetStringFromObject(root, "command_name", "-1");     //get value of command_name
    printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), name %s\n", command_name);

    JSON* paras = JSON_GetObjectFromObject(root, "paras");       //get value of data
    printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), id %s\n", paras);

    if (paras)
    {
        sleepTime = JSON_GetIntFromObject(paras, "value", 1) * 1000;

        printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), sleepTime %d\n", sleepTime);
    }

    Test_commandResponse(requestId);     //command reponse

    JSON_Delete(root);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这是笔者根据自己的项目需要进行的修改,仅供参考:

void handleCommandRequest(void* context, int messageId, int code, char *message, char *requestId)
{
    //printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), messageId %d, code %d, messsage %s, requestId %s\n", messageId, code, message, requestId);


    //这里的修改需要特别注意,如果需要对两种不同的命令做出判断,需要先提取command_name后,再细分判断,不然会报错
    JSON * root =  JSON_Parse(message);  //Convert string to JSON

    char* command_name = JSON_GetStringFromObject(root, "command_name", "-1");

    if(strstr(command_name,"led"))
    {
        JSON* paras = JSON_GetObjectFromObject(root, "paras");
        JSON* lled = JSON_GetObjectFromObject(paras, "led");
        // memcpy(sendled[0],cJSON_Print(lled),strlen(cJSON_Print(lled)));
        // printf("%s\n",sendled[0]);
        if (JSON_GetBoolFromObject(paras, "led状态", NULL) == true )
        {
            strcpy(ledstat, "true");
            //设置一个v操作,表示收到云端下发的命令
            sem_post(&xf);
        }else
        {
            strcpy(ledstat, "false");
            //设置一个v操作,表示收到云端下发的命令
            sem_post(&xf);
        }

        printf("%s\n", JSON_GetBoolFromObject(paras, "led状态", NULL)?"开灯":"关灯");
    }
    
    

    if(strstr(command_name,"beep"))
    {
        JSON* paras = JSON_GetObjectFromObject(root, "paras");
        JSON* lled = JSON_GetObjectFromObject(paras, "beep");

        if (JSON_GetBoolFromObject(paras, "beep状态", NULL) == true )
        {
            strcpy(beepstat, "true");
            //设置一个v操作,表示收到云端下发的命令
            sem_post(&bp);
        }else
        {
            strcpy(beepstat, "false");
            //设置一个v操作,表示收到云端下发的命令
            sem_post(&bp);
        }   

        printf("%s\n", JSON_GetBoolFromObject(paras, "beep状态", NULL)?"开警报":"关警报");          
    }


    JSON_Delete(root);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

如此修改完之后,保存后,在编译器直接输入make进行编译,然后给脚本文件start.sh赋予777权限,不然执行的时候会报权限不足的问题,编译好之后,在终端直接输入./start.sh执行这个SDK文件,运行结果会是如此:

可以看到,Ubuntu已经顺利执行华为云提供的SDK,在云端也可以看见设备已经激活,并且已经向云端发送ADC,LED,BEEP的数据,(此时的数据并不是真实设备的数据,只是rand函数随机模拟的数据,如果你想要发送真实设备的数据,还需要接通开发板上的设备),反正不管怎么说,现在已经打通了Ubuntu与云端的通信,下一步就应该想着怎么打通Ubuntu与开发板的联系,就是怎么把开发板的真实设备状态通过tcp或者udp发送到ubuntu,再由ubuntu转发给云端,以达到物联网数据监测的目的。

6、编写设备端代码

这里说的设备端是真实设备,也就是开发板上的蜂鸣器,LED和ADC旋钮,如果你需要将设备的状态简单的显示在开发板上,那还需要用到lcd屏幕,要控制这些硬件,当然需要相应的驱动模块,这里笔者就不给出驱动文件,在这提一嘴笔者踩过的雷,驱动一定要安装正确的版本与之相对应,不然会出现莫名其妙的错误。

这里给出一些常用的驱动命令:

lsmod:列出当前装载的驱动模块

rmmod: 删除指定的驱动模块

insmod: 安装指定驱动模块

还有对应的设备路径:

蜂鸣器:beep/buzzer/pwm

ADC: adc/gec6818_adc

LED: led/Led/gec_led

按键:button/gecBt/key

好了,铺垫了这么久,我们现在开始编写设备端的代码。在编写之前,我们需要考虑,每一个设备都有其对应的控制代码,还有其对应的逻辑控制。也就是每一个设备都有自己的.c文件,每个.c文件都有一个main函数。那么该如何实现,这些设备之间的交互呢,比如ADC到达一定的阈值后会触发警报。那就需要用到我们学过的知识了——进程间的通信。我们可以弄一个管理进程,通过exce函数启动其他设备的进程,例如:

#include "head.h"

//蜂鸣器标记位,配合共享内存使用的,可惜没玩明白共享内存,暂时报废
const char *beepmanageron = "true";

//设置一个互斥锁,所有的锁都是为了共享内存准备的,很可惜没玩明白共享内存
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

int main(int argc, char const *argv[])
{   
    //想用共享内存没有用出来,可惜,所以关于共享内存的代码都是无效的,不用管
    int shmid;
    // 创建或打开一个大小为30的SHM对象,用来存放开关的状态,获取其ID
    shmid = shmget(key, 40, IPC_CREAT|0666);
    if(shmid < 0)
    {
        perror("创建SHM对象失败");
    }

    //映射共享内存
    char *shm_addr = shmat(shmid, NULL, 0);

    pthread_mutex_lock(&m);
    //把蜂鸣器的标记位写入共享内存(30-40),共享内存的代码用不着,不用在意
    memcpy(shm_addr + 30, beepmanageron, strlen(beepmanageron));
    pthread_mutex_unlock(&m);

    printf("共享内存内容:%s\n", shm_addr);
    
    // 1. 准备各个模块所需的IPC
    mkfifo("/root/fifo", O_CREAT|0666);
    mkfifo("/root/led", O_CREAT|0666);
    mkfifo("/root/beep", O_CREAT|0666);
    mkfifo("/root/ledstat", O_CREAT|0666);
    mkfifo("/root/beepstat", O_CREAT|0666);
    mkfifo("/root/setting", O_CREAT|0666);

    // 2. 依次启动各个模块
    if(fork() == 0)
    {   
        execl("./adc_test", "./adc_test", NULL);
    }
    if(fork() == 0)
    {
        execl("./buzzer", "./buzzer", NULL);
    }
    if(fork() == 0)
    {
        execl("./bt_test", "./bt_test" , NULL);
    }
    if(fork() == 0)
    {
        execl("./led_test", "led_test", NULL);
    }


    // 分离共享内存与当前进程,很可惜没弄出来
    if (shmdt(shm_addr) == -1) {
        perror("shmdt");
        return 1;
    }

    // 删除共享内存对象
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        return 1;
    }

    pause();

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

这是笔者的管理程序,笔者通过execl函数启动其他的子线程,使用具名管道进行通信。如果大家觉得很麻烦,那大可以把所有的.c文件都放在一个文件里面,这样就不需要进程间通信,也不需要弄共享内存这些吃力不讨好的东西,但是问题在于一个.c文件集成了所有的设备代码,会显得很臃肿,而且也不能练习我们学过的各种进程间通信的知识。所以笔者不建议都弄到一个文件。

下面展示笔者弄的各设备模块的代码:

adc_test2.c

#include "head.h"

#define GEC6818_ADC_IN0     _IOR('A',  1, unsigned long)
#define GEC6818_ADC_IN1     _IOR('A',  2, unsigned long)

int sockfd;
//套接字
int recvfd, sendfd, recvfd1;
//这两个数组用来存放灯和凤鸣器的状态
char lednow[6];
char beepnow[6];

//两个信号量,用来让两个更新程序一直等待执行
sem_t lo;
sem_t bo;
sem_t lf;
sem_t bf;
//这个是屏幕显示的方法
void showbitmap(bitmap *bm, int x, int y, char *p)
{
    // 直接写指针,不在这里写打开设备,避免重复调用打开
    char *q = p + (y*800 + x)*4;
    for(int j=0;j<bm->height && j < 480 ;j++)
    {
     for(int i=0;i<bm->width && i< 800 ;i++)   
         memcpy(q+(800*4*j)+i*4,bm->map+(bm->width*bm->byteperpixel*j)+
                                         bm->byteperpixel*i,bm->byteperpixel);
    } 
    
    bzero(bm->map,bm->width*bm->height*bm->byteperpixel);   
}


//这个函数用来一直更新灯的状态
void *updateledon(void *arg)
{
    while (1)
    {
        //p操作,如果没有资源就会一直等待
        sem_wait(&lo);
        strcpy(lednow, "on");
    }
    
}

void *updateledoff(void *arg)
{
    while (1)
    {
        //p操作,如果没有资源就会一直等待
        sem_wait(&lf);
        strcpy(lednow, "off");
    }
    
}

//这个函数用来一直更新蜂鸣器的状态
void *updatebeepon(void *arg)
{
    while (1)
    {
        //p操作,如果没有资源就会一直等待
        sem_wait(&bo);
        strcpy(beepnow, "on");
    }
}

void *updatebeepoff(void *arg)
{
    while (1)
    {
        //p操作,如果没有资源就会一直等待
        sem_wait(&bf);
        strcpy(beepnow, "off");
    }
}

//用来接收云端发送过来的警报指令 
void *recvudp1(void *arg)
{   
    //打开led具名管道,把读到的云端命令写到管道里面
    int beepfd = open("/root/fifo", O_RDWR);
    int setting = open("/root/setting", O_RDWR | O_NONBLOCK);

    if(beepfd == -1 || setting == -1)
    {
        perror("打开BEEP和setting具名管道失败!");
        exit(0);
    }

    //准备好本机的ip
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    //当一个服务器程序需要绑定到本机的某个ip地址上时,可以使用这个
    //表示服务器愿意接受来自任何可用网络接口的连接
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(50003);

    //绑定上面的地址
    if(bind(recvfd1, (struct sockaddr *)&addr, sizeof(addr)) != 0)
    {
        perror("102绑定地址失败!");
    }

    //等待对方发来的信息
    struct sockaddr_in clientAddr;
    //用来存放信息
    char buf[6];

    while (1)
    {
        bzero(buf, 6);

        socklen_t len = sizeof(clientAddr);
        bzero(&clientAddr, len);

        //等待udp数据
        int n = recvfrom(recvfd1, buf, 6, 0,
                        (struct sockaddr *)&clientAddr, &len);

        if (buf[0] == 't')
        {
            printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"开警报!");
            //把开警报信息写入管道
            write(setting, "on", 2);
            usleep(200*1000);
            write(beepfd, "on", 2);
            sem_post(&bo);

        }else if (buf[0] == 'f')
        {
            printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"关警报!");

            //把关灯信息写入管道
            write(beepfd, "off", 3);
            write(setting, "off", 3);
            sem_post(&bf);

        }else{
            printf("与云端[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"通信良好!");
        }
        
        
    }


}

//用来接收云端发送过来的灯指令 
void *recvudp(void *arg)
{   
    //打开led具名管道,把读到的云端命令写到管道里面
    int ledfd = open("/root/led", O_RDWR);

    if(ledfd == -1)
    {
        perror("打开LED具名管道失败!");
        exit(0);
    }

    //准备好本机的ip
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    //当一个服务器程序需要绑定到本机的某个ip地址上时,可以使用这个
    //表示服务器愿意接受来自任何可用网络接口的连接
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(50002);

    //绑定上面的地址
    if(bind(recvfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
    {
        perror("154绑定地址失败!");
    }

    //打开显示设备,实现把状态信息显示到屏幕上
    //等待对方发来的信息
    struct sockaddr_in clientAddr;
    //用来存放信息
    char buf[6];

    while (1)
    {
        bzero(buf, 6);

        socklen_t len = sizeof(clientAddr);
        bzero(&clientAddr, len);

        //等待udp数据
        int n = recvfrom(recvfd, buf, 6, 0,
                        (struct sockaddr *)&clientAddr, &len);

        if (buf[0] == 't')
        {
            printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"开灯!");
            //把开灯信息写入管道
            write(ledfd, "on", 2);
            sem_post(&lo);

        }else if (buf[0] == 'f')
        {
            printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"关灯!");

            //把关灯信息写入管道
            write(ledfd, "off", 3);
            sem_post(&lf);

        }else{
            printf("与云端[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
                                                   ntohs(clientAddr.sin_port),"通信良好!");
        }
        
        
    }


}


//设置一个互斥锁, 本来是用来控制读写共享内存的,结果没弄出来,所以不必在意
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;



int main(int argc, char **argv)
{
    //打开设备
    int lcd = open("/dev/fb0",O_RDWR);

    if (lcd == -1)
    {
        perror("打开屏幕设备错误!");
        exit(0);
    }

    // 获取屏幕属性
    struct fb_var_screeninfo fixinfo; 
    ioctl(lcd,FBIOGET_VSCREENINFO,&fixinfo);  
    unsigned long VWIDTH  = fixinfo.xres; //可见区宽度(单位:像素)
    unsigned long VHEIGHT = fixinfo.yres; //可见区高度(单位:像素)
    unsigned long BPP = fixinfo.bits_per_pixel;  //色深  

    char  *p = mmap(NULL, VWIDTH * VHEIGHT * BPP/8, PROT_WRITE,
                   MAP_SHARED, lcd, 0); 

    bzero(p,VWIDTH*VHEIGHT*BPP/8);

    //1.初始化字库 
    font *f1 = fontLoad("simfang.ttf"); // 指定字库文件,比如simfang.ttf
    font *f2 = fontLoad("simfang.ttf"); 
    font *f3 = fontLoad("simfang.ttf"); 
    font *f4 = fontLoad("simfang.ttf"); 

    //2.设置字体的大小 
    fontSetSize(f1, 40);
    fontSetSize(f2, 70);
    fontSetSize(f3, 60);
    fontSetSize(f4, 60);
    //3.设置指针指向分配框区域
    bitmap *bm1;
    bitmap *bm2;
    bitmap *bm3;
    bitmap *bm4;
    //4.给分配框设置不同的大小,因为第三块用来显示通知文本,所以分了200行
    bm1 = createBitmapWithInit(800, 50, 4, 0x00000000);
    bm2 = createBitmapWithInit(800, 200, 4, 0x00000000);
    bm3 = createBitmapWithInit(800, 100, 4, 0x00000000);
    bm4 = createBitmapWithInit(800, 100, 4, 0x00000000);
        
    int fd=-1;
    int rt;
    int i=0;
    unsigned long adc_vol = 0;

    //初始化信号量,设置为0
    sem_init(&lo, 0, 0);
    sem_init(&bo,0, 0);
    sem_init(&lf, 0, 0);
    sem_init(&bf,0, 0);

    // 创建SHM对象或者打开
    int shmid = shmget(key, 40, IPC_CREAT|0666);
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }

    //映射共享内存
    char *shm_addr = shmat(shmid, NULL, 0); 

    //创建一个套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    recvfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    recvfd1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    //sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if (sockfd == -1 ||recvfd == -1 || recvfd1 == -1)
    {
        perror("创建套接字失败!");
    }

    //创建两个线程,一个运行发送,一个运行接收
    pthread_t t1,t2,t3,t4,t5,t6;
    pthread_create(&t1, NULL, recvudp, NULL);
    pthread_create(&t2, NULL, recvudp1, NULL);
    pthread_create(&t3, NULL, updateledon, NULL);
    pthread_create(&t4, NULL, updateledoff, NULL);
    pthread_create(&t5, NULL, updatebeepon, NULL);
    pthread_create(&t6, NULL, updatebeepoff, NULL);
    //准备好对端的ip
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    bzero(&addr, len);

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("192.168.2.10");
    addr.sin_port = htons(50001);
    
    //打开adc设备
    fd = open("/dev/adc_drv", O_RDWR);
    
    if(fd < 0)
    {
        perror("open /dev/adc_drv:");
        
        return fd;
        
    }

    //弄一个具名管道,把读到的数据写到管道里面
    int fifofd = open("/root/fifo", O_RDWR);
    //这两个管道用来更新灯和蜂鸣器的状态
    int ledstat = open("/root/ledstat", O_RDONLY | O_NONBLOCK);
    int beepstat = open("/root/beepstat", O_RDONLY | O_NONBLOCK);
    int setting = open("/root/setting", O_RDONLY | O_NONBLOCK);
    if(fifofd == -1 || ledstat == -1 || beepstat == -1)
    {
        perror("打开具名管道失败!");
        exit(0);
    }
        
    unsigned long n = 0;

    //设置一个字符数组用于存放adc数据
    char msg[10];
    char led[6];
    char beep[6];
    char ledmsg[6];
    char beepmsg[6];

    //这个字符串用来存储ADC数据
    char BUF1[100];  
    bzero(BUF1,100);

    //这个字符串用来存储灯状态
    char BUF2[100];  
    bzero(BUF2,100);

    //这个字符串用来存储蜂鸣器的状态
    char BUF3[50];  
    bzero(BUF3,50);

    //读取共享内存内的灯和蜂鸣器状态
    pthread_mutex_lock(&m);

    memcpy(led, shm_addr + 20, 6);
    memcpy(beep, shm_addr + 20, 6);

    pthread_mutex_unlock(&m);
 
    while(1)
    {   
        //显示系统时间
        time_t t; //获取系统时间
        struct tm *Time;
        time(&t);
        char buf[50];  //定义buf缓冲区,用来存放时间数据
        bzero(buf,50);  
        Time=localtime(&t); 
        char *wd[7] = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"}; 
        //把要输出的数据保存到缓冲区buf
        snprintf(buf,50,"%d年%d月%d日 %s %d时%d分%d秒",(1900+Time->tm_year),
                                                    (1+Time->tm_mon),(Time->tm_mday),
                                                    wd[Time->tm_wday],(Time->tm_hour),
                                                    Time->tm_min,Time->tm_sec);

        //这些数组是暂时用来存放管道里面的数据的
        bzero(msg, 10);
        bzero(ledmsg, 6);
        bzero(beepmsg, 6);
        //读取管道内的数据
        read(ledstat, ledmsg, 6);
        read(beepstat, beepmsg, 6);         

        //读取ADC通道0的电压值
        rt=ioctl(fd,GEC6818_ADC_IN0,&adc_vol);

        if(strcmp(ledmsg, "on") == 0)
        {   
            //让灯更新为开
            sem_post(&lo);
        }

        if(strcmp(ledmsg, "off") == 0)
        {   
            //让灯更新为关
            sem_post(&lf);

        }

        if(strcmp(beepmsg, "on") == 0)
        {   
            //让蜂鸣器状态更新为开
            sem_post(&bo);

        }

        if(strcmp(beepmsg, "off") == 0)
        {   
            //让蜂鸣器状态更新为关
            sem_post(&bf);

        }
            
        if(rt != 0)
        {
            printf("adc in0 read filed\r\n");       
            usleep(50*1000);            
            continue;
        }

        unsigned long m1 = adc_vol + n;

        if(m1 >= 3000 && m1 <= 3100)
        {   
            //把数据写到具名管道
            write(fifofd, "on", 2);
            n = n + 100;
        }

        if (m1 > 3500)
        {
            n = 0;
        }
        
        if (m1 >800 && m1 <3000)
        {
            n = n + 100;
        }

        if (m1 > 3100)
        {
            n = n + 100;
        }
            
            
        //把数据写入msg
        snprintf(msg, sizeof(msg), "%lu", m1);

        //发送数据
        int n = sendto(sockfd, msg, strlen(msg), 0,
                            (struct sockaddr *)&addr, sizeof(addr));

        //发送led灯的状态数据
        int n1 = sendto(sockfd, lednow, strlen(lednow), 0,
                            (struct sockaddr *)&addr, sizeof(addr));
        //发送蜂鸣器的状态数据
        int n2 = sendto(sockfd, beepnow, strlen(beepnow), 0,
                            (struct sockaddr *)&addr, sizeof(addr));

        if(n == -1)
        {
            perror("发送adc数据失败!");
        }

        if(n1 == -1)
        {
            perror("发送led数据失败!");
        }else
        {
            printf("发送成功!");
        }
            
        if(n2 == -1)
        {
            perror("发送beep数据失败!");
        }           

        printf("温度: %lu mv\r\n",m1);
            // 从共享内存中读取数据
            // printf("共享内存内容:%s\n", shm_addr);
        printf("灯状态:%s\n", (strcmp(lednow, "on") == 0) ? "开" : "关");
        printf("蜂鸣器状态:%s\n", (strcmp(beepnow, "on") == 0) ? "开" : "关");
        //把要输出的内容显示到显示屏上,50表示x的偏移量,5表示距离上一个分配框的距离   

        //把adc数据写入BUF0
        snprintf(BUF1, 100, "ADC值:%lu", m1);
        snprintf(BUF2, 100, "灯状态:%s\n", (strcmp(lednow, "on") == 0) ? "开" : "关");
        snprintf(BUF3, 50, "蜂鸣器状态:%s\n", (strcmp(beepnow, "on") == 0) ? "开" : "关");

        fontPrint(f1, bm1 ,50 ,5,buf, 0x00FFFF00, 0);  
        fontPrint(f2, bm2, 5,40, BUF1, 0xFF000000, 0); 
        fontPrint(f4, bm3,100,5, BUF2,  0xFF33CC66,750); 
        fontPrint(f3, bm4,100,40, BUF3,   0xFFD70000, 0); 

        //bm妥善地放置到LCD上显示出来 
        showbitmap(bm1,    10,    0,   p); 
        showbitmap(bm2,    200, 50,  p); 
        showbitmap(bm3,    100, 200, p);//为了让文本有一种居中对齐的效果,所以右边偏移量也-200
        showbitmap(bm4,    100, 270, p); 

        sleep(1);
    }

        
    // 分离共享内存与当前进程
    if (shmdt(shm_addr) == -1) {
        perror("shmdt");
        return 1;
    }

    // 删除共享内存对象
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
        perror("shmctl");
        return 1;
    }

    close(fd);  
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536

这个adc_test2.c里面集成了控制蜂鸣器开关的代码,集成了接收云端命令控制led灯开关和蜂鸣器开关的代码,还整合了所有的设备信息向ubuntu发送的功能,还有在lcd上显示设备信息的功能,所以代码比较长,大家仅供参考。

buzzer.c代码:

#include "head.h"

#define  BUZZER_IOCTL_SET_FREQ 1
#define  BUZZER_IOCTL_STOP 0



void Usage(char *args)
{
    printf("Usage: %s <on/off> <freq>\n",args);
    return ;
}

//定义一个全局变量
int buzzer_fd;
## 最后

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/269da7a2d07f8e8278ce9154d9feadbb.png)

![img](https://img-blog.csdnimg.cn/img_convert/04912a1eb7fa719af8f01fc62ac3224b.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/65f1559f61b5069ac181cf301107a33f.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/65e6a2122bc2b957b286ca9038fc2b06.png)

![img](https://img-blog.csdnimg.cn/img_convert/ba3035ca2e316e279be0bfdb2d961646.png)

![img](https://img-blog.csdnimg.cn/img_convert/2c72b4f6bd4fb593e24b15ac516d0736.png)

![](https://img-blog.csdnimg.cn/img_convert/cf584ea6eee456d9267be5db3039bba5.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


整合了所有的设备信息向ubuntu发送的功能,还有在lcd上显示设备信息的功能,所以代码比较长,大家仅供参考。


buzzer.c代码:



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

#include “head.h”

#define BUZZER_IOCTL_SET_FREQ 1
#define BUZZER_IOCTL_STOP 0

void Usage(char *args)
{
printf(“Usage: %s <on/off> \n”,args);
return ;
}

//定义一个全局变量
int buzzer_fd;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-bO0DOpsl-1715682465863)]

[外链图片转存中…(img-RiE9M8p1-1715682465863)]

[外链图片转存中…(img-ylfeJ6iI-1715682465864)]

[外链图片转存中…(img-3BHbnKRU-1715682465864)]

[外链图片转存中…(img-FAU3YUHq-1715682465865)]

[外链图片转存中…(img-Gec1JD1e-1715682465865)]

[外链图片转存中…(img-hDCrgsmB-1715682465866)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/855485
推荐阅读
相关标签
  

闽ICP备14008679号