Linux+ARM 简单环境检测---软件部分

1、前言

        这个是我学习linux+ARM的在做的第一个软硬件结合项目,以往的类似这种整体类项目还是光单片机的时候,linux软件部分学习了差不多快一年了,因为各种事情耽搁,这个项目一直没有静下心来完成,不过终于哈哈哈哈搞完了软件部分。其实并行的还想做另一个涉及到can通信的项目,那个重点可能是偏各种通信,不过软件部分大同小异,直接改改就可以变成那个的软件部分。驱动部分等我搞定我再发出来。(板子为什么选友善之臂S2440,因为便宜。。不过最近有点小钱又买了一块正点原子的6ULL,还在路上)

2、摘要

  1. 本文主要记录并分享软件部分,用于模拟将数据上传到互联网上以供使用,内容包含数据上传、数据库存储、屏幕显示三部分
  2. 使用软件:VMware+Ubuntu22.04
  3. ARM版芯片:S3C2440(友善之臂mini2440)
  4. 上传采用MQTT协议上传到OneNet云,数据库使用sqlite3,屏幕显示采用FrameBuffer 帧缓存技术
  5. 实现效果:数据可以在云上、屏幕上、数据库中查看
  6. 学习文章会在本文中标记出来

3、内容简介

软件部分内容一共分为三部分:

  1. 数据上传部分:将获得的数据上传到OneNet云上

  2. 数据库存储部分:将数据存储到数据库中

  3. 屏幕显示部分:Framebuff显示在屏幕上

4、应用到的知识

完成上面所有的功能使用到的相关知识,我按照我自己的学习顺序梳理了一下

  1. 文件编程:系统函数(文件I/O) open read write close 等等

  2. 进程:进程原理及使用、进程之间的通信等等

  3. 线程:线程原理及使用,线程之间的通信等等

  4. 网络TCP通信:socket套接字、原理及使用等等,bind、listen、accept,读写函数recv、send等

  5. MQTT协议:linux上代码实现以及软件使用,使用MQTT协议上传到OneNet云上(HTTP协议理论上也可以,但是MQTT网上教程多)

  6. 数据库sqlite:数据库的基本操作(增删改查),相关函数 sqlite3_open等等

  7. FrameBuffer帧缓存:理解及代码实现流程

  8. 数据结构:链表,C语言代码实现(与线程邮箱有关)

  9. 线程邮箱:涉及到数据结构链表,线程邮箱是后面实现上面功能三部分整合的时候才知道的这个名词,挺重要的,用起来比线程之间sem信号量好用。

5、软件框架

6、代码

6.1 数据上传部分

数据上传部分可以分为两部分:OneNet云网站相关配置和MQTT相关代码编写,第一部分按照网上资料逐一配置即可,第二部分比较复杂的点是需要安装MQTT的库,代码流程固定:连接发送断开

6.1.1 流程图

6.1.2 实现代码

 没有代码注释,因为代码很多,需要自己去理解一下

