目录
11.ZIGBEE发送数据,由6818开发板接收后发送到ONENET
说实话,对于这个粤嵌的实训,真的有很多想吐槽的地方,以下就是粤嵌给的一块板子,屏幕已经碎了,只有一根串口线(甚至是RS232,tm的)和一根DC电源(可能是为了省成本,要我就整个TYPEC供电了),它甚至一条MIRCOusb都不给(接OTG,后来我发现adb传输用不了,可能是这块板子OTG口需要特定的驱动,是的,我没资料),网线也没给,tftp,nfs都没法用,后面发现它竟然是用板载的一个rx工具(当时真是知识盲区),对比我用的一块全志的T113的板子,这块板子真的寄。
吐槽完就进入正题吧,就是关于整个实训的各个实验:
1. LCD换自己喜欢的颜色
对于传输文件,我这里就统一用TFTP传输了
环境配置过程:
1.在windows环境下创建一个share文件,就用来存需要传到开发板的文件。
2.关掉防火墙(记得把那些360之类的也关了,下面的是防火墙关闭工具)
链接:https://pan.baidu.com/s/1R5ycBw-_kbUw-jruMJyZmQ
提取码:1234
3.TFTP工具配置
链接:https://pan.baidu.com/s/18gele0YKJ_-J2cbJhg-QuQ
提取码:1234
就改这两个,一个是share文件夹的路径,一个是本机的ip
4.把开发板IP改成与本机IP同一网段(因为我本机IP是192.168.5.10,开发板就改成192.168.5.9)
ifconfig eth0 192.168.5.9
5.尝试ping通本机IP
6.TFTP传输
我在share文件夹下放了一张BMP格式的图片
tftp 192.168.5.10 -g -r func.bmp
参数的详情见这篇博客 Linux命令之tftp常用参数说明_小小小羊羊羊的博客-CSDN博客_tftp参数这玩意主要是快啊,比rx快太多了,如果你还是没配出来,那建议参考韦东山老师的配置双网卡的教程走一遍,其实我在玩粤嵌这块板子前是先去玩了T113的开发板,试着走驱动开发方向,但没办法,既然学校强制学习应用开发,那就来吧!(鸡汤)
然后还是正题,就是显示个喜欢的颜色,很简单哈。
代码贴出来,扔到ubuntu拿交叉编译工具链跑就行
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> //ssize_t write(int fd, const void *buf, size_t count); //int open(const char *pathname, int flags); int main() { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open hello.c fail"); } //2.写入颜色数据 int w_ret=0; int i=0; int j=0; unsigned int color[480][800]={0}; for(i=0;i<480;i++) { for(j=0;j<800;j++) { color[i][j]=0xff0000; //红色 } } w_ret=write(fd, color, 480*800*4); if(w_ret==-1)//做错误判断 { perror("write fail"); } //3.关闭文件 close(fd); }
arm-linux-gnueabi-gcc -o LCD LCD.c
因为用的是自己的编译环境就直接搞了,编译出来的程序文件已经框出来了。
TFTP传输进去开发板,然后添加运行权限运行。
tftp 192.168.5.10 -g -r LCD1
chmod 777 LCD1
./LCD1
代码效果如下,实在有点简单,代码就不改了。
2. LCD换个图案
代码贴出来,操作也是和上面那个实验类似。
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> //ssize_t write(int fd, const void *buf, size_t count); //int open(const char *pathname, int flags); int main() { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open hello.c fail"); } //2.写入颜色数据 int w_ret=0; int i=0; int j=0; unsigned int color[480][800]={0}; for(i=0;i<480;i++) { for(j=0;j<800;j++) { if((j-400)*(j-400)+(i-240)*(i-240)<=200*200) //(x-x0)*(x-x0) + (y-y0)*(y-y0) =r*r { color[i][j]=0xff0000; //红色 } else { color[i][j]=0x000000; //黑色 } } } w_ret=write(fd, color, 480*800*4); if(w_ret==-1)//做错误判断 { perror("write fail"); } //3.关闭文件 close(fd); }
arm-linux-gnueabi-gcc -o LCD2 LCD.c
tftp 192.168.5.10 -g -r LCD2
chmod 777 LCD2
./LCD2
效果如上,因为前面的三个LCD实验比较简单,过得快一点了,后面的网络编程才是重头戏
3. LCD换张图片
代码贴在这里,图片用的是我在实验一用TFTP传输过去的那张,像素为800*480,必须为BMP格式,且必须命名(func.bmp)图片不是我做的,虽然我会,但我不想自己整一张了,就沿用别人发的图片吧
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> //off_t lseek(int fd, off_t offset, int whence); //ssize_t read(int fd, void *buf, size_t count); //ssize_t write(int fd, const void *buf, size_t count); //int open(const char *pathname, int flags); int main() { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open fb0 fail"); } //打开图片 int bmp_fd=0; //接受open的返回值 bmp_fd=open("./func.bmp", O_RDWR); if(bmp_fd==-1) //做错误判断 { perror("open func.bmp fail"); } //2.偏移54字节 lseek(bmp_fd,54,SEEK_SET); //3.读取像素数据 800*480 unsigned char bmp[800*480*3]={0}; read(bmp_fd,bmp,sizeof(bmp)); //4.数据处理 /* bmp[0]--B bmp[1]--G bmp[2]--R bmp[3]--B .... lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16; lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16; lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16; */ unsigned int lcd[800*480]={0}; int i=0; int j=0; for(i=0;i<800*480;i++) { lcd[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16; } //5.写入屏幕 int w_ret=0; w_ret=write(fd, lcd, sizeof(lcd)); if(w_ret==-1)//做错误判断 { perror("write fail"); } //6.关闭文件 close(bmp_fd); close(fd); }
arm-linux-gnueabi-gcc -o LCD3 LCD.c
tftp 192.168.5.10 -g -r LCD3
chmod 777 LCD3
./LCD3
效果如上,可以看到图片是颠倒的。下面贴个如何把图片正过来的代码。
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> //off_t lseek(int fd, off_t offset, int whence); //ssize_t read(int fd, void *buf, size_t count); //ssize_t write(int fd, const void *buf, size_t count); //int open(const char *pathname, int flags); int main() { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open fb0 fail"); } //打开图片 int bmp_fd=0; //接受open的返回值 bmp_fd=open("./func.bmp", O_RDWR); if(bmp_fd==-1) //做错误判断 { perror("open func.bmp fail"); } //2.偏移54字节 lseek(bmp_fd,54,SEEK_SET); //3.读取像素数据 800*480 unsigned char bmp[800*480*3]={0}; read(bmp_fd,bmp,sizeof(bmp)); //4.数据处理 /* bmp[0]--B bmp[1]--G bmp[2]--R bmp[3]--B .... lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16; lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16; lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16; */ unsigned int temp[800*480]={0}; unsigned int lcd[800*480]={0}; int i=0; int j=0; for(i=0;i<800*480;i++) { temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16; } for(i=0;i<480;i++) { for(j=0;j<800;j++) { lcd[(480-1-i)*800+j]=temp[i*800+j]; } } //5.写入屏幕 int w_ret=0; w_ret=write(fd, lcd, sizeof(lcd)); if(w_ret==-1)//做错误判断 { perror("write fail"); } //6.关闭文件 close(bmp_fd); close(fd); }
这里省去交叉编译的过程图
效果图如上,其实就是把图反着写入。
在这里把执行的程序文件放上来,大伙自己烧板子自己试哈
链接:https://pan.baidu.com/s/1BuQ5Q2FEGbgdJ1yEr4o86w
提取码:1234
4.网线登录
啧...我觉得这个可能没太大必要,虽然好像可以省一个串口,但还不如串口换成个带5V的TYPEC,也是两条线,搞这个不如整个WiFi模块远程无线调试,我不做了,但里面有一个过程比较有价值,就是更改开机脚本的
其实就是改ifconfig之后得到的开发板的网卡IP,我这里是改成了192.168.5.9,需要的话改,不需要就每次开机都输入一条vi /etc/profile
ifconfig eth0 192.168.5.9
5.触屏电子相册
我靠,晴天霹雳,完成这东西需要整多几张图,太难受了
然后在图画另存为bmp格式就行,我做的是这三张。
下面贴出代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include <linux/input.h> //void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); //off_t lseek(int fd, off_t offset, int whence); //ssize_t read(int fd, void *buf, size_t count); //ssize_t write(int fd, const void *buf, size_t count); //int open(const char *pathname, int flags); //函数声明 int show_bmp(const char *bmpname); int show_anybmp(const char *bmpname); int show_anywherebmp(int x0,int y0,const char *bmpname); int get_xy(int *x,int *y); int main() { int x=-1; int y=-1; int tmp=0; char photo[][30]={"./1.bmp","./2.bmp","./3.bmp"}; //1.显示主界面 show_anybmp("./func.bmp"); //规则界面 while(1) { //2.获取坐标 get_xy(&x,&y); if(x>=400) //下一张 { tmp=(tmp+1)%3; show_bmp(photo[tmp]); } else if(x<400) //上一张 { tmp=tmp-1; if(tmp==-1){ tmp=2; } show_bmp(photo[tmp]); } //用完坐标得清零 坐标 x=-1; y=-1; } } //函数实现 //显示800*480的图片 int show_bmp(const char *bmpname) { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open fb0 fail"); } //建立屏幕映射 unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //打开图片 int bmp_fd=0; //接受open的返回值 bmp_fd=open(bmpname, O_RDWR); if(bmp_fd==-1) //做错误判断 { perror("open func.bmp fail"); } //2.偏移54字节 lseek(bmp_fd,54,SEEK_SET); //3.读取像素数据 800*480 unsigned char bmp[800*480*3]={0}; read(bmp_fd,bmp,sizeof(bmp)); //4.数据处理 /* bmp[0]--B bmp[1]--G bmp[2]--R bmp[3]--B .... lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16; lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16; lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16; */ unsigned int temp[800*480]={0}; int i=0; int j=0; for(i=0;i<800*480;i++) { temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16; } //解决上下颠倒 把一维数组 二维化思考 for(i=0;i<480;i++) { for(j=0;j<800;j++) { lcd[(480-1-i)*800+j]=temp[i*800+j]; } } //解除映射 munmap(lcd,800*480*4); //6.关闭文件 close(bmp_fd); close(fd); } //显示任意大小图片 int show_anybmp(const char *bmpname) { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open fb0 fail"); } //建立屏幕映射 unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //打开图片 int bmp_fd=0; //接受open的返回值 bmp_fd=open(bmpname, O_RDWR); if(bmp_fd==-1) //做错误判断 { perror("open func.bmp fail"); } //2.偏移54字节 //先提取到宽 lseek(bmp_fd,18,SEEK_SET); int w=0; read(bmp_fd,&w,4); //printf("w=%d\n",w);//打印宽度信息 //再提取高 lseek(bmp_fd,22,SEEK_SET); int h=0; read(bmp_fd,&h,4); //printf("h=%d\n",h);//打印宽度信息 lseek(bmp_fd,54,SEEK_SET); //3.读取像素数据 800*480 unsigned char bmp[w*h*3]; read(bmp_fd,bmp,sizeof(bmp)); //4.数据处理 /* bmp[0]--B bmp[1]--G bmp[2]--R bmp[3]--B .... lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16; lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16; lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16; */ unsigned int temp[800*480]={0}; int i=0; int j=0; for(i=0;i<w*h;i++) { temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16; } //解决上下颠倒 把一维数组 二维化思考 for(i=0;i<h;i++) { for(j=0;j<w;j++) { lcd[(h-1-i)*800+j]=temp[i*w+j]; } } //解除映射 munmap(lcd,800*480*4); //6.关闭文件 close(bmp_fd); close(fd); } //在指定位置显示图片 x0,y0为起点坐标 int show_anywherebmp(int x0,int y0,const char *bmpname) { //1.打开屏幕 int fd=0; //接受open的返回值 fd=open("/dev/fb0", O_RDWR); if(fd==-1) //做错误判断 { perror("open fb0 fail"); } //建立屏幕映射 unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //打开图片 int bmp_fd=0; //接受open的返回值 bmp_fd=open(bmpname, O_RDWR); if(bmp_fd==-1) //做错误判断 { perror("open func.bmp fail"); } //2.偏移54字节 //先提取到宽 lseek(bmp_fd,18,SEEK_SET); int w=0; read(bmp_fd,&w,4); printf("w=%d\n",w);//打印宽度信息 //再提取高 lseek(bmp_fd,22,SEEK_SET); int h=0; read(bmp_fd,&h,4); printf("h=%d\n",h);//打印宽度信息 lseek(bmp_fd,54,SEEK_SET); //3.读取像素数据 800*480 unsigned char bmp[w*h*3]; read(bmp_fd,bmp,sizeof(bmp)); //4.数据处理 /* bmp[0]--B bmp[1]--G bmp[2]--R bmp[3]--B .... lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16; lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16; lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16; */ unsigned int temp[800*480]={0}; int i=0; int j=0; for(i=0;i<w*h;i++) { temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16; } //解决上下颠倒 把一维数组 二维化思考 for(i=0;i<h;i++) { for(j=0;j<w;j++) { lcd[(h-1-i+y0)*800+j+x0]=temp[i*w+j]; } } //解除映射 munmap(lcd,800*480*4); //6.关闭文件 close(bmp_fd); close(fd); } int get_xy(int *x,int *y) { int count=0; //1.打开触摸屏 int tsfd =open("/dev/input/event0",O_RDWR); if(tsfd == -1) { perror("open ts fail"); } //2.read struct input_event ts; while(1) { read(tsfd,&ts,sizeof(struct input_event)); //筛选 if(ts.type ==EV_ABS && ts.code==ABS_X ) { *x=ts.value; //适合蓝底屏幕 //*x= ts.value*800/1024; //适合黑底屏幕 count++; } if(ts.type ==EV_ABS && ts.code==ABS_Y ) { *y=ts.value; //适合蓝底屏幕 //*y= ts.value*480/600; //适合黑底屏幕 count++; } if(count == 2) { break; } } //关闭触摸屏 close(tsfd); }
arm-linux-gnueabi-gcc -o touch LCD_drv_touch.c
效果如下:
效果
6.网络编程(TCP通信)
因为我没听课,所以就不知道他做的什么内容了..这部分我确实没学过,本来打算是寒假去学的,刚刚好,他竟然教了。
前面还有一个多线程的实验,因为不难我就不做了,拿gcc编译工具在UBUNTU上跑就行
代码贴出来
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include <linux/input.h> #include <pthread.h> //int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); //线程任务函数 void *pth_function1(void *arg) { while(1) { printf("你真帅!!!\n"); sleep(1);//延时一秒 } } //主线程 int main() { pthread_t thid; //定义线程ID //创建一个新的线程,默认属性 任务函数 不传参 pthread_create(&thid, NULL, pth_function1, NULL); while(1) { printf("年轻人不讲武德!!!\n"); sleep(1);//延时一秒 } }
gcc pth.c -o pth -pthread
然后是第一个实验,TCP的客户端与服务端间的通信
ifconfig
需要改这里:
服务端代码:(server.c)
#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include <strings.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include <linux/input.h> //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //int listen(int sockfd, int backlog); //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //int socket(int domain, int type, int protocol); int main() { //1.创建socket int skfd=socket(AF_INET ,SOCK_STREAM, 0); if(skfd == -1) { perror("socket fail"); } else { printf("socket ok\n"); } //2.bind IP和端口号 //定义结构体 struct sockaddr_in seraddr={0}; seraddr.sin_family=AF_INET; //IPV4 seraddr.sin_port= htons(12345); //端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号 //htons() 把本地转换为网络序 认识大端和小端存储 seraddr.sin_addr.s_addr=htonl(INADDR_ANY); //htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP int b_ret=bind(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr)); if(b_ret !=0) { perror("bind fail"); } else { printf("bind ok\n"); } //3.listen--等待连接 int l_ret = listen(skfd,3); if(l_ret!=0) { perror("listen fail"); } else { printf("listen ok\n"); } //4.accept struct sockaddr_in cliaddr={0}; //为了存储连接的客户端信息 int len=sizeof(cliaddr); int newskfd=accept(skfd,(struct sockaddr*)&cliaddr, &len); if(newskfd == -1) { perror("accept fail"); return -1; } else { printf("accept ok\n"); printf("newskfd=%d,client-ip:%s,client-port:%d\n",newskfd,inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port)); } //5.read/write 服务器一直接收 char buf[1024]={0}; while(1) { read(newskfd,buf,sizeof(buf)); //读取消息 printf("buf=%s\n",buf); //打印消息 if( strcmp(buf,"exit") == 0) //字符串的判断 { break; //跳出循环 关闭通信 } memset(buf,0,sizeof(buf)); //清空数组 } //6. 关闭通信 close(skfd); }
客户端代码:(client.c)
#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include <strings.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include <linux/input.h> //int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //int listen(int sockfd, int backlog); //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //int socket(int domain, int type, int protocol); int main() { //1.创建socket int skfd=socket(AF_INET ,SOCK_STREAM, 0); if(skfd == -1) { perror("socket fail"); } else { printf("socket ok\n"); } //2.发起连接请求 connect struct sockaddr_in seraddr={0}; seraddr.sin_family=AF_INET; //IPV4 seraddr.sin_port= htons(12345); //端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号 //htons() 把本地转换为网络序 认识大端和小端存储 seraddr.sin_addr.s_addr=inet_addr( "192.168.42.168"); //服务器的地址 //htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP int c_ret=connect(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr)); if(c_ret!=0) { perror("connect fail"); return -1; } else { printf("connect ok\n"); } //3.read /write 通信:客户端一直发消息 char buf[1024]={0}; while(1) { printf("请输入要发送的消息:\n"); scanf("%s",buf); write(skfd,buf,strlen(buf)); //发送消息 if(strcmp(buf,"exit")==0) //判断消息为退出关键字 { break; } printf("buf=%s\n",buf); } //4.关闭通信 close(skfd); }
效果如下:
7.网络编程(UDP通信)
直接贴代码了,比较简单,难在理解整个过程,不然代码是没法写的
本机UBUNTUip为192.168.5.11,想要啥设备接收就写哪个设备的ip
服务端(server.c)
#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include <strings.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include <linux/input.h> //ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); int main() { //1.创建socket int skfd=socket(AF_INET ,SOCK_DGRAM, 0); if(skfd == -1) { perror("socket fail"); } else { printf("socket ok\n"); printf("skfd=%d\n",skfd); } int s_ret=0; //返回值 char buf[512]={0}; //存储读取内容 struct sockaddr_in seraddr={0}; //来自客户端地址 seraddr.sin_family=AF_INET; //IPV4 seraddr.sin_port= htons(12345); //端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号 //htons() 把本地转换为网络序 认识大端和小端存储 seraddr.sin_addr.s_addr=inet_addr( "192.168.5.11"); //服务器的地址 //htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP socklen_t addrlen=sizeof(seraddr); //地址长度 while(1) { printf("请输入发送的消息\n"); scanf("%s",buf); s_ret=sendto(skfd,buf, strlen(buf),0,(struct sockaddr*)&seraddr, addrlen); //面试题 strlen 和 sizeof 对比 if(s_ret==-1) { perror("sendto fail"); } if(strcmp(buf,"exit")== 0) { break; } memset(buf,0,sizeof(buf)); //用完之后清空 } //关闭通信 close(skfd); }
客户端(client.c)
#include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include <strings.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include <linux/input.h> //ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen); int main() { //1.创建socket int skfd=socket(AF_INET ,SOCK_DGRAM, 0); if(skfd == -1) { perror("socket fail"); } else { printf("socket ok\n"); printf("skfd=%d\n",skfd); } //2.bind IP和端口号 //定义结构体 struct sockaddr_in seraddr={0}; seraddr.sin_family=AF_INET; //IPV4 seraddr.sin_port= htons(12345); //端口号 http-80 8080 Telnet--23 范围:0~65535 个人编程的时候建议5位数的端口号 //htons() 把本地转换为网络序 认识大端和小端存储 seraddr.sin_addr.s_addr=htonl(INADDR_ANY); //htonl() 课后 认识一下 转换为网络序 INADDR_ANY--0.0.0.0--表示自动获取本机IP int b_ret=bind(skfd, (struct sockaddr*)&seraddr,sizeof(seraddr)); if(b_ret !=0) { perror("bind fail"); } else { printf("bind ok\n"); } int r_ret=0; //返回值 char buf[512]={0}; //存储读取内容 struct sockaddr_in cliaddr={0}; //来自客户端地址 socklen_t addrlen=sizeof(cliaddr); //地址长度 while(1) { //接收消息 r_ret=recvfrom(skfd, buf,sizeof(buf),0,(struct sockaddr*)&cliaddr, &addrlen); if(r_ret == -1) { perror("recvfrom fail"); } else { printf("from %s:%s\n",inet_ntoa(cliaddr.sin_addr),buf); } if(strcmp(buf,"exit")==0)//判断消息内容 { break; } memset(buf,0,sizeof(buf)); //用完之后清空 memset(&cliaddr,0,sizeof(cliaddr)); } //关闭通信 close(skfd); }
8.开发板串口通信MCU(32或Zigbee节点)
这个功能确实是我想学的..
但很难受,手头上没杜邦线
这里做一个开发板多线程自己通信自己
贴出来代码:
#include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <termios.h> #include <unistd.h> #include <string.h> int set_serial_uart(int ser_fd) { struct termios new_cfg,old_cfg; /*保存并测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/ if (tcgetattr(ser_fd, &old_cfg) != 0) { perror("tcgetattr"); return -1; } bzero( &new_cfg, sizeof(new_cfg)); /*原始模式*/ /* 设置字符大小*/ new_cfg = old_cfg; cfmakeraw(&new_cfg); /* 配置为原始模式 */ /*波特率为115200*/ cfsetispeed(&new_cfg, B115200); cfsetospeed(&new_cfg, B115200); //用于本地连接和接受使能 new_cfg.c_cflag |= CLOCAL | CREAD; /*8位数据位*/ new_cfg.c_cflag &= ~CSIZE; new_cfg.c_cflag |= CS8; /*无奇偶校验位*/ new_cfg.c_cflag &= ~PARENB; /*1位停止位*/ new_cfg.c_cflag &= ~CSTOPB; /*清除串口缓冲区*/ tcflush( ser_fd,TCIOFLUSH); new_cfg.c_cc[VTIME] = 0; //等待时间 new_cfg.c_cc[VMIN] = 1; //最少接收字节数 tcflush ( ser_fd, TCIOFLUSH); /*串口设置使能*/ tcsetattr( ser_fd ,TCSANOW,&new_cfg); } int main(void) { int ret; char buf[10]; //打开串口 0 int fd = open("/dev/ttyUSB0" , O_RDWR|O_NOCTTY); if(fd < 0) { perror ("open failed"); return 0; } set_serial_uart(fd); while(1) { bzero(buf, 10); ret = read(fd , buf , 10-1); // 留一个位置给‘\0' if(ret <= 0 ) { perror("write failed"); break; } printf("I GOT : %s \n", buf); // 打印 } }
硬件连接如下:
用的善学坊的一款板子,板载ch340,接收路由器设备采集到的光照强度数据,温湿度数据发送到协调器,然后协调器再通过USB0发送给开发板。
开发板接收到数据如下,有点冷...
9.EDP接入onenet
哇,真的是不想搞这玩意,没想到又遇到了,之前弄完之后把环境全删掉了,觉得有点没意思,现在用的stm32连接onenet,至于MQTT通信,因为在学这玩意之前先去学了ros通信,其实也就差不多,就是客户端发布话题,服务端订阅,差别就差在ros通信里面有个通信的master。
但MQTT的环境有点问题,所以在这里先把EDP的通信解决了。
我不知道你们界面是不是这样:
这里有个多协议接入,我们要用到的EDP协议貌似只有这里有
或者以这种形式也能进去
选择EDP,点击添加产品
主要是设备接入协议那里选择EDP就行,其他随便
添加完就是这样了,点击下面的位置进入
点击设备列表再点击添加设备
填写只需注意鉴权信息就行
添加好后如下,点击详情
添加APIkey后将这三个信息记录下来
放入记事本
点击数据流模板,再点击添加数据流模板
因为代码内设置的是Temp,所以这里也就用Temp了,但实际上这东西按理讲是不用加的,当数据上传上来就会自动生成才是。
设置好后如下
然后就是改代码了,代码用的是老师给的一份代码,在这里直接贴链接了
链接:https://pan.baidu.com/s/1FxXrvckHxBiyX9E-HZakgA
提取码:1234
更改代码如下,分别是设备ID及API密钥
可以看到,该代码将会上传一个名为Temp的数据流,并且该数据将不断加1,到100,再清0
直接放到UBUNTU上编译就行,可以看到,选中的为执行文件
运行
设备连接成功
数据流如下
然后就是试一下,将该代码用在开发板上了,怎么用呢,首先得让开发板连上网吧?..
这就涉及到我的知识盲区了..
先不管了,先把开机脚本改一下:
vi /etc/profile
先把这两行注释掉,屏蔽开发板的嵌入式物联网综合实验箱
然后再配置上网
怎么找信息呢..我是连上了从路由器接过来的网线到电脑上
点击这里
自动配置IP
可以看到IPV4地址在该机为192.168.1.5
这信息不就来了嘛
所以开发板内就这样配置
哎,每次进入这个开机程序之后,只要这个串口线一松,就掉出界面,然后就拒绝访问,我是真的烦,所以我就直接输了
ifconfig eth0 up
ifconfig eth0 192.168.1.6
route add default gw 192.168.1.1
echo "nameserver 114.114.114.114" > /etc/resolv.conf
echo "search lan" >> /etc/resolv.conf
然后来到更改适配器选项这里
用哪个网卡改哪个网卡,右键属性
配置就结束了。
然后把网线插到开发板上,哇这网络延迟,ping是ping通了,感觉这延迟不对劲啊
现在说明开发板能连上网了
然后就是改代码了,这份代码也是现成的,需要改的部分和之前一致。
这里直接贴链接了
链接:https://pan.baidu.com/s/1yxfU5qXSzRodnv8JJjQSAg
提取码:1234
这里只需要把交叉编译工具链改成自己的就行
编译出的程序文件如下
把它扔到开发板运行试试
因为网口被占用被迫用回RX工具了..
运行发现,开发板已经连上onenet了
显示在线
数据正常
下发个数据试试
正常
10.MQTT协议接入onenet
这个..需要配置
openssl-OpenSSL_1_0_2q,paho.mqtt.c-1.3.0
(编译paho时需打开PAHO_WITH_SSL选项) 直接跟着走就行
首先还是这个界面,但用的是MQTT物联网套件
点击添加产品
重点还是这个接入协议
点进去
设备列表,添加设备
信息随便设置
然后就是要改代码了
直接贴上来了
链接:https://pan.baidu.com/s/1daXTwM9xmNwG62TnBOYvDw
提取码:1234
要改如下几个部分,分别对应于以下几个位置的信息
const char *server_url = "ssl://mqttstls.heclouds.com:8883";
然后Cmakelist.txt中需要加一个参数
代码就算改完了,然后是环境配置
把代码扔上ubuntu后
安装CMake
sudo apt install cmake
安装OpenSSL
sudo apt-get install libssl-dev
安装paho.mqtt.c
git clone https://github.com/eclipse/paho.mqtt.c.git cd paho.mqtt.c //修改编辑CMakeLists.txt文件,打开PAHO_WITH_SSL,编辑下图所示的位置,将FALSR改为TRUE
//修改
编辑CMakeLists.txt
文件,将FALSR
改为TRUE
make clean make sudo make install
编译示例代码:
cmake . make clean make
链接onenet成功
如下
11.ZIGBEE发送数据,由6818开发板接收后发送到ONENET
硬件连接如下,可以看到,协调器通过USB0连接到6818开发板,然后路由器节点连接到电脑(仅供电,)6818开发板连接网线与电脑通过RS232串口线相连(需要上网和串口调试)
这里直接贴用的代码了
链接:https://pan.baidu.com/s/18w0fwo3Zz8gmhAKkiTzEgA
提取码:1234
ZIGBEE代码就不给了,我这里的ZIGBEE是把温度湿度光照强度,三个数放在一个字符串变量里面,到时候直接开发板自己拆分解决
对比一下数据流
下发命令呢?也正常
12.开发板接收onenet下发命令通过协调器控制路由器开关灯