打印
[技术问答]

NUC980的串口通信问题询问

[复制链接]
1342|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dongwb001|  楼主 | 2019-8-25 21:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dongwb001 于 2019-8-25 21:58 编辑

串口通信电路板接收电脑的数据都是正常的,发送不正常,代码如下
配置相关的#include  <stdio.h>      
#include  <stdlib.h>   
#include  <unistd.h>   
#include  <sys/types.h>  
#include  <sys/stat.h>   
#include  <fcntl.h>     
#include  <termios.h>   
#include  <errno.h>   
#include  <string.h>  
#include  <assert.h>
#include "uart.h"

static int fd;

/*******************************************************************
* 名称:                  UART0_Open
* 功能:                打开串口并返回串口设备文件描述
* 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/  
int uart_open(int fd,const char *pathname)
{
        assert(pathname);

        fd = open(pathname,O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
        if(fd == -1)
        {
                perror("Open UART failed!");
                return FALSE;
        }
        /*恢复串口为阻塞状态,阻塞状态即在读写串口的过程中,
        *        如果没有读取到足够的数据,则会一直等待,直到出现对应的数据为止,可以使用select绕过阻塞
        *非阻塞:fcntl(fd,F_SETFL,FNDELAY)
        */
                        
        if(fcntl(fd, F_SETFL, 0) < 0)  
        {  
                printf("fcntl failed!\n");  
                return FALSE;  
        }      
        else  
        {  
                printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));  
        }  
        //测试是否为终端设备      
        if(0 == isatty(STDIN_FILENO))  
        {  
                printf("standard input is not a terminal device\n");  
                return FALSE;  
        }  
        else  
        {  
                printf("isatty success!\n");  
        }               
        printf("fd->open=%d\n",fd);  
        return fd;  
}
/*******************************************************************
* 名称:                uart_close
* 功能:                关闭串口并返回串口设备文件描述
* 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数:        void
*******************************************************************/  
void uart_close(int fd)  
{  
    close(fd);  
}  
/*******************************************************************
* 名称:                 uart_set
* 功能:                设置串口数据位,停止位和效验位
* 入口参数:        fd        串口文件描述符
*                              speed     串口速度
*                              flow_ctrl   数据流控制
*                           databits   数据位   取值为 7 或者8
*                           stopbits   停止位   取值为 1 或者2
*                           parity     效验类型 取值为N,E,O,,S
*出口参数:          正确返回为1,错误返回为0
*******************************************************************/  
int uart_set(int fd,int baude,int c_flow,int bits,char parity,int stop)
{
       
        struct termios options;
        /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,
        *该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.
        */  
        if(tcgetattr(fd,&options) < 0)
        {
                perror("tcgetattr error");
                return -1;
        }
     //设置串口输入波特率和输出波特率  
     switch(baude)
        {
                case 115200:
                        cfsetispeed(&options, B115200);   
            cfsetospeed(&options, B115200);
                        printf("enter bande 115200\n");
                        break;
                case 9600:
                        cfsetispeed(&options, B9600);   
            cfsetospeed(&options, B9600);
                        printf("enter bande 9600\n");
                        break;
                default:
                        printf("enter bande Error \n");
                        break;
        }

     /*设置控制模式*/
    options.c_cflag |= CLOCAL;//保证程序不占用串口
    options.c_cflag |= CREAD;//保证程序可以从串口中读取数据

     /*设置数据流控制*/
     switch(c_flow)
     {
          case 0://不进行流控制
               options.c_cflag &= ~CRTSCTS;
                           printf("no c_flow \n");
               break;
          case 1://进行硬件流控制
               options.c_cflag |= CRTSCTS;
               break;
          case 2://进行软件流控制
               options.c_cflag |= IXON|IXOFF|IXANY;
               break;
          default:
               fprintf(stderr,"Unkown c_flow!\n");
               return -1;
     }

    /*设置数据位*/
    switch(bits)
    {
        case 5:
            options.c_cflag &= ~CSIZE;//屏蔽其它标志位
            options.c_cflag |= CS5;
            break;
        case 6:
            options.c_cflag &= ~CSIZE;//屏蔽其它标志位
            options.c_cflag |= CS6;
            break;
        case 7:
            options.c_cflag &= ~CSIZE;//屏蔽其它标志位
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag &= ~CSIZE;//屏蔽其它标志位
            options.c_cflag |= CS8;
                        printf("CS8 \n");
            break;
        default:
            fprintf(stderr,"Unkown bits!\n");
            return -1;
    }

    /*设置校验位*/
    switch(parity)
    {
        /*无奇偶校验位*/
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag &= ~INPCK;//INPCK:使奇偶校验起作用
                        fprintf(stderr,"parity n \n");
            break;
        /*设为空格,即停止位为2位*/
        case 's':
        case 'S':
            options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
            break;
        /*设置奇校验*/
        case 'o':
        case 'O':
            options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag |= PARODD;//PARODD:若设置则为奇校验,否则为偶校验
            options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
            options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
            break;
        /*设置偶校验*/
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag &= ~PARODD;//PARODD:若设置则为奇校验,否则为偶校验
            options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
            options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
            break;
        default:
            fprintf(stderr,"Unkown parity!\n");
            return -1;
    }

    /*设置停止位*/
    switch(stop)
    {
        case 1:
            options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
                        fprintf(stderr,"stop 1 \n");
            break;
        case 2:
            options.c_cflag |= CSTOPB;//CSTOPB:使用两位停止位
            break;
        default:
            fprintf(stderr,"Unkown stop!\n");
            return -1;
    }

        /*设置输出模式为原始输出*/
        options.c_oflag &= ~OPOST;//OPOST:若设置则按定义的输出处理,否则所有c_oflag失效

        options.c_oflag &= ~(ONLCR|OCRNL);
        /*设置本地模式为原始模式*/
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//        options.c_lflag &= ~(ISIG | ICANON);  

        options.c_iflag &=~(ICRNL|INLCR|BRKINT|IXON|IXOFF|IXANY);
       
        /*
        *ICANON:允许规范模式进行输入处理
        *ECHO:允许输入字符的本地回显
        *ECHOE:在接收EPASE时执行Backspace,Space,Backspace组合
        *ISIG:允许信号
        */

        /*使用二进制,删除不必要的控制符号*/
//        options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IGNCR);

        /*设置等待时间和最小接受字符*/
        options.c_cc[VTIME] = 0;//可以在select中设置
        options.c_cc[VMIN] = 1;//最少读取一个字符

        /*如果发生数据溢出,只接受数据,但是不进行读操作*/
        tcflush(fd,TCIFLUSH);

     /*激活配置*/
     if(tcsetattr(fd,TCSANOW,&options) < 0)
     {
          perror("tcsetattr failed");
          return -1;
     }

     return TRUE;

}