//head.h
#ifndef _HEAD_H_
#define _HEAD_H_#include <MQTTAsync.h>
#include <MQTTClient.h>#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>#define NEW_IP "tcp://183.230.40.96:1883"
#define NAME "cityheathly"
#define PRODUCT_ID "gUsHWQWmcp"
#define PASSWD "version=2018-10-31&res=products%2FgUsHWQWmcp%2Fdevices%2Fcityheathly&et=1837255523&method=md5&sign=sAR1RwRYplyky9oRoTAuHA%3D%3D"
#define QOS 0
#define TIMEOUT 10000L#define CONNECT_OK 1
#define CONNECT_FAIL 2static char topic[2][200] = {0};
static int id = 1000;
static MQTTClient client;
volatile static MQTTClient_deliveryToken deliveredtoken;extern int mqtt_connect_flag;
void mqtt_deinit();
void mqtt_send(char * db ,float db_value,char *dust,float dust_value,char *pos,char *pos_value);
void mqtt_init();
#endif
//mqqt.c
#include "head.h"void pack_topic(char * dev_name, char * pro_id)
{sprintf(topic[0], "$sys/%s/%s/thing/property/post/reply", pro_id, dev_name);        //订阅sprintf(topic[1], "$sys/%s/%s/thing/property/post", pro_id, dev_name);                        //发布
}
int MessageArrived (void *context, char *topicName, int topicLen, MQTTClient_message *message)
{printf("MessageArrived \n");printf("    topic:%s\n",topicName);printf("  message : ");char *payloadptr = (char *)message->payload;int i ;for(i =0 ; i < message->payloadlen ; i++){putchar(*payloadptr++);}putchar('\n');MQTTClient_freeMessage(&message);MQTTClient_free(topicName);return 1;
}
//传递完成
void DeliveryComplete(void *context, MQTTClient_deliveryToken dt)
{printf("Message with token value %d delivery confirmed\n", dt);deliveredtoken = dt;
}
//连接丢失
void ConnectLost(void *context, char *cause)
{printf("\n Connect lost\n");printf("cause :%s\n",cause);
}
int mqtt_connect_flag=0;
void mqtt_init()
{pack_topic(NAME,PRODUCT_ID);int creat_flag = 0;int setcallback_flag = 0;int connect_flag = 0;creat_flag = MQTTClient_create(&client,NEW_IP,NAME,MQTTCLIENT_PERSISTENCE_NONE,NULL);if(creat_flag != MQTTCLIENT_SUCCESS){printf("creat fail:%d\n",creat_flag);exit(1);}setcallback_flag = MQTTClient_setCallbacks(client,NULL,ConnectLost,MessageArrived,DeliveryComplete);if(setcallback_flag != MQTTCLIENT_SUCCESS){printf("faile setcallback :%d\n",setcallback_flag);}MQTTClient_connectOptions connect_opt = MQTTClient_connectOptions_initializer;connect_opt.keepAliveInterval = 20;connect_opt.cleansession = 1;connect_opt.username = PRODUCT_ID;connect_opt.password = PASSWD;connect_flag =  MQTTClient_connect(client,&connect_opt);if(connect_flag != MQTTCLIENT_SUCCESS){printf("connect fail : %d\n",connect_flag);mqtt_connect_flag = CONNECT_FAIL;}else{mqtt_connect_flag = CONNECT_OK;}
}
void mqtt_send(char * db ,float db_value,char *dust,float dust_value,char *pos,char *pos_value)
{int send_flag = 0;MQTTClient_deliveryToken deliveryToken;MQTTClient_message test2_pubmsg = MQTTClient_message_initializer;// 需要发送的正文char message[1024]={0};test2_pubmsg.qos = QOS;test2_pubmsg.retained = 0;test2_pubmsg.payload =message;sprintf(message,"{\"id\":\"%d\",\"version\":\"1.0\",\"params\":{\"%s\":{\"value\":%f},\"%s\":{\"value\":%f},\"%s\":{\"value\":\"%s\"}}}",id++, db,db_value,dust,dust_value, pos,pos_value);test2_pubmsg.payloadlen = strlen(message);printf("%s\n",message);send_flag = MQTTClient_publishMessage(client,topic[1],&test2_pubmsg,&deliveryToken) ;if(send_flag != MQTTCLIENT_SUCCESS){printf("client to publish fail : %d\n",send_flag);exit(1);}printf("Waiting for up to %d seconds for publication on topic %s for client with ClientID: %s\n",(int)(TIMEOUT/1000), topic[0], NAME);MQTTClient_waitForCompletion(client,deliveryToken,TIMEOUT);sleep(1);
}
void mqtt_deinit()
{MQTTClient_disconnect(client, 10000);MQTTClient_destroy(&client);
}

6.2 数据存储部分

数据存储部分就一个点:使用sqlite3进行数据库的创建,新增,删除,调用sqlite3的库中代码实现,流程过于简单就不画流程图了

