1.项目名称:基于cortex-A7的智慧物联仓储可视化管理系统
2.开发语言:C、HTML
3.开发平台:Ubuntu-18.4 Windows10
4.linux内核版本 5.10
5.硬件平台:STM32MP157a(cortex-A7 & cortex-M4)
STM32MP157a由 意法半导体提供
6.开发工具:VIM、arm-linux-gnueabihf-gcc 、VSCode
关于项目:
项目主要实现了 客户端登录 boa 服务端实现对仓库的信息掌握和仓库的管理 ;客户端主要由网页提供人机交互支持(HTML) ;服务端主要由 BOA 服务器提供数据交互支持,网页后台由 CGI 处理;
项目主要实现了对仓库温湿度、光照、货物数量的监控(可拓展视频监控) ;实现了对环境阈值设置的功能(温度上/下限 湿度上\下限 光照强度上\下限 等) ; 实现了对仓库设备节点操作的功能(灯光、风扇、警报、数码管等设备) ; 客户端通过网页登录服务器(客户信息由sqlite3数据库管理),可以实现对1号仓库(157a) 进行监控管理 ;
当用户设置阈值时 ,通过网页传输给服务器,服务器接收到用户指令后 ,由指定CGI程序处理用户网页指令数据交由 数据处理 进程 来 处理用户指令,
以设置阈值为例:
数据处理 进程 会分配对应的 线程 来处理阈值设置事件,设置完阈值后,仓库设备会根据阈值的上下限 来控制仓库设备节点(如设置温度上\下限为 30-5 摄氏度 仓库温度超过 30 摄氏度则风扇开启(降温),低于5摄氏度led灯亮起(升温) ,并向用户发出高温警报(蜂鸣器响起) );
用户查看仓库环境时 ,仓库要实时为用户提供当前仓库的环境数据 , 用户控制仓库设备节点时 ,要反馈给用户操作结果
BOA 服务器是一个小巧高效的web服务器
移植步骤在 /01-boa移植/boa移植及错误解决
boa开机自启动配置
进入~/nfs /rootfs/etc/init.d 目录下
打开 rcS 最后一行添加 /etc/boa/boa
移植步骤在 /02-sqlite3移植/sqlite的移植
最重要的是配置gcc编译器,链接才不会报错gcc -lsqlite3
我们参考 手册对 sqlite3 源码进行了编译 sqlite3 要运行在 157a 平台上(ARM 架构)
所以我们需要修改 Makefile 对应的编译器 ./config --host arm-linux-gnueabi --prefix ./install
--host:指定运行主机平台的 指定编译器编译源码
--prefix:指定编译好的类库二进制文件的安装路径
配置gcc编译器,链接gcc -lsqlite3不报错:
污染交叉编译器
1.将 include 目录下的 所有 .h 文件拷贝
到 ~/toolchain/gcc-7.5.0/arm-linux-gnueabihf/include 下
此操作解决包含头文件的问题cp ./*.h ~/toolchain/gcc-7.5.0/arm-linux-gnueabihf/include
2.将 install 目录下的 lib 目录下的 libsqlite3.* 所有文件 拷贝到 ~/toolchain/gcc-7.5.0/arm-linux-gnueabihf/lib 下
在 install/lib cp libsqlite3.* ~/toolchain/gcc-7.5.0/arm-linux-gnueabihf/lib -arf
此操作解决的是 使用sqlite3 时 链接库的问题 arm-linux-gnueabihf-gcc xxx.c -o xxx -lsqlite3
一定要注意在 拷贝 www 文件时,要注意.html文件的可执行权限
解析都在代码中,帮助文档也在 1.tar.gz
1.git智慧物联仓储可视化管理系统
2.有道云:智慧物联仓储可视化管理系统
按键1[KEY1]为入库操作,商品数量++,同时LED1、LED2状态发生改变
按键3[KEY3]为出库操作,商品数量–,同时LED3状态发生改变
按键2[KEY2]为切换温湿度显示操作
本项目的实现思路:
由A7主程序 读取 [ 设备节点 ] 从A7发送过来的环境信息数据和货物信息数据 写入共享内存中,
然后 网页程序(CGI)读取 共享内存 中的信息显示在网页上,
{
处理上层 下发的控制命令主线程: 读取消息队列msgid中的控制消息 到queuemsg,唤醒->读取数据线程1[pthr_t1]
线程1[pthr_t1] :通过ioctl,读取A7内核的环境信息,写入buf中, 唤醒->仓库1处理线程pthr_t2
仓库1处理线程pthr_t2 :存放处理后的数据到envmsg, 唤醒->共享内存线程pthr_t4
共享内存线程pthr_t4 : 将处理完的数据拷贝到共享内存addr, 唤醒->接收网页下发的阈值的线程pthr_t6
接收网页下发的阈值的线程pthr_t6 : 将读取息队列的(节点200),网页设置阈值 赋值给限定阈值,便于报警线程pthr_t5使用 唤醒->报警线程pthr_t5
报警线程pthr_t5 : 处理过限阈值,唤醒->主线程
线程3 数码管显示温湿度 不使用信号量,不然代码执行太慢,余辉就灭了[msg.c的228行]
-----------------------------------------------------------------------------------------------------------------
0. 主 线程 ->读取消息队列msgid中的控制消息 到queuemsg 唤醒->读取数据线程1[pthr_t1]
1. 读取数据线程1[pthr_t1] ->从内核 读取数据 -> 唤醒 仓库1处理线程
线程3 数码管显示温湿度 不使用信号量,不然代码执行太慢,余辉就灭了[msg.c的228行]
2. 仓库1处理线程 ->将内核读取的数据处理 -> 唤醒 共享内存线程
3. 刷新共享内存的线程 ->将处理完的数据拷贝到共享内存addr(上传到网页的数据,节点100) -->唤醒 接收网页下发的阈值的线程
4. 接收网页下发的阈值的线程 ->将读取息队列的(节点200),网页设置阈值 赋值给限定阈值 ->唤醒 报警线程
5. 报警线程 ->处理超阈值 ->唤醒主线程
--------------------------------------------------------------
}
1.加装火焰传感器,
2.在msg.c文件中186行加入,实现商品数量、阈值,掉电不丢失;也就是第一次读取内核时,需要先从数据库读取商品数量,使用ioctl写入内核(在按键中断驱动key_irq.c中使用copy_from_user,初始化商品数量)
因为我不是直接在开发板启动根目录 rootfs/ 下写代码,而是写完一个功能后,再拷贝到 rootfs/ ,
而拷贝后会改变 .html、.cgi文件的 可执行权限,这个问题坑了我整整3天
最后使用cp -p
解决,为了保险起见又 使用chmod +x
所以我的copy.sh
脚本文件才全是chmod +x
#!/bin/bash
cd /home/linux/hqyj/14project/02仓储/www/cgisource
arm-linux-gnueabihf-gcc login.c cgic.c -o login.cgi -lsqlite3
arm-linux-gnueabihf-gcc store1.c cgic.c -o store1.cgi -lsqlite3
arm-linux-gnueabihf-gcc operation.c cgic.c -o operation.cgi -lsqlite3
arm-linux-gnueabihf-gcc store1_set.c cgic.c -o store1_set.cgi
arm-linux-gnueabihf-gcc store1_ctl.c cgic.c -o store1_ctl.cgi
cp login.cgi ../cgi-bin/
cp store1.cgi ../cgi-bin/
cp operation.cgi ../cgi-bin/
cp store1_set.cgi ../cgi-bin/
cp store1_ctl.cgi ../cgi-bin/
cd /home/linux/hqyj/14project/02仓储/www
arm-linux-gnueabihf-gcc project.c msg.c -o pro -lsqlite3 -lpthread
rm -rf /home/linux/nfs/rootfs/www
cp -rfp /home/linux/hqyj/14project/02仓储/www /home/linux/nfs/rootfs/
cd /home/linux/nfs/rootfs/www/
chmod +x *
cd /home/linux/nfs/rootfs/www/cgi-bin/
chmod +x *
cd /home/linux/nfs/rootfs/www/cgisource/
chmod +x *
看看这问题别人如何解决的:
1.修改其权限,这一步非常重要,我就是因为这一步走了很多弯路
2.cp -p命令保留文件权限
共享的全局变量,在头文件里声明为extern的:
不要初始化值
extern int g; // 注意,不要初始化值!
extern int g=0;错误
// create_mem()函数用于创建共享内存,首先使用ftok函数生成一个key,然后使用shmget函数创建一个共享内存段,最后使用shmat函数将共享内存段映射到进程的地址空间,并返回指向共享内存段的指针。
char*create_mem()
{
key_t key = ftok("/root/",'z');
int shmid = shmget(key,sizeof(char)*128,IPC_CREAT);
char* share_me =(char *)shmat(shmid, 0, 0);
return share_me;
}
char* share_me=create_mem();
//在函数create_mem()中,share_me指针是一个局部变量,在函数结束后,share_me指针所指向的内存空间会被释放,但是由于share_me指针指向的是共享内存段,所以即使函数结束,share_me指针仍然可以访问共享内存段,因此不会报错。
指向共享内存段的指针
,也就是一个地址值
char *GetMemory(void)
{
char p[] = "hello world";
return p; /* char *p = (char *)malloc(100);strcpy(p,"Hello World!");这才是对的*/
}//因为p的生命周期在GetMemory函数执行完了就被销毁了,str指向的是个野指针
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}