Ubuntu下的串口軟體, 除了 CuteCOM, screen, MiniCOM 以外, 還有一個和 MiniCOM 很像的 PicoCOM. 最近在調試 CH340C 串口的過程中, 發現只有 PicoCOM 的連接Reset才能正常工作, 因此單獨記錄一下. ...
PICOCOM
Ubuntu下的串口軟體, 除了 CuteCOM, screen, MiniCOM 以外, 還有一個和 MiniCOM 很像的 PicoCOM. 最近在調試 CH340C 串口的過程中, 發現只有 PicoCOM 的連接Reset才能正常工作, 因此單獨記錄一下.
- GitHub 倉庫 https://github.com/npat-efault/picocom
- 倉庫的所有者 Nick Patavalis (npat-efault) 在 2018 年之後就未再更新
- 在 Ubuntu22.04 下能編譯通過並正常工作
- GitLab 分支倉庫 https://gitlab.com/wsakernel/picocom
- Wolfram Sang 維護的, 在原倉庫基礎上繼續開發的一個版本
安裝
在 Ubuntu 上直接通過sudo apt install picocom
安裝, 版本是3.1
使用
連接和斷開
使用 115200 波特率連接串口設備 /dev/ttyUSB0
picocom -b115200 /dev/ttyUSB0
斷開有兩種方式
- Ctrl+A, Ctrl+Q 退出, NO RESET
- Ctrl+A, Ctrl+X 退出, RESET
在串口通信時, RTS(Ready To Send)會處於低電平, 當斷開串口時如果RESET, 就會恢復高電平, 預設會進行RESET.
在調試STC單片機的時候, 往往會使用帶自動燒錄的串口轉USB設備連接, 而這種設備的自動燒錄機制, 就是通過拉低RTS觸發MCU斷電重啟. 在使用這種RTS觸發的設備進行燒錄和調試時, 就要靈活使用RESET機制.
- 當進行調試時, 我們不希望每次連接MCU時自動重啟, 因此斷開串口時要避免RESET, 讓RTS一直處於低電平, 斷開連接時使用 Ctrl+A Ctrl+Q 退出, 可以避免RESET
- 當進行燒錄時, 如果RTS還處於低電平, 拉低RTS無效, 導致無法重啟MCU. 所以在燒錄時, 斷開串口要RESET, 讓RTS回到高電平, 使用 Ctrl+A Ctrl+X 退出
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
各參數的說明
- spchex (map special chars (< 0x20 || 0x7f), excl. CR, LF, and TAB to hex)
- tabhex (map TAB to hex)
- crhex (map CR to hex)
- lfhex (map LF to hex)
- 8bithex (map chars with 8th-bit set to hex)
- nrmhex (map normal ascii chars (0x20 <= c < 0x7f) to hex)
二次開發: 增加時間戳
調試串口時經常會用到時間戳, 例如觀察延時是否正確. 雖然這個時間戳並不准確, 但是作為一個粗略的時間標記還是非常方便的. 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