在 Linux 下,移植一個 boa 服務器,編寫相應 cgi,在網頁上動態刷新串口數據(使用虛擬串口),使用到串口編程,數據庫編程及簡單前端知識。
該測控系統測量數據通過虛擬串口傳遞(由於條件限制未使用傳感器),目前只有測的功能,未來會進一步改進。
以下是具體內容
讀取串口數據程序:
這裏用到串口編程,寫一個程序讀取串口數據,然後將讀取數據插入數據庫,有用到數據庫編程的知識。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sqlite3.h>
#define BUFFER_SIZE 200
int open_port()
{
int fd;
fd = open("/dev/ttyS1",O_RDWR | O_NOCTTY | O_NDELAY);//打開串口
if(fd < 0)
{
perror("open serial port");
return (-1);
}
if(fcntl(fd,F_SETFL,0) < 0)//回覆串口爲阻塞狀態
{
perror("fcntl F_SETFL\n");
}
if(isatty(fd) == 0)//測試打開的文件是否爲終端設備
{
perror("This is not a terminal device");
}
return fd;
}
int set_com_config(int fd)
{
struct termios new_cfg,old_cfg;
int speed;
if(tcgetattr(fd,&old_cfg) != 0)//保留原串口配置
{
perror("tcgetattr");
return -1;
}
new_cfg = old_cfg;
cfmakeraw(&new_cfg);//將終端設置爲原始模式
new_cfg.c_cflag &= ~CSIZE;//用數據位掩碼清空數據位設置
speed = B115200;
cfsetispeed(&new_cfg,speed);//設置波特率
cfsetospeed(&new_cfg,speed);
new_cfg.c_cflag |= CS8;//重新設置字符大小
new_cfg.c_cflag &= ~PARENB;//設置奇偶校驗位
new_cfg.c_iflag &= ~INPCK;
new_cfg.c_cflag &= ~CSTOPB;//設置停止位
new_cfg.c_cc[VTIME] = 0;//設置最少字符和等待時間
new_cfg.c_cc[VMIN] = 1;
tcflush(fd,TCIFLUSH);//清空緩衝區
if((tcsetattr(fd,TCSANOW,&new_cfg)) != 0)//激活配置
{
perror("tcsetattr");
return -1;
}
return 0;
}
int main(void)
{
int fd;
int nread;
char buff[BUFFER_SIZE];
int rc,i;
sqlite3 *db = NULL;
sqlite3_stmt *stmt;
char *errmsg = NULL;
char sql[512];
rc = sqlite3_open("ph.db",&db);//打開數據庫
if((fd = open_port()) < 0)//打開串口
{
perror("open_port");
return 1;
}
if(set_com_config(fd) < 0)//串口設置
{
perror("set_com_config");
return 1;
}
while(1)
{
printf("receive is \n");
memset(buff,0,BUFFER_SIZE);
read(fd,buff,BUFFER_SIZE);
printf("%s\n",buff);
sprintf(sql,"update PHdata set id = %c,Pid = %c,Pph = %c,we = %c",buff[0],buff[1],buff[2],buff[3]);
sqlite3_exec(db,sql,NULL,NULL,errmsg);//向數據庫插入數據
printf("%s\n",sql);
}
sqlite3_close(db);
close(fd);
return 0;
}
簡易CGI:由於前端只是還在起步階段,所以這個網頁界面做的比較簡單,未來會進一步改進。
代碼:
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
int main()
{
sqlite3 *pdb=NULL;
sqlite3_stmt *stmt;
char *szErrMsg=0;
int rc,i;
rc=sqlite3_open("ph.db",&pdb);
if(rc)
{
fprintf(stderr,"can't open database: %s",sqlite3_errmsg(pdb));
sqlite3_close(pdb);
return -1;
}
printf("Content-type:text/html\n\n");
printf("<html>\n<head>\n<Meta http-equiv=\"Refresh\" Content=\"1;\"><title>test</title></head>\n<body>\n");
printf("<h1 align=\"center\">PHDATA</h1>\n");
printf("<table border=\"1\" align=\"center\">\n");
printf("<tr>\n");
printf("<th>id</th><th>Pid</th><th>Pph</th><th>we</th>\n");
printf("</tr>\n");
char sql[512];
//char *sql="select *from wsd where id=(select max(id)from wsd where dnum=1)";
// int j=1;
// for(;j<=3;j++)
// {
sprintf(sql,"select * from PHdata;");
sqlite3_prepare(pdb,sql,-1,&stmt,0);
//sqlite3_bind_int(stmt,kk,i);
//sqlite3_bind_int(stmt,1,i);
/*
rc=sqlite3_column_count(stmt);
for(i=0;i<rc;i++)
{
printf("%s\t",sqlite3_column_name(stmt,i));
}
printf("\n");
*/ printf("<tr>\n");
while(sqlite3_step(stmt)==SQLITE_ROW)
{
printf("<td>%d</td>",sqlite3_column_int(stmt,0));
printf("<td>%d</td>",sqlite3_column_int(stmt,1));
printf("<td>%.1f</td>",sqlite3_column_double(stmt,2));
printf("<td>%s</td>\n",sqlite3_column_text(stmt,3));
/*
for(i=0;i<rc-1;i++)
{
printf("%d\t",sqlite3_column_int(stmt,i));
}
printf("%s\n",sqlite3_column_text(stmt,i));
//sqlite3_reset(stmt);
*/
}
printf("</tr>\n");
// }
printf("</table>\n</body>\n</html>");
sqlite3_finalize(stmt);
sqlite3_close(pdb);
return 0;
}
通過boa服務器對數據庫內容定時刷新,數據庫內容由串口收到數據定時刷新。