串口的认识
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方
式的扩展接口。串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简
单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成
本,特别适用于远距离通信,但传送速度较慢
-
是设备间接线通信的一种方式
-
数据一位一位地顺序传送
-
双向通信,全双工
-
传送速度相对较慢
UART
异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。
UART包含TTL电平的串口和RS232电平的串口
RS-232
也称标准串口,最常用的一种[串行通讯接口,比如我们的电脑主机的9针串口 ,最高速率为20kb/s
RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其传送距离最大为约15米。所以RS-232适
合本地设备之间的通信
RS232电平
- 逻辑1为-3~-15V的电压, 逻辑0为3~15V的电压
TTL
TTL是Transistor-Transistor Logic,即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备内部各部分之间通信的标准技术。
TTL电平
-
TTL电平信号应用广泛,是因为其数据表示采用二进制规定,
-
+5V等价于逻辑”1”,0V等价于逻辑”0”。
-
数字电路中,由TTL电子元器件组成电路的电平是个电压范围,规定:
- 输出高电平>=2.4V,输出低电平<=0.4V;
- 输入高电平>=2.0V,输入低电平<=0.8V
笔记本电脑通过TTL电平与单片机通信 :USB转TTL,使用ch340芯片
香橙派有三个串口驱动设备文件
-
三个引脚的为s0,是串口调试信息的接口
-
两排引脚的为s5,是串口通信的接口
-
香橙派没有s1
wiringPi示例代码
在 examples/serialTest.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main ()
{
int fd ;
int count ;
unsigned int nextTime ;
//serialOpen是对open函数的封装
//该函数主要设置结构体struct termios,也就是设备参数初始化,将结构体的参数配置完毕通过函数发送给内核,进而配置硬件的寄存器
if ((fd = serialOpen ("/dev/ttyS2", 115200)) < 0)
{
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiSetup () == -1)
{
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
nextTime = millis () + 300 ;
for (count = 0 ; count < 256 ; )
{
if (millis () > nextTime)
{
printf ("\nOut: %3d: ", count) ;
fflush (stdout) ;
serialPutchar (fd, count) ;
nextTime += 300 ;
++count ;
}
delay (3) ;
while (serialDataAvail (fd))
{
printf (" -> %3d", serialGetchar (fd)) ;
fflush (stdout) ;
}
}
printf ("\n") ;
return 0 ;
}
-
WiringPi库是也是基于LinuxC库的,分析串口源码可以下载C库一起分析
-
C库、内核与应用层的关系图如下:
基于wiringPi的串口开发
串口通信是全双工的,可以创建两个线程
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
int fd; //打开串口的描述符
void* Sendhandler()
{
char *sendBuf;
sendBuf = (char *)malloc(32*sizeof(32));
while(1){
memset(sendBuf,'\0',32);
scanf("%s",sendBuf);
//如果不是\0就一直发送
while(*sendBuf){
serialPutchar (fd, *sendBuf++) ;
}
}
}
void* Revhandler()
{
while(1){
//检测串口通道是否有数据
while (serialDataAvail(fd)) {
printf ("%c", serialGetchar(fd)) ;
fflush (stdout) ;
}
}
}
int main ()
{
int count ;
unsigned int nextTime ;
pthread_t idSend;
pthread_t idRev;
if ((fd = serialOpen ("/dev/ttyS5", 115200)) < 0) {
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
pthread_create(&idSend, NULL,Sendhandler,NULL);
pthread_create(&idRev, NULL,Revhandler,NULL);
if (wiringPiSetup () == -1) {
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
while(1){sleep(10);}
printf ("\n") ;
return 0 ;
}
自己实现串口通信
完成功能:
- 通过自己封装的open,write,read函数来完成串口的通信
实现流程:
- 首先要打开文件,得到文件的句柄,在封装的open函数中将termios结构体和status控制字发送给内核,完成硬件的初始化,传输和读取数据就是对句柄进行读写操作
uartTool.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "wiringSerial.h"
int myserialOpen (const char *device, const int baud)
{
struct termios options ;
speed_t myBaud ;
int status, fd ;
switch (baud){
case 9600: myBaud = B9600 ; break ;
case 115200: myBaud = B115200 ; break ;
}
if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
return -1 ;
fcntl (fd, F_SETFL, O_RDWR) ;
// Get and modify current options:
tcgetattr (fd, &options) ; //
cfmakeraw (&options) ;
cfsetispeed (&options, myBaud) ; //设置波特率
cfsetospeed (&options, myBaud) ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~PARENB ; //无校验位
options.c_cflag &= ~CSTOPB ; //1位停止位
options.c_cflag &= ~CSIZE ; //用数据位掩码清空数据位设置
options.c_cflag |= CS8 ; //数据位为8
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
tcsetattr (fd, TCSANOW, &options) ; //
ioctl (fd, TIOCMGET, &status); //status是控制字
status |= TIOCM_DTR ;
status |= TIOCM_RTS ;
ioctl (fd, TIOCMSET, &status);
usleep (10000) ; // 10mS
return fd ;
}
void serialSendstring (const int fd, const char *s)
{
int ret;
ret = write (fd, s, strlen (s));
if (ret < 0)
printf("Serial Sendstring Error\n");
}
int serialGetstring (const int fd, char *buffer)
{
int n_read;
n_read = read(fd, buffer,32);
return n_read;
}
uartTool.h
int myserialOpen (const char *device, const int baud) ;
void serialSendstring (const int fd, const char *s) ;
int serialGetstring (const int fd, char *buffer) ;
uartTest.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include "uartTool.h"
int fd;
void* readSerial()
{
char buffer[32];
while(1){
memset(buffer,'\0',sizeof(buffer));
serialGetstring(fd, buffer);
printf("GET->%s\n",buffer);
}
}
void* sendSerial()
{
char buffer[32];
while(1){
memset(buffer,'\0',sizeof(buffer));
scanf("%s",buffer);
serialSendstring(fd, buffer);
}
}
int main(int argc, char **argv)
{
char deviceName[32] = {'\0'};
pthread_t readt;
pthread_t sendt;
if(argc < 2){
printf("uage:%s /dev/ttyS?\n",argv[0]);
return -1;
}
strcpy(deviceName, argv[1]);
if( (fd = myserialOpen(deviceName, 115200)) == -1){
printf("open %s error\n",deviceName);
return -1;
}
pthread_create(&readt, NULL, readSerial,NULL);
pthread_create(&sendt, NULL, sendSerial,NULL);
while(1){sleep(10);}
}
gcc uartTest.c uartTool.c -lpthread
./a.out /dev/ttyS5