本文讲述树莓派用C语言程序采集温度传感器DS18B20数据,并存入SQLite和MySQL数据库。之前我们已经用Shell脚本程序实现了这些功能。


为顺利阅读本文,应先看后面参考文档中的相关内容。


《树莓派采集温度数据并存入数据库(Shell版)》https://blog.csdn.net/chentuo2000/article/details/108723075


  • 硬件连接和基本操作

细节请看参考文档《树莓派+温度传感器DS18B20》一文。


https://blog.csdn.net/chentuo2000/article/details/81051701


  • 查看DS18B20序列号

每个传感器有一个唯一的序列号。


ls /sys/bus/w1/devices/



我的DS18B20温度传感器序列号是28-000004d6162f。下面我们通过序列号读传感器的温度值。


  • 读温度值

cat /sys/bus/w1/devices/28-000004d6162f/w1_slave



第二行的t=23125就是当前的温度值,要換算成攝氏度,除以1000,即当前温度为23125/1000=23.125攝氏度。


2. 获取数据库编程头文件和链接库


我们的温度数据将写入SQLite和MySQL两个数据库,需要相应的文件。


2.1 SQLite头文件和库文件


在C语言编程时需要头文件sqlite3.h和动态链接库文件libsqlite3.so。


  • 下载sqlite3.h

在编译时会用到sqlite3.h,可以到SQLite官网下载。


https://www.sqlite.org/download.html



SQLite目前最新版本是3.33.0。


右击sqlite-autoconf-3330000.tar.gz(2.78 MiB),复制链接地址:


https://www.sqlite.org/2020/sqlite-autoconf-3330000.tar.gz


下载:


wget -c https://www.sqlite.org/2020/sqlite-autoconf-3330000.tar.gz



安装ca-certificates包:


sudo apt-get install -y ca-certificates



重新下载:sqlite-autoconf-3330000.tar.gz



解压缩:


tar zxvf sqlite-autoconf-3330000.tar.gz


复制sqlite3.h到当前目录:


cp sqlite-autoconf-3330000/sqlite3.h .



  • 查看sqlite3动态链接库



 libsqlite3.so.0是一个指向libsqlite3.so.0.8.6的软链接,也就是一个快捷方式。


  • 再创建一个libsqlite3.so.0.8.6的软链接libsqlite3.so

sudo ln -s libsqlite3.so.0.8.6 /usr/lib/arm-linux-gnueabihf/libsqlite3.so



3.2 MySQL头文件和库文件


在C语言编程时需要头文件mysql.h和动态链接库文件libmariadbclient.so。


  • 安装库文件

sudo apt-get install libmariadb-dev



  • 查找mysql.h

sudo find / -name mysql.h



/usr/include/mariadb/mysql.h


  • 查找libmariadbclient.so

sudo find / -name libmariadbclient.so



/usr/lib/arm-linux-gnueabihf/libmariadbclient.so


4. 编写C程序


在《树莓派采集温度数据并存入数据库(Shell版)》一文中我们用Shell程序实现了温度采样和数据存储功能,在本文中我们用C语言实现同样的功能。


4.1 创建数据库


  • 进入工作目录

cd idata



在《树莓派安装使用数据库SQLite》一文中我们已经创建了SQLite的数据库文件:smarthome.db。


在《树莓派安装使用数据库MariaDB (MySQL)》一文中我们也已经创建了数据库smarthome。


read_data.sh是我们在《树莓派采集温度数据并存入数据库(Shell版)》一文中写的shell脚本程序。


4.2 写C程序