//sql.h
#ifndef _SQL_H_
#define _SQL_H_
#include <sqlite3.h>
void sqlite_control(sqlite3 *db,float noise,float flower,char *pos1);#endif
//sql.c
#include "sql.h"
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <unistd.h>
char message[100]={0};
int callback(void *arg,int n,char **pvalue,char **pname)
{static int flag = 0;int i =0;if(flag ==0){for (i =0;i<n;i++){printf("%s\t",pname[i]);}putchar('\n');for (i =0;i<n;i++){printf("------ ");}putchar('\n');flag = 1;}for (i =0;i < n;i++){sprintf(message,"%s %s",message,pvalue[i]);printf("%s\t",pvalue[i]);}printf("\n--------------------------\n");printf("\n %s \n",message);return 0;
}void sqlite_control(sqlite3 *db,float noise,float flower,char *pos1)
{if(sqlite3_open("data.db",&db) !=0 ){printf("sqlite3_open fail! :%s \n",sqlite3_errmsg(db));}char buf[500];char sql[1024] = {0};char *errmsg = NULL;sqlite3_exec(db,"create table dict (id INTEGER PRIMARY KEY ASC,noise float, flower float, pos1 text,dt datetime)",NULL,NULL,&errmsg);int i =0;
#if 1sprintf(sql,"insert into dict values(NULL,%f,%f,\"%s\",datetime('now','+8 hours'));",noise,flower,pos1);if(sqlite3_exec(db,sql,callback,NULL,&errmsg)!=0){printf("sqlite3_exec fail :%s\n",errmsg);}printf("%s\n",message);fflush(stdout);sleep(1);
#endif
#if 0for(int i =0 ;i<10 ;i++){sprintf(sql,"select * from dict where id =%d",i);if(sqlite3_exec(db,sql,callback,NULL,&errmsg)!=0){printf("sqlite3_exec fail :%s\n",errmsg);}//上传云端数据//清空上传数据memset(message,0,sizeof(message));//删除信息sprintf(sql,"delete from dict where id=%d",i);if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=0){printf("sqlite3_exec fail :%s\n",errmsg);}printf("data delect succes!\n");}
#endifsqlite3_close(db);
}

6.3 显示部分

购买的屏幕是配套的,使用的技术是Framebuff,相对上面的比较特殊,因为要开启板子上的功能设备,不过流程也是同样的固定顺序:打开,读取,显示,关闭

