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镜像才行呀。
全部0条评论
快来发表一下你的评论吧 !