0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

linux下串口的應(yīng)用開發(fā)

CHANBAEK ? 來源:小陳學(xué)不停 ? 作者:小陳學(xué)不停 ? 2023-01-12 16:42 ? 次閱讀

1 背景
BB-BLACK是16年買的一塊開發(fā)板,時(shí)隔5年,板子上面卻看不到一絲歲月的痕跡,這兩天研究一下linux下串口的應(yīng)用開發(fā)。

2 所使用的鏡像文件以及rootfs

名稱 描述
U-引導(dǎo) bb-black-debian-u-boot.tar.bz2
內(nèi)核 bb-black-debian-kernel-3.8.tar.bz2
根FS prebuild-BBB-Exp-V2-eMMC-flasher-20140626.tar.gz/build/systems/Debian/rootfs.tar.gz

3 硬件連接
選擇串口4

圖片

4 cape的使用
BB-BLACK的一些引腳功能,外設(shè)接口設(shè)備都可以通過cape來管理,我們要使用串口4設(shè)備,那就需要向這個(gè)cape中插入串口4設(shè)備
4.1 添加環(huán)境變量

export SLOTS=/sys/devices/bone_capemgr.9/slots

4.2 查看當(dāng)前設(shè)備

cat $SLOTS 
 0: 54:PF--- 
 1: 55:PF--- 
 2: 56:PF--- 
 3: 57:PF--- 
 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
 5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI

4.3 向cape中添加串口4設(shè)備

echo BB-UART4 > $SLOTS

4.4 檢查是否添加成功

ls ttyO*
ttyO0  ttyO4

4.5 設(shè)置波特率

stty -F /dev/ttyO4 115200

4.6 簡單測試收發(fā)

echo "test" > /dev/ttyO4
cat /dev/ttyO4

5 安裝輔助工具
基本的收發(fā)測試正常后就可以進(jìn)行應(yīng)用開發(fā)了,我們需要安裝一些工具來提高效率
5.1 掛載nfs文件系統(tǒng)
5.1.1 ubuntu下安裝nfs

sudo apt-get install nfs-kernel-server
sudo apt-get install nfs-common

5.1.2 設(shè)置路徑

/home/samba *(rw,sync,no_root_squash)

5.1.3 測試掛載

mount -t nfs 192.168.0.193:/home/samba /mnt -o nolock

如果報(bào)錯(cuò)提示報(bào)錯(cuò)可能是路徑不對(duì)、目錄權(quán)限問題

mount.nfs: access denied by server while mounting
192.168.0.193:/home/samba

5.2 安裝samba實(shí)現(xiàn)windows和ubuntu之間的文件共享
5.2.1 安裝samba

sudo apt install samba samba-common -y

5.2.2 配置samba

sudo mkdir /home/samba
sudo vim /etc/samba/smb.conf
[samba]
    comment=samba
    path = /home/samba
    public = yes
    writable = yes
    create mask = 0777
    directory mask = 0777

5.2.3 開機(jī)啟動(dòng)samba

systemctl enable smbd

5.2.4 啟動(dòng)samba

samba systemctl start smbd

5.3 安裝出錯(cuò)時(shí)可能需要重新配置一下dpkg

sudo dpkg --configure -a
sudo apt update

6 應(yīng)用測試
6.1 相關(guān)代碼
6.1.1 串口的配置、打開、關(guān)閉、讀寫接口

int uart_open(int fd,char*port)
{    
    fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);    
    if (fd<0)    
    {    
        perror("Can't Open Serial Port");    
        return(RES_UART_FALSE);    
    }    
    //恢復(fù)串口為阻塞狀態(tài)                                   
    if(fcntl(fd, F_SETFL, 0) < 0)    
    {    
        printf("fcntl failed!\\n");    
        return(RES_UART_FALSE);    
    }         
    else    
    {    
        printf("fcntl=%d\\n",fcntl(fd, F_SETFL,0));    
    }    
    return fd;    
}    



void uart_close(int fd)    
{    
    close(fd);    
}    


