arm-linux_学习简单串口编程问题

来源:互联网 发布:阿里云企业邮箱pop 编辑:程序博客网 时间:2024/06/12 18:58

# 本人所使用的是 ARM tiny6410开发板。

# 以下所属个人实际操作的来,若有不妥或是不对之处,请多多之处不足之处。

# 部分解释来源百度百科Termios

# 首先要明确:实现串口编程的要点在何处,只有明白才会简单明了。

#要验证编程是否成功,记得准备平台哦!不然怎么知道自己的对错呢!

        一.准备ARM和一台宿主计算机,要能通信及编译哈~不会?请看此处!

        二.理解解释的代码,试着对比管道,回想下。

        三.尝试自己加点 信号、线程、进程编译调试,看看结果和不和自己的意思,但不需要强求。

——————————————————————————————————————————————————————————

程序头文件提供

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "serial.h"    //自己编写的头文件

——————————————————————————————————————————————————————————

基层的代码 serial.c中的串口数据初始化函数 set_opt。(后面会给出相关代码)

        函数定义 int set_opt(int fd, int nspeed, int nbits, char nevent, int nstop)

                fd:文件描述符。

                nspeed:波特率设置。

                nbits:数据位传输格式。

                nevent:传输协议方式。

                nstop:设置停止位。

       

        函数大致内容:

                1.定义termios 变量,保存初始化数据。

                2.变量值清空,大致是置全零的意思。

                3.根据自己的ARM设置波特率。

                4.设置传输格式。

                5.设置传输协议。

                6.设置停止位。

                7.设置传输模式


        实现内容:c_cflag—控制模式  c_cc—控制字符

        定义两个 struct termios类的变量 new_state old_state

                termios 是记录有大量数据的参数的结构体,里面包括了许许多多的状态标志。

                old_state 是保存现有状态值,如果串口操作乱套了,要回复不是很麻烦?所以养成好习惯吧!就算用不到!

                new_state 则就是用来使用的啦~

        清零 new_state

                bzero(&new_state,sizeof(new_state));//将new_state这一个内存空间清零

                new_state.c_cflag |= CLOCAL | CREAD; //此句是可以不要的,因为这句是为了以前串口发展还不成熟用的

                new_state.c_cflag &= ~CSIZE; //将字符长度掩码

        设置波特率

                cfsetispeed(&new_state,B115200);//设置 输入 波特率是115200

                cfsetospeed(&new_state,B115200);//设置 输出 波特率是115200

        设置传输格式

                new_state.c_cflag |= CS8; //设置传输以8位bit位为传输方式

        设置传输协议

                new_state.c_cflag |= PARENB;  //允许输出产生奇偶信息以及输入的奇偶校验。我的理解就是“开启”

                new_state.c_cflag |= PARODD;  //输入输出是奇校验

                new_state.c_cflag |= (INPCK | ISTRIP);//启用输入奇偶检测  |  去掉第8位   //想知道为什么去掉第八位请百度奇偶检验吧~

        设置停止位

                new_state.c_cflag |= CSTOPB;//设置为2位停止位

        设置传输模式

                new_state.c_cc[VTIME] = 0;//非 canonical 模式非 canonical 模式读的最小字符数。

                new_state.c_cc[VMIN] = 0;  //非 canonical 模式读的最小字符数。

        清空串口里面数据

                tcflush(fd,TCIFLUSH);

以下是set_opt参考代码

int set_opt(int fd, int nspeed, int nbits, char nevent, int nstop){
    struct termios old_state, new_state;
    if (tcgetattr(fd, &old_state)!=0){
        perror("SetupSerial old");
        return -1;
    }
    bzero(&new_state,sizeof(new_state));
//    new_state.c_cflag |= CLOCAL | CREAD;
    new_state.c_cflag &= ~CSIZE;

    switch(nspeed){
        case 2400:
            cfsetispeed(&new_state,B2400);
            cfsetospeed(&new_state,B2400);
            break;
        case 4800:
            cfsetispeed(&new_state,B4800);
            cfsetospeed(&new_state,B4800);
            break;
        case 9600:
            cfsetispeed(&new_state,B9600);
            cfsetospeed(&new_state,B9600);
            break;
        case 115200:
            cfsetispeed(&new_state,B115200);
            cfsetospeed(&new_state,B115200);
            break;
        case 460800:
            cfsetispeed(&new_state,B460800);
            cfsetospeed(&new_state,B460800);
            break;
        default:
            cfsetispeed(&new_state, B9600);
            cfsetospeed(&new_state, B9600);
            break;
    }

    switch(nbits){
        case 7:
            new_state.c_cflag |= CS7;
            break;
        case 8:
            new_state.c_cflag |= CS8;
            break;
    }

    switch(nevent){
        case 'O':
            new_state.c_cflag |= PARENB;
            new_state.c_cflag |= PARODD;
            new_state.c_cflag |= (INPCK | ISTRIP);
            break;
        case 'E':
            new_state.c_cflag |= PARENB;
            new_state.c_cflag |= (INPCK | ISTRIP);
            new_state.c_cflag &= ~PARODD;
            break;
        case 'N':
            new_state.c_cflag &= ~PARENB;
            break;
    }

    if(nstop==1)
        new_state.c_cflag &= ~CSTOPB;
    else
        if(nstop==2)
            new_state.c_cflag |= CSTOPB;
    new_state.c_cc[VTIME] = 0;
    new_state.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&new_state))!=0){
        perror("con set error");
        return -1;
    }
    printf("set done!\n");
    return 0;
}

