1、前言
这个是我学习linux+ARM的在做的第一个软硬件结合项目,以往的类似这种整体类项目还是光单片机的时候,linux软件部分学习了差不多快一年了,因为各种事情耽搁,这个项目一直没有静下心来完成,不过终于哈哈哈哈搞完了软件部分。其实并行的还想做另一个涉及到can通信的项目,那个重点可能是偏各种通信,不过软件部分大同小异,直接改改就可以变成那个的软件部分。驱动部分等我搞定我再发出来。(板子为什么选友善之臂S2440,因为便宜。。不过最近有点小钱又买了一块正点原子的6ULL,还在路上)
2、摘要
- 本文主要记录并分享软件部分,用于模拟将数据上传到互联网上以供使用,内容包含数据上传、数据库存储、屏幕显示三部分
- 使用软件:VMware+Ubuntu22.04
- ARM版芯片:S3C2440(友善之臂mini2440)
- 上传采用MQTT协议上传到OneNet云,数据库使用sqlite3,屏幕显示采用FrameBuffer 帧缓存技术
- 实现效果:数据可以在云上、屏幕上、数据库中查看
- 学习文章会在本文中标记出来
3、内容简介
软件部分内容一共分为三部分:
-
数据上传部分:将获得的数据上传到OneNet云上
-
数据库存储部分:将数据存储到数据库中
-
屏幕显示部分:Framebuff显示在屏幕上
4、应用到的知识
完成上面所有的功能使用到的相关知识,我按照我自己的学习顺序梳理了一下
-
文件编程:系统函数(文件I/O) open read write close 等等
-
进程:进程原理及使用、进程之间的通信等等
-
线程:线程原理及使用,线程之间的通信等等
-
网络TCP通信:socket套接字、原理及使用等等,bind、listen、accept,读写函数recv、send等
-
MQTT协议:linux上代码实现以及软件使用,使用MQTT协议上传到OneNet云上(HTTP协议理论上也可以,但是MQTT网上教程多)
-
数据库sqlite:数据库的基本操作(增删改查),相关函数 sqlite3_open等等
-
FrameBuffer帧缓存:理解及代码实现流程
-
数据结构:链表,C语言代码实现(与线程邮箱有关)
-
线程邮箱:涉及到数据结构链表,线程邮箱是后面实现上面功能三部分整合的时候才知道的这个名词,挺重要的,用起来比线程之间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 2
static 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 1
sprintf(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 0
for(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");
}
#endif
sqlite3_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;
}
else
return 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、参考内容
书籍没有全部看完,所以还是各取所需,更多时候都是看的文章。文章这里很多,有很多都忘记看的哪些了
书:
- Linux命令行大全
- Linux网络编程
- 计算机网络(谢希仁第五版)
- 大话数据结构
文章:
-
Linux FrameBuffer(一) —— FrameBuffer是什么?怎么用?-CSDN博客
-
Linux线程邮箱-CSDN博客
-
sqlite3入门基础、sqlite3常用函数_sqlite3函数-CSDN博客 等等