int uart_config(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)    
{    

    int   i;    
    int   status;    
    int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};    
    int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};    

    struct termios options;    

    int res = tcgetattr( fd,&options);
    if( res  !=  0)    
    {    
        perror("SetupSerial 1");  
        return(RES_UART_FALSE);     
    }    

    //設(shè)置串口輸入波特率和輸出波特率    
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)    
    {    
        if  (speed == name_arr[i])    
        {                 
            cfsetispeed(&options, speed_arr[i]);     
            cfsetospeed(&options, speed_arr[i]);      
        }    
    }         

    //修改控制模式,保證程序不會(huì)占用串口    
    options.c_cflag |= CLOCAL;    
    //修改控制模式,使得能夠從串口中讀取輸入數(shù)據(jù)    
    options.c_cflag |= CREAD;    

    //設(shè)置數(shù)據(jù)流控制    
    switch(flow_ctrl)    
    {    

        case 0 ://不使用流控制    
              options.c_cflag &= ~CRTSCTS;    
              break;       

        case 1 ://使用硬件流控制    
              options.c_cflag |= CRTSCTS;    
              break;    
        case 2 ://使用軟件流控制    
              options.c_cflag |= IXON | IXOFF | IXANY;    
              break;    
    }    
    //設(shè)置數(shù)據(jù)位    
    //屏蔽其他標(biāo)志位    
    options.c_cflag &= ~CSIZE;    
    switch (databits)    
    {      
        case 5    :    
                     options.c_cflag |= CS5;    
                     break;    
        case 6    :    
                     options.c_cflag |= CS6;    
                     break;    
        case 7    :        
                 options.c_cflag |= CS7;    
                 break;    
        case 8:        
                 options.c_cflag |= CS8;    
                 break;      
        default:       
                 fprintf(stderr,"Unsupported data size\\n");    
                 return (RES_UART_FALSE);     
    }    
    //設(shè)置校驗(yàn)位    
    switch (parity)    
    {      
        case 'n':    
        case 'N': //無奇偶校驗(yàn)位。
                 options.c_cflag &= ~PARENB;     
                 options.c_iflag &= ~INPCK;        
                 break;     
        case 'o':      
        case 'O'://設(shè)置為奇校驗(yàn)        
                 options.c_cflag |= (PARODD | PARENB);     
                 options.c_iflag |= INPCK;                 
                 break;     
        case 'e':     
        case 'E'://設(shè)置為偶校驗(yàn)      
                 options.c_cflag |= PARENB;           
                 options.c_cflag &= ~PARODD;           
                 options.c_iflag |= INPCK;          
                 break;    
        case 's':    
        case 'S': //設(shè)置為空格     
                 options.c_cflag &= ~PARENB;    
                 options.c_cflag &= ~CSTOPB;    
                 break;     
        default:      
                 fprintf(stderr,"Unsupported parity\\n");        
                 return (RES_UART_FALSE);     
    }     
    // 設(shè)置停止位     
    switch (stopbits)    
    {      
        case 1:       
                 options.c_cflag &= ~CSTOPB; break;     
        case 2:       
                 options.c_cflag |= CSTOPB; break;    
        default:       
                       fprintf(stderr,"Unsupported stop bits\\n");     
                       return (RES_UART_FALSE);    
    }    

    //修改輸出模式,原始數(shù)據(jù)輸出    
    options.c_oflag &= ~OPOST;    

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);    
    //options.c_lflag &= ~(ISIG | ICANON);    

    //設(shè)置等待時(shí)間和最小接收字符    
    options.c_cc[VTIME] = 1; /* 讀取一個(gè)字符等待1*(1/10)s */      
    options.c_cc[VMIN] = 1; /* 讀取字符的最少個(gè)數(shù)為1 */    

    //如果發(fā)生數(shù)據(jù)溢出,接收數(shù)據(jù),但是不再讀取 刷新收到的數(shù)據(jù)但是不讀    
    tcflush(fd,TCIFLUSH);    

    //激活配置 (將修改后的termios數(shù)據(jù)設(shè)置到串口中)    
    if (tcsetattr(fd,TCSANOW,&options) != 0)      
    {    
        perror("com set error!\\n");      
        return (RES_UART_FALSE);     
    }    
    return (RES_UART_TRUE);     
}    