#ifndef __FRAMEBUFF_H__
#define __FRAMEBUFF_H__#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>/* 测试FrameBuff设备是否为RGB565标准 */
#define IS_RGB565_FORMAT(bits)                                (((bits) / 8 == 2) ? 1 : 0)
/* 测试FrameBuff设备是否为RGB888标准 */
#define IS_RGB888_FORMAT(bits)                                (((bits) / 8 == 4) ? 1 : 0)/* 填充RGB888颜色 */
#define FILL_RGB888_COL(col, r, g, b)                do { \(col)->R = r; \(col)->G = g; \(col)->B = b; \
} while (0)/* 填充RGB565颜色 */
#define FILL_RGB565_COL(col, r, g, b)                do { \(*(short *)col) = ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x07E0) | ((b >> 3) & 0x001F)); \
} while (0)/* RGB888 像素点结构类型 */
typedef struct rgb888 
{unsigned char B;                                                //红unsigned char G;                                                //绿unsigned char R;                                                //蓝unsigned char Reserved;                                        //保留(内存对齐)
}RGB888_T;/* RGB565 像素点结构类型 */
typedef struct rgb565
{unsigned short R:5;                                                //红unsigned short G:6;                                                //绿unsigned short B:5;                                                //蓝
}RGB565_T;/* FrameBuff结构信息类型 */
typedef struct framebuff_dev
{RGB888_T *pRGB888Addr;                                        //RGB888显存首地址RGB565_T *pRGB565Addr;                                        //RGB565显存首地址struct fb_var_screeninfo ScreenInfo;        //Framebuff设备信息
}FB_T;extern FB_T *FrameBuffInit(const char *pDevName);
extern int FrameBuffDeInit(FB_T *pFb);
extern int DrawOnePixel(FB_T *pFb, int x, int y, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB);
#include "framebuff.h"
#include <sys/mman.h>FB_T *FrameBuffInit(const char *pDevName)
{int fb = 0;int ret = 0;FB_T *pFbInfo = NULL;pFbInfo = malloc(sizeof(FB_T));if (NULL == pFbInfo){perror("create fb info struct failed");return NULL;}fb = open(pDevName, O_RDWR);if (-1 == fb){perror("fail to open");return NULL;}ret = ioctl(fb, FBIOGET_VSCREENINFO, &pFbInfo->ScreenInfo);if (-1 == ret){perror("get screen info failed");return NULL;}printf("=================== Lcd Info ====================\n");printf("Width: %d\n", pFbInfo->ScreenInfo.xres_virtual);printf("Height: %d\n", pFbInfo->ScreenInfo.yres_virtual);if (IS_RGB565_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel)){printf("FrameBuff Device Rgb565 Format!\n");}else if (IS_RGB888_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel)){printf("FrameBuff Device Rgb888 Format!\n");}printf("================================================\n");if (IS_RGB565_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel)){pFbInfo->pRGB565Addr = mmap(NULL, pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8,PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);}else if (IS_RGB888_FORMAT(pFbInfo->ScreenInfo.bits_per_pixel)){pFbInfo->pRGB888Addr = mmap(NULL, pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8,PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);}printf("create Frmamebuff size:%d display buff success!\n", pFbInfo->ScreenInfo.xres_virtual * pFbInfo->ScreenInfo.yres_virtual * pFbInfo->ScreenInfo.bits_per_pixel / 8);return pFbInfo;
}int FrameBuffDeInit(FB_T *pFb)
{if (IS_RGB565_FORMAT(pFb->ScreenInfo.bits_per_pixel)){munmap(pFb->pRGB565Addr, pFb->ScreenInfo.xres_virtual * pFb->ScreenInfo.yres_virtual * pFb->ScreenInfo.bits_per_pixel / 8);}else if (IS_RGB888_FORMAT(pFb->ScreenInfo.bits_per_pixel)){munmap(pFb->pRGB888Addr, pFb->ScreenInfo.xres_virtual * pFb->ScreenInfo.yres_virtual * pFb->ScreenInfo.bits_per_pixel / 8);}free(pFb);return 0;
}int DrawOnePixel(FB_T *pFb, int x, int y, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB)
{RGB888_T *pTmp1 = NULL;RGB565_T *pTmp2 = NULL;if (IS_RGB888_FORMAT(pFb->ScreenInfo.bits_per_pixel)){pTmp1 = pFb->pRGB888Addr;pTmp1 += y * (pFb->ScreenInfo.xres_virtual) + x;FILL_RGB888_COL(pTmp1, TmpR, TmpG, TmpB);}else if (IS_RGB565_FORMAT(pFb->ScreenInfo.bits_per_pixel)){pTmp2 = pFb->pRGB565Addr;pTmp2 += y * (pFb->ScreenInfo.xres_virtual) + x;FILL_RGB565_COL(pTmp2, TmpR, TmpG, TmpB);}return 0;
}
int DrawString(FB_T *pFb, int x, int y,  const char *pstr, unsigned char TmpR, unsigned char TmpG, unsigned char TmpB)
{const char *ptmp = NULL;int i = 0;ptmp = pstr;while (*ptmp != '\0'){DrawOneAscii(pFb, x+10*i, y, *ptmp, TmpR, TmpG, TmpB);i++;ptmp++;}return 0;
}
void frame_control(FB_T *pFb,float db,float flower,char *pos1,char *pos2)
{char project_name[100]="Urban health data";char noise_data[100]={0};char flower_data[100] = {0};ClearScreen(pFb);sprintf(noise_data,"noise  %f",db);sprintf(flower_data,"flower %f",flower);DrawString(pFb,40,50,project_name,255,255,255);DrawString(pFb,50,100,pos1,255,255,255);DrawString(pFb,50,140,pos2,255,255,255);DrawString(pFb,50,250,flower_data,255,255,255);DrawString(pFb,50,200,noise_data,255,255,255);sleep(1);
}