——————————————————————————————————————————————————————————

基层的代码 serial.c中连接端口设置函数 open_port。(后面会给出相关代码)

        函数定义int open_port (int fd, int comport)

                fd:文件描述符

                comport:端口选择

        函数大致内容

                1.选择端口,建立连接

                2.提供描述符控制参数  //具体我还不清楚是做什么的

        实现内容:

        open("端口",O_RDWR|O_NOCTTY|O_NDELAY)

                 //读写模式

                 //如果路径指向终端设备,不要把设备用作控制终端

                 //如果路径名FIFO/块文件/字符文件,则文件的打开和后继I/O

        fcntl和isatty  不会哈……以后修改


        以下是open_port参考代码

int open_port (int fd, int comport){
    char *dev[]={"/dev/ttySAC3","/dev/ttyUSB1"};
    long vdisable;
    if (comport==1){
        fd=open("/dev/ttySAC3", O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 ==fd ){
            perror("Can't Open Serial Port");
            return (-1);
        }
    }
    else if(comport==2){
        fd=open("/dev/ttyUSB1", O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd){
            perror("Can't Open Serial Port");
            return(-1);
        }
    }

    if(fcntl(fd, F_SETFL, 0)<0)
        printf("fcntl failed!\n");
    else
        printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
    if(isatty(STDIN_FILENO)==0)
        printf("standard input is not a terminal device\n");
    else
        printf("isatty success!\n");
        printf("fd-open=%d\n",fd);
    return fd;
}

——————————————————————————————————————————————————————————

基于上述serial.c文件,我们生成一个简单.h文件吧

int set_opt(int,int,int,char,int);

int open_oprt(int,int);

——————————————————————————————————————————————————————————

读的代码 read.c(后面会给出相关代码)

        select 函数相关用法

        FD_ZERO(&rd) //设立分组rd为一个组

        FD_SET(fd,&rd)//绑定描述符

        FD_ISSET(fd,&rd)//判断描述符fd是否在给定的描述符集fdset中

实现代码  以下我是想加入signal的程序 不过都已注释

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/stat.h>
#include "serial.h"
#include <signal.h>
/*
int k=1;

void sig(int sig){
    k=0;
    printf("this system will be exit!\n");
}
*/
int main(){
    int fd;
    int nread,i;
    char buff[8];
    fd_set rd;
    if ((fd=open_port(fd,1))<0){
        perror("open_port");
        return;
    }
    if ((i=set_opt(fd,115200,8,'N',1))<0){
        perror("set_pot error");
        return;
    }
    FD_ZERO(&rd);
    FD_SET(fd,&rd);//归并集合
//    signal(SIGINT,sig);
//    while(k){
        while(FD_ISSET(fd,&rd)){
            if(select(fd+1,&rd,NULL,NULL,NULL)<0)
                perror("select");
            else {
                while ((nread=read(fd, buff, 8))>0){
                    printf("nread=%d,%s\n",nread,buff);
                }
            }
        }
//    }
    close(fd);
    return;
}

——————————————————————————————————————————————————————————

写的代码write.c(相关代码)

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include "serial.h"
#include <malloc.h>
#include <signal.h>
/*
int k=1;
void sig(int sig){
    k=0;
    printf("this system will be exit!\n");
}
*/
int main(){
    int fd;
    int nwrite,i;
    printf("please give me Ctrl+c that exit system!\n");
//    getchar();
//    signal(SIGINT,sig);
//    char *p=NULL;
    char p[]="Hello\n";
    if((fd=open_port(fd,2))<0){
        perror("open_port error");
        return;
    }
    if((i=set_opt(fd,115200,8,'N',1))<0){
        perror("set_opt error");
        return;
    }
/*    p=(char*)malloc(sizeof(char)*8);
    if(p==NULL){
        printf("create malloc that is fail!\n");
        exit(0);
    }
*/
    printf("fd=%d\n\n",fd);
//    while(k){
        puts("please give message\n");
//        gets(p);
        nwrite=write(fd,p,8);
        printf("nwrite=%d\n",nwrite);
//    }
//    free(p);
    close(fd);
    return;
}


下面说下我的见解  串口编程  与  进程见通信、管道基本上都是相同的 

建立fd 描述符,打开“通道”,对通道的读与写的操作都是一致的。

不同用的是所利用的“通道”建立方式不一样。具体……

0 0
原创粉丝点击