int uart_init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)    
{    
    int err;    
    //設(shè)置串口數(shù)據(jù)幀格式    
    if (uart_config(fd,speed,flow_ctrl,databits,stopbits,parity) == RES_UART_FALSE)    
    {                                                             
        return RES_UART_FALSE;    
    }    
    else    
    {    
        return  RES_UART_TRUE;    
    }    
}    

int uart_read(int fd, char *rcv_buf,int data_len)    
{    
    int len,fs_sel;    
    fd_set fs_read;    

    struct timeval time;    

    FD_ZERO(&fs_read);    
    FD_SET(fd,&fs_read);    

    time.tv_sec = 10;    
    time.tv_usec = 0;    

    //使用select實(shí)現(xiàn)串口的多路通信    
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);    
    //printf("fs_sel = %d\\n",fs_sel);    
    if(fs_sel)    
    {    
        len = read(fd,rcv_buf,data_len);    
        return len;    
    }    
    else    
    {    
        return RES_UART_FALSE;    
    }         
}    


int uart_write(int fd, char *send_buf,int data_len)    
{    
    int len = 0;    

    len = write(fd,send_buf,data_len);    
    if (len == data_len )    
    {    
        printf("send data is %s\\n",send_buf);  
        return len;    
    }         
    else       
    {    

        tcflush(fd,TCOFLUSH);    
        return RES_UART_FALSE;    
    }    

}

6.1.2 測試代碼

#include "stdint.h"


#include "app_usart.h"
#include "app_config.h"
#include "rtservice.h"


#include "ful_communication.h"


#include      /*標(biāo)準(zhǔn)輸入輸出定義*/    
#include     /*標(biāo)準(zhǔn)函數(shù)庫定義*/    
#include     /*Unix 標(biāo)準(zhǔn)函數(shù)定義*/    
#include     
#include       
#include      /*文件控制定義*/    
#include    /*PPSIX 終端控制定義*/    
#include      /*錯(cuò)誤號(hào)定義*/    
#include


#define SLOTS   "/sys/devices/bone_capemgr.9/slots"
#define CONFIG_SLOTS_UART_DEV "ADAFRUIT-UART4"
static int8_t s_read_firmware_version(uint32_t length, uint8_t *);
static int8_t s_config_baudrate(uint32_t length, uint8_t *);
extern void g_ful_com_detect_command(uint8_t checkData);
extern int8_t callback_register(action_t *obj);


int fd = -1;           //文件描述符,先定義一個(gè)與程序無關(guān)的值,防止fd為任意值導(dǎo)致程序出bug    


static action_t action_list[] =
{
    {CMD_READ_FW_VERSION,s_read_firmware_version},
    {CMD_CONFIG_BAUDRATE,s_config_baudrate},
};

static int8_t s_read_firmware_version(uint32_t length, uint8_t *pbuf)
{
    if(NULL == pbuf)
    {
        return -1;
    }


  printf("s_read_firmware_version length: [%d]\\n",length);
  printf("pbuf[0]=[%02x]\\n",pbuf[0]);


    if (3 == length)
    {
        uint8_t response_version[60]={0};


        sprintf(response_version,"%s_%s %s %s\\n",CONFIG_PRODUCT_NAME,CONFIG_FIRMWARE_VERSION,__DATE__,__TIME__);


        return uart_write(fd,response_version,strlen(response_version));
    }


    return 0;
}


static int8_t s_config_baudrate(uint32_t length, uint8_t *pbuf)
{
    if(NULL == pbuf)
    {
        return -1;
    }


    //if (3 == length)
    {
        uint32_t get_baudrate = (pbuf[1]<<24) | (pbuf[2]<<16) | (pbuf[3]<<8) | (pbuf[4]);


    printf("config baudrate to [%d]\\n",get_baudrate);

        int err = uart_init(fd,get_baudrate,0,8,1,'N');

    }


    return 0;
}




