歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux基礎串口編程

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\n", current_serial.serial_baud);
   printf("current_serial.data_bits = %d\n" , current_serial.data_bits);
   printf("current_serial.stop_bits = %d\n", current_serial.stop_bits);
   printf("current_serial.parity = %c\n", 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\n");
        return ERROR;
    }
    memset(serial_port.serial_name, 0 ,sizeof(serial_port.serial_name));
    fscanf(serial_fp, "DEV=%s\n", serial_port.serial_name);
   
    fscanf(serial_fp, "SPEED=%s\n", temp);
    serial_port.serial_baud = atoi(temp);

    fscanf(serial_fp, "DATABITS=%s\n", temp);
    serial_port.data_bits = atoi(temp);

    fscanf(serial_fp, "STOPBITS=%s\n", temp);
    serial_port.stop_bits = atoi(temp);

    fscanf(serial_fp, "PARITY=%s\n", temp);
    serial_port.parity = temp[0];

    if(DEBUG){
        printf(" Serial Dev = %s\n", serial_port.serial_name);
        printf(" Serial Speed = %d\n", serial_port.serial_baud);
        printf(" Serial DataBits = %d\n", serial_port.data_bits);
        printf(" Serial StopBite = %d\n ", serial_port.stop_bits);
        printf(" Serial Parity = %c\n", 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\n");
  return ERROR;
    }else{
  tcflush(fd, TCIOFLUSH);//清空輸入輸出隊列
        if(DEBUG) printf("set serial baudrate sucessed\n");
  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\n");
 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\n");
    }

    /*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;//原始模式,有兩種模式,若不是原始模式的話,則會在\n後,才會輸出
    options.c_iflag &= ~(IXON|IXOFF|IXANY); 


    tcflush(fd, TCIFLUSH);
    if(tcsetattr(fd, TCSANOW, &options) != 0){
 printf("set serial other parma failed\n");
 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...\n");
 ret = serial_config();
 if(ret != 1){
  printf("Failed to config serial\n");
  return -1;
 }
 serial_p = get_current_serial();
 fd = open(serial_p.serial_name,O_RDWR, 0);//以讀寫的方式打開
 printf(".opening. %s\n", serial_p.serial_name);
 if(fd == -1){
  printf("Can't open tty\n");
  return -1;
 }
 // set speed
    if(set_speed(fd) < 0){
  printf("set speed Failed\n");
  return -1;
 }
 if(fcntl(fd, F_SETFL, O_NONBLOCK) < 0){
  printf("fcntl failed\n");
  return -1;
 }
    if(isatty(STDIN_FILENO)==0)
    {
        printf("not a terminal device\n");
    }else
        printf("isatty success!\n");
 //set other parma like stopbites etc.
    if(set_other_parm(fd) < 0 ){
  printf("set other parm failed\n");
  return -1;
 }
 //write data
 int i;
    char buff[512];
    char buff21[] = "Hi Babby!";

    int nread,nwrite = 0;
    int nx;
    printf("fd = %d\n",fd );
    nx = write(fd,buff21,sizeof(buff21));


    printf("nx=%d\n",nx);
    while(1)
    {
        if((nread = read(fd,buff,512))>0)
        {
            buff[nread] = '\0';
            //write(fd,buff,nread);
            printf("\nrecv:%d\n",nread);
            //printf("%s",buff);
   printf("%d",buff[0] );
   printf("%d",buff[1] );
   printf("%d",buff[2] );
   printf("%d",buff[3] );
            printf("\n");
        }
 
    }
 return 1;
}

搞個MakeFile

CC=arm-linux-gcc
SEND_EXEC=serial_send

all: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指令來通信的。到時候調通了在進行相關的分析。

Copyright © Linux教程網 All Rights Reserved