聚豐項(xiàng)目 > 呼吸式酒精檢測(cè)儀檢定設(shè)備
本項(xiàng)目是一套用于酒精檢測(cè)儀的檢定的設(shè)備,用于測(cè)試酒精檢測(cè)儀器精確性的檢定。如可用于檢定呼吸式警用酒精檢測(cè)儀等。系統(tǒng)要實(shí)現(xiàn)溫濕度檢測(cè)、輸入輸出壓力檢測(cè)、溫度控制及高精度溫度檢測(cè)等,因?yàn)樵跍y(cè)試過(guò)程中溫度和濕度會(huì)對(duì)檢定的精確性有重要影響。進(jìn)氣分為6路,除了空氣和酒精氣體外,還有CO和丙酮等干擾性氣體,有一套復(fù)炸的氣體配置方式。同時(shí)又有4路氣體加熱腔室對(duì)測(cè)試氣體進(jìn)行加熱并進(jìn)行精確的溫度控制。另外對(duì)氣體的流量要進(jìn)行控制并能實(shí)現(xiàn)數(shù)據(jù)遠(yuǎn)傳和操作。
Cresta
分享Cresta
團(tuán)隊(duì)成員
尹家軍 工程師
根據(jù)項(xiàng)目需求,在氣體流量控制方面選優(yōu)MFC(氣體質(zhì)量流量控制器)通過(guò)ADC和DAC實(shí)現(xiàn)控制。ADC和DAC都使用片上自帶的,采用運(yùn)算放大器進(jìn)行隔離和放大使其輸入輸出0-5VDC信號(hào)。
溫度檢測(cè)通過(guò)LTC2400實(shí)現(xiàn)熱電阻高精度溫度采集。由于對(duì)溫度非常敏感所以這部分要求較高,使用了24位的ADC實(shí)現(xiàn)高進(jìn)度采集,通過(guò)SPI總線獲取。
試驗(yàn)氣體的配置采用6個(gè)六個(gè)電磁閥控制配置不同成分的測(cè)試氣體。沒(méi)路輸出根據(jù)需要可輸出干觸點(diǎn)或者24VDC濕觸點(diǎn)。
溫度控制器采用宇電AI-7804同時(shí)實(shí)現(xiàn)4路溫度的檢測(cè)與控制。采用RS-485的通訊方式和PWM輸出控制加熱功率。
上位通訊采用兩種方式,以太網(wǎng)遠(yuǎn)傳和串口觸摸屏控制。以太網(wǎng)采用W5500和SPI接口方式實(shí)現(xiàn):
而串口觸摸屏的通訊采用RS485或者RS232方式,本次采用RS485的通訊方式,使用MAX3485芯片實(shí)現(xiàn)。
壓力檢測(cè)采用MS5803采集壓力的變化,采用I2C通訊。濕度檢測(cè)使用SHT15實(shí)現(xiàn),采用類(lèi)式I2C通訊方式,通過(guò)GPIO模擬。
軟件的設(shè)計(jì)采用IAR EWARM V7.8和ST標(biāo)準(zhǔn)庫(kù)V3.5實(shí)現(xiàn)。具體的軟件設(shè)計(jì)包括上位遠(yuǎn)傳通訊、模擬量輸入輸出控制、邏輯控制、熱電阻溫度采集、溫濕度和壓力數(shù)據(jù)采集以及加熱和溫度控制。
為了讓軟件更好地適應(yīng)更換傳感器和應(yīng)用不同場(chǎng)合的功能增減要求,我們?cè)谠O(shè)計(jì)軟件時(shí)使用了一個(gè)配置文件來(lái)配置更能的使用和增減。這個(gè)配置文件就是一個(gè)頭文件,定義了一些宏來(lái)控制條件編譯,節(jié)選部分配置文件如下:
/*定義以太網(wǎng)通訊功能的使能,1:?jiǎn)⒂茫?:禁用*/
#ifndef Ethernet_ENABLE
#define Ethernet_ENABLE (1)
#endif
/*定義串口上位通訊使能,1:?jiǎn)⒂茫?:禁用*/
#ifndef UPPER_SERIAL_ENABLE
#define UPPER_SERIAL_ENABLE (0)
#endif
/*定義片上Flash存取使能,1:?jiǎn)⒂茫?:禁用*/
#ifndef STORAGE_ENABLE
#define STORAGE_ENABLE (0)
#endif
/*定義模擬量輸入是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef ANALOG_INPUT_ENABLE
#define ANALOG_INPUT_ENABLE (1)
#endif
/*定義模擬量輸出是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef ANALOG_OUTPUT_ENABLE
#define ANALOG_OUTPUT_ENABLE (1)
#endif
/*定義數(shù)字量操作是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef DIGITAL_ENABLE
#define DIGITAL_ENABLE (1)
#endif
/*定義溫濕度計(jì)是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef HYGRO_THERMO_ENABLE
#define HYGRO_THERMO_ENABLE (1)
#endif
/*壓力變送器是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef PRESS_TRANS_ENABLE
#define PRESS_TRANS_ENABLE (1)
#endif
/*熱電阻采集電路是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef RTD_COLLECT_ENABLE
#define RTD_COLLECT_ENABLE (0)
#endif
/*備用串行設(shè)備是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef SERIAL_SPARE_ENABLE
#define SERIAL_SPARE_ENABLE (0)
#endif
/*溫控器是否啟用,1:?jiǎn)⒂茫?:禁用*/
#ifndef THERMOSTAT_ENABLE
#define THERMOSTAT_ENABL (0)
#endif
/*定義串口上位通訊方式的選擇,1:RS232;0:RS485*/
#ifndef UPUSART_COMM_TYPE
#define UPUSART_COMM_TYPE (0)
#endif
/*定義壓力變送器MS4515DO的通訊方式的選擇,1:SPI;0:I2C*/
#ifndef MS4515DO_COMM_TYPE
#define MS4515DO_COMM_TYPE (0)
#endif
/*定義啟用的壓力變送器類(lèi)型,1:MS5837;0:MS5803*/
#ifndef PRESSURE_TRANSMITTER_TYPE
#define PRESSURE_TRANSMITTER_TYPE (0)
#endif
/*定義MS5803(MS5837)采集值是否啟用濾波功能,1:?jiǎn)⒂茫?:禁用*/
#ifndef MS5803_FILTER_ENABLE
#define MS5803_FILTER_ENABLE (1)
#endif
上位遠(yuǎn)傳通訊包括有以太網(wǎng)通訊和串口通訊,以太網(wǎng)通訊用于連接遠(yuǎn)程計(jì)算機(jī),出口通訊用于連接觸摸屏。均使用Modbus協(xié)議,支持03、06、16等功能碼。
//解析接收到的數(shù)據(jù)
uint16_t ReceivedDataParsing(uint8_t *rxBuffer,uint8_t *txBuffer)
{
uint16_t length=0;
uint8_t fuctionCode=rxBuffer[7];
switch(fuctionCode)
{
case READ_HOLDING_REGISTERS:
{
uint16_t startAddress=rxBuffer[8];
startAddress=(startAddress<<8)+(uint16_t)rxBuffer[9];
uint16_t RegisterNumber=rxBuffer[10];
RegisterNumber=(RegisterNumber<<8)+(uint16_t)rxBuffer[11];
//RegisterNumber=0;
//讀取對(duì)應(yīng)寄存器數(shù)值
uint8_t returnData[REGISTERAMOUNT*2+2];
GetRegisterValue(startAddress,RegisterNumber,returnData);
uint16_t byteCount=0;
txBuffer[byteCount++]=rxBuffer[0];
txBuffer[byteCount++]=rxBuffer[1];
txBuffer[byteCount++]=rxBuffer[2];
txBuffer[byteCount++]=rxBuffer[3];
uint16_t byteAmount=RegisterNumber*2+3;
txBuffer[byteCount++]=(byteAmount>>8);
txBuffer[byteCount++]=byteAmount;
txBuffer[byteCount++]=rxBuffer[6];
for(int i=0;i<RegisterNumber*2+2;i++)
{
txBuffer[byteCount++]=returnData[i];
}
length=byteCount;
break;
}
case WRITE_SINGLE_REGISTER:
{
//txBuffer=rxBuffer;//將指針賦值,不能改變數(shù)組的值
uint16_t ByteAmount=rxBuffer[4];
ByteAmount=(ByteAmount<<8)+(uint16_t)rxBuffer[5];
length=ByteAmount+6;
uint16_t objectRegister=0;
objectRegister=rxBuffer[8];
objectRegister=(objectRegister<<8)+(uint16_t)rxBuffer[9];
uint16_t setValue=rxBuffer[10];
setValue=(setValue<<8)+(uint16_t)rxBuffer[11];
//將設(shè)定值寫(xiě)到對(duì)應(yīng)的寄存器
SetRegisterValue(objectRegister,setValue);
for(int i=0;i<length;i++)
{
txBuffer[i]=rxBuffer[i];
}
break;
}
case WRITE_MULTI_REGISTER:
{
length=12;
SetMultiRegisterValue(rxBuffer+8);
for(int i=0;i<length;i++)
{
txBuffer[i]=rxBuffer[i];
}
txBuffer[5]=0x06;
break;
}
default:
{
break;
}
}
return length;
}
模擬量輸入輸出控制的控制較為簡(jiǎn)單,直接使用DMA操作方式,實(shí)現(xiàn)簡(jiǎn)單方便,不用詳述。數(shù)字量的控制方式以及溫度的SPI操作與前面文章中的一致。
溫濕度采集使用的SHT15模塊,它的通訊協(xié)議類(lèi)是于I2C方式,但是用STM32自帶的I2C來(lái)操作卻不方便,所以使用GPIO來(lái)實(shí)現(xiàn)通訊。為了方便在不同的系統(tǒng)使用所以對(duì)時(shí)鐘和數(shù)據(jù)引腳的操作采用的回掉函數(shù)來(lái)實(shí)現(xiàn)。
先便寫(xiě)SHT15(實(shí)際上SHT1X均可用)的操作函數(shù),并在此時(shí)用弱化的操作函數(shù):
/*讀取DATA引腳位,弱化的函數(shù),無(wú)操作,必須在應(yīng)用中實(shí)現(xiàn)該函數(shù),并自動(dòng)調(diào)用*/
__weak uint8_t ReadDataPinBit(void)
{
return 0;
}
/*將DATA線設(shè)置為輸入輸出方向模式*/
__weak void SetDataPineDirection(IODirection direction)
{
}
事實(shí)上是,什么也不做,然后在最終的應(yīng)用中來(lái)實(shí)現(xiàn)這兩個(gè)函數(shù),以實(shí)現(xiàn)相應(yīng)的操作,對(duì)于不同的系統(tǒng)只需在應(yīng)用中實(shí)現(xiàn)不同操作。
/*讀取DATA引腳位*/
uint8_t ReadDataPinBit(void)
{
return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7);
}
/*將DATA線設(shè)置為輸入輸出方向模式*/
void SetDataPineDirection(IODirection direction)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(direction)
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
}
else
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
}
GPIO_Init( GPIOB, &GPIO_InitStructure);
}
同時(shí)使用函數(shù)執(zhí)政數(shù)組的方式來(lái)簡(jiǎn)化SCK和DATA引腳的操作函數(shù)的編寫(xiě):
/*定義操作GPIO管腳的函數(shù)指針*/
void (*OperationSHT1xIO[])(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)={GPIO_ResetBits,GPIO_SetBits};
/*定義SHT1X總線引腳操作函數(shù)指針*/
BusPinOperation SetBusPin[]={OperationSckPin,OperationDataPin};
/*操作SCK引腳,設(shè)置高低操作*/
void OperationSckPin(BusPinValue value)
{
OperationSHT1xIO[value](GPIOB,GPIO_Pin_6);
}
/*操作DATA引腳,設(shè)置高低操作*/
void OperationDataPin(BusPinValue value)
{
OperationSHT1xIO[value](GPIOB,GPIO_Pin_7);
}
同時(shí)定義幾個(gè)枚舉類(lèi)型:
typedef enum{
Set=1,
Reset=(!Set)
}BusPinValue;
typedef enum{
Out=1,
In=(!Out)
}IODirection;
typedef enum{
SckPin=0,
DataPin=1
}SHT1XPin;
這樣要操作那個(gè)引腳就非常方便了:
/*將data線設(shè)置為輸出模式*/
SetDataPineDirection(Out);
/*將DATA引腳置位*/
SetBusPin[DataPin](Set);
壓力數(shù)據(jù)采集的采用I2C總線,對(duì)STM32的I2C通訊網(wǎng)上文章很多此處不再重復(fù),需要提一下的是整個(gè)操作也是適用函數(shù)指針來(lái)實(shí)現(xiàn)毀掉的方式來(lái)簡(jiǎn)化編程過(guò)程。另外STM32的I2C好像比較容易出現(xiàn)死鎖的情況,不知為何,有待解惑。
加熱和溫度控制采用RS485通訊,使用宇電的AI-BUS協(xié)議,這個(gè)比較簡(jiǎn)單,不再多說(shuō)。
經(jīng)過(guò)差不多2周的調(diào)試,現(xiàn)在設(shè)備已經(jīng)成型,效果還是比較理想的,首先來(lái)一張調(diào)試圖片:
這是現(xiàn)實(shí)的DAC輸出電壓:
這是數(shù)據(jù)遠(yuǎn)傳以Modscan讀取數(shù)據(jù)的結(jié)果:
來(lái)一張組裝后的圖片:
最后來(lái)一組測(cè)試是的上位操作及顯示畫(huà)面:
最后說(shuō)一下這次的一點(diǎn)體會(huì),以往程序調(diào)試沒(méi)問(wèn)題就算好了,由于這個(gè)產(chǎn)品對(duì)時(shí)間非常敏感,有些測(cè)試過(guò)程必須在很短的時(shí)間(以毫秒為單位)完成。所以這次我再軟解的整體結(jié)構(gòu)上下了一些功夫,讓速度提升了好幾倍,所以我覺(jué)得規(guī)劃好程序結(jié)構(gòu)也是一很重要的方面。
黑科技大學(xué): 有聯(lián)系方式嗎
回復(fù)
超級(jí)開(kāi)發(fā)板: 這個(gè)不錯(cuò),我也做個(gè)
回復(fù)
zh559663: 你好,您做了嗎,我也想做一個(gè)可以請(qǐng)教一下嗎
回復(fù)
動(dòng)心忍性1234: 您好我是無(wú)線電雜志的編輯,我們對(duì)您的項(xiàng)目十分感興趣,請(qǐng)問(wèn)您有興趣投稿嗎?成為我們的作者除稿費(fèi)外還有其他優(yōu)厚條件。敬請(qǐng)參與。投稿請(qǐng)聯(lián)系QQ260534978.
回復(fù)