6.4 整合

        整合这里,很让人头大,因为这三部分是都要独立执行的,因此肯定是需要使用线程,但是如果光使用线程和信号量,需要设置各种全局变量和标志,弄得很混乱。在搜索的过程中查到了线程邮箱,尝试着学习,原理弄清楚个大概,但是代码借鉴的其他博主大神,自己修改修改就可以用了。

        下面这个代码是做控制的整个.c文件,一共启用了三个线程,分别用于收集信息、发送云端,发送屏幕。收集信息由于还没开始弄硬件,所以调用了随机数模拟收集到的数据,数据是共享的,发送给其他两个线程。发送云端这里设计成:有网络数据上传到云服务器,无网络上传到数据库中。

#ifndef __LIST_H__
#define __LIST_H__
#include <pthread.h>
#include <stdlib.h>
#include <string.h>typedef void*(*th_fun)(void* arg);
typedef struct{float noise;float flower;char *pos;
}DATATYPE;
typedef struct mail_data
{pthread_t   id_of_sender;char       name_of_sender[256];pthread_t   id_of_recver;char       name_of_recver[256];DATATYPE data;
}MAIL_DATA;
typedef struct queue{MAIL_DATA data;struct queue* next;
//        int pro;
}Que, *pQue;
typedef struct thread_node
{pthread_t tid;         //线程id号char name[256];        //线程名字 ,必须唯一Que *mail_head, *mail_tail;th_fun th;
}LIST_DATA;typedef struct Link{LIST_DATA elem;struct Link *next;
}LIST_LINK;typedef struct mail_box_system
{pthread_mutex_t mutex;  //保护邮件系统LIST_LINK *thread_list;
}MBS;
extern LIST_LINK * list_init();
extern LIST_LINK * list_for_each(LIST_LINK* head, char *name);extern void list_add(LIST_LINK *head, LIST_LINK *info);int  register_to_mail_system(MBS *mbs,char name[],th_fun th);
int destroy_mail_box_system(MBS*mbs);
MBS* create_mail_box_system();
extern MBS *mbs;int wait_all_end(MBS*msb);
void* MQTT_th(void* arg);
void* data_collect_th(void* arg);
void* FramBuffer_th(void* arg);
#endif
#include "pthread_mail.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "list.h"
#include "queue.h"
#include "../head.h"
#include "../FrameBuff/framebuff.h"
#include "sql.h"
#define ENTER_CRITICAL_AREA(mutex)  do{pthread_mutex_lock(mutex);}while(0)
#define QUIT_CRITICAL_AREA(mutex)  do{pthread_mutex_unlock(mutex);}while(0)unsigned pthread_index;LIST_LINK *end_list = NULL;MBS* mbs;int send_msg(MBS*msb,char*recvname,DATATYPE data);
int recv_msg(MBS*msb,char*sendname,DATATYPE *data);MBS* create_mail_box_system()
{MBS *temp =(MBS*)malloc(sizeof(MBS));if(NULL ==  temp){perror("create_mail_box_system mutex malloc failure\n");return NULL;}int ret = pthread_mutex_init(&temp->mutex,NULL);if(0 != ret){perror("create_mail_box_system mutex init failure\n");return NULL;}temp->thread_list = (LIST_LINK *)malloc(sizeof(LIST_LINK));temp->thread_list->next = NULL;printf("mail box create ok!! \n");return temp;
}int destroy_mail_box_system(MBS*mbs)
{pthread_mutex_destroy(&mbs->mutex);LIST_LINK *temp = NULL;LIST_LINK *find = mbs->thread_list;while(find !=  NULL){temp = find;find = find->next;free(temp);}free(find);return 0;
}char *get_th_name(MBS*msb)
{pthread_t tid = pthread_self();LIST_LINK *find = msb->thread_list;LIST_LINK *end = end_list;while(find != end){if(find->elem.tid == tid)break;find = find->next;}if(find->elem.tid == tid){return find->elem.name;}elsereturn NULL;
}
int  register_to_mail_system(MBS *mbs,char name[],th_fun th)
{LIST_LINK* temp =  (LIST_LINK *)malloc(sizeof(LIST_LINK));if(NULL == temp){perror("register to mail malloc  \n");return -1;}strcpy(temp->elem.name ,name);temp->elem.th = th;temp->next = NULL;init_que(temp);pthread_t ret = pthread_create(&(temp->elem.tid),NULL,th,NULL);if(0!=ret){perror("register to mail thread create\n");return -1;}list_add(mbs->thread_list, temp);printf("register mail system  |%s|  ok \n", temp->elem.name);return 0;
}int unregister_from_mailbox(MBS*msb,char*name)
{LIST_LINK* find=msb->thread_list->next;LIST_LINK *temp = NULL;while(find !=  NULL){temp = find;find = find->next;if(0 == strcmp(temp->elem.name ,name)){destroy(find);free(temp);return 0;}}if(0 == strcmp(find->elem.name ,name)){destroy(find);free(find);return 0;}return -1;
}int wait_all_end(MBS*msb)
{LIST_LINK *find=msb->thread_list->next;LIST_LINK *end=end_list;while(find != end){pthread_join(find->elem.tid,NULL);find = find->next;}pthread_join(find->elem.tid,NULL);return 0;
}int send_msg(MBS*msb, char*recvname, DATATYPE data)
{MAIL_DATA* temp =  (MAIL_DATA *)malloc(sizeof(MAIL_DATA));temp->data = data;temp->id_of_sender = pthread_self();LIST_LINK *find = list_for_each(msb->thread_list, recvname);if (find == NULL){printf("can,t find msg \n");}char* name = get_th_name(msb);strcpy(temp->name_of_sender,name);strcpy(temp->name_of_recver,recvname);ENTER_CRITICAL_AREA(&msb->mutex);in_queue(find, temp);QUIT_CRITICAL_AREA(&msb->mutex);return 0;
}int recv_msg(MBS*msb,char*sendname,DATATYPE *data)
{MAIL_DATA* temp = (MAIL_DATA *) malloc(sizeof(MAIL_DATA));pthread_t tid =  pthread_self();LIST_LINK *find = msb->thread_list;while(find != NULL){if( find->elem.tid == tid)break;find = find->next;}if( find->elem.tid == tid){while (1){if(find->elem.mail_head != find->elem.mail_tail){ENTER_CRITICAL_AREA(&msb->mutex);out_queue(find, temp);QUIT_CRITICAL_AREA(&msb->mutex);break;}}}strcpy(sendname, temp->name_of_sender);*data = temp->data;free(temp);return 0;
}void* data_collect_th(void* arg)
{DATATYPE info;while(1){srand(time(NULL));// 生成在0到RAND_MAX之间的整数int random_int = rand();// 将整数映射到0到2000之间的浮点数info.noise = ((float)random_int / RAND_MAX) * 200;info.flower = ((float)random_int / RAND_MAX) * 100;send_msg(mbs,"mqtt",info);send_msg(mbs,"frambuffer",info);sleep(1);}return NULL;
}
void* MQTT_th(void* arg)
{sqlite3 *sqlite;while(1){char sendname[256];DATATYPE data;recv_msg(mbs,sendname,&data);printf("mqtt_flag=%d\n",mqtt_connect_flag);if(mqtt_connect_flag == CONNECT_OK){mqtt_send("db",data.noise,"dust",data.flower,"pos","199,N,200,S");}else if(mqtt_connect_flag == CONNECT_FAIL){sqlite_control(sqlite,data.noise,data.flower,"1992,N,200,S");}else {printf("mqtt_connect_flag has nothing!\n");}}mqtt_deinit();return NULL;
}
void* FramBuffer_th(void* arg)
{FB_T *pFb = NULL;pFb = FrameBuffInit("/dev/fb0");while(1){DATATYPE data;char sendname[256];recv_msg(mbs,sendname,&data);char pos1[100]="12345.6789,N";char pos2[100]="98765.4321,S";frame_control(pFb,data.noise,data.flower,pos1,pos2);}FrameBuffDeInit(pFb);return NULL;
}

7、实现效果

软件搞定

8、总结

        软件部分大体都是有整体流程的,比较有规律,相对于代码,更复杂的应该是配置库和环境,需要使用大量时间去配置这些东西。等把硬件代码部分弄出来然后也分享出来。后面有时间会把上面学习到的东西,自己整理一下发出来。很多东西已经在笔记里面记好了,不过发CSDN文档改格式有点费时间,就一直没弄。我把这段时间看过的文档和书艾特在下面了。

9、参考内容

书籍没有全部看完,所以还是各取所需,更多时候都是看的文章。文章这里很多,有很多都忘记看的哪些了

书:

  1. Linux命令行大全
  2. Linux网络编程
  3. 计算机网络(谢希仁第五版)
  4. 大话数据结构

文章:

  1. Linux FrameBuffer(一) —— FrameBuffer是什么?怎么用?-CSDN博客

  2. Linux线程邮箱-CSDN博客

  3. sqlite3入门基础、sqlite3常用函数_sqlite3函数-CSDN博客       等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/781253.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录——移除元素(Leetcode27)

题目链接 暴力&#xff1a;&#xff08;没有改变元素相对位置&#xff09; class Solution {public int removeElement(int[] nums, int val) {int len nums.length;for(int i 0; i < len; i){if(nums[i] val){for(int j i 1; j < len; j){nums[j-1] nums[j];}i…

VS2019连接MySQL

VS2019连接MySQL 下载MySQL Connector/C配置头文件&#xff0c;库文件路径配置头文件路径配置库的路径复制dll文件 MySQL的用户设置将权限赋值给新用户 编写代码往数据库写入 老师布置的作业让我们用VS2019连接MySQL实现一个小型的日志系统&#xff0c;中间踩了很多的坑&#x…

chatui工具使用记录与比较

概述 cahtui相关工具可谓是层出不穷&#xff0c;方便了我们使用各个大模型。这里我把我知道的整理下列出来&#xff0c;顺便做一比较。 简单比较 openWebUI&#xff0c;star 11.1k&#xff0c;仿chatgpt风格&#xff0c;支持openapi、可以对接Ollama进行对话&#xff0c;功能…

Finetuned Language Models Are Zero-Shot Learners

Abstract 本文探索了一种简单的方法来提升语言模型的零样本(zero-shot)学习能力。我们发现 指令微调(instruction tuning) 显著提高了未见任务的零样本性能。 指令微调:即在一组通过指令描述的数据集上对模型进行微调我们对一个 137B 参数的预训练模型在 60 个 NLP 任务上…

springboot婚庆系统

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于婚庆系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了婚庆系统&#xff0c;它彻底改变了过去传统的管理方式…

【Gitea的介绍】

&#x1f525;博主&#xff1a;程序员不想YY啊&#x1f525; &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f4ab; &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 &#x1f308;希望本文对您有所裨益&#xff0c;如有…

Matlab-R2022b-安装文件分享

​一、MATLAB主要特点和功能 MATLAB是一款强大的科学计算软件&#xff0c;专门用于算法开发、数据分析、数值计算以及科学数据可视化。 以下是一些MATLAB的主要特点和功能&#xff1a; 1.矩阵运算: MATLAB的名字来源于"Matrix Laboratory"&#xff08;矩阵实验室&…

在同一个网站上自动下载多个子页面内容

一、问题现象 第一次遇到这样的问题&#xff0c;如下图&#xff1a; 即在同一个网站上下载多个内容时&#xff0c;第一个内容明明已经正常get到了&#xff0c;但开始第二个页面的查询 以后&#xff0c;原来已经查出的内容就找不到了。 二、解决办法 我不知道大家是不是遇到…

常见的数据结构相关的面试问题

1.请解释什么是数据结构,以及它在计算机科学中的重要性。 数据结构定义:数据结构是一种组织数据的方式,它包括数据元素之间的关系以及对这些数据元素进行操作的规则。常见的数据结构包括数组、链表、栈、队列、树、图等。 数据结构的重要性: 提高算法效率:选择合适的数据结…

配置vsftpd服务

服务简介 1、FTP协议概览 FTP&#xff08;File Transfer Protocol&#xff09;⽂件传输协议&#xff0c;在TCP/IP协议族中属于应⽤层协议&#xff0c;是运⾏于 TCP协议之上是⼀种可靠的传输协议&#xff0c;主要功能⽤于实现⽤户间⽂件分发共享&#xff0c;以及⽹络管理 者在进…

Flutter开发之objectbox

Flutter开发之objectbox 在之前进行iOS开发的时候使用WCDB去进行管理数据库很方便&#xff0c;它支持ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;&#xff0c;用于实现面向对象编程语言里不同类型系统的数据之间的转换。 那么在Flutter开发…

perl:字符串模糊匹配,计算 edit 距离

Levenshtein Distance&#xff0c;通常被称为编辑距离(Edit Distance)。该算法的概念是俄罗斯科学家弗拉基米尔莱文斯坦&#xff08;Levenshtein Vladimir&#xff09;于1965年提出。 它是用来计算两个字串之间&#xff0c;通过替换、插入、删除等操作将字符串str1转换成str2所…

作业练习(python)

第一题&#xff1a; cel eval(input()) fah 9 / 5 * cel 32 print("%.1f" % fah) 第二题&#xff1a; radius, length eval(input()) area radius * radius * 3.14159267 volume area * length print("%.2f" % area) print("%.2f" …

MNN介绍、安装与编译:移动端深度学习推理引擎

MNN介绍、安装与编译&#xff1a;移动端深度学习推理引擎 引言第一部分&#xff1a;MNN简介第二部分&#xff1a;MNN的安装第三部分&#xff1a;MNN的编译结语 引言 大家好&#xff0c;这里是程序猿代码之路。在移动设备上实现高效的深度学习模型推理一直是人工智能领域的一个挑…

代码随想录(day10)——栈和队列

Leetcode.1047 删除字符串中所有相邻重复项&#xff1a; 1047. 删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09; 本题可以利用栈的思想进行解答。但是此处并不是真正的去使用一个栈&#xff0c;而是利用来替代栈在本题中的作用。具体如下&#xff1a; …

RHCE-2-chrony服务器

简介 重要性 由于IT系统中&#xff0c;准确的计时非常重要&#xff0c;有很多种原因需要准确计时&#xff1a; 在网络传输中&#xff0c;数据包括和日志需要准确的时间戳 各种应用程序中&#xff0c;如订单信息&#xff0c;交易信息等 都需要准确的时间戳 Linux的两个时钟 硬…

Mysql数据库与PostgreSQL数据库语法比较

目录 前言 模式的概念 模式的主要作用 一、Mysql和PostgreSQL语法比较 1.数据类型差异 1.1整型 1.2浮点数类型 1.3字符串差异 1.4数组类型 2.字符串连接 3.日期和时间函数差异 4.Limit子句的差异 5.NULL值的处理 6.自增主键列 7.变量和参数差异 8.连接查询 9.…

【JavaScript编程】前端实现文件下载

在前端实现文件下载&#xff0c;主要有以下几种常见的方法&#xff1a; 一、使用<a>标签 这种方法是最常见的&#xff0c;只需要在HTML中创建一个<a>标签&#xff0c;并通过JavaScript控制其点击行为&#xff0c;就可以实现文件下载。例如&#xff1a; function…

【Vue】动态样式

内联样式的动态样式 body(){ boxASelect:false, } v-bind:style"{borderColor:boxASelect ? red : #ccc}" <body><header><h1>Vue Dynamic Styling</h1></header><section id"styling"><div class"demo&quo…

2024年MathorCup数学建模思路A题B题C题D题思路分享

文章目录 1 赛题思路2 比赛日期和时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…