在傳統 UART(串口)通信中,每一幀數據通常包含1位起始位,8位數據位,可以選配的1位奇偶校驗位,以及1位或者2位停止位,可參考下圖的數據幀結構:
在一些特定的應用中,比如多機通信、地址/數據區分等場景中,需要用到串口的9bit通訊模式,該模式下每幀數據會擴展到9位,數據的最后一位為額外的標識位。這個額外的第 9 位可以用于標識數據類型(比如地址/數據區分)或者多機通信中的設備尋址等。可參考下圖的數據幀結構:
串口的9bit模式比較常見的使用方式是當總線上有多個設備時,第一幀數據使用第 9 位標記為“地址幀”,其余設備判斷是否接收。后續幀第 9 位標記為“數據幀”,所有設備按需處理。一般第 9 位為0 表示普通數據,為1 表示特殊命令或地址。
在這種應用模式下,就要求程序先設置為地址模式(即第9位為1),發送第一個地址幀后再切換為數據模式(第9位為0),再發送后續的數據幀。如果用戶每次發送都進行切換的話,一是代碼相對繁瑣,另一點是在應用層切換存在調度機制,可能會讓地址幀與數據幀出現一定的間隔。如果實際的場景對通訊的響應速度有一定的要求的話,在應用層來回切換可能就無法達到要求。
考慮到這一點,英創公司在Linux工控主板的驅動中進行了優化,給要使用9bit通訊模式的用戶增加了一個專用的設置接口。通過這個設置接口,用戶只需在發送數據前進行一次設置,就可以將數據一次性填入,主板會自動以地址幀的模式發送第一個字節,然后切換為數據幀發送后續字節,整個切換流程都是在驅動中自動完成,能夠保證數據之間幾乎沒有間隔。下面就介紹一下具體的使用方法。
專用的設置接口借鑒了原來設置串口參數的方式,在struct termios中的c_cflag指定了一個未使用特殊的值,當驅動檢測到這個特殊值后,就會自動切換地址幀與數據幀來發送填入的數據。這樣就可保持UART串口設置的習慣方式不變。具體設置c_cflag的值方法為:使能CMSPAR位,異或PARODD位,對應的代碼如下(在英創提供的串口例程基礎上修改):
int CSerial::set_port_bit9() { struct termios new_opt; int status; tcgetattr(m_fd,&new_opt); new_opt.c_cflag &= ~(PARENB | CMSPAR); new_opt.c_cflag |= CMSPAR; new_opt.c_cflag ^= PARODD; new_opt.c_iflag |= INPCK; status = tcsetattr(m_fd,TCSANOW,&new_opt); if(status != 0) { perror("Cannot set the serial bit9"); return -1; } return status; } int main( int argc,char* argv[] ) { int i1; int portno, baudRate; char Buf[20], cmd; //打開串口,并設置參數 i1 = m_Serial.OpenPort( portno, baudRate, '8', '1', 'N'); if( i1<0 ) { printf( "serial open fail\n"); return -1; } Buf[0] = 0xaa; //第一個字節為地址 Buf[1] = 0xaa; //后面的字節為數據 //設置9bit通訊模式 m_Serial.set_port_bit9(); //發送填入的數據 i1 = m_Serial.WritePort(Buf, 2); return 0; }
用戶使用時,如果需要按照9bit通訊模式發送數據,在調用發送前先調用一次封裝好的set_port_bit9()函數設置串口后,再進行發送即可。為了避免做其他設置的時候影響到相關的標志位,建議用戶在調用發送函數前,再調用set_port_bit9()函數設置,然后就立即進行發送。
下圖是測試的波形,使用9bit通訊模式發送了兩個字節(都是0xaa),第一個字節位的第9位(標識位)為1,代表地址或者特殊命令,第二個字節的第9位(標識位)為0,代表正常數據,圖中紅色箭頭指向的就是兩個字節的第9位:
另外可以看到由于是一次性填入的數據進行發送,所以兩個字節之間(第一個字節的停止位和第二個字節的起始位)幾乎沒有什么間隔,能夠保證數據發送的實時性。
我們在主流的產品ESM335x、ESM6800、ESM7000、ESM6200、ESM6400、ESM8000、ESM7400、ESM8400、ESM3568中均已實現該功能,如果對該方案感興趣的用戶,可以聯系英創的工程師獲取詳細的測試例程。
成都英創信息技術有限公司 028-8618 0660