Ubuntu下的串列埠軟體, 除了 CuteCOM, screen, MiniCOM 以外, 還有一個和 MiniCOM 很像的 PicoCOM. 最近在偵錯 CH340C 串列埠的過程中, 發現只有 PicoCOM 的連線Reset才能正常工作, 因此單獨記錄一下.
在 Ubuntu 上直接通過sudo apt install picocom
安裝, 版本是3.1
使用 115200 波特率連線串列埠裝置 /dev/ttyUSB0
picocom -b115200 /dev/ttyUSB0
斷開有兩種方式
在串列埠通訊時, RTS(Ready To Send)會處於低電平, 當斷開串列埠時如果RESET, 就會恢復高電平, 預設會進行RESET.
在偵錯STC微控制器的時候, 往往會使用帶自動燒錄的串列埠轉USB裝置連線, 而這種裝置的自動燒錄機制, 就是通過拉低RTS觸發MCU斷電重啟. 在使用這種RTS觸發的裝置進行燒錄和偵錯時, 就要靈活使用RESET機制.
PS: 這個功能在 picocom 上工作是正常的, 但是在 minicom 上工作不正常, 使用 Ctrl+A, Q 退出一次之後, 無論再使用 Ctrl+A,X, 還是 Ctrl+A,Q 都無法再觸發 RESET
在偵錯串列埠通訊時, 有時候需要觀察串列埠的二進位制輸出, 這時候就需要將資料通過16進位制列印出來, 在 picocom 下需要用 --imap
引數, 這個引數是一個多選項, 可以區分不同型別的數值進行轉換.
--imap <map> (input mappings)
<map> is a comma-separated list of one or more of ...
例如
picocom --imap spchex,tabhex,crhex,lfhex,nrmhex,8bithex -b 19200 /dev/ttyS0
各引數的說明
偵錯串列埠時經常會用到時間戳, 例如觀察延時是否正確. 雖然這個時間戳並不準確, 但是作為一個粗略的時間標記還是非常方便的. minicom在較新的版本中已經支援時間戳輸出, 但是 picocom 上還沒有這個功能.
開源軟體的好處就在於, 用得不順手可以自己改. 在 picocom 上增加時間戳輸出也並不麻煩.
先通過專案倉庫 https://github.com/npat-efault/picocom 匯出程式碼, 直接make
編譯驗證環境是否正確. 如果編譯不成功先解決編譯環境問題.
而後是修改程式碼, 主要修改的部分都在 picocom.c
標頭檔案引入 sys/time.h, 因為會用到時間取值函數
#include <sys/time.h>
增加定義, n/N 這個引數用於開關/選擇時間戳格式
#define KEY_TIMESTAMP CKEY('n') /* show timestamp */
在結構體 struct { ... } opts 中增加一個欄位 int timestamp;
用於記錄時間戳選項
在幫助顯示中增加按鍵提示
fd_printf(STO, "*** [C-%c] : Toggle display timestamp\r\n",
KEYC(KEY_TIMESTAMP));
增加對應的按鍵處理
case KEY_TIMESTAMP:
opts.timestamp = (opts.timestamp + 1) % 4;
fd_printf(STO, "\r\n*** display timestamp, format:%d ***\r\n",
opts.timestamp);
在輸出部分, 增加時間戳的生成方法, 這裡會產生4種顯示方式, 0:不顯示, 1:分:秒, 2:時:分:秒, 3:年-月-日 時:分:秒
/* print leading timestamp */
void print_lead_str(void)
{
struct timeval tv;
struct tm lt = {0};
char buff[32], buff2[64];
gettimeofday(&tv, NULL);
localtime_r(&(tv.tv_sec), <);
switch (opts.timestamp) {
case 3:
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", <);
sprintf(buff2, "%s.%03ld ", buff, tv.tv_usec / 1000);
write(STO, buff2, 24);
break;
case 2:
strftime(buff, sizeof(buff), "%H:%M:%S", <);
sprintf(buff2, "%s.%03ld ", buff, tv.tv_usec / 1000);
write(STO, buff2, 13);
break;
case 1:
strftime(buff, sizeof(buff), "%M:%S", <);
sprintf(buff2, "%s.%03ld ", buff, tv.tv_usec / 1000);
write(STO, buff2, 10);
break;
default:
break;
}
}
在顯示中增加呼叫
if ( FD_ISSET(tty_fd, &rdset) ) {
char buff_rd[TTY_RD_SZ];
char buff_map[TTY_RD_SZ * M_MAXMAP];
/* read from port */
do {
n = read(tty_fd, &buff_rd, sizeof(buff_rd));
} while (n < 0 && errno == EINTR);
if (n == 0) {
fatal("read zero bytes from port");
} else if ( n < 0 ) {
if ( errno != EAGAIN && errno != EWOULDBLOCK )
fatal("read from port failed: %s", strerror(errno));
} else {
print_lead_str(); //<--- 輸出時間戳
int i;
char *bmp = &buff_map[0];
if ( opts.log_filename )
if ( writen_ni(log_fd, buff_rd, n) < n )
fatal("write to logfile failed: %s", strerror(errno));
for (i = 0; i < n; i++) {
bmp += do_map(bmp, opts.imap, buff_rd[i]);
}
n = bmp - buff_map;
if ( writen_ni(STO, buff_map, n) < n )
fatal("write to stdout failed: %s", strerror(errno));
}
}
詳細的程式碼改動可以參考
https://github.com/IOsetting/picocom
除了增加了 -N 引數顯示時間戳功能, 還修改了預設的通訊波特率, 將 9600 改為 115200, 因為現在基本上都是 115200 了. 執行make
編譯後可以直接使用.
在通訊過程中通過 Ctrl+A Ctrl+N 依次切換不同顯示格式, 也可以在啟動時直接指定, 例如
./picocom --imap nrmhex,8bithex /dev/ttyUSB0 -N3