/*******************************************************************
* 名称:                uart_init()
* 功能:                串口初始化
* 入口参数:        fd       :  文件描述符   
*               speed  :  串口速度
*                              flow_ctrl  数据流控制
*               databits   数据位   取值为 7 或者8
*                           stopbits   停止位   取值为 1 或者2
*                           parity     效验类型 取值为N,E,O,,S
*                       
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/  
int uart_init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
     int err;  
     //设置串口数据帧格式  
     if (uart_set(fd,115200,0,8,'N',1) == FALSE)  
     {                                                           
          return FALSE;  
     }  
     else  
     {  
          return  TRUE;  
     }  
}  
/*******************************************************************
* 名称:                  uart_recv
* 功能:                接收串口数据
* 入口参数:        fd                  :文件描述符     
*                              rcv_buf     :接收串口中数据存入rcv_buf缓冲区中
*                              data_len    :一帧数据的长度
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/  
int uart_recv(int fd, char *rcv_buf,int data_len)  
{  
    int len,fs_sel;  
    fd_set fs_read;  
     /*fd_set是一组文件描述字(fd)的集合,
      * 它用一位来表示一个fd,定义在头文件<sys/select.h>中定义常量FD_SETSIZE,一般可表示1024个ID
     */

    struct timeval time;  

    FD_ZERO(&fs_read);  /*初始化读取的集合*/
    FD_SET(fd,&fs_read);  /*用于在文件描述符集合中增加一个新的文件描述符*/

    time.tv_sec = 1; /*等待1秒,超时则会退出*/
    time.tv_usec = 0;  

    //使用select实现串口的多路通信  
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  
    printf("fs_sel = %d\n",fs_sel);  
    if(fs_sel)  
    {  
        len = read(fd,rcv_buf,data_len);  
        printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);  
        return len;  
    }  
    else  
    {  
        printf("Sorry,I am wrong!");  
        return FALSE;  
    }      
}  
/********************************************************************
* 名称:                  uart_send
* 功能:                发送数据
* 入口参数:        fd                  :文件描述符     
*                              send_buf    :存放串口发送数据
*                              data_len    :一帧数据的个数
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/  
int uart_send(int fd, char *send_buf,int data_len)  
{  
    int len = 0;  
        len = write(fd,send_buf,data_len);  
    if (len == data_len )  
    {  
        printf("send data is %s\n",send_buf);
        return len;  
    }      
    else     
    {                  
        tcflush(fd,TCOFLUSH);  
        return FALSE;  
    }   
}
主程序如下:


#include  <stdio.h>      
#include  <stdlib.h>   
#include  <unistd.h>   
#include  <sys/types.h>  
#include  <sys/stat.h>   
#include  <fcntl.h>     
#include  <termios.h>   
#include  <errno.h>   
#include  <string.h>  
#include <assert.h>
#include "uart.h"

/*
*主程序,循环读取数据
*参数,./usar <参数数量> <路径> <参数cmd>
*cmd <0> 发送数据
*    <1> 其他则循环读取数据
*/
int main(int argc, char **argv)  
{  
    int fd;                            //文件描述符  
    int err;                           //返回调用函数的状态  
    int len;                          
    int i;  
    char rcv_buf[100];         
    char send_buf[20]="123456789";
    if(argc != 3)  
    {  
          printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]);  
          return FALSE;  
    }  
    fd = uart_open(fd,argv[1]); //打开串口,返回文件描述符,需要提供相应的路径
    do
    {  
          err = uart_init(fd,115200,0,8,1,'N');  
          printf("Set Port Exactly!\n");  
          sleep(1);  
    }while(FALSE == err || FALSE == fd);  

    if(0 == strcmp(argv[2],"0"))  
    {  
        for(i = 0;i < 10;i++)  
        {  
             len = uart_send(fd,send_buf,7);  
            if(len > 0)  
                printf(" %d time send %d data successful\n",i,len);  
            else  
                printf("send data failed!\n");  

            sleep(2);  
        }  
        uart_close(fd);               
    }  
    else  
    {                                       
        while (1) //循环读取数据  
        {   
            len = uart_recv(fd, rcv_buf,99);  
              if(len > 0)  
            {  
                rcv_buf[len] = '\0';  
                printf("receive data is %s\n",rcv_buf);  
                printf("len = %d\n",len);  
            }  
            else  
            {  
                printf("cannot receive data\n");  
            }  
            sleep(2);  
        }              
        uart_close(fd);   
    }  
}  


发送的数据到电脑,都不正确,但是数据是正确的,比如发送7个a接收到的为E1 E1 B8 B8 5C 5C FE,非常奇怪的现象,难道新唐的单片机有问题吗?



使用特权

评论回复
沙发
dongwb001|  楼主 | 2019-8-25 22:10 | 只看该作者
自己顶一贴,不要沉了

使用特权

评论回复
板凳
21mengnan| | 2019-8-26 09:16 | 只看该作者
找个官方的工程,试试发送,一般那个printf就是串口发送。

使用特权

评论回复
地板
wanduzi| | 2019-8-26 23:01 | 只看该作者
这个系列的串口还是挺难搞的?

使用特权

评论回复
5
dongnanxibei| | 2019-8-27 13:09 | 只看该作者
ARM9的貌似论坛玩的人不多。

使用特权

评论回复
6
huahuagg| | 2019-8-28 23:52 | 只看该作者
这个一般跑Linux,在Linux上应该比较好实现。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

5

帖子

0

粉丝