一、前言
使用beagle bone的串口功能
二、步骤
1、查询外设名称
在linux中,外设以文件的形式存在,所以查询要加载的外设的文件地址依次打开外设。beaglebone的外设信息存放在 /lib/firmware 下,所以输入 ls /lib/firmware | grep UART 即可查询可加载的串口外设。本文使用UART1,所以文件地址是 /lib/firmware/BB-UART1-00A0.dtbo
2、加载外设(两种方法)
(1)、预加载
beaglebone开机的时候会按照 /boot/uEnv.txt 里面的内容加载外设,因此修改该文件就可以让beaglebone开机的时候自动加载串口,输入 sudo vim /boot/uEnv.txt,并在文件里添加
uboot_overlay_addr0=/lib/firmware/BB-UART1-00A0.dtbo保存退出重启beaglebone即可。
这里的 addr0 根据实际顺序进行修改。
(2)、即时加载
该加载方式需要beaglebone每次开机重新加载。
3、测试
将串口IO通过CH340与电脑连接,打开串口后
输入 echo “hello” > /dev/ttyS1 进行测试。
4、C语言使用串口
(1)、头文件:BBB_serial.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <error.h>
#include <termios.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
typedef struct serial_data {
char rxbuff[32];//发送/接受数据
char txbuff[32];//发送/接受数据
int serfd;//串口文件描述符
}ser_Data;
//端口地址 串口句柄号 波特率 B9600 B115200
unsigned char serial_init(const char* port, int baudrate, ser_Data* serial);//读写模式打开串口
/********************线程接收串口数据示例************************/
void* sersend(void* arg);//串口发送线程函数
void* serrecv(void* arg);//串口发送线程函数
(2)、源文件:BBB_serial.cpp
#include <BBB_serial.h>
//该函数以读写模式打开串口
unsigned char serial_init(const char* port, int baudrate, ser_Data* serial)
{
//读写方式打开串口文件
serial->serfd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);//修改第二个参数改变打开方式
//判断是否打开成功
if (serial->serfd < 0) { printf("%s open faild\r\n", port);return -1;}
else { printf("%s open success\r\n", port); }
//串口参数设置
termios* ter_s = (termios*)malloc(sizeof(*ter_s));//初始化串口参数结构体
bzero(ter_s, sizeof(*ter_s));//初始化结构体,全部置零
ter_s->c_cflag |= CLOCAL | CREAD; //激活本地连接与接受使能
ter_s->c_cflag &= ~CSIZE;//失能数据位屏蔽
ter_s->c_cflag |= CS8;//8位数据位
ter_s->c_cflag &= ~CSTOPB;//1位停止位
ter_s->c_cflag &= ~PARENB;//无校验位
ter_s->c_cc[VTIME] = 10;
ter_s->c_cc[VMIN] = 32;//读取32个
/*1 VMIN> 0 && VTIME> 0
VMIN为最少读取的字符数,当读取到一个字符后,会启动一个定时器,在定时器超时事前,
如果已经读取到了VMIN个字符,则read返回VMIN个字符。如果在接收到VMIN个字符之前,
定时器已经超时,则read返回已读取到的字符,注意这个定时器会在每次读取到一个字符后
重新启用,即重新开始计时,而且是读取到第一个字节后才启用,也就是说超时的情况下,
至少读取到一个字节数据。
2 VMIN > 0 && VTIME== 0
在只有读取到VMIN个字符时,read才返回,可能造成read被永久阻塞。
3 VMIN == 0 && VTIME> 0
和第一种情况稍有不同,在接收到一个字节时或者定时器超时时,read返回。如果是超时这种情况,read返回值是0。
4 VMIN == 0 && VTIME== 0
这种情况下read总是立即就返回,即不会被阻塞。----by 解释粘贴自博客园
*/
cfsetispeed(ter_s, baudrate);//设置输入波特率
cfsetospeed(ter_s, baudrate);//设置输出波特率
tcflush(serial->serfd, TCIFLUSH);//刷清未处理的输入和/或输出
if (tcsetattr(serial->serfd, TCSANOW, ter_s) != 0) {printf("com set error!\r\n");}
free(ter_s);//释放内存
return 0;
}
void* sersend(void* arg)//串口发送线程函数
{
ser_Data* serial = (ser_Data*) arg;
while (1)
{
write(serial->serfd, "send\n", 5);
sleep(1);
}
return NULL;
}
void* serrecv(void* arg)//串口接收线程函数
{
ser_Data* serial = (ser_Data*)arg;
int datanumber;
while (1)
{
datanumber = read(serial->serfd, serial->rxbuff, 32);
if (datanumber > 0)
{
printf("%d\n", datanumber);
}
}
return NULL;
}
(3)主函数: main
#include <stdio.h>
#include <BBB_serial.h>
ser_Data serial = { 0 };//串口结构体
int main(void)
{
unsigned char res = 0;
res = serial_init("/dev/ttyS1", B9600, &serial);//打开串口
if (res) return 0;
pthread_t pid1, pid2;
pthread_attr_t* pthread_arr1, * pthread_arr2;
pthread_arr1 = NULL; pthread_arr2 = NULL;
pthread_create(&pid1, pthread_arr1, serrecv, (void*)(&serial));//接收任务
pthread_create(&pid2, pthread_arr2, sersend, (void*)(&serial));//发送任务
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
while (1)
{
}
return 0;
}