PM2.5检测 -- PMS7003 开发程序
昨天看了一天的?PMS7003 傳輸協議。然后網上搜索了一下,僅有的幾篇文章講代碼怎么寫的。
參看:DIY 空氣質量檢測表
參看:Dust Sensor - PMS 5003/6003/7003
參看:MartyMacGyver/PMS7003-on-Particle
參看:PMS7003 PM2.5測試儀,帶SHT20溫濕度 STM32源碼
參看:(SKU:SEN0177)PM2.5激光粉塵傳感器
但是你有沒有發現,這幾篇文章要么是在 QT 上實現的、要么用的是 Arduino 開發板、要么是單片機。
對于我現在要在 DM368 板子上實現,好像沒什么卵用... ?現在真的有點懵逼。
還算好的是,前輩有留下一點,之前的PM2.5采集器的源碼。僅供參看... ??沒辦法,只能一點一點來做。
一、首先看一下?PMS7003 傳輸協議?
默認波特率:9600bps 校驗位:無 停止位:1位?
協議總長度:32字節
| 起始符1 | 0x42 |
| 起始符2 | 0x4D |
| 幀長度高八位 | 幀長度=2x13+2(數據+校驗位) |
| 幀長度低八位 | |
| 數據1高八位 | 數據1表示PM1.0濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數據1低八位 | |
| 數據2高八位 | 數據2表示PM2.5濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數據2低八位 | |
| 數據3高八位 | 數據3表示PM10濃度(CF=1,標準顆粒物)單位μg/m3 |
| 數據3低八位 | |
| 數據4高八位 | 數據4表示PM1.0濃度(大氣環境下)單位μg/m3 |
| 數據4低八位 | |
| 數據5高八位 | 數據5表示PM2.5濃度(大氣環境下)單位μg/m3 |
| 數據5低八位 | |
| 數據6高八位 | 數據6表示PM10濃度 (大氣環境下)單位μg/m3 |
| 數據6低八位 | |
| 數據7高八位 | 數據7表示0.1升空氣中直徑在0.3um以上顆粒物個數 |
| 數據7低八位 | |
| 數據8高八位 | 數據8表示0.1升空氣中直徑在0.5um以上顆粒物個數 |
| 數據8低八位 | |
| 數據9高八位 | 數據9表示0.1升空氣中直徑在1.0um以上顆粒物個數 |
| 數據9低八位 | |
| 數據10高八位 | 數據10表示0.1升空氣中直徑在2.5um以上顆粒物個數 |
| 數據10低八位 | |
| 數據11高八位 | 數據11表示0.1升空氣中直徑在5.0um以上顆粒物個數 |
| 數據11低八位 | |
| 數據12高八位 | 數據12表示0.1升空氣中直徑在10um以上顆粒物個數 |
| 數據12低八位 | |
| 數據13高八位 | 版本號 |
| 數據13低八位 | 錯誤代碼 |
| 數據和校驗高八位 | 校驗碼=起始符1+起始符2+……..+數據13低八位 |
| 數據和校驗低八位 |
輸出結果
主要輸出為單位體積內各濃度顆粒物質量以及個數,其中顆粒物個數的單位體積為 0.1 升,質量濃度單位為:微克/立方米。
輸出分為主動輸出和被動輸出兩種狀態。傳感器上電后默認狀態為主動輸出,即傳感器主動向主機發送串行數據,時間間隔為 200~800ms,空氣中顆粒物濃度越高,時間間隔越短。主動輸出又分為兩種模式:平穩模式和快速模式。在空氣中顆粒物濃度變化較小時,傳感器輸出為平穩模式,即每三次輸出同樣的一組數值,實際數據更新周期約為 2s。當空氣中顆粒物濃度變化較大時,傳感器輸出自動切換為快速模式,每次輸出都是新的數值,實際數據更新周期為 200~800ms。
二、PMS7003 傳輸協議代碼講解 ?(重點)
參看: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 傳輸協議寫的不錯哦,我們來講一下。《1》定義數組和結構體
這里面主要看一下,完全參照的傳輸協議定義的串口數據的結構體《2》串口配置
不用看這個,因為我們用的是 485 通信,里面自有它那一套串口配置的方式,下面會講到的。《3》傳輸協議代碼如何寫
重點來了哦然后這里可以復習一下大小端、位操作和分支跳轉語句的基礎知識。 參看:C語言再學習-- 大端小端詳解(轉) 參看:C語言再學習 -- 位操作 參看:C語言再學習 -- 分支與跳轉語句
三、快速學習驅動程序基本框架
需要寫傳感器的驅動程序,這里快速的瀏覽一遍。 (之前以為單獨寫驅動呢,現在看來直接用 485 串口編程的即可,這部分只做參考學習。) 驅動程序的基本框架 #include <linux/init.h> #include <linux/module.h> static int helloword_init (void) //入口函數 成功返回0 static限定作用域 { printf (“hello,world!\n”); return 0; } static void helloworld_exit (void) //出口函數 { printf (“goodbye,world!\n”);} module_init (helloworld_init); module_exit (helloworld_exit); MODULE_LICENSE (“GPL”); //GPL 開源Makefile 編寫 obj-m += helloworld.o #將helloworld.c #編譯生成最終的二進制可執行文件helloworld.ko all:make -C /opt/kernel SUBDIRS=$(PWD) modules #到內核/opt/kernel源碼中進行make編譯,然后告訴內核,在你的源碼以外還有一個目錄/opt/drivers/day01/1.0,在這個目錄下有一個.c文件需要你進行編譯,要把它編譯生成.ko文件 clean:make -C /opt/kernel SUBDIRS=$(PWD) clean 內核程序操作命令insmod 加載 rmmod 卸載 lsmod 查看內核提供的GPIO操作庫函數
gpio_request:申請資源gpio_free:釋放資源gpio_direction_output:配置工作模式為輸出,輸出某個狀態gpio_direction_input:配置工作模式為輸入gpio_get_value:獲取狀態gpio_set_value:設置狀態 設備號的操作 申請alloc_chrdev_region(設備號,0, 次設備號的個數,設備名稱); 釋放unregister_chrdev_region(設備號,次設備號的個數); 實現一個字符設備驅動的編程步驟 定義初始化字符設備對象cdev_init 注冊字符設備對象到內核cdev_add 卸載字符設備對象cdev_dellinux內核描述字符設備使用的數據結構 struct cdev {dev_t dev; //保存申請的設備號unsigned int count;//設備的個數const struct file_operations *ops; //給字符設備驅動賦予操作硬件的方法,并且將這些方法最終提供給用戶}; linux內核字符設備硬件操作接口
struct file_operations { .owner ?= THIS_MODULE, .open = led_open, //打開設備 .release = led_close, //關閉設備 .read = led_read, //讀設備 .write = led_write, //寫設備 .unlocked_ioctl = led_ioctl, //向設備發送命令并且能夠進行讀寫操作 ...... };設備文件創建函數
struct class *cls; //創建設備類指針//定義初始化設備類(長樹枝,樹枝名叫tarena)//結果是在/sys/class目錄下生成一個tarena目錄,存放創建設備文件所需的原材料 cls = class_create(THIS_MODULE, "tarena");//創建設備文件(長蘋果)//結果是在/dev/生成設備文件 device_create(cls, NULL, 申請的設備號,NULL,s設備文件名);//刪除設備文件(采摘蘋果) device_destroy(cls, 申請的設備號);//刪除設備類(砍樹枝) class_destroy(cls);混雜設備驅動的編程步驟 1.定義初始化混雜設備對象struct file_operations led_fops = {...};struct miscdevice led_misc = {.minor = MISC_DYNAMIC_MINOR,.name = "myled",.fops = &led_fops}; 2.向內核注冊混雜設備對象,一旦注冊完畢,內核就有一個真實的混雜設備驅動misc_register(&led_misc);3.從內核卸載混雜設備對象misc_deregister(&led_misc);
四、UART 接口 (重點)
上文中有提到,用的 485 通信,然后看一下它所接的 GPIO 口是哪個。然后之前寫過一篇關于 485 串口編程的文章,可供參考。
參看:UNIX再學習 -- RS485 串口編程
這個很有必要哦,里面的串口編程,很實用。然后只需要將其改為只接收即可。
然后具體的更改代碼,這里我就不再重復。
編譯執行: 編譯: arm-none-linux-gnueabi-gcc com.c -o com -pthreadtftp 到文件系統中: tftp -g -r com 192.168.2.xx設置權限: chmod 777 com手動加載設備: mknod /dev/pio c 203 0執行 ./com 這里看一下,輸出的結果。
然后通過 校驗碼=起始符1+起始符2+……..+數據13?來驗證第一行的數據。校驗碼是 02 81 說明是正確的。?
五、開發程序
最后是傳輸協議開發程序,只看 read 讀取部分即可。其他的沒啥可講的。
#include <fcntl.h> //文件控制定義 #include <stdio.h> //標準輸入輸出定義 #include <stdlib.h> //標準函數庫定義 #include <unistd.h> //Unix標準函數定義 #include <errno.h> //錯誤好定義 #include <termios.h> //POSIX終端控制定義 #include <sys/ioctl.h> //ioctl函數定義 #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; //驅動判斷輸入輸出模式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; }//配置串口 /* 參數說明:fd 設備文件描述符,nspeed 波特率,nbits 數據位數(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 );//保存并測試現在有串口參數設置,在這里如果串口號等出錯,會有相關的出錯信息 if( tcgetattr( fd, &oldtio ) != 0 ){sprintf( szTmp, "SetupSerial 1" );log_out( "./485.log", szTmp );perror( "SetupSerial 1" );return -1;}//修改輸出模式,原始數據輸出bzero( &newtio, sizeof( newtio ));newtio.c_cflag &=~(OPOST);//屏蔽其他標志位newtio.c_cflag |= (CLOCAL | CREAD );newtio.c_cflag &= ~CSIZE;//設置數據位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,不管能否讀取到數據,read都會立即返回。//輸入模式newtio.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG); //設置數據流控制newtio.c_iflag &= ~(IXON|IXOFF|IXANY); //使用軟件流控制 //如果發生數據溢出,接收數據,但是不再讀取 刷新收到的數據但是不讀tcflush( fd, TCIFLUSH ); //激活配置 (將修改后的termios數據設置到串口中)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; }//單片機數據收發 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; //設為低電平 接收態 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);//執行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)){//接收數據 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));}//退出循環, 這里有點疑問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;//創建線程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 开发程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 独享代理产品介绍
- 下一篇: 给textView设置文字渐变色