nano read_data.c



  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include “sqlite3.h”
  8. #include <mysql.h>
  9. // 保存数据到SQLite数据库
  10. int save_data_sqlite(char sql[]) {
  11. sqlite3 _pdb = NULL; /_数据库连接指针_/
  12. char _error_msg = 0; /_错误信息指针_/
  13. int rc, return_value;
  14. rc=sqlite3_open(“smarthome.db”,&pdb);
  15. if(rc) {
  16. fprintf(stderr , “can’t open database: %s\n”,sqlite3_errmsg(pdb));
  17. return_value = -1;
  18. } else {
  19. // 插入或更新命令
  20. rc = sqlite3_exec(pdb,sql,0,0,&error_msg); // sqlite3_exec()是sqlite3_ prepare(), sqlite3_step(), and sqlite3_finalize() 三个函数的一个封装,最好的方法是直接使用sqlite3_exec()。
  21. if (rc == SQLITE_OK) {
  22. //printf(“Insert data OK! rc=%d\n”, rc); //测试
  23. return_value = 0;
  24. } else {
  25. //printf(“Insert data Error! rc=%d\n”, rc); //测试
  26. return_value = -2;
  27. }
  28. }
  29. sqlite3_close(pdb);
  30. return return_value;
  31. }
  32. static inline void _mysql_check(MYSQL _ con) {
  33. fprintf(stderr, “%s\n”, mysql_error(con));
  34. mysql_close(con);
  35. exit(EXIT_FAILURE);
  36. }
  37. // 保存数据到MySQL数据库
  38. void save_data_mysql(char sql[]) {
  39. int rc;
  40. // 创建数据连接对象,需要和 mysql_close成对出现
  41. MYSQL _con = mysql_init(NULL);
  42. if (con == NULL) {
  43. fprintf(stderr, “%s\n”, mysql_error(con));
  44. exit(EXIT_FAILURE);
  45. }
  46. // 创建TCP常连接对象
  47. if (!mysql_real_connect(con, “127.0.0.1”, “ct”, “ct”, “smarthome”, 0, NULL, 0)) {
  48. _mysql_check(con);
  49. }
  50. //puts(“mariadb is connect and run succesed!”);
  51. // 插入或更新命令
  52. rc = mysql_real_query(con, sql, strlen(sql));
  53. if (0 != rc) {
  54. _mysql_check(con);
  55. }
  56. mysql_close(con);
  57. }
  58. int main(int argc, char _argv[])
  59. {
  60. char itime[255];
  61. char buf[128];
  62. char path[64] = “/sys/bus/w1/devices/28-000004d6162f/w1_slave”;
  63. char _itemp;
  64. float ftemp;
  65. int fd = -1;
  66. char sql[256];
  67. char deviceid[10] = “temp001”;
  68. int ibattery_voltage = 3333;
  69. // 设置时区
  70. setenv(“TZ”, “GMT-8”, 1);
  71. while(1) {
  72. // 取系统时间
  73. time_t t = time( 0 );
  74. strftime(itime, 255, “%Y-%m-%d %H:%M:%S”, localtime(&t)); //format date and time.
  75. printf(“%s\n”, itime);
  76. // 读传感器数据
  77. if((fd = open(path, O_RDONLY)) < 0) {
  78. printf(“Open temperature file error! Please check /sys/bus/w1/devices/28-00000xxxxxxx file! \n”);
  79. } else {
  80. if(read(fd, buf, sizeof(buf)) < 0) {
  81. printf(“Read temperature error!\n”);
  82. } else {
  83. itemp = strchr(buf,‘t’);
  84. sscanf(itemp, “t=%s”, itemp);
  85. ftemp = atof(itemp)/1000;
  86. printf(“ temp=%3.2f°C\n”, ftemp);
  87. // 构造SQL语句
  88. sprintf(sql, “INSERT INTO temperature(deviceid, time, battery_voltage, celsius_temp) VALUES(‘%s’, ‘%s’, %d, %f);”, deviceid, itime, ibattery_voltage, ftemp);
  89. puts(sql);
  90. puts(“ “);
  91. // 保存数据到SQLite数据库
  92. save_data_sqlite(sql);
  93. // 保存数据到MySQL数据库
  94. save_data_mysql(sql);
  95. sleep(300); // 延时300秒
  96. }
  97. }
  98. }
  99. return 0;
  100. }



数据同时写入SQLite和MySQL数据库,具体项目可根据情况取舍。


  • 编译

gcc -I /usr/include/mariadb read_data.c -o read_data -lmariadbclient -lsqlite3



3.3 运行C程序


./read_data



3.4 查看数据库


  • 查看SQLite数据库

具体操作请看《树莓派安装使用数据库SQLite》
https://blog.csdn.net/chentuo2000/article/details/108682421


查看最后一条数据:


select * from temperature where id=(select max(id) from temperature);



  • 查看MySQL数据库

具体操作请看《树莓派安装使用数据库MariaDB (MySQL)》https://blog.csdn.net/chentuo2000/article/details/108702880




参考文档


  1. 树莓派采集温度数据并存入数据库(Shell版) https://blog.csdn.net/chentuo2000/article/details/108723075
  2. 树莓派安装使用数据库SQLite https://blog.csdn.net/chentuo2000/article/details/108682421
  3. 树莓派安装使用数据库MariaDB (MySQL) https://blog.csdn.net/chentuo2000/article/details/108702880
  4. 树莓派+温度传感器DS18B20 https://blog.csdn.net/chentuo2000/article/details/81051701
  5. ESP8266_SDK发送温度数据到阿里云 https://blog.csdn.net/chentuo2000/article/details/105592791
  6. 树莓派系列教程14:单总线控制DS18B20 https://www.waveshare.net/study/article-607-1.html