PM2.5检测 -- PMS7003 开发程序
昨天看了一天的?PMS7003 傳輸協(xié)議。然后網(wǎng)上搜索了一下,僅有的幾篇文章講代碼怎么寫的。
參看:DIY 空氣質(zhì)量檢測表
參看:Dust Sensor - PMS 5003/6003/7003
參看:MartyMacGyver/PMS7003-on-Particle
參看:PMS7003 PM2.5測試儀,帶SHT20溫濕度 STM32源碼
參看:(SKU:SEN0177)PM2.5激光粉塵傳感器
但是你有沒有發(fā)現(xiàn),這幾篇文章要么是在 QT 上實現(xiàn)的、要么用的是 Arduino 開發(fā)板、要么是單片機。
對于我現(xiàn)在要在 DM368 板子上實現(xiàn),好像沒什么卵用... ?現(xiàn)在真的有點懵逼。
還算好的是,前輩有留下一點,之前的PM2.5采集器的源碼。僅供參看... ??沒辦法,只能一點一點來做。
一、首先看一下?PMS7003 傳輸協(xié)議?
默認波特率:9600bps 校驗位:無 停止位:1位?
協(xié)議總長度:32字節(jié)
| 起始符1 | 0x42 |
| 起始符2 | 0x4D |
| 幀長度高八位 | 幀長度=2x13+2(數(shù)據(jù)+校驗位) |
| 幀長度低八位 | |
| 數(shù)據(jù)1高八位 | 數(shù)據(jù)1表示PM1.0濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數(shù)據(jù)1低八位 | |
| 數(shù)據(jù)2高八位 | 數(shù)據(jù)2表示PM2.5濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數(shù)據(jù)2低八位 | |
| 數(shù)據(jù)3高八位 | 數(shù)據(jù)3表示PM10濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數(shù)據(jù)3低八位 | |
| 數(shù)據(jù)4高八位 | 數(shù)據(jù)4表示PM1.0濃度(大氣環(huán)境下)單位μg/m3 |
| 數(shù)據(jù)4低八位 | |
| 數(shù)據(jù)5高八位 | 數(shù)據(jù)5表示PM2.5濃度(大氣環(huán)境下)單位μg/m3 |
| 數(shù)據(jù)5低八位 | |
| 數(shù)據(jù)6高八位 | 數(shù)據(jù)6表示PM10濃度 (大氣環(huán)境下)單位μg/m3 |
| 數(shù)據(jù)6低八位 | |
| 數(shù)據(jù)7高八位 | 數(shù)據(jù)7表示0.1升空氣中直徑在0.3um以上顆粒物個數(shù) |
| 數(shù)據(jù)7低八位 | |
| 數(shù)據(jù)8高八位 | 數(shù)據(jù)8表示0.1升空氣中直徑在0.5um以上顆粒物個數(shù) |
| 數(shù)據(jù)8低八位 | |
| 數(shù)據(jù)9高八位 | 數(shù)據(jù)9表示0.1升空氣中直徑在1.0um以上顆粒物個數(shù) |
| 數(shù)據(jù)9低八位 | |
| 數(shù)據(jù)10高八位 | 數(shù)據(jù)10表示0.1升空氣中直徑在2.5um以上顆粒物個數(shù) |
| 數(shù)據(jù)10低八位 | |
| 數(shù)據(jù)11高八位 | 數(shù)據(jù)11表示0.1升空氣中直徑在5.0um以上顆粒物個數(shù) |
| 數(shù)據(jù)11低八位 | |
| 數(shù)據(jù)12高八位 | 數(shù)據(jù)12表示0.1升空氣中直徑在10um以上顆粒物個數(shù) |
| 數(shù)據(jù)12低八位 | |
| 數(shù)據(jù)13高八位 | 版本號 |
| 數(shù)據(jù)13低八位 | 錯誤代碼 |
| 數(shù)據(jù)和校驗高八位 | 校驗碼=起始符1+起始符2+……..+數(shù)據(jù)13低八位 |
| 數(shù)據(jù)和校驗低八位 |
輸出結果
主要輸出為單位體積內(nèi)各濃度顆粒物質(zhì)量以及個數(shù),其中顆粒物個數(shù)的單位體積為 0.1 升,質(zhì)量濃度單位為:微克/立方米。
輸出分為主動輸出和被動輸出兩種狀態(tài)。傳感器上電后默認狀態(tài)為主動輸出,即傳感器主動向主機發(fā)送串行數(shù)據(jù),時間間隔為 200~800ms,空氣中顆粒物濃度越高,時間間隔越短。主動輸出又分為兩種模式:平穩(wěn)模式和快速模式。在空氣中顆粒物濃度變化較小時,傳感器輸出為平穩(wěn)模式,即每三次輸出同樣的一組數(shù)值,實際數(shù)據(jù)更新周期約為 2s。當空氣中顆粒物濃度變化較大時,傳感器輸出自動切換為快速模式,每次輸出都是新的數(shù)值,實際數(shù)據(jù)更新周期為 200~800ms。
二、PMS7003 傳輸協(xié)議代碼講解 ?(重點)
參看:MartyMacGyver/PMS7003-on-Particle(1)源碼
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // Demo: interfacing a Plantower PMS7003 air quality sensor to a Particle IoT microcontroller /*Copyright (c) 2016 Martin F. FalaticLicensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License. */ //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=int incomingByte = 0; // for incoming serial dataconst int MAX_FRAME_LEN = 64; char frameBuf[MAX_FRAME_LEN]; int detectOff = 0; int frameLen = MAX_FRAME_LEN; bool inFrame = false; char printbuf[256];const bool DEBUG = false;uint16_t calcChecksum = 0;struct PMS7003_framestruct {uint8_t frameHeader[2];uint16_t frameLen = MAX_FRAME_LEN;uint16_t concPM1_0_CF1;uint16_t concPM2_5_CF1;uint16_t concPM10_0_CF1;uint16_t concPM1_0_amb;uint16_t concPM2_5_amb;uint16_t concPM10_0_amb;uint16_t rawGt0_3um;uint16_t rawGt0_5um;uint16_t rawGt1_0um;uint16_t rawGt2_5um;uint16_t rawGt5_0um;uint16_t rawGt10_0um;uint8_t version;uint8_t errorCode;uint16_t checksum; } thisFrame;void setup() {Serial.begin(57600);delay(1000);Serial.println("-- Initializing..."); }bool pms7003_read() {// Particle.publish("PMS7003", printbuf, 60, PRIVATE);// send data only when you receive data:Serial.println("-- Reading PMS7003");Serial1.begin(9600);bool packetReceived = false;while (!packetReceived) {if (Serial1.available() > 32) {int drain = Serial1.available();if (DEBUG) {Serial.print("-- Draining buffer: ");Serial.println(Serial1.available(), DEC);}for (int i = drain; i > 0; i--) {Serial1.read();}}if (Serial1.available() > 0) {if (DEBUG) {Serial.print("-- Available: ");Serial.println(Serial1.available(), DEC);}incomingByte = Serial1.read();if (DEBUG) {Serial.print("-- READ: ");Serial.println(incomingByte, HEX);}if (!inFrame) {if (incomingByte == 0x42 && detectOff == 0) {frameBuf[detectOff] = incomingByte;thisFrame.frameHeader[0] = incomingByte;calcChecksum = incomingByte; // Checksum init!detectOff++;}else if (incomingByte == 0x4D && detectOff == 1) {frameBuf[detectOff] = incomingByte;thisFrame.frameHeader[1] = incomingByte;calcChecksum += incomingByte;inFrame = true;detectOff++;}else {Serial.print("-- Frame syncing... ");Serial.print(incomingByte, HEX);if (DEBUG) {}Serial.println();}}else {frameBuf[detectOff] = incomingByte;calcChecksum += incomingByte;detectOff++;uint16_t val = frameBuf[detectOff-1]+(frameBuf[detectOff-2]<<8);switch (detectOff) {case 4:thisFrame.frameLen = val;frameLen = val + detectOff;break;case 6:thisFrame.concPM1_0_CF1 = val;break;case 8:thisFrame.concPM2_5_CF1 = val;break;case 10:thisFrame.concPM10_0_CF1 = val;break;case 12:thisFrame.concPM1_0_amb = val;break;case 14:thisFrame.concPM2_5_amb = val;break;case 16:thisFrame.concPM10_0_amb = val;break;case 18:thisFrame.rawGt0_3um = val;break;case 20:thisFrame.rawGt0_5um = val;break;case 22:thisFrame.rawGt1_0um = val;break;case 24:thisFrame.rawGt2_5um = val;break;case 26:thisFrame.rawGt5_0um = val;break;case 28:thisFrame.rawGt10_0um = val;break;case 29:val = frameBuf[detectOff-1];thisFrame.version = val;break;case 30:val = frameBuf[detectOff-1];thisFrame.errorCode = val;break;case 32:thisFrame.checksum = val;calcChecksum -= ((val>>8)+(val&0xFF));break;default:break;}if (detectOff >= frameLen) {sprintf(printbuf, "PMS7003 ");sprintf(printbuf, "%s[%02x %02x] (%04x) ", printbuf,thisFrame.frameHeader[0], thisFrame.frameHeader[1], thisFrame.frameLen);sprintf(printbuf, "%sCF1=[%04x %04x %04x] ", printbuf,thisFrame.concPM1_0_CF1, thisFrame.concPM2_5_CF1, thisFrame.concPM10_0_CF1);sprintf(printbuf, "%samb=[%04x %04x %04x] ", printbuf,thisFrame.concPM1_0_amb, thisFrame.concPM2_5_amb, thisFrame.concPM10_0_amb);sprintf(printbuf, "%sraw=[%04x %04x %04x %04x %04x %04x] ", printbuf,thisFrame.rawGt0_3um, thisFrame.rawGt0_5um, thisFrame.rawGt1_0um,thisFrame.rawGt2_5um, thisFrame.rawGt5_0um, thisFrame.rawGt10_0um);sprintf(printbuf, "%sver=%02x err=%02x ", printbuf,thisFrame.version, thisFrame.errorCode);sprintf(printbuf, "%scsum=%04x %s xsum=%04x", printbuf,thisFrame.checksum, (calcChecksum == thisFrame.checksum ? "==" : "!="), calcChecksum);Serial.println(printbuf);Particle.publish("Data1", printbuf, 60, PRIVATE);packetReceived = true;detectOff = 0;inFrame = false;}}}}Serial1.end();return (calcChecksum == thisFrame.checksum); }void loop () {if (!pms7003_read()) {delay(4000);} }(2)講解
這篇文章對于 PMS7003 傳輸協(xié)議寫的不錯哦,我們來講一下。《1》定義數(shù)組和結構體
這里面主要看一下,完全參照的傳輸協(xié)議定義的串口數(shù)據(jù)的結構體《2》串口配置
不用看這個,因為我們用的是 485 通信,里面自有它那一套串口配置的方式,下面會講到的。《3》傳輸協(xié)議代碼如何寫
重點來了哦然后這里可以復習一下大小端、位操作和分支跳轉(zhuǎn)語句的基礎知識。 參看:C語言再學習-- 大端小端詳解(轉(zhuǎn)) 參看:C語言再學習 -- 位操作 參看:C語言再學習 -- 分支與跳轉(zhuǎn)語句
三、快速學習驅(qū)動程序基本框架
需要寫傳感器的驅(qū)動程序,這里快速的瀏覽一遍。 (之前以為單獨寫驅(qū)動呢,現(xiàn)在看來直接用 485 串口編程的即可,這部分只做參考學習。) 驅(qū)動程序的基本框架 #include <linux/init.h> #include <linux/module.h> static int helloword_init (void) //入口函數(shù) 成功返回0 static限定作用域 { printf (“hello,world!\n”); return 0; } static void helloworld_exit (void) //出口函數(shù) { printf (“goodbye,world!\n”);} module_init (helloworld_init); module_exit (helloworld_exit); MODULE_LICENSE (“GPL”); //GPL 開源Makefile 編寫 obj-m += helloworld.o #將helloworld.c #編譯生成最終的二進制可執(zhí)行文件helloworld.ko all:make -C /opt/kernel SUBDIRS=$(PWD) modules #到內(nèi)核/opt/kernel源碼中進行make編譯,然后告訴內(nèi)核,在你的源碼以外還有一個目錄/opt/drivers/day01/1.0,在這個目錄下有一個.c文件需要你進行編譯,要把它編譯生成.ko文件 clean:make -C /opt/kernel SUBDIRS=$(PWD) clean 內(nèi)核程序操作命令insmod 加載 rmmod 卸載 lsmod 查看內(nèi)核提供的GPIO操作庫函數(shù)
gpio_request:申請資源gpio_free:釋放資源gpio_direction_output:配置工作模式為輸出,輸出某個狀態(tài)gpio_direction_input:配置工作模式為輸入gpio_get_value:獲取狀態(tài)gpio_set_value:設置狀態(tài) 設備號的操作 申請alloc_chrdev_region(設備號,0, 次設備號的個數(shù),設備名稱); 釋放unregister_chrdev_region(設備號,次設備號的個數(shù)); 實現(xiàn)一個字符設備驅(qū)動的編程步驟 定義初始化字符設備對象cdev_init 注冊字符設備對象到內(nèi)核cdev_add 卸載字符設備對象cdev_dellinux內(nèi)核描述字符設備使用的數(shù)據(jù)結構 struct cdev {dev_t dev; //保存申請的設備號unsigned int count;//設備的個數(shù)const struct file_operations *ops; //給字符設備驅(qū)動賦予操作硬件的方法,并且將這些方法最終提供給用戶}; linux內(nèi)核字符設備硬件操作接口
struct file_operations { .owner ?= THIS_MODULE, .open = led_open, //打開設備 .release = led_close, //關閉設備 .read = led_read, //讀設備 .write = led_write, //寫設備 .unlocked_ioctl = led_ioctl, //向設備發(fā)送命令并且能夠進行讀寫操作 ...... };設備文件創(chuàng)建函數(shù)
struct class *cls; //創(chuàng)建設備類指針//定義初始化設備類(長樹枝,樹枝名叫tarena)//結果是在/sys/class目錄下生成一個tarena目錄,存放創(chuàng)建設備文件所需的原材料 cls = class_create(THIS_MODULE, "tarena");//創(chuàng)建設備文件(長蘋果)//結果是在/dev/生成設備文件 device_create(cls, NULL, 申請的設備號,NULL,s設備文件名);//刪除設備文件(采摘蘋果) device_destroy(cls, 申請的設備號);//刪除設備類(砍樹枝) class_destroy(cls);混雜設備驅(qū)動的編程步驟 1.定義初始化混雜設備對象struct file_operations led_fops = {...};struct miscdevice led_misc = {.minor = MISC_DYNAMIC_MINOR,.name = "myled",.fops = &led_fops}; 2.向內(nèi)核注冊混雜設備對象,一旦注冊完畢,內(nèi)核就有一個真實的混雜設備驅(qū)動misc_register(&led_misc);3.從內(nèi)核卸載混雜設備對象misc_deregister(&led_misc);
四、UART 接口 (重點)
上文中有提到,用的 485 通信,然后看一下它所接的 GPIO 口是哪個。然后之前寫過一篇關于 485 串口編程的文章,可供參考。
參看:UNIX再學習 -- RS485 串口編程
這個很有必要哦,里面的串口編程,很實用。然后只需要將其改為只接收即可。
然后具體的更改代碼,這里我就不再重復。
編譯執(zhí)行: 編譯: arm-none-linux-gnueabi-gcc com.c -o com -pthreadtftp 到文件系統(tǒng)中: tftp -g -r com 192.168.2.xx設置權限: chmod 777 com手動加載設備: mknod /dev/pio c 203 0執(zhí)行 ./com 這里看一下,輸出的結果。
然后通過 校驗碼=起始符1+起始符2+……..+數(shù)據(jù)13?來驗證第一行的數(shù)據(jù)。校驗碼是 02 81 說明是正確的。?
五、開發(fā)程序
最后是傳輸協(xié)議開發(fā)程序,只看 read 讀取部分即可。其他的沒啥可講的。
#include <fcntl.h> //文件控制定義 #include <stdio.h> //標準輸入輸出定義 #include <stdlib.h> //標準函數(shù)庫定義 #include <unistd.h> //Unix標準函數(shù)定義 #include <errno.h> //錯誤好定義 #include <termios.h> //POSIX終端控制定義 #include <sys/ioctl.h> //ioctl函數(shù)定義 #include <string.h> //字符操作 #include <sys/types.h> #include <sys/stat.h> #include <pthread.h> #include <sys/time.h> int fd_gpio;struct termios newtio, oldtio; typedef struct {int pin_idx;int pin_dir;int pin_sta; } davinci_gio_arg;typedef enum {AT91PIO_DIR_OUT = 0,AT91PIO_DIR_INP } davinci_gio_dir; //驅(qū)動判斷輸入輸出模式davinci_gio_arg arg;#define DEV_PIO_LED "/dev/pio" // 需要手動添加設備號 mknod /dev/pio c 203 0 #define PIO_NUM 47 // 47pin 為控制輸入輸出方向引腳 #define DEV_UART "/dev/ttyS1" // /dev/ttyS1 為串口設備#define IOCTL_PIO_SETDIR 1 //set gpio direct #define IOCTL_PIO_GETDIR 2 //get gpio direct #define IOCTL_PIO_SETSTA 3 //set gpio status #define IOCTL_PIO_GETSTA 4 //get gpio status//保存信息 int log_init( const char *strFileName ) {int fdLog = -1;if( -1 == (fdLog = open( strFileName, O_CREAT|O_TRUNC ) ) ){}close( fdLog ); }int log_out( const char *strFileName, const char * szLog ) {int fdLog = -1;if( -1 == ( fdLog = open( strFileName, O_CREAT|O_WRONLY|O_APPEND ) ) ){printf( "LOG (%s) open error!\n", strFileName );return -1;}write( fdLog, szLog, strlen( szLog ) );close( fdLog );return 0; }//配置串口 /* 參數(shù)說明:fd 設備文件描述符,nspeed 波特率,nbits 數(shù)據(jù)位數(shù)(7位或8位),parity 奇偶校驗位('n'或'N'為無校驗位,'o'或'O'為偶校驗,'e'或'E'奇校驗),nstop 停止位(1位或2位)成功返回1,失敗返回-1。 */ int set_com_opt( int fd, int nspeed, int nbits, char parity, int nstop ) {char szTmp[128]; //打印配置信息sprintf( szTmp, "set_com_opt - speed:%d,bits:%d,parity:%c,stop:%d\n", nspeed, nbits, parity, nstop );log_out( "./485.log", szTmp );//保存并測試現(xiàn)在有串口參數(shù)設置,在這里如果串口號等出錯,會有相關的出錯信息 if( tcgetattr( fd, &oldtio ) != 0 ){sprintf( szTmp, "SetupSerial 1" );log_out( "./485.log", szTmp );perror( "SetupSerial 1" );return -1;}//修改輸出模式,原始數(shù)據(jù)輸出bzero( &newtio, sizeof( newtio ));newtio.c_cflag &=~(OPOST);//屏蔽其他標志位newtio.c_cflag |= (CLOCAL | CREAD );newtio.c_cflag &= ~CSIZE;//設置數(shù)據(jù)位switch( nbits ){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;default:perror("Unsupported date bit!\n");return -1;}//設置校驗位switch( parity ){case 'n':case 'N': //無奇偶校驗位newtio.c_cflag &= ~PARENB;newtio.c_iflag &= ~INPCK;break;case 'o':case 'O': //設置為奇校驗newtio.c_cflag |= ( PARODD | PARENB );newtio.c_iflag |= ( INPCK | ISTRIP );break;case 'e':case 'E': //設置為偶校驗newtio.c_iflag |= ( INPCK |ISTRIP );newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;default:perror("unsupported parity\n");return -1;}//設置停止位switch( nstop ) {case 1: newtio.c_cflag &= ~CSTOPB;break;case 2:newtio.c_cflag |= CSTOPB;break;default :perror("Unsupported stop bit\n");return -1;}//設置波特率switch( nspeed ){case 2400:cfsetispeed( &newtio, B2400 );cfsetospeed( &newtio, B2400 );break;case 4800:cfsetispeed( &newtio, B4800 );cfsetospeed( &newtio, B4800 );break; case 9600:cfsetispeed( &newtio, B9600 );cfsetospeed( &newtio, B9600 );break; case 115200:cfsetispeed( &newtio, B115200 );cfsetospeed( &newtio, B115200 );break;case 460800:cfsetispeed( &newtio, B460800 );cfsetospeed( &newtio, B460800 );break;default: cfsetispeed( &newtio, B9600 );cfsetospeed( &newtio, B9600 );break;}//設置等待時間和最小接收字符newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; //VTIME=0,VMIN=0,不管能否讀取到數(shù)據(jù),read都會立即返回。//輸入模式newtio.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG); //設置數(shù)據(jù)流控制newtio.c_iflag &= ~(IXON|IXOFF|IXANY); //使用軟件流控制 //如果發(fā)生數(shù)據(jù)溢出,接收數(shù)據(jù),但是不再讀取 刷新收到的數(shù)據(jù)但是不讀tcflush( fd, TCIFLUSH ); //激活配置 (將修改后的termios數(shù)據(jù)設置到串口中)if( tcsetattr( fd, TCSANOW, &newtio ) != 0 ){sprintf( szTmp, "serial set error!\n" );log_out( "./485.log", szTmp );perror( "serial set error!" );return -1;}log_out( "./485.log", "serial set ok!\n" );return 1; }//打開串口并返回串口設備文件描述 int open_com_dev( char *dev_name ) {int fd;char szTmp[128];log_init( "./485.log" );if(( fd = open( dev_name, O_RDWR|O_NOCTTY|O_NDELAY)) == -1 ){perror("open\n");//printf("Can't open Serial %s Port!\n", dev_name );sprintf( szTmp, "Can't open Serial %s Port!\n", dev_name );log_out( "./485.log", szTmp );return -1;}sprintf( szTmp, "open %s ok!\n", dev_name );log_out( "./485.log", szTmp );if(fcntl(fd,F_SETFL,0)<0){printf("fcntl failed!\n");}//printf("Open %s ok\n",dev_name );return fd; }//單片機數(shù)據(jù)收發(fā) void* task(void* p) {char buf[64];char frameBuf[64];int detectOff = 0;int res = 0, nread = 0;int m_pm1_factory;int m_pm25_factory;int m_pm10_factory;int m_pm1_outdoor;int m_pm25_outdoor;int m_pm10_outdoor;int m_count03;int m_count05;int m_count1;int m_count25;int m_count5;int m_count10;unsigned short m_length;unsigned short m_version;unsigned short m_errorno;while (1) {arg.pin_sta = 0; //設為低電平 接收態(tài) ioctl(fd_gpio, IOCTL_PIO_SETSTA, &arg);int fd_r=open_com_dev( DEV_UART );if( fd_r < 0 ){printf( "open UART device error! %s\n", DEV_UART );}elseset_com_opt(fd_r, 9600,8,'n',1);//執(zhí)行selectfd_set rd; FD_ZERO(&rd); FD_SET(fd_r, &rd); if ((res = select (fd_r+1,&rd, NULL, NULL, NULL) )< 0){perror ("read err");exit (-1);}memset (buf, 0, sizeof (buf));if (FD_ISSET (fd_r, &rd)){//接收數(shù)據(jù) 8 8 2 int res1 = 0;int val = 0;int calcChecksum = 0;int checksum = 0;int i = 0;while ((nread = read(fd_r, buf, 1)) > 0){//printf ("%02X ",*buf);//frameBuf[detectOff] = buf[0];memcpy (frameBuf+detectOff, buf, 1);//calcChecksum += *buf;detectOff++;if (frameBuf[0] == 0x42 && frameBuf[1] == 0x4d){// m_length = frameBuf[3]+(frameBuf[2]<<8);m_pm1_factory = frameBuf[5]+(frameBuf[4]<<8);m_pm25_factory = frameBuf[7]+(frameBuf[6]<<8);m_pm10_factory = frameBuf[9]+(frameBuf[8]<<8);m_pm1_outdoor = frameBuf[11]+(frameBuf[10]<<8);m_pm25_outdoor = frameBuf[13]+(frameBuf[12]<<8);m_pm10_outdoor = frameBuf[15]+(frameBuf[14]<<8);// m_count03 = frameBuf[17]+(frameBuf[16]<<8);// m_count05 = frameBuf[19]+(frameBuf[18]<<8);// m_count1 = frameBuf[21]+(frameBuf[20]<<8);// m_count25 = frameBuf[23]+(frameBuf[22]<<8);// m_count5 = frameBuf[25]+(frameBuf[24]<<8);// m_count10 = frameBuf[27]+(frameBuf[26]<<8);// m_version = frameBuf[28];// m_errorno = frameBuf[29];// checksum = frameBuf[31]+(frameBuf[30]<<8);// calcChecksum -= ((checksum>>8)+(checksum&0xFF));}//退出循環(huán), 這里有點疑問if (detectOff == 32){printf ("\n");printf ("pm1_factory = %d ug/m3\npm25_factory = %d ug/m3\npm10_factory = %d ug/m3\n", m_pm1_factory, m_pm25_factory, m_pm10_factory);printf ("pm1_outdoor = %d ug/m3\npm25_outdoor = %d ug/m3\npm10_outdoor = %d ug/m3\n",m_pm1_outdoor,m_pm25_outdoor,m_pm10_outdoor);// printf ("m_count03 = %02X\nm_count05 = %02X\nm_count1 = %02X\nm_count25 = %02X\nm_count5 = %02X\nm_count10 = %02X\n",// m_count03, m_count05, m_count1, m_count25, m_count5, m_count10);// printf ("m_length = %d\n", m_length);// printf ("m_version = %s\n", m_version);// printf ("m_errorno = %s\n", m_errorno);// printf("checksum = %02X %s calcChecksum = %02X",checksum, (calcChecksum == checksum ? "==" : "!="), calcChecksum);// for (i = 0;i<32;i++)// {// printf ("%02X ", frameBuf[i]);// }// printf ("\n");memset (frameBuf, 0, sizeof (frameBuf));detectOff = 0;break;}}}close (fd_r); usleep (200000);} }int main (void) {int error = 0, error1 = 0;arg.pin_idx = PIO_NUM; arg.pin_dir = AT91PIO_DIR_OUT;//打開/dev/pio設備fd_gpio = open(DEV_PIO_LED, O_RDWR); if(fd_gpio < 0){perror("fd_gpio open err");exit (-1);}pthread_t tid;//創(chuàng)建線程if ((error = pthread_create (&tid, NULL, task, NULL)) < 0){perror ("pthread_cread error");return -1; }//等待線程結束pthread_join (tid, NULL);//關閉設備 close (fd_gpio);return 0; }
測試結果:
總結
以上是生活随笔為你收集整理的PM2.5检测 -- PMS7003 开发程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 独享代理产品介绍
- 下一篇: 给textView设置文字渐变色