int main(int argc, char **argv)    
{
    int err;               //返回調(diào)用函數(shù)的狀態(tài)    
    int len;                            
    int i;    
    char rcv_buf[256];           

    if(argc != 2)    
    {    
        printf("Usage: %s /dev/ttySn      #1(receive data)\\n",argv[0]);
        printf("open failure : %s\\n", strerror(errno));

        return RES_UART_FALSE;    
    }  


    uint8_t action_index = 0;


    for (action_index=0;action_index<LENGTH_OF_ARRAY(action_list);action_index++)
    {
        callback_register(&action_list[action_index]);
    }

  int fd_drv_uart,count=0;

  //mount the Drive of Uart
  if ((fd_drv_uart = open(SLOTS, O_WRONLY)) < 0) 
  { 
    perror("SLOTS: Failed to open the file. \\n"); 
    return -1; 
  }

  printf("fd_drv_uart=%d\\n",fd_drv_uart); 

  if ((count = write(fd_drv_uart, CONFIG_SLOTS_UART_DEV,strlen(CONFIG_SLOTS_UART_DEV)))<0) 
  {
    perror("SLOTS:Failed to write to the file\\nFailed to mount the UART"); 
    //return -1; 
  }
    close(fd_drv_uart);

    fd = uart_open(fd,argv[1]); //打開串口,返回文件描述符    

    do  
    {    
        printf("uart_init fd=%d\\n",fd); 

        err = uart_init(fd,115200,0,8,1,'N');

    if (err>=0)
        {
            break;
        }
        printf("err=%d\\n",err); 

    uart_close(fd);     

    fd = uart_open(fd,argv[1]);
    }while(RES_UART_FALSE == err || RES_UART_FALSE == fd); 

    while (1) 
    {   
        len = uart_read(fd, rcv_buf,sizeof(rcv_buf));  
        if(len > 0)    
        {    
            int idx = 0;

            printf("receive data len=%d\\n",len);  

            for (idx=0; idxuint8_t ch = rcv_buf[idx];
                printf("%02x ",ch);  
        g_ful_com_detect_command(ch);
            }

            printf("\\n");  
        }    

        usleep(10000);   
    }         

    uart_close(fd);     
    close(fd_drv_uart);
}

6.1.3 生成文件

