今天是老师催稿的最后一天,由于上课时间冲突,没有把博文写完,今天在这补个博文,这个博文会持续更新,因为目前的项目我还没有改完整,所以后续会补上。
首先,我们用到的器件有如下几个:
树莓派Pi3、DS18B20温湿度传感器、L9110S桥两路直流电机驱动板、两个马达、两个轮子、HC-SR04超声波模块、SG90舵机、0.91‘Oled。
以下为服务端代码代码:
#include "oled.h" //oled.h文件包含了所有的需要用到的器件的驱动代码
#include <time.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <unistd.h>
#include <stdio.h>
#include "log.h"
#include <sys/socket.h>
//#include <linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "msg.h"
#include <pthread.h>
#include "char.h"
int g_running;
void handle_cmd(struct Msg *in_cmd,struct Msg *out_cmd){
out_cmd->cmd = in_cmd->cmd;
switch(in_cmd->cmd){
case FTP_CMD_QUIT:
g_running = 0;
Write("recv command: quit\n");
//exit(0);
break;
case FTP_CMD_GO:
digitalWrite(21,0);
digitalWrite(22,1);
digitalWrite(23,0);
digitalWrite(24,1);
Write("recv command: go\n");
break;
case FTP_CMD_BACK:
digitalWrite(21,1);
digitalWrite(22,0);
digitalWrite(23,1);
digitalWrite(24,0);
Write("recv command: back\n");
break;
//case FTP_CMD_TEMPTURE:
// pthread_create(&poled,NULL,(void *)oled,NULL);
//oled();
// Write("recv command: tempture\n");
// break;
case FTP_CMD_STOP:
digitalWrite(21,1);
digitalWrite(22,1);
digitalWrite(23,1);
digitalWrite(24,1);
Write("recv command: stop\n");
break;
case FTP_CMD_LEFT:
digitalWrite(21,0);
digitalWrite(22,1);
digitalWrite(23,1);
digitalWrite(24,1);
Write("recv command: left\n");
break;
case FTP_CMD_RIGHT:
digitalWrite(21,1);
digitalWrite(22,1);
digitalWrite(23,0);
digitalWrite(24,1);
Write("recv command: right\n");
break;
default:
Write("command is not right\n");
break;
}
}
int main(int argc, char const *argv[])
{
wiringPiSetup(); //程序一运行,先初始化
pinMode(21,OUTPUT); //设置引脚
pinMode(22,OUTPUT);
pinMode(23,OUTPUT);
pinMode(24,OUTPUT);
pinMode(1,PWM_OUTPUT); //设置引脚1为脉冲输出信号
pwmSetMode(PWM_MODE_MS);
pwmSetRange(2500); //设置脉冲周期
pwmSetClock(192); //默认为192,可不写
struct Msg *send_msg = NULL;
struct Msg *recv_msg = NULL;
send_msg = (struct Msg *)malloc(sizeof(struct Msg));
recv_msg = (struct Msg *)malloc(sizeof(struct Msg));
int s_fd;
int c_fd;
int ret;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
pthread_t ac;
pthread_t poled;
pthread_create(&poled,NULL,(void *)oled,NULL); //运行线程,此时所有的功能都在这个线程里运行,其实这样根本没有用到客户端,但是因为时间比较短,暂时先写成这样,后续修改。
Create("./server.txt");
//1 socket
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
Write("socket failed\n");
exit(-1);
}
//2 bind
memset(&c_addr,0,sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(8990);
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr));
if(ret < 0){
Write("bind error %d\n",ret);
return -1;
}
//3 listen
if(listen(s_fd,10)== -1){
Write("listen failed\n");
exit(-1);
}
//4 accept
socklen_t clen = sizeof(struct sockaddr);
c_fd =accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd == -1){
Write("accept error\n");
exit(-1);
}
Write("Get connect:%s\n", inet_ntoa(c_addr.sin_addr));
struct Auth auth;
ret = recv_handle(c_fd,(char *)&auth,sizeof(struct Auth));
Write("recd ret %d %s %s\n",ret,auth.username,auth.password);
struct Auth server;
FILE *fp = fopen("psw","r");
if(fp != NULL ){
fscanf(fp,"%s %s",server.username,server.password);
Write("server %s %s\n",server.username,server.password);
fclose(fp);
}
if(0 != memcmp(auth.username,server.username,strlen(server.username)) ||
0 != memcmp(auth.password,server.password,strlen(server.password))){
auth.cmd = FTP_CMD_ERROR;
Write("auth falied\n");
}
ret =send_handle(c_fd,(char *)&auth,sizeof(struct Auth));
Write("send ret %d\n",ret);
memset(auth.username,0,sizeof(auth.username));
memset(auth.password,0,sizeof(auth.password));
memset(server.username,0,sizeof(server.username));
memset(server.password,0,sizeof(server.password));
if(FTP_CMD_ERROR == auth.cmd){
return -1;
}
//5 recv
//memset(readBuf,0,sizeof(readBuf));
g_running = 1;
while(1){
memset(send_msg,0,sizeof(struct Msg));
memset(recv_msg,0,sizeof(struct Msg));
//ret = recv(c_fd,recv_msg,sizeof(struct Msg),0);
ret = recv_handle(c_fd,(char *)recv_msg,sizeof(struct Msg));
if(ret == -1){
Write("recv error\n");
exit(-1);
}
if(FTP_CMD_QUIT == recv_msg->cmd){
printf("server quit\n");
exit(-1);
}
handle_cmd(recv_msg,send_msg);
//6 send
//send_handle(c_fd,send_msg->data,send_msg->data_length);
//ret = send(c_fd,send_msg,sizeof(struct Msg),0);
ret = send_handle(c_fd,(char *)send_msg,sizeof(struct Msg));
Write("send ret %d\n",ret);
}
Destroy();
return 0;
}
oled.c部分代码:
#include "temperature.h"
#include <time.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#define Echo 29
#define Trig 28
int fd;
void UltrasonicInit(){ //初始化超声波引脚和设置引脚1的脉冲信号
pinMode(Trig,OUTPUT);
pinMode(Echo,INPUT);
pinMode(1,PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);
pwmSetRange(2500);
pwmSetClock(192);
}
float Distance(){ //超声波测距的代码
struct timeval tv1;
struct timeval tv2;
long start;
long stop;
float dis;
digitalWrite(Trig,LOW);
delayMicroseconds(2);
digitalWrite(Trig,HIGH);
delayMicroseconds(10);
digitalWrite(Trig,LOW);
while(!(digitalRead(Echo) == 1));
gettimeofday(&tv1,NULL);
while(!(digitalRead(Echo) == 0));
gettimeofday(&tv2,NULL);
start = tv1.tv_sec * 1000000 + tv1.tv_usec;
stop = tv2.tv_sec * 1000000 + tv2.tv_usec;
dis = (float)(stop - start)/1000000 *34000/2;
return dis;
}
unsigned char yi[4][16] = {" C Ray", //第一行
" ", //第二行
" ", //第三行
"IP:192.168.43.86" //第四行
}; //显示内容
const unsigned char zi[];
void init(void) //初始化
{
//wiringPiSetup();
fd = wiringPiI2CSetup(0x3c); // i2c初始化 0x3c是oled的从机地址
wiringPiI2CWriteReg8(fd, 0x00, 0xa1); //图像反了修改成0xa0
wiringPiI2CWriteReg8(fd, 0x00, 0xc8); //行输出反了修改成0xc0
wiringPiI2CWriteReg8(fd, 0x00, 0x8d); //允许电荷泵
wiringPiI2CWriteReg8(fd, 0x00, 0x14);
wiringPiI2CWriteReg8(fd, 0x00, 0xa6); //想反相显示改成0xa7
wiringPiI2CWriteReg8(fd, 0x00, 0x21); //重置列地址
wiringPiI2CWriteReg8(fd, 0x00, 0x00);
wiringPiI2CWriteReg8(fd, 0x00, 0x7f);
wiringPiI2CWriteReg8(fd, 0x00, 0xaf); //开显示
}
void qingping(void) //清屏
{
char zt1, zt2;
for (zt1 = 0; zt1 < 8; zt1++) {
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + zt1);
for (zt2 = 0; zt2 < 128; zt2++) wiringPiI2CWriteReg8(fd, 0x40, 0x00);
}
}
void ascii(void) //显示ASCII码8*16
{
int zt;
char zt3, zt4;
for (zt3 = 0; zt3 < 4; zt3++) {
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + (zt3 * 2));
for (zt4 = 0; zt4 < 16; zt4++)
for (zt = 0; zt < 8; zt++)
wiringPiI2CWriteReg8(fd, 0x40, zi[yi[zt3][zt4] * 16 + zt]);
wiringPiI2CWriteReg8(fd, 0x00, 0xb0 + (zt3 * 2) + 1);
for (zt4 = 0; zt4 < 16; zt4++)
for (zt = 0; zt < 8; zt++)
wiringPiI2CWriteReg8(fd, 0x40, zi[yi[zt3][zt4] * 16 + zt + 8]);
}
}
void shijian(void) //当前时间
{
struct tm *ptr;
time_t lt;
lt = time(<);
ptr = localtime(<);
strftime(yi[1], 16, "%m/%d %a", ptr); //月/日 周几
strftime(yi[2], 16, "%R %p", ptr); //时:分 am或pm
}
void oled(){
float c;
float dis;
char pstr[20];
init();
UltrasonicInit();
qingping();
digitalWrite(21,0); //程序一调用,先让轮子跑起来
digitalWrite(22,1);
digitalWrite(23,0);
digitalWrite(24,1);
while (1) {
dis = Distance(); //然后调用Distance函数测距
printf("Distance:%0.2f cm\n",dis);
if(dis < 10){ //如果距离小于10cm,给四个引脚置高电平,轮子停止运转,
digitalWrite(21,1);
digitalWrite(22,1);
digitalWrite(23,1);
digitalWrite(24,1);
pwmWrite(1,50); //向舵机发送脉冲信号,角度调到0度,然后延迟一段时间再把角度转到180
delay(1000);
pwmWrite(1,250);
c = Temperature(); //调用检测温度函数,获取温度数据
gcvt(c,3,pstr); //把单精度转成字符型
strcpy(yi[0],pstr); //把温度数据拷入yi字符数组,输出到屏幕上
shijian();
ascii();
printf("Temperature: %s C\n",pstr);
}else{ //如果不是上面的情况,就让轮子一直转
digitalWrite(21,0);
digitalWrite(22,1);
digitalWrite(23,0);
digitalWrite(24,1);
}
}
}
temperature代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
float value;
float Temperature() {
char path[50] = "/sys/bus/w1/devices/";
char rom[20];
char buf[100];
DIR *dirp;
struct dirent *direntp;
int fd = -1;
char *temp;
system("sudo modprobe w1-gpio");
system("sudo modprobe w1-therm");
if ((dirp = opendir(path)) == NULL) {
printf("opendir error\n");
return -1;
}
while ((direntp = readdir(dirp)) != NULL) {
if (strstr(direntp->d_name, "28-03169779636a")) {
strcpy(rom, direntp->d_name);
osedir(dirp);
strcat(path, rom);
strcat(path, "/w1_slave");
if ((fd = open(path, O_RDONLY)) < 0) {
printf("open error\n");
return -1;
if (read(fd, buf, sizeof(buf)) < 0) {
printf("read error\n");
return -1;
}
temp = strchr(buf, 't');
sscanf(temp, "t=%s", temp);
value = atof(temp) / 1000;
// printf("Temperature: %0.1f\n",value);
// sleep(3);
return value;
}
}
}
}
代码实现的大概效果:程序一运行,轮子就会不停地砖,直到检测到有障碍物靠近10厘米内,轮子会停止转动,舵机会打开一段时间然后关闭。
今天比较仓促,代码就先改到这里,中间有遇到一个问题是加入多个线程之后运行客户端时服务端会出现段错误,找了半天不知道在哪,个人估计是两个线程在运行时争夺某个共同的资源时产生了冲突,因为这个问题我去掉了多线程,所以我改成了所有的功能都写在了一个.c文件下,后面持续调改。