前段時(shí)間一直在做超聲波的調(diào)試,很多模擬量的問(wèn)題沒有解決這段時(shí)間降模擬量和通信做了調(diào)整,目前完成了Modbus-RTU的數(shù)據(jù)通信以及超聲波測(cè)距的工作,整體的項(xiàng)目進(jìn)展目前已經(jīng)基本完成了,所以這里來(lái)和大家做一下匯報(bào),分享一下自己的成果,首先從整體的項(xiàng)目規(guī)劃以及框圖開始說(shuō)起,可能會(huì)比較繁瑣一點(diǎn),但是我還是覺得盡量詳細(xì)的介紹我們現(xiàn)在的東西,也許會(huì)對(duì)大家?guī)?lái)一些啟發(fā)。
1 項(xiàng)目介紹
AGV在現(xiàn)在物流運(yùn)輸和分揀中起到了重要作用,通常情況下是由上級(jí)電腦完成系統(tǒng)路徑的規(guī)劃,然后車輛按照分配路線將物流包裹配送到對(duì)應(yīng)的區(qū)域內(nèi),從而完成大量包裹的分揀的工作,節(jié)約了很多人力成本,也避免了由于人為操作失誤造成物流停滯、延遲的負(fù)面影響。因此AGV在物流分揀的重要性可想而知。在AGV的整體路徑規(guī)劃中,AGV的智能性也將起到至關(guān)重要的作用,其中最主要的一點(diǎn)就是安全距離檢測(cè),可以判斷對(duì)于障礙物的判斷,以及車輛急停、車輛會(huì)根據(jù)障礙物距離做出相應(yīng)的減速、停止、轉(zhuǎn)向等動(dòng)作。
2 硬件方案
整體的硬件方案是STM32F103CBT6作為主控,通過(guò)分時(shí)復(fù)用完成多多個(gè)超聲波探頭的然后通過(guò)RS485或者CAN總線完成數(shù)據(jù)的傳輸,通常情況下,RS485和CAN總線在實(shí)時(shí)性上是有一些距離的。目前的話只做了RS485這塊,支持Modbus_RTU的協(xié)議。整體還配備了溫度采集傳感器,可以通過(guò)溫度來(lái)進(jìn)行聲音測(cè)距的溫度補(bǔ)償,計(jì)算出當(dāng)前溫度的聲速,從而對(duì)測(cè)量距離進(jìn)行修正。
2.1 硬件原理圖
整體的原理圖如上圖,采用八個(gè)國(guó)內(nèi)的超聲波測(cè)距芯片,然后使用DCDC,完成12V到3.3V的電壓轉(zhuǎn)換,通過(guò)兩個(gè)8通道的選擇開關(guān)完成對(duì)每個(gè)傳感器的數(shù)據(jù)選擇和讀取,通過(guò)TTL串口實(shí)現(xiàn)數(shù)的采集。軟件內(nèi)配置狀態(tài)機(jī),可以正常的完成采集。
整體的電路板如上圖。每個(gè)傳感器都有自己的驅(qū)動(dòng)芯片。
3 軟件流程圖
3.1 狀態(tài)機(jī)切換機(jī)制
狀態(tài)機(jī)是在控制最常用的一種機(jī)制,可以避免阻塞,完成程序的流暢運(yùn)行,同樣避免了不必要的程序運(yùn)行占用資源。目前我使用的狀態(tài)機(jī)一共設(shè)置了幾個(gè)狀態(tài),每個(gè)狀態(tài)有對(duì)應(yīng)狀態(tài)的工作任務(wù)。
目前一共分為:空閑狀態(tài)、命令發(fā)送狀態(tài)、回復(fù)等待狀態(tài)、超時(shí)狀態(tài)、異常狀態(tài)。
3.2 代碼展示
3.2.1 狀態(tài)機(jī)代碼
void get_Data(struct CSB_Get *CSB_Struct)
{
int i=0;
unsigned int Status=CSB_Struct->Stttus;
unsigned int Data=0;
if(CSB_Struct->Channel_Count>CSB_Struct->Channel_MAX)
{
CSB_Struct->Channel_Count=0;/*-- 如果當(dāng)前通道計(jì)數(shù)大于 最大通道--那么這次就作廢---*/
return ;
}
else
{
switch(Status)
{
/*--------*/
case Status_Ideal:/*--數(shù)據(jù)采集之前的數(shù)據(jù)初始化工作 ---*/
{
for(i=0;i<CSB_Struct->Channel_MAX;i++)
{
CSB_Struct->CSB_Data_Stable[i]=CSB_Struct->CSB_Curent_Data[i];
SysTemInfo.Sys_Data.CSB_Data[i]=CSB_Struct->CSB_Curent_Data[i]/1000;
}
select(CSB_Struct->Channel_Count); /*-- 選擇發(fā)送通道 --*/
CSB_Struct->TimeOut_Flag=0; /*-- 超時(shí)標(biāo)志清零--*/
CSB_Struct->UART_GetData_Flag=0; /*-- 串口接收數(shù)據(jù)標(biāo)志清零--*/
CSB_Struct->Uart_GetData_Count=0; /*-- 串口接收數(shù)量計(jì)數(shù)清零 ---*/
CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=0;/*當(dāng)前通道長(zhǎng)度清零--*/
CSB_Struct->TimeStart_Flag=1;
CSB_Struct->TimeOutCount=0;
CSB_Struct->Uart_Data[0]=0;
CSB_Struct->Uart_Data[1]=0;
CSB_Struct->Uart_Data[2]=0;
CSB_Struct->Stttus=Status_SendCND;
}break;
case Status_SendCND:
{
select(CSB_Struct->Channel_Count); /*-- 選擇發(fā)送通道 --*/
Send_Cmd(); /*-- 發(fā)送超聲波的數(shù)據(jù)采集命令 --*/
timer_enable(TIMER1); /*-- 開啟定時(shí)器 -------*/
CSB_Struct->Uart_Data[2]=0;
CSB_Struct->Stttus=Status_WaitReply;
}break;
case Status_WaitReply :
{
if(CSB_Struct->UART_GetData_Flag==1)
{
Data =(Data|(CSB_Struct->Uart_Data[0]<<16) |(CSB_Struct->Uart_Data[1]<<8)|(CSB_Struct->Uart_Data[2]));
CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=Data;
CSB_Struct->Channel_Count++;
CSB_Struct->Stttus=Status_Ideal;
}
/*-- 如果超時(shí) --*/
if(CSB_Struct->TimeOut_Flag==1)
{
CSB_Struct->Stttus=Status_TimeOut;
}
}break;
case Status_TimeOut: /*-- 直接跳轉(zhuǎn)到空閑模式,繼續(xù)下一個(gè)通道的測(cè)量 ----*/
{
CSB_Struct->Channel_Count++;
CSB_Struct->TimeStart_Flag=0;
CSB_Struct->TimeOutCount=0;
timer_disable(TIMER1); /*-- 開啟定時(shí)器 -------*/
CSB_Struct->Stttus=Status_Ideal;
}break;
/*--------*/
default:
{
CSB_Struct->TimeOut_Flag=0; /*-- 超時(shí)標(biāo)志清零--*/
CSB_Struct->UART_GetData_Flag=0; /*-- 串口接收數(shù)據(jù)標(biāo)志清零--*/
CSB_Struct->Uart_GetData_Count=0; /*-- 串口接收數(shù)量計(jì)數(shù)清零 ---*/
CSB_Struct->Uart_Data[0]=0;
CSB_Struct->Uart_Data[1]=0;
CSB_Struct->Uart_Data[2]=0;
CSB_Struct->Channel_Count=0;
CSB_Struct->TimeStart_Flag=0;
timer_disable(TIMER1); /*-- 開啟定時(shí)器 -------*/
}
}
}
}
3.2.2 通信代碼展示 這里僅展示部分代碼
case ReadMultRegister : //--功能碼:03 -- 讀多個(gè)寄存器----
{
MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC數(shù)值--
//--進(jìn)入這里,說(shuō)明地址和功能碼都滿足了,現(xiàn)在需要做的事判斷輸出數(shù)量是否在規(guī)定范圍內(nèi)--
//--IO數(shù)量的計(jì)算應(yīng)當(dāng)從起始地址+數(shù)量來(lái)計(jì)算--如果起始地址加上數(shù)量之后大于IO的點(diǎn)數(shù),
//--此時(shí)應(yīng)當(dāng)報(bào)錯(cuò)處理--
DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+讀取數(shù)量---
if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
{
MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站號(hào)---
MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能碼--
//--讀取線圈的函數(shù)----unsigned short ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
RTN_DataLen=ReadMultReg_03(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
//--填充字節(jié)數(shù)--
MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字節(jié)數(shù)--
//--開始填充數(shù)據(jù)--
//計(jì)算CRC---校驗(yàn)和----校驗(yàn)是按照從包頭開始 -- 一直到數(shù)據(jù)結(jié)束---
CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--計(jì)算CRC的數(shù)值
RTN_DataLen=RTN_DataLen+5; //--這里是包含了CRC校驗(yàn)的----站號(hào) +功能碼 +數(shù)量+CRCData*2=5
MB->MB_TxData_Len=RTN_DataLen;//--傳入帶發(fā)送的字節(jié)長(zhǎng)度--
MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff); //--CRC-H
MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff); //--CRC-L
// 完成數(shù)據(jù)包的組包
//-- 發(fā)送標(biāo)志----
MB->SendFlag=1;
}
else/*--說(shuō)明--超出范圍了---應(yīng)當(dāng)返回異常碼------ --*/
{
MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站號(hào)--
MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能碼--錯(cuò)誤碼--
MB->MB_TxData_Len=2;
MB->SendFlag=1;
}
}
break ;
//--
case ReadinputRegister : //--功能碼:04 -- 讀輸入寄存器----
{
MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC數(shù)值--
DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+讀取數(shù)量---
if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
{
MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站號(hào)---
MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能碼--
//--讀取線圈的函數(shù)----unsigned short ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
RTN_DataLen=ReadInputReg_04(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
//--填充字節(jié)數(shù)--
MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字節(jié)數(shù)--
//--開始填充數(shù)據(jù)--
//計(jì)算CRC---校驗(yàn)和----校驗(yàn)是按照從包頭開始 -- 一直到數(shù)據(jù)結(jié)束---
CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--計(jì)算CRC的數(shù)值
RTN_DataLen=RTN_DataLen+5; //--這里是包含了CRC校驗(yàn)的----站號(hào) +功能碼 +數(shù)量+CRCData*2=5
MB->MB_TxData_Len=RTN_DataLen;//--傳入帶發(fā)送的字節(jié)長(zhǎng)度--
MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff); //--CRC-H
MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff); //--CRC-L
// 完成數(shù)據(jù)包的組包
//-- 發(fā)送標(biāo)志----
MB->SendFlag=1;
}
else/*--說(shuō)明--超出范圍了---應(yīng)當(dāng)返回異常碼------ --*/
{
MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站號(hào)--
MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能碼--錯(cuò)誤碼--
MB->MB_TxData_Len=2;
MB->SendFlag=1;
}
}
break ;
//----
case WriteSingelRegister : //--功能碼:06 -- 寫單個(gè)寄存器----
{
MB->ProtocalStr.MB_DataNum=1;
//--站號(hào)-功能碼-起始地址 - 數(shù)量 字節(jié)計(jì)數(shù)-- 寄存器數(shù)值--
DataLimit=MB->ProtocalStr.MB_StartAddr+MB->ProtocalStr.MB_DataNum;
//--進(jìn)入這里,說(shuō)明地址和功能碼都滿足了,現(xiàn)在需要做的事判斷輸出數(shù)量是否在規(guī)定范圍內(nèi)--
if((MB->ProtocalStr.MB_DataNum>=1)&&(MB->ProtocalStr.MB_DataNum<=0x07D0))
{
//--站號(hào)-功能碼-寄存器地址- 寄存器值
for(i=0;i<6;i++)
MB->MB_TxData[i]=MB->MB_RxData[i];
//--寫多個(gè)寄存器的函數(shù)----unsigned short WriteMultRegister_16(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
RTN_DataLen=WriteSingelReg_06(&MB->MB_RxData[4],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
//--填充字節(jié)數(shù)--
// MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字節(jié)數(shù)--
//--開始填充數(shù)據(jù)--
//計(jì)算CRC---校驗(yàn)和----校驗(yàn)是按照從包頭開始 -- 一直到數(shù)據(jù)結(jié)束---
CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+6 );//--計(jì)算CRC的數(shù)值
RTN_DataLen=RTN_DataLen+8; //--這里是包含了CRC校驗(yàn)的----站號(hào) +功能碼 +數(shù)量+CRCData*2=5
MB->MB_TxData_Len=RTN_DataLen;//--傳入帶發(fā)送的字節(jié)長(zhǎng)度--
MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff); //--CRC-H
MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff); //--CRC-L
// 完成數(shù)據(jù)包的組包
//-- 發(fā)送標(biāo)志----
MB->SendFlag=1;
}
else/*--說(shuō)明--超出范圍了---應(yīng)當(dāng)返回異常碼------ --*/
{
MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站號(hào)--
MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能碼--錯(cuò)誤碼--
MB->MB_TxData_Len=2;
MB->SendFlag=1;
}
}
break ;
4 實(shí)物測(cè)試圖
由于電路沒有處理好,所以目前可以穩(wěn)定測(cè)試的距離在40cm以內(nèi),下面是Modbus-RTU 的測(cè)試界面。