CFILE = $(wildcard  *.c)
  CFILE += $(wildcard functions/*.c)
  CFILE += $(wildcard app/*.c)
  DIRSRC += -I functions/include
  DIRSRC += -I app/include
all:
  @gcc $(CFILE) $(DIRSRC) -o u_app
#gcc *.c  -o  usart


.PHONY:clean
clean:  
  @-rm u_app

6.1.4 目錄結(jié)構(gòu)

app
--include
--app_test.c
--app_uart.c
functions
--include
--fun_communication.c
Makefile
u_app

6.3 串口應(yīng)用的開機(jī)自啟動(dòng)
開機(jī)自啟動(dòng),運(yùn)行在后臺(tái),u_app需要添加可執(zhí)行權(quán)限

cp u_app /usr/my_app
vim /etc/rc.local
./usr/my_app/u_app /dev/ttyO4 &   
exit 0

6.4 測試
可正常解析指令,返回結(jié)果

圖片

7 總結(jié)
用虛擬機(jī)來跑ubuntu總是不太穩(wěn)定,如果不能進(jìn)入桌面系統(tǒng)也不能進(jìn)入tty控制臺(tái)基本上就要重裝了,還是得找個(gè)穩(wěn)定的ubuntu鏡像才行呀。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11304

    瀏覽量

    209497
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1554

    瀏覽量

    76516
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5050

    瀏覽量

    97471
  • 應(yīng)用開發(fā)
    +關(guān)注

    關(guān)注

    0

    文章

    58

    瀏覽量

    9361
  • BB-Black
    +關(guān)注

    關(guān)注

    1

    文章

    15

    瀏覽量

    13201
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    基于Linux環(huán)境串口通信的應(yīng)用設(shè)計(jì)

    本文介紹了Linux環(huán)境串口通信的設(shè)計(jì)方法和步驟,并介紹了ARM9微處理器s3c2440在Linux和C8051Fxxx系列單片機(jī)進(jìn)行串
    發(fā)表于 05-24 10:50 ?2843次閱讀

    【教程】Linux串口與工業(yè)協(xié)議開發(fā) - 2

    Linux串口與工業(yè)協(xié)議開發(fā)2,視頻教程回復(fù)帖子查看資料下載鏈接:[hide][/hide]
    發(fā)表于 08-18 10:44

    【教程】Linux串口與工業(yè)協(xié)議開發(fā) - 3

    Linux串口與工業(yè)協(xié)議開發(fā)3,視頻教程回復(fù)帖子查看資料下載鏈接:[hide][/hide]
    發(fā)表于 08-18 10:46

    【教程】Linux串口與工業(yè)協(xié)議開發(fā) - 4

    Linux串口與工業(yè)協(xié)議開發(fā)4,視頻教程回復(fù)帖子查看資料下載鏈接:[hide][/hide]
    發(fā)表于 08-18 10:49

    【教程】Linux串口與工業(yè)協(xié)議開發(fā) - 6

    Linux串口與工業(yè)協(xié)議開發(fā)6,視頻教程回復(fù)帖子查看資料下載鏈接:[hide][/hide]
    發(fā)表于 08-18 10:51

    Linux可用的串口助手在linux使用串口終端

    ?。?!如果使用的是虛擬機(jī),確保串口設(shè)備掛載到虛擬機(jī)里!?。?.Linux可用的串口助手在linux
    發(fā)表于 11-05 08:48

    Linux串口編程下載

    linux 中的串口設(shè)備文件存放于/dev 目錄下,其中串口一,串口二對(duì)應(yīng)設(shè)備名依次為/dev/ttyS0、/dev/ttyS1。在linux
    發(fā)表于 11-15 17:39 ?108次下載

    LinuxARM和單片機(jī)的串口通信設(shè)計(jì)

    介紹Linux 環(huán)境串口通信的設(shè)計(jì)方法和步驟,并介紹了ARM9 微處理器s3c2440 在Linux 和C8051Fxxx 系列單片機(jī)進(jìn)
    發(fā)表于 09-29 10:06 ?2015次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>下</b>ARM和單片機(jī)的<b class='flag-5'>串口</b>通信設(shè)計(jì)

    Linux串口編程入門

    嵌入式開發(fā)學(xué)習(xí),關(guān)于Linux串口編程入門,感興趣的小伙伴可以瞧一瞧。
    發(fā)表于 11-03 15:15 ?0次下載

    串口編程參考資料 linux環(huán)境

    串口編程參考資料 linux環(huán)境
    發(fā)表于 10-24 14:39 ?8次下載
    <b class='flag-5'>串口</b>編程參考資料 <b class='flag-5'>linux</b>環(huán)境<b class='flag-5'>下</b>的

    基于WinCE_NET串口驅(qū)動(dòng)開發(fā)設(shè)計(jì)

    基于WinCE_NET串口驅(qū)動(dòng)開發(fā)設(shè)計(jì)
    發(fā)表于 10-25 09:54 ?3次下載
    基于WinCE_NET<b class='flag-5'>下</b><b class='flag-5'>串口</b>驅(qū)動(dòng)<b class='flag-5'>開發(fā)</b>設(shè)計(jì)

    基于嵌入式linux系統(tǒng)串口編程具體設(shè)置詳解

    本文基于嵌入式linux串口應(yīng)用編程進(jìn)行了研究,詳細(xì)介紹了串口設(shè)置的步驟,可以更好的理解串口的工作原理。
    發(fā)表于 09-17 17:10 ?6995次閱讀

    嵌入式linux串口編程

    嵌入式開發(fā)——Linux串口編程筆記
    發(fā)表于 11-02 10:21 ?14次下載
    嵌入式<b class='flag-5'>linux</b><b class='flag-5'>串口</b>編程

    【嵌入式Linux(環(huán)境篇)】Linux串口助手 —— minicom或putty

    ?。?!如果使用的是虛擬機(jī),確保串口設(shè)備掛載到虛擬機(jī)里!??!1.Linux可用的串口助手在linux
    發(fā)表于 11-02 12:50 ?10次下載
    【嵌入式<b class='flag-5'>Linux</b>(環(huán)境篇)】<b class='flag-5'>Linux</b><b class='flag-5'>下</b>的<b class='flag-5'>串口</b>助手 —— minicom或putty

    Linux開發(fā)板通過串口和PC文件傳輸

    Linux開發(fā)板通過串口和PC文件傳輸
    發(fā)表于 10-28 10:59 ?0次下載