Rockchip UART (Universal Asynchronous Receiver/Transmitter) 基于16550A串口标准。内核里面使用8250串口通用驱动,因此能够支持Linux下的标准串口编程。
板上引出四组通用串口,还有一路调试串口,建议不要把调试串口用于其他用途。
这四组通用串口的序号分别是1、6、7、9,在Linux下对应的设备节点分别是/dev/ttyS1 /dev/ttyS6 /dev/ttyS7 /dev/ttyS9.下面以ttyS9为例介绍其用法,其他几路串口也是类似的。
下面通过在硬件上短接ttyS9的TX 和RX,来进行收发测试,接线如下
"/dev/ttyS*"的节点都需要system或者root权限才能操作,使用命令行或者android studio编译出来的程序操作串口都需要system权限。如果是使用adb命令行的,先执行如下命令获取system权限。
su system
查看串口信息
busybox stty -F /dev/ttyS9
设置串口波特率为115200
busybox stty -F /dev/ttyS9 speed 115200
设置串口八位数据位 无校验 一位停止位 无回显
busybox stty -F /dev/ttyS9 cs8 -parenb -cstopb -echo
将串口的TXRX短接,然后进行收发测试
后台接收数据,前台执行发送
cat /dev/ttyS9 &
echo -e "12345\n" > /dev/ttyS9
执行结果如下,可以看到接收到的数据即为发送的
android 编程时可以使用C语言操作串口,然后封装一个jni接口,由java来调用。C语言实现如下
int speed_arr[] = {
B921600, B460800, B230400, B115200, B57600, B38400, B19200,
B9600, B4800, B2400, B1200, B300,
};
int name_arr[] = {
921600, 460800, 230400, 115200, 57600, 38400, 19200,
9600, 4800, 2400, 1200, 300,
};
int user_uart_open(int uart_num)
{
int fd = -1;
char str[40] = {0};
snprintf(str, sizeof(str) - 1, "/dev/ttyS%d", uart_num);
if (access(str, F_OK) != 0) {
printf("%s do not exist \n", str);
return -1;
}
fd = open(str, O_RDWR | O_NONBLOCK);
if (fd < 0) {
printf("open %s fail \n", str);
return -1;
}
return fd;
}
int user_uart_set_property(int fd, int speed, int databits, int stopbits, int parity)
{
struct termios options;
if (tcgetattr(fd, &options) != 0) {
return -1;
}
tcflush(fd, TCIOFLUSH);
for (unsigned char 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 &= ~CSIZE;
switch (databits) /*设置数据位数*/ {
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
return -1;
}
switch (parity) {
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
return -1;
}
/* 设置停止位*/
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
return -1;
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
options.c_cc[VTIME] = 150; // 15 seconds
options.c_cc[VMIN] = 1;
options.c_iflag |= ICRNL; // cr -> nl
options.c_lflag &= ~(ECHO | ICANON);
tcflush(fd, TCIOFLUSH); /* Update the options and do it NOW */
if (tcsetattr(fd, TCSANOW, &options) != 0) {
return -1;
}
return 0;
}
这里封装了user_uart_open用于打开指定编号的串口,user_uart_set_property用于设置串口属性,剩下的读写和关闭使用Linux原始的read write和close即可
JNI接口代码如下,这里返回是一个字符串,保存了执行的结果
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_testdemo_MainActivity_UARTTest(JNIEnv *env, jobject /* this */)
{
int ret = 0;
int fd = -1;
unsigned char buf_write[5] = {0};
unsigned char buf_read[5] = {0};
memset(test_result,0,sizeof(test_result));
for (unsigned char i = 0; i < sizeof(buf_write); i++) {
buf_write[i] = 0x30 + i;
}
fd = user_uart_open(9);
if (fd < 0) {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "uart_open fail \n");
goto out1;
}
ret = user_uart_set_property(fd, 115200, 8, 1, 'n');
if (ret < 0) {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "uart set_property fail \n");
goto out;
}
ret = write(fd, buf_write, sizeof(buf_write));
if (ret <= 0) {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "uart write fail \n");
goto out;
}
fsync(fd);
usleep(200 * 1000);
ret = read(fd, buf_read, sizeof(buf_read));
if (ret <= 0) {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "uart read fail \n");
goto out;
}
if (memcmp(buf_write, buf_read, sizeof(buf_write)) == 0) {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "buf_write buf_read same\n");
} else {
snprintf(reinterpret_cast<char *const>(test_result), sizeof(test_result) - 1, "buf_write buf_read diff %d %d %d %d %d \n",
buf_read[0], buf_read[1], buf_read[2], buf_read[3], buf_read[4]);
}
out:
close(fd);
out1:
LOGE("%s",test_result);
return env->NewStringUTF(reinterpret_cast<const char *>(test_result));
}
在上一章节创建的app基础上,增加一个按钮和一个文本框,按下按钮则执行此测试程序
在MainActivity的onCreate增加
button1.setText("uart test");
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textDisplay.setText(" start uart test... \n");
new Thread(new Runnable() {
@Override
public void run() {
final String uart_test_result = UARTTest();
runOnUiThread(new Runnable() {
@Override
public void run() {
textDisplay.append("uarttest: " + uart_test_result + "\n");
}
});
}
}).start();
}
});
同时声明上面定义的JNI接口
public native String UARTTest();
测试时按下 uart test 的按钮可以看到如下效果