Linux串口的编程,过程也是配置像停止位、奇偶校验位、波特率和数据位。像打开文件一样打开串口设备,然后配置上面说的几个参数。串口的写用标准的Linux系统调用write,读用read。其中还有一些配置,在代码中在详细阐述,下面直接贴代码:首先用一个serial.cfg的配置文件来指定串口的参数,后面就直接更改配置文件来修改参数。我们把这个配置文件放置在/etc/下面DEV=/dev/tq2440_serial2
SPEED=115200
DATABITS=8
STOPBITS=1
PARITY=N这里的设备文件用已经有的串口驱动生成的设备节点。定义头文件Serial.h,定义表征串口的结构体#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H#define TRUE 1
#define FALSE 0#define z_U32 unsigned int
#define z_U8 unsigned char#define SERIAL_NAME_LEN 32
extern int serial_config();
extern int set_speed(int fd);
extern int set_other_parm(int fd);typedef struct z_Serial_port { z_U8 serial_name[SERIAL_NAME_LEN];
z_U32 serial_baud;
z_U8 data_bits;
z_U8 stop_bits;
z_U8 parity;}HI_Serial_port;extern z_Serial_port get_current_serial();
#endif接下来当然是serial.c文件咯,实现串口的各个参数的设置/*
** author: z
** CopyRight: z
** funtion: serial port Interface
** Date: 2014
*/#include <stdio.h> /**/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "pthread.h"#include "serial_port.h"#define CFG_FILE "/etc/serial.cfg"//放置配置文件的地方
#define DEBUG 1
#define ERROR -1
#define OK 1/*Serial Port Struct*/
z_Serial_port serial_port ;int speed_array[] = {B230400, B115200, B57600, B38400, B19200, B9600, B4800,
B2400, B1200, B300, B38400, B19200, B9600, B4800,
B2400, B1200, B300};
int name_array[] = {230400, 115200, 57600, 38400, 19200, 9600, 4800,
2400, 1200, 300, 38400, 19200, 9600, 4800,
2400, 1200, 300};//得到当前的串口结构体 z_Serial_port get_current_serial(){
z_Serial_port current_serial;
memset(current_serial.serial_name, 0, sizeof(current_serial.serial_name)); strncpy(current_serial.serial_name, serial_port.serial_name, sizeof(current_serial.serial_name));
current_serial.serial_baud = serial_port.serial_baud;
current_serial.data_bits = serial_port.data_bits;
current_serial.stop_bits = serial_port.stop_bits;
current_serial.parity = serial_port.parity;
if(DEBUG){
printf("current_serial.serial_baud = %d
", current_serial.serial_baud);
printf("current_serial.data_bits = %d
" , current_serial.data_bits);
printf("current_serial.stop_bits = %d
", current_serial.stop_bits);
printf("current_serial.parity = %c
", current_serial.parity);
}
return current_serial;
}//读取串口的配置文件,并将配置填充到结构体 int serial_config()
{
FILE *serial_fp;
char read_buf[20] = {0};
char temp[20];
char parity; /*read serial config from file*/
serial_fp = fopen(CFG_FILE, "r");
if(serial_fp == NULL){
printf("Can"t open serial config file
");
return ERROR;
}
memset(serial_port.serial_name, 0 ,sizeof(serial_port.serial_name));
fscanf(serial_fp, "DEV=%s
", serial_port.serial_name);
fscanf(serial_fp, "SPEED=%s
", temp);
serial_port.serial_baud = atoi(temp); fscanf(serial_fp, "DATABITS=%s
", temp);
serial_port.data_bits = atoi(temp); fscanf(serial_fp, "STOPBITS=%s
", temp);
serial_port.stop_bits = atoi(temp); fscanf(serial_fp, "PARITY=%s
", temp);
serial_port.parity = temp[0]; if(DEBUG){
printf(" Serial Dev = %s
", serial_port.serial_name);
printf(" Serial Speed = %d
", serial_port.serial_baud);
printf(" Serial DataBits = %d
", serial_port.data_bits);
printf(" Serial StopBite = %d
", serial_port.stop_bits);
printf(" Serial Parity = %c
", serial_port.parity);
}
fclose(serial_fp);
return OK;
}/*
* Set Baudrate
* 设置波特率,fd是打开设备节点的句柄
* */
int set_speed(int fd)
{
struct termios option;
struct termios old_option;
int i = 0; //get the old option
tcgetattr(fd, &old_option);// termios是所要操作的结构体 for (i = 0; i < sizeof(speed_array)/sizeof(int); i++){
if(serial_port.serial_baud == name_array[i]){
tcflush(fd, TCIOFLUSH);
cfsetispeed(&option, speed_array[i]);
cfsetospeed(&option, speed_array[i]); if(tcsetattr(fd, TCSANOW, &option) != 0){//配置立即生效
printf("set serial baudrate failed
");
return ERROR;
}else{
tcflush(fd, TCIOFLUSH);//清空输入输出队列
if(DEBUG) printf("set serial baudrate sucessed
");
return OK;
}
}
}
}/*
* Set Other Paramters
*设置其他的参数
* */
int set_other_parm(int fd)
{
struct termios options;
struct termios old_options; if(tcgetattr(fd, &old_options) != 0){
printf("Failed to getattr
");
return ERROR;
}
options.c_cflag |= (CLOCAL|CREAD);
options.c_cflag &= ~CSIZE; /*set Date Bits*/
switch (serial_port.data_bits){
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
options.c_cflag |= CS8;
break;
} /*Set Parity Bites*/
switch (serial_port.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;
default:
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
printf("default parity none parity
");
} /*Set Stop Bites*/
switch (serial_port.stop_bits){
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
options.c_cflag &= ~CSTOPB;
}
if(serial_port.parity != "n" || serial_port.parity != "N"){
options.c_iflag |= INPCK;
}
options.c_cc[VTIME] = 0;//Timeout parma 超时时间的设置
options.c_cc[VMIN] = 0;//read x bite return 读到多少个字节才进行操作,这里设置为0 options.c_iflag |= IGNPAR|ICRNL;
options.c_oflag |= OPOST;//原始模式,有两种模式,若不是原始模式的话,则会在
后,才会输出
options.c_iflag &= ~(IXON|IXOFF|IXANY);
tcflush(fd, TCIFLUSH);
if(tcsetattr(fd, TCSANOW, &options) != 0){
printf("set serial other parma failed
");
return ERROR;
}
return OK;
}到这里,基本的参数就配置完毕了,这里需要注意VMIN和VTIME的配置和原始模式的配置。接口写好了,写个测试的程序来进行测试就好,测试程序写的比较丑,见谅,哈哈:#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>#include "serial_port.h"int main(int argc, char *argv[])
{
int ret;
int fd;
unsigned char data[50]; z_Serial_port serial_p; printf("Configing serial from local file...
");
ret = serial_config();
if(ret != 1){
printf("Failed to config serial
");
return -1;
}
serial_p = get_current_serial();
fd = open(serial_p.serial_name,O_RDWR, 0);//以读写的方式打开
printf(".opening. %s
", serial_p.serial_name);
if(fd == -1){
printf("Can"t open tty
");
return -1;
}
// set speed
if(set_speed(fd) < 0){
printf("set speed Failed
");
return -1;
}
if(fcntl(fd, F_SETFL, O_NONBLOCK) < 0){
printf("fcntl failed
");
return -1;
}
if(isatty(STDIN_FILENO)==0)
{
printf("not a terminal device
");
}else
printf("isatty success!
");
//set other parma like stopbites etc.
if(set_other_parm(fd) < 0 ){
printf("set other parm failed
");
return -1;
}
//write data
int i;
char buff[512];
char buff21[] = "Hi Babby!"; int nread,nwrite = 0;
int nx;
printf("fd = %d
",fd );
nx = write(fd,buff21,sizeof(buff21));
printf("nx=%d
",nx);
while(1)
{
if((nread = read(fd,buff,512))>0)
{
buff[nread] = " ";
//write(fd,buff,nread);
printf("
recv:%d
",nread);
//printf("%s",buff);
printf("%d",buff[0] );
printf("%d",buff[1] );
printf("%d",buff[2] );
printf("%d",buff[3] );
printf("
");
}
}
return 1;
}搞个MakeFileCC=arm-linux-gcc
SEND_EXEC=serial_sendall:serial_port.c serial_port.h serial_send_msg.c
$(CC) -o $(SEND_EXEC) serial_port.c serial_send_msg.c
#chmod 777 $(SEND_EXEC)
clean:
rm -rf *.o serial_send哈哈,完成,接下来就是测试了。这里将电路板中的TXD2和RXD2短接,即自发自读,串口打印“Hi Babby!”嘿嘿,搞定。后面会搞一个GSM模块玩玩。也是串口发送AT指令来通信的。到时候调通了在进行相关的分析。本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-01/128025.htm