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 上實(shí)現(xiàn)的、要么用的是 Arduino 開發(fā)板、要么是單片機(jī)。
對于我現(xiàn)在要在 DM368 板子上實(shí)現(xiàn),好像沒什么卵用... ?現(xiàn)在真的有點(diǎn)懵逼。
還算好的是,前輩有留下一點(diǎn),之前的PM2.5采集器的源碼。僅供參看... ??沒辦法,只能一點(diǎn)一點(diǎn)來做。
一、首先看一下?PMS7003 傳輸協(xié)議?
默認(rèn)波特率:9600bps 校驗(yàn)位:無 停止位:1位?
協(xié)議總長度:32字節(jié)
| 起始符1 | 0x42 |
| 起始符2 | 0x4D |
| 幀長度高八位 | 幀長度=2x13+2(數(shù)據(jù)+校驗(yàn)位) |
| 幀長度低八位 | |
| 數(shù)據(jù)1高八位 | 數(shù)據(jù)1表示PM1.0濃度(CF=1,標(biāo)準(zhǔn)顆粒物)單位μg/m3 |
| 數(shù)據(jù)1低八位 | |
| 數(shù)據(jù)2高八位 | 數(shù)據(jù)2表示PM2.5濃度(CF=1,標(biāo)準(zhǔn)顆粒物)單位μg/m3 |
| 數(shù)據(jù)2低八位 | |
| 數(shù)據(jù)3高八位 | 數(shù)據(jù)3表示PM10濃度(CF=1,標(biāo)準(zhǔn)顆粒物)單位μ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以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)7低八位 | |
| 數(shù)據(jù)8高八位 | 數(shù)據(jù)8表示0.1升空氣中直徑在0.5um以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)8低八位 | |
| 數(shù)據(jù)9高八位 | 數(shù)據(jù)9表示0.1升空氣中直徑在1.0um以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)9低八位 | |
| 數(shù)據(jù)10高八位 | 數(shù)據(jù)10表示0.1升空氣中直徑在2.5um以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)10低八位 | |
| 數(shù)據(jù)11高八位 | 數(shù)據(jù)11表示0.1升空氣中直徑在5.0um以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)11低八位 | |
| 數(shù)據(jù)12高八位 | 數(shù)據(jù)12表示0.1升空氣中直徑在10um以上顆粒物個(gè)數(shù) |
| 數(shù)據(jù)12低八位 | |
| 數(shù)據(jù)13高八位 | 版本號 |
| 數(shù)據(jù)13低八位 | 錯(cuò)誤代碼 |
| 數(shù)據(jù)和校驗(yàn)高八位 | 校驗(yàn)碼=起始符1+起始符2+……..+數(shù)據(jù)13低八位 |
| 數(shù)據(jù)和校驗(yàn)低八位 |
輸出結(jié)果
主要輸出為單位體積內(nèi)各濃度顆粒物質(zhì)量以及個(gè)數(shù),其中顆粒物個(gè)數(shù)的單位體積為 0.1 升,質(zhì)量濃度單位為:微克/立方米。
輸出分為主動(dòng)輸出和被動(dòng)輸出兩種狀態(tài)。傳感器上電后默認(rèn)狀態(tài)為主動(dòng)輸出,即傳感器主動(dòng)向主機(jī)發(fā)送串行數(shù)據(jù),時(shí)間間隔為 200~800ms,空氣中顆粒物濃度越高,時(shí)間間隔越短。主動(dòng)輸出又分為兩種模式:平穩(wěn)模式和快速模式。在空氣中顆粒物濃度變化較小時(shí),傳感器輸出為平穩(wěn)模式,即每三次輸出同樣的一組數(shù)值,實(shí)際數(shù)據(jù)更新周期約為 2s。當(dāng)空氣中顆粒物濃度變化較大時(shí),傳感器輸出自動(dòng)切換為快速模式,每次輸出都是新的數(shù)值,實(shí)際數(shù)據(jù)更新周期為 200~800ms。
二、PMS7003 傳輸協(xié)議代碼講解 ?(重點(diǎn))
參看: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é)議寫的不錯(cuò)哦,我們來講一下。《1》定義數(shù)組和結(jié)構(gòu)體
這里面主要看一下,完全參照的傳輸協(xié)議定義的串口數(shù)據(jù)的結(jié)構(gòu)體《2》串口配置
不用看這個(gè),因?yàn)槲覀冇玫氖?485 通信,里面自有它那一套串口配置的方式,下面會講到的。《3》傳輸協(xié)議代碼如何寫
重點(diǎn)來了哦然后這里可以復(fù)習(xí)一下大小端、位操作和分支跳轉(zhuǎn)語句的基礎(chǔ)知識。 參看:C語言再學(xué)習(xí)-- 大端小端詳解(轉(zhuǎn)) 參看:C語言再學(xué)習(xí) -- 位操作 參看:C語言再學(xué)習(xí) -- 分支與跳轉(zhuǎn)語句
三、快速學(xué)習(xí)驅(qū)動(dòng)程序基本框架
需要寫傳感器的驅(qū)動(dòng)程序,這里快速的瀏覽一遍。 (之前以為單獨(dú)寫驅(qū)動(dòng)呢,現(xiàn)在看來直接用 485 串口編程的即可,這部分只做參考學(xué)習(xí)。) 驅(qū)動(dòng)程序的基本框架 #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 #編譯生成最終的二進(jìn)制可執(zhí)行文件helloworld.ko all:make -C /opt/kernel SUBDIRS=$(PWD) modules #到內(nèi)核/opt/kernel源碼中進(jìn)行make編譯,然后告訴內(nèi)核,在你的源碼以外還有一個(gè)目錄/opt/drivers/day01/1.0,在這個(gè)目錄下有一個(gè).c文件需要你進(jìn)行編譯,要把它編譯生成.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:配置工作模式為輸出,輸出某個(gè)狀態(tài)gpio_direction_input:配置工作模式為輸入gpio_get_value:獲取狀態(tài)gpio_set_value:設(shè)置狀態(tài) 設(shè)備號的操作 申請alloc_chrdev_region(設(shè)備號,0, 次設(shè)備號的個(gè)數(shù),設(shè)備名稱); 釋放unregister_chrdev_region(設(shè)備號,次設(shè)備號的個(gè)數(shù)); 實(shí)現(xiàn)一個(gè)字符設(shè)備驅(qū)動(dòng)的編程步驟 定義初始化字符設(shè)備對象cdev_init 注冊字符設(shè)備對象到內(nèi)核cdev_add 卸載字符設(shè)備對象cdev_dellinux內(nèi)核描述字符設(shè)備使用的數(shù)據(jù)結(jié)構(gòu) struct cdev {dev_t dev; //保存申請的設(shè)備號unsigned int count;//設(shè)備的個(gè)數(shù)const struct file_operations *ops; //給字符設(shè)備驅(qū)動(dòng)賦予操作硬件的方法,并且將這些方法最終提供給用戶}; linux內(nèi)核字符設(shè)備硬件操作接口
struct file_operations { .owner ?= THIS_MODULE, .open = led_open, //打開設(shè)備 .release = led_close, //關(guān)閉設(shè)備 .read = led_read, //讀設(shè)備 .write = led_write, //寫設(shè)備 .unlocked_ioctl = led_ioctl, //向設(shè)備發(fā)送命令并且能夠進(jìn)行讀寫操作 ...... };設(shè)備文件創(chuàng)建函數(shù)
struct class *cls; //創(chuàng)建設(shè)備類指針//定義初始化設(shè)備類(長樹枝,樹枝名叫tarena)//結(jié)果是在/sys/class目錄下生成一個(gè)tarena目錄,存放創(chuàng)建設(shè)備文件所需的原材料 cls = class_create(THIS_MODULE, "tarena");//創(chuàng)建設(shè)備文件(長蘋果)//結(jié)果是在/dev/生成設(shè)備文件 device_create(cls, NULL, 申請的設(shè)備號,NULL,s設(shè)備文件名);//刪除設(shè)備文件(采摘蘋果) device_destroy(cls, 申請的設(shè)備號);//刪除設(shè)備類(砍樹枝) class_destroy(cls);混雜設(shè)備驅(qū)動(dòng)的編程步驟 1.定義初始化混雜設(shè)備對象struct file_operations led_fops = {...};struct miscdevice led_misc = {.minor = MISC_DYNAMIC_MINOR,.name = "myled",.fops = &led_fops}; 2.向內(nèi)核注冊混雜設(shè)備對象,一旦注冊完畢,內(nèi)核就有一個(gè)真實(shí)的混雜設(shè)備驅(qū)動(dòng)misc_register(&led_misc);3.從內(nèi)核卸載混雜設(shè)備對象misc_deregister(&led_misc);
四、UART 接口 (重點(diǎn))
上文中有提到,用的 485 通信,然后看一下它所接的 GPIO 口是哪個(gè)。然后之前寫過一篇關(guān)于 485 串口編程的文章,可供參考。
參看:UNIX再學(xué)習(xí) -- RS485 串口編程
這個(gè)很有必要哦,里面的串口編程,很實(shí)用。然后只需要將其改為只接收即可。
然后具體的更改代碼,這里我就不再重復(fù)。
編譯執(zhí)行: 編譯: arm-none-linux-gnueabi-gcc com.c -o com -pthreadtftp 到文件系統(tǒng)中: tftp -g -r com 192.168.2.xx設(shè)置權(quán)限: chmod 777 com手動(dòng)加載設(shè)備: mknod /dev/pio c 203 0執(zhí)行 ./com 這里看一下,輸出的結(jié)果。
然后通過 校驗(yàn)碼=起始符1+起始符2+……..+數(shù)據(jù)13?來驗(yàn)證第一行的數(shù)據(jù)。校驗(yàn)碼是 02 81 說明是正確的。?
五、開發(fā)程序
最后是傳輸協(xié)議開發(fā)程序,只看 read 讀取部分即可。其他的沒啥可講的。
#include <fcntl.h> //文件控制定義 #include <stdio.h> //標(biāo)準(zhǔn)輸入輸出定義 #include <stdlib.h> //標(biāo)準(zhǔn)函數(shù)庫定義 #include <unistd.h> //Unix標(biāo)準(zhǔn)函數(shù)定義 #include <errno.h> //錯(cuò)誤好定義 #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ū)動(dòng)判斷輸入輸出模式davinci_gio_arg arg;#define DEV_PIO_LED "/dev/pio" // 需要手動(dòng)添加設(shè)備號 mknod /dev/pio c 203 0 #define PIO_NUM 47 // 47pin 為控制輸入輸出方向引腳 #define DEV_UART "/dev/ttyS1" // /dev/ttyS1 為串口設(shè)備#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 設(shè)備文件描述符,nspeed 波特率,nbits 數(shù)據(jù)位數(shù)(7位或8位),parity 奇偶校驗(yàn)位('n'或'N'為無校驗(yàn)位,'o'或'O'為偶校驗(yàn),'e'或'E'奇校驗(yàn)),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ù)設(shè)置,在這里如果串口號等出錯(cuò),會有相關(guān)的出錯(cuò)信息 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);//屏蔽其他標(biāo)志位newtio.c_cflag |= (CLOCAL | CREAD );newtio.c_cflag &= ~CSIZE;//設(shè)置數(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;}//設(shè)置校驗(yàn)位switch( parity ){case 'n':case 'N': //無奇偶校驗(yàn)位newtio.c_cflag &= ~PARENB;newtio.c_iflag &= ~INPCK;break;case 'o':case 'O': //設(shè)置為奇校驗(yàn)newtio.c_cflag |= ( PARODD | PARENB );newtio.c_iflag |= ( INPCK | ISTRIP );break;case 'e':case 'E': //設(shè)置為偶校驗(yàn)newtio.c_iflag |= ( INPCK |ISTRIP );newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;default:perror("unsupported parity\n");return -1;}//設(shè)置停止位switch( nstop ) {case 1: newtio.c_cflag &= ~CSTOPB;break;case 2:newtio.c_cflag |= CSTOPB;break;default :perror("Unsupported stop bit\n");return -1;}//設(shè)置波特率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;}//設(shè)置等待時(shí)間和最小接收字符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è)置數(shù)據(jù)流控制newtio.c_iflag &= ~(IXON|IXOFF|IXANY); //使用軟件流控制 //如果發(fā)生數(shù)據(jù)溢出,接收數(shù)據(jù),但是不再讀取 刷新收到的數(shù)據(jù)但是不讀tcflush( fd, TCIFLUSH ); //激活配置 (將修改后的termios數(shù)據(jù)設(shè)置到串口中)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; }//打開串口并返回串口設(shè)備文件描述 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; }//單片機(jī)數(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; //設(shè)為低電平 接收態(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), 這里有點(diǎ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設(shè)備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; }//等待線程結(jié)束pthread_join (tid, NULL);//關(guān)閉設(shè)備 close (fd_gpio);return 0; }
測試結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的PM2.5检测 -- PMS7003 开发程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 独享代理产品介绍
- 下一篇: 给textView设置文字渐变色