1 背景
BB-BLACK是16年買的一塊開發板,時隔5年,板子上面卻看不到一絲歲月的痕跡,這兩天研究一下linux下串口的應用開發。
2 所使用的鏡像文件以及rootfs
名稱 | 描述 |
---|---|
U-引導 | bb-black-debian-u-boot.tar.bz2 |
內核 | 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的一些引腳功能,外設接口設備都可以通過cape來管理,我們要使用串口4設備,那就需要向這個cape中插入串口4設備
4.1 添加環境變量
export SLOTS=/sys/devices/bone_capemgr.9/slots
4.2 查看當前設備
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設備
echo BB-UART4 > $SLOTS
4.4 檢查是否添加成功
ls ttyO*
ttyO0 ttyO4
4.5 設置波特率
stty -F /dev/ttyO4 115200
4.6 簡單測試收發
echo "test" > /dev/ttyO4
cat /dev/ttyO4
5 安裝輔助工具
基本的收發測試正常后就可以進行應用開發了,我們需要安裝一些工具來提高效率
5.1 掛載nfs文件系統
5.1.1 ubuntu下安裝nfs
sudo apt-get install nfs-kernel-server
sudo apt-get install nfs-common
5.1.2 設置路徑
/home/samba *(rw,sync,no_root_squash)
5.1.3 測試掛載
mount -t nfs 192.168.0.193:/home/samba /mnt -o nolock
如果報錯提示報錯可能是路徑不對、目錄權限問題
mount.nfs: access denied by server while mounting
192.168.0.193:/home/samba
5.2 安裝samba實現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 開機啟動samba
systemctl enable smbd
5.2.4 啟動samba
samba systemctl start smbd
5.3 安裝出錯時可能需要重新配置一下dpkg
sudo dpkg --configure -a
sudo apt update
6 應用測試
6.1 相關代碼
6.1.1 串口的配置、打開、關閉、讀寫接口
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);
}
//恢復串口為阻塞狀態
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);
}
//設置串口輸入波特率和輸出波特率
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]);
}
}
//修改控制模式,保證程序不會占用串口
options.c_cflag |= CLOCAL;
//修改控制模式,使得能夠從串口中讀取輸入數據
options.c_cflag |= CREAD;
//設置數據流控制
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;
}
//設置數據位
//屏蔽其他標志位
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);
}
//設置校驗位
switch (parity)
{
case 'n':
case 'N': //無奇偶校驗位。
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o':
case 'O'://設置為奇校驗
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E'://設置為偶校驗
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
case 's':
case 'S': //設置為空格
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr,"Unsupported parity\\n");
return (RES_UART_FALSE);
}
// 設置停止位
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);
}
//修改輸出模式,原始數據輸出
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//options.c_lflag &= ~(ISIG | ICANON);
//設置等待時間和最小接收字符
options.c_cc[VTIME] = 1; /* 讀取一個字符等待1*(1/10)s */
options.c_cc[VMIN] = 1; /* 讀取字符的最少個數為1 */
//如果發生數據溢出,接收數據,但是不再讀取 刷新收到的數據但是不讀
tcflush(fd,TCIFLUSH);
//激活配置 (將修改后的termios數據設置到串口中)
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;
//設置串口數據幀格式
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實現串口的多路通信
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 /*標準輸入輸出定義*/
#include /*標準函數庫定義*/
#include /*Unix 標準函數定義*/
#include
#include
#include /*文件控制定義*/
#include /*PPSIX 終端控制定義*/
#include /*錯誤號定義*/
#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; //文件描述符,先定義一個與程序無關的值,防止fd為任意值導致程序出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; //返回調用函數的狀態
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 目錄結構
app
--include
--app_test.c
--app_uart.c
functions
--include
--fun_communication.c
Makefile
u_app
6.3 串口應用的開機自啟動
開機自啟動,運行在后臺,u_app需要添加可執行權限
cp u_app /usr/my_app
vim /etc/rc.local
./usr/my_app/u_app /dev/ttyO4 &
exit 0
6.4 測試
可正常解析指令,返回結果
7 總結
用虛擬機來跑ubuntu總是不太穩定,如果不能進入桌面系統也不能進入tty控制臺基本上就要重裝了,還是得找個穩定的ubuntu鏡像才行呀。
-
Linux
+關注
關注
87文章
11294瀏覽量
209341 -
串口
+關注
關注
14文章
1551瀏覽量
76431 -
開發板
+關注
關注
25文章
5033瀏覽量
97375 -
應用開發
+關注
關注
0文章
58瀏覽量
9357 -
BB-Black
+關注
關注
1文章
15瀏覽量
13197
發布評論請先 登錄
相關推薦
評論