gpt4 book ai didi

Linux驱动像单片机一样读取一帧dmx512串口数据

转载 作者:我是一只小鸟 更新时间:2023-01-17 14:37:46 24 4
gpt4 key购买 nike

硬件全志R528 。

目标:实现Linux 读取一帧dmx512串口数据.

问题分析:因为串口数据量太大,帧与帧之间的间隔太小。通过Linux自带的读取函数方法无法获取到 。

帧头和帧尾,读取到的数据都是缓存区中的,数据量又大。导致缓冲区中一直有很多数据, 。

又由于dmx512数据协议中并没有帧头帧尾字段只有普通数据,无法通过特定的帧头帧尾截取到一完整帧的数据.

所以只能像单片机一样通过串口寄存器对LSR 的UART_LSR_FE位 (接收到 错误帧 )认为是一帧结束和开始.

通过对Linux驱动读取串口数据的过程分析, 。

tty_read() ----> ld->ops->read() ----> n_tty_read() n_tty_read()中add_wait_queue(&tty->read_wait, &wait)没有数据的时候上层的read进程阻塞在此 而在串口有数据来的时候n_tty_receive_buf()--->wake_up_interruptible(&tty->read_wait),唤醒上面的read进程n_tty_read()中会继续运行,将数据拷到用户空间 从整个分析来看,uart驱动会把从硬件接受到的数据暂时存放在tty_buffer里面,然后调用线路规程的receive_buf()把数据存放到tty->read_buf里面, 。

而系统调用的read()函数直接从tty->read_buf里面读取数据.

所以最终判断在uart的串口中断接收处理函数中增加接收代码比较合适.

  。

 Linux 设置非标准波特率参考上次的博客.

方法:

1、写一个简单字符驱动 dmx512_uart.c, 放在sunxi-uart.c同文件夹中.

在驱动读函数中设置全局变量标识,等待读取数据,后copy_to_user上传到用户空间. 。

修改同目录下的Makefile 和Kconfig 后添加到内核,编译到内核中.

  。

                          
                            /*
                          
                          
                            dmx512_uart.c 代码
                          
                          
                            */
                          
                          
                            
#include 
                          
                          <linux/module.h>
                          
                            
#include 
                          
                          <linux/slab.h>
                          
                            
#include 
                          
                          <linux/delay.h>
                          
                            
#include 
                          
                          <linux/fs.h>
                          
                            
#include 
                          
                          <linux/uaccess.h>
                          
                            
#include 
                          
                          <linux/init.h>
                          
                            
#include 
                          
                          <linux/cdev.h>
                          
                            
#include 
                          
                          
                            "
                          
                          
                            dmx512_uart.h
                          
                          
                            "
                          
                          
                            #define
                          
                           CDEV_NAME  "dmx512_uart_dev"

                          
                            struct
                          
                           dmx512_uart_dev *
                          
                            dmx512_devp;



                          
                          
                            static
                          
                           ssize_t dmx512drv_read (
                          
                            struct
                          
                           file *filp, 
                          
                            char
                          
                           __user *buf, size_t size, loff_t *
                          
                            ppos)
{
    
                          
                          
                            int
                          
                           len =
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           num =
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           ret =
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           i=
                          
                            0
                          
                          
                            ;
    
                          
                          
                            //
                          
                          
                            printk("%s start\n",__func__);
                          
                          
                            if
                          
                          (size >
                          
                             DMX512_BUF_LEN)
    {
        dmx512_devp
                          
                          ->r_size =
                          
                             DMX512_BUF_LEN;
    }
    
                          
                          
                            else
                          
                          
                            
    {
        dmx512_devp
                          
                          ->r_size =
                          
                             size;
    }
    memset(dmx512_devp
                          
                          ->dmx_buff,
                          
                            0
                          
                          ,
                          
                            sizeof
                          
                          (dmx512_devp->
                          
                            dmx_buff));
    dmx512_devp
                          
                          ->end_read_flag = 
                          
                            false
                          
                          
                            ;
    dmx512_devp
                          
                          ->recv_len =
                          
                            0
                          
                          
                            ;
    dmx512_devp
                          
                          ->num_break =
                          
                            0
                          
                          
                            ;
    dmx512_devp
                          
                          ->start_read_flag = 
                          
                            true
                          
                          
                            ;

    
                          
                          
                            while
                          
                          (!dmx512_devp->end_read_flag) 
                          
                            /*
                          
                          
                            等待获取数据
                          
                          
                            */
                          
                          
                            
    {
        msleep(
                          
                          
                            100
                          
                          
                            );
        num
                          
                          ++
                          
                            ;
        
                          
                          
                            if
                          
                          (num > 
                          
                            50
                          
                          
                            )
        {
            printk(
                          
                          
                            "
                          
                          
                            timeout\n
                          
                          
                            "
                          
                          
                            );
            
                          
                          
                            break
                          
                          
                            ;
        }
    }
    
                          
                          
                            if
                          
                          (dmx512_devp->recv_len <
                          
                             size)
    {
        len 
                          
                          = dmx512_devp->
                          
                            recv_len;
    }
    
                          
                          
                            else
                          
                          
                            
    {    
        len 
                          
                          =
                          
                             size;    
    }
    
    
                          
                          
                            if
                          
                          (copy_to_user(buf,dmx512_devp->
                          
                            dmx_buff, len))
        ret 
                          
                          = -
                          
                            EFAULT;
    
                          
                          
                            else
                          
                          
                            {
        ret 
                          
                          =
                          
                             len;
    }
    
                          
                          
                            //
                          
                          
                            printk("%s end\n",__func__);
                          
                          
                            return
                          
                          
                             ret;
    
}

                          
                          
                            static
                          
                           ssize_t dmx512drv_write(
                          
                            struct
                          
                           file *filp, 
                          
                            const
                          
                          
                            char
                          
                           __user *buf, size_t size, loff_t *
                          
                            ppos)
{

    
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;
}

                          
                          
                            static
                          
                          
                            int
                          
                           dmx512drv_close (
                          
                            struct
                          
                           inode *inodp, 
                          
                            struct
                          
                           file *
                          
                            filp)
{
    
                          
                          
                            //
                          
                          
                            printk("%s\n",__func__);
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;

}

                          
                          
                            static
                          
                          
                            int
                          
                           dmx512drv_open (
                          
                            struct
                          
                           inode *inodp, 
                          
                            struct
                          
                           file *
                          
                            filp)
{
    
                          
                          
                            //
                          
                          
                            printk("%s\n",__func__);
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;
}


                          
                          
                            static
                          
                          
                            const
                          
                          
                            struct
                          
                           file_operations dmx512drv_fops =
                          
                            
{
    .owner 
                          
                          =
                          
                             THIS_MODULE,
    .open 
                          
                          =
                          
                            dmx512drv_open,
    .read 
                          
                          =
                          
                            dmx512drv_read,
    .write 
                          
                          =
                          
                            dmx512drv_write,
    .release 
                          
                          =
                          
                            dmx512drv_close,
};


                          
                          
                            static
                          
                          
                            int
                          
                           __init dmx512_init(
                          
                            void
                          
                          
                            )
{
    
                          
                          
                            int
                          
                          
                             ret;
    dmx512_devp 
                          
                          =kzalloc(
                          
                            sizeof
                          
                          (
                          
                            struct
                          
                          
                             dmx512_uart_dev), GFP_KERNEL);
    
                          
                          
                            if
                          
                          (!
                          
                            dmx512_devp)
    {
        ret 
                          
                          = -
                          
                            ENOMEM;
        
                          
                          
                            return
                          
                          
                             ret;
    }

                          
                          
                            #if
                          
                           0    
    
                          
                            /*
                          
                          
                            动态申请dev
                          
                          
                            */
                          
                          
                            
    ret 
                          
                          = alloc_chrdev_region(&dmx512_devp->dev,
                          
                            0
                          
                          , 
                          
                            1
                          
                          
                            , CDEV_NAME);
    
                          
                          
                            if
                          
                          
                            (ret)
    {
        printk(
                          
                          
                            "
                          
                          
                            failed to allocate char device region\n
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            return
                          
                          
                             ret;
    }

    cdev_init(
                          
                          &dmx512_devp->cdev,&
                          
                            dmx512drv_fops);
    
    ret 
                          
                          = cdev_add(&dmx512_devp->cdev,dmx512_devp->dev,
                          
                            1
                          
                          
                            );    
    
                          
                          
                            if
                          
                          
                            (ret)
    {
        printk(
                          
                          
                            "
                          
                          
                            failed to cdev_add\n
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            goto
                          
                          
                             unregister_chrdev;

    }
        
    
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;
unregister_chrdev:
    unregister_chrdev_region(dmx512_devp
                          
                          ->dev,
                          
                            1
                          
                          
                            );
    
                          
                          
                            return
                          
                          
                             ret;

                          
                          
                            #endif
                          
                          
                            
    dmx512_devp
                          
                          ->dev_major = register_chrdev(
                          
                            0
                          
                          ,
                          
                            "
                          
                          
                            dmx512_uart_drv
                          
                          
                            "
                          
                          ,&
                          
                            dmx512drv_fops);
    
                          
                          
                            if
                          
                          (dmx512_devp->dev_major < 
                          
                            0
                          
                          
                            )
    {
        printk(KERN_ERR
                          
                          
                            "
                          
                          
                            register_chrdev error\n
                          
                          
                            "
                          
                          
                            );
        ret 
                          
                          =-
                          
                             ENODEV;
        
                          
                          
                            goto
                          
                          
                             err_0;

    }
    dmx512_devp
                          
                          ->cls = class_create(THIS_MODULE,
                          
                            "
                          
                          
                            dmx512_cls
                          
                          
                            "
                          
                          
                            );
    
                          
                          
                            if
                          
                          (IS_ERR(dmx512_devp->
                          
                            cls))
    {
        printk(KERN_ERR
                          
                          
                            "
                          
                          
                            class_create error\n
                          
                          
                            "
                          
                          
                            );
        ret 
                          
                          = PTR_ERR(dmx512_devp->
                          
                            cls);
        
                          
                          
                            goto
                          
                          
                             err_1;
    }
    dmx512_devp
                          
                          ->dev = device_create(dmx512_devp->cls, NULL,MKDEV(dmx512_devp->dev_major, 
                          
                            0
                          
                          ),NULL,
                          
                            "
                          
                          
                            dmx512_uart
                          
                          
                            "
                          
                          
                            );
    
                          
                          
                            if
                          
                          (IS_ERR(dmx512_devp->
                          
                            dev))
    {
        printk(KERN_ERR
                          
                          
                            "
                          
                          
                            device_create error\n
                          
                          
                            "
                          
                          
                            );
        ret 
                          
                          = PTR_ERR(dmx512_devp->
                          
                            dev);
        
                          
                          
                            goto
                          
                          
                             err_2;
    }
    
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;

err_2:
        class_destroy(dmx512_devp
                          
                          ->
                          
                            cls);
err_1:
        unregister_chrdev(dmx512_devp
                          
                          ->dev_major,
                          
                            "
                          
                          
                            dmx512_uart_drv
                          
                          
                            "
                          
                          
                            );
            
err_0:
    kfree(dmx512_devp);
    
                          
                          
                            return
                          
                          
                             ret;

}


                          
                          
                            static
                          
                          
                            void
                          
                           __exit  dmx512_exit(
                          
                            void
                          
                          
                            )
{

                          
                          
                            #if
                          
                           0
                          
                            
    cdev_del(
                          
                          &dmx512_devp->
                          
                            cdev);
    unregister_chrdev_region(dmx512_devp
                          
                          ->dev,
                          
                            1
                          
                          
                            );

                          
                          
                            #endif
                          
                          
                            
    device_destroy(dmx512_devp
                          
                          ->cls, MKDEV(dmx512_devp->dev_major, 
                          
                            0
                          
                          
                            ));
    class_destroy(dmx512_devp
                          
                          ->
                          
                            cls);
    unregister_chrdev(dmx512_devp
                          
                          ->dev_major,
                          
                            "
                          
                          
                            dmx512_uart_drv
                          
                          
                            "
                          
                          
                            );
    kfree(dmx512_devp);

}


module_init(dmx512_init);
module_exit(dmx512_exit);
MODULE_LICENSE(
                          
                          
                            "
                          
                          
                            GPL
                          
                          
                            "
                          
                          
                            );



                          
                          
                            /*
                          
                          
                            dmx512_uart.h 头文件
                          
                          
                            */
                          
                          
                            
#ifndef _DMX512_UART_H_

                          
                          
                            #define
                          
                           _DMX512_UART_H_


                          
                            #define
                          
                           DMX512_BUF_LEN (4096+1+3)

                          
                            struct
                          
                          
                             dmx512_uart_dev
{
    unsigned 
                          
                          
                            int
                          
                          
                             dev_major;
    
                          
                          
                            struct
                          
                          
                            class
                          
                           *
                          
                            cls;
    
                          
                          
                            struct
                          
                           device *
                          
                            dev;
    
                          
                          
                            int
                          
                          
                             recv_len;
    
                          
                          
                            int
                          
                          
                             r_size;
    
                          
                          
                            bool
                          
                          
                             start_read_flag;
    
                          
                          
                            bool
                          
                          
                             end_read_flag;
    unsigned 
                          
                          
                            char
                          
                          
                             num_break;
    unsigned 
                          
                          
                            char
                          
                          
                             dmx_buff[DMX512_BUF_LEN];
};


                          
                          
                            extern
                          
                          
                            struct
                          
                           dmx512_uart_dev *
                          
                            dmx512_devp;


                          
                          
                            #endif
                          
                           /*_DMX512_UART_H_*/
                        

  。

2、串口接收中断处理函数中根据全局变量标识开始读取数据.

通过对寄存器LSR 的UART_LSR_FE位进行判断,为新的一帧的开始和结束.

通过对内核源码的分析找到uart的串口中断接收处理函数。在 。

sunxi-uart.c -》 static unsigned int sw_uart_handle_rx(struct sw_uart_port *sw_uport, unsigned int lsr) 。

                          
                            static
                          
                           unsigned 
                          
                            int
                          
                           sw_uart_handle_rx(
                          
                            struct
                          
                           sw_uart_port *sw_uport, unsigned 
                          
                            int
                          
                          
                             lsr)
{
    unsigned 
                          
                          
                            char
                          
                           ch = 
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           max_count = 
                          
                            256
                          
                          
                            ;
    
                          
                          
                            char
                          
                          
                             flag;


                          
                          
                            #if
                          
                           IS_ENABLED(CONFIG_SERIAL_SUNXI_DMA)
    
                          
                            if
                          
                           ((sw_uport->dma->use_dma &
                          
                             RX_DMA)) {
        
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_RXFIFOE) {
            dev_info(sw_uport
                          
                          ->port.dev, 
                          
                            "
                          
                          
                            error:lsr=0x%x\n
                          
                          
                            "
                          
                          
                            , lsr);
            lsr 
                          
                          = serial_in(&sw_uport->
                          
                            port, SUNXI_UART_LSR);
            
                          
                          
                            return
                          
                          
                             lsr;
        }
    }

                          
                          
                            #endif
                          
                          
                                if(lsr & SUNXI_UART_LSR_FE)
    {
        if((dmx512_devp->start_read_flag) && (strncmp(sw_uport->name,"uart1",5) ==0))  /*现在用的是uart1 不同的端口需要调整,也可以通过驱动直接传过来*/
        {
            dmx512_devp->num_break++;
            if(dmx512_devp->num_break ==1)
                dmx512_devp->recv_len =0;
        }
    }
    
                          
                          
                            do
                          
                          
                             {

        
                          
                          
                            if((dmx512_devp->start_read_flag) && (strncmp(sw_uport->name,"uart1",5) ==0))
        {
                if((lsr & SUNXI_UART_LSR_FE) &&(max_count !=256))
                        dmx512_devp->num_break++;    
        }
        
        
                          
                          
                            if
                          
                           (likely(lsr &
                          
                             SUNXI_UART_LSR_DR)) {
            ch 
                          
                          = serial_in(&sw_uport->
                          
                            port, SUNXI_UART_RBR);

                          
                          
                            #if
                          
                           IS_ENABLED(CONFIG_SW_UART_DUMP_DATA)
                          
                            
            sw_uport
                          
                          ->dump_buff[sw_uport->dump_len++] =
                          
                             ch;

                          
                          
                            #endif
                          
                          
                            
        } 
                          
                          
                            else
                          
                          
                            
            ch 
                          
                          = 
                          
                            0
                          
                          
                            ;

        flag 
                          
                          =
                          
                             TTY_NORMAL;
        sw_uport
                          
                          ->port.icount.rx++
                          
                            ;
        
                          
                          
                            if
                          
                           (unlikely(lsr &
                          
                             SUNXI_UART_LSR_BRK_ERROR_BITS)) {
            
                          
                          
                            /*
                          
                          
                            
             * For statistics only
             
                          
                          
                            */
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_BI) {
                lsr 
                          
                          &= ~(SUNXI_UART_LSR_FE |
                          
                             SUNXI_UART_LSR_PE);
                sw_uport
                          
                          ->port.icount.brk++
                          
                            ;

                
                          
                          
                            /*
                          
                          
                            
                 * We do the SysRQ and SAK checking
                 * here because otherwise the break
                 * may get masked by ignore_status_mask
                 * or read_status_mask.
                 
                          
                          
                            */
                          
                          
                            if
                          
                           (!ch && uart_handle_break(&sw_uport->
                          
                            port))
                    
                          
                          
                            goto
                          
                          
                             ignore_char;
            } 
                          
                          
                            else
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_PE)
                sw_uport
                          
                          ->port.icount.parity++
                          
                            ;
            
                          
                          
                            else
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_FE)
                sw_uport
                          
                          ->port.icount.frame++
                          
                            ;
            
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_OE)
                sw_uport
                          
                          ->port.icount.overrun++
                          
                            ;

            
                          
                          
                            /*
                          
                          
                            
             * Mask off conditions which should be ignored.
             
                          
                          
                            */
                          
                          
                            
            lsr 
                          
                          &= sw_uport->
                          
                            port.read_status_mask;

                          
                          
                            #if
                          
                           IS_ENABLED(CONFIG_SERIAL_SUNXI_CONSOLE)
            
                          
                            if
                          
                           (sw_is_console_port(&sw_uport->
                          
                            port)) {
                
                          
                          
                            /*
                          
                          
                             Recover the break flag from console xmit 
                          
                          
                            */
                          
                          
                            
                lsr 
                          
                          |= sw_uport->
                          
                            lsr_break_flag;
            }

                          
                          
                            #endif
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_BI)
                flag 
                          
                          =
                          
                             TTY_BREAK;
            
                          
                          
                            else
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_PE)
                flag 
                          
                          =
                          
                             TTY_PARITY;
            
                          
                          
                            else
                          
                          
                            if
                          
                           (lsr &
                          
                             SUNXI_UART_LSR_FE)
                flag 
                          
                          =
                          
                             TTY_FRAME;
        }
        
                          
                          
                            if
                          
                           (uart_handle_sysrq_char(&sw_uport->
                          
                            port, ch))
            
                          
                          
                            goto
                          
                          
                             ignore_char;
        
        
                          
                          
                            //
                          
                          
                            printk("sw_uport->name =%s\n",sw_uport->name);
                          
                          
                            /*
                          
                          
                            增加对break的判断
                          
                          
                            */
                          
                          
                                   if((dmx512_devp->start_read_flag) && (strncmp(sw_uport->name,"uart1",5) ==0))
        {    
            if(dmx512_devp->num_break ==1)
            {
                dmx512_devp->dmx_buff[dmx512_devp->recv_len] =ch;
                dmx512_devp->recv_len++;
                if(dmx512_devp->recv_len >= dmx512_devp->r_size)
                {
                    dmx512_devp->start_read_flag = false;
                    dmx512_devp->end_read_flag = true;
     
                }
            }
            else if(dmx512_devp->num_break > 1)
            {
                    dmx512_devp->start_read_flag = false;
                    dmx512_devp->end_read_flag = true;
           

                          
                          
                             } } 
                            
        
        uart_insert_char(
                          
                          &sw_uport->
                          
                            port, lsr, SUNXI_UART_LSR_OE, ch, flag);
ignore_char:
        lsr 
                          
                          = serial_in(&sw_uport->
                          
                            port, SUNXI_UART_LSR);
    } 
                          
                          
                            while
                          
                           ((lsr & (SUNXI_UART_LSR_DR | SUNXI_UART_LSR_BI)) && (max_count-- > 
                          
                            0
                          
                          
                            ));

    SERIAL_DUMP(sw_uport, 
                          
                          
                            "
                          
                          
                            Rx
                          
                          
                            "
                          
                          
                            );
    spin_unlock(
                          
                          &sw_uport->port.
                          
                            lock
                          
                          
                            );
    tty_flip_buffer_push(
                          
                          &sw_uport->port.state->
                          
                            port);
    spin_lock(
                          
                          &sw_uport->port.
                          
                            lock
                          
                          
                            );

    
                          
                          
                            return
                          
                          
                             lsr;
}
                          
                        

  。

3、写应用程序进行验证.

打开设置串口uart1 波特率250000 8 N 2 。

  。

                          #include<stdio.h>
                          
                            
#include
                          
                          <stdlib.h>
                          
                            
#include
                          
                          <
                          
                            string
                          
                          .h>
                          
                            

#include 
                          
                          <sys/time.h>
                          
                            
#include 
                          
                          <sys/types.h>
                          
                            
#include 
                          
                          <sys/stat.h>
                          
                            
#include 
                          
                          <fcntl.h>
                          
                            
#include 
                          
                          <unistd.h>
                          
                            

#include 
                          
                          <termios.h>
                          
                            
#include 
                          
                          <errno.h>
                          
                            
#include 
                          
                          <signal.h>
                          
                            

#include 
                          
                          <stdbool.h>



                          
                            #define
                          
                           UART1_DEV_NAME  "/dev/ttyS1"  /*需根据实际端口修改*/

                          
                            #define
                          
                           DMX512_DEV_NAME "/dev/dmx512_uart"

                          
                            #define
                          
                           BUF_LEN 100

                          
                            #define
                          
                           MAX_BUF 2048



                          
                            int
                          
                           oflags =
                          
                            0
                          
                          
                            ;

                          
                          
                            int
                          
                           fd =-
                          
                            1
                          
                          
                            ;

                          
                          
                            char
                          
                           buff[MAX_BUF] ={
                          
                            0
                          
                          
                            };




                          
                          
                            /*
                          
                          
                            *
*@brief  配置串口
*@param  fd:串口文件描述符. 
         nSpeed:波特率,
         nBits:数据位 7 or 8, 
         nEvent:奇偶校验位,
         nStop:停止位
*@return 失败返回-1;成功返回0;

                          
                          
                            */
                          
                          
                            int
                          
                           set_serial(
                          
                            int
                          
                           fd, 
                          
                            int
                          
                           nSpeed, 
                          
                            int
                          
                           nBits, 
                          
                            char
                          
                           nEvent, 
                          
                            int
                          
                          
                             nStop)
{
    
                          
                          
                            struct
                          
                          
                             termios newttys1, oldttys1;

    
                          
                          
                            /*
                          
                          
                            保存原有串口配置
                          
                          
                            */
                          
                          
                            if
                          
                          (tcgetattr(fd, &oldttys1) != 
                          
                            0
                          
                          
                            )
    {
        perror(
                          
                          
                            "
                          
                          
                            Setupserial 1
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            return
                          
                           - 
                          
                            1
                          
                          
                            ;
    }
    memset(
                          
                          &newttys1, 
                          
                            0
                          
                          , 
                          
                            sizeof
                          
                          
                            (newttys1));
    
                          
                          
                            //
                          
                          
                            memcpy(&newttys1, &oldttys1, sizeof(newttys1));
                          
                          
                            /*
                          
                          
                            CREAD 开启串行数据接收,CLOCAL并打开本地连接模式
                          
                          
                            */
                          
                          
                            
    newttys1.c_cflag 
                          
                          |= (CLOCAL |
                          
                             CREAD);

    newttys1.c_cflag 
                          
                          &=~CSIZE; 
                          
                            /*
                          
                          
                            设置数据位
                          
                          
                            */
                          
                          
                            switch
                          
                          (nBits)    
                          
                            /*
                          
                          
                            数据位选择
                          
                          
                            */
                          
                          
                            
    {
        
                          
                          
                            case
                          
                          
                            7
                          
                          
                            :
            newttys1.c_cflag 
                          
                          |=
                          
                             CS7;
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            8
                          
                          
                            :
            newttys1.c_cflag 
                          
                          |=
                          
                             CS8;
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            default
                          
                          :
                          
                            break
                          
                          
                            ;
    }
    
    
                          
                          
                            switch
                          
                          (nEvent)  
                          
                            /*
                          
                          
                            奇偶校验位
                          
                          
                            */
                          
                          
                            
    {
        
                          
                          
                            case
                          
                          
                            '
                          
                          
                            0
                          
                          
                            '
                          
                          
                            :
            newttys1.c_cflag 
                          
                          |= PARENB; 
                          
                            /*
                          
                          
                            开启奇偶校验
                          
                          
                            */
                          
                          
                            
            newttys1.c_iflag 
                          
                          |= (INPCK | ISTRIP); 
                          
                            /*
                          
                          
                            INPCK打开输入奇偶校验,ISTRIP 去除字符的第八个比特
                          
                          
                            */
                          
                          
                            
            newttys1.c_cflag 
                          
                          |= PARODD; 
                          
                            /*
                          
                          
                            启动奇校验(默认为偶校验)
                          
                          
                            */
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            '
                          
                          
                            E
                          
                          
                            '
                          
                          
                            :
            newttys1.c_cflag 
                          
                          |= PARENB; 
                          
                            /*
                          
                          
                            开启奇偶校验
                          
                          
                            */
                          
                          
                            
            newttys1.c_iflag 
                          
                          |= (INPCK | ISTRIP); 
                          
                            /*
                          
                          
                            INPCK打开输入奇偶校验,ISTRIP 去除字符的第八个比特
                          
                          
                            */
                          
                          
                            
            newttys1.c_cflag 
                          
                          &= ~PARODD; 
                          
                            /*
                          
                          
                            启动偶校验
                          
                          
                            */
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            '
                          
                          
                            N
                          
                          
                            '
                          
                          
                            :
            newttys1.c_cflag 
                          
                          &= ~PARENB; 
                          
                            /*
                          
                          
                            无奇偶校验
                          
                          
                            */
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            default
                          
                          :
                          
                            break
                          
                          
                            ;
    }
    
    
                          
                          
                            switch
                          
                          (nSpeed) 
                          
                            /*
                          
                          
                            设置波特率
                          
                          
                            */
                          
                          
                            
    {
        
                          
                          
                            case
                          
                          
                            2400
                          
                          
                            :
            cfsetispeed(
                          
                          &
                          
                            newttys1, B2400);
            cfsetospeed(
                          
                          &
                          
                            newttys1, B2400);
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            4800
                          
                          
                            :
            cfsetispeed(
                          
                          &
                          
                            newttys1, B4800);
            cfsetospeed(
                          
                          &
                          
                            newttys1, B4800);
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            9600
                          
                          
                            :
            cfsetispeed(
                          
                          &
                          
                            newttys1, B9600);
            cfsetospeed(
                          
                          &
                          
                            newttys1, B9600);
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            115200
                          
                          
                            :
            cfsetispeed(
                          
                          &
                          
                            newttys1, B115200);
            cfsetospeed(
                          
                          &
                          
                            newttys1, B115200);
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            case
                          
                          
                            250000
                          
                          
                            :
            
                          
                          
                            //
                          
                          
                            ret = cfsetispeed(&newttys1, 0020001);
            
                          
                          
                            //
                          
                          
                            printf("reti = %d\n",ret);
            
                          
                          
                            //
                          
                          
                            ret = cfsetospeed(&newttys1, 0020001);        
            
                          
                          
                            //
                          
                          
                            printf("reto = %d\n",ret);
                          
                          
            newttys1.c_cflag |= 
                          
                            0020001
                          
                          
                            ;
            
                          
                          
                            break
                          
                          
                            ;
        
                          
                          
                            default
                          
                          
                             :
            cfsetispeed(
                          
                          &
                          
                            newttys1, B9600);
            cfsetospeed(
                          
                          &
                          
                            newttys1, B9600);
            
                          
                          
                            break
                          
                          
                            ;
    }
    
    
                          
                          
                            /*
                          
                          
                            设置停止位
                          
                          
                            */
                          
                          
                            /*
                          
                          
                            停止位为1,则清除CSTOPB,如停止位为2,则激活CSTOPB
                          
                          
                            */
                          
                          
                            if
                          
                          (nStop == 
                          
                            1
                          
                          
                            )
    {
        newttys1.c_cflag 
                          
                          &= ~CSTOPB;  
                          
                            /*
                          
                          
                            默认为停止位1
                          
                          
                            */
                          
                          
                            
    }
    
                          
                          
                            else
                          
                          
                            if
                          
                          (nStop == 
                          
                            2
                          
                          
                            )
    {
        newttys1.c_cflag 
                          
                          |=
                          
                             CSTOPB;
    }

    newttys1.c_iflag 
                          
                          &=~(PARMRK); 
                          
                            /*
                          
                          
                            不设置的
                          
                          
                            */
                          
                          
                            

    newttys1.c_iflag 
                          
                          |= IGNBRK ; 
                          
                            /*
                          
                          
                            设置的
                          
                          
                            */
                          
                          
                            
    printf(
                          
                          
                            "
                          
                          
                            newttys1.c_iflag= 0x%\n
                          
                          
                            "
                          
                          
                            ,newttys1.c_iflag);


    
                          
                          
                            /*
                          
                          
                            设置最少字符和等待时间,对于接收字符和等待时间没有特别的要求时
                          
                          
                            */
                          
                          
                            
    newttys1.c_cc[VTIME] 
                          
                          = 
                          
                            0
                          
                          ; 
                          
                            /*
                          
                          
                            非规范模式读取时的超时时间
                          
                          
                            */
                          
                          
                            
    newttys1.c_cc[VMIN] 
                          
                          = 
                          
                            0
                          
                          ; 
                          
                            /*
                          
                          
                            非规范模式读取时的最小字符数
                          
                          
                            */
                          
                          
                            /*
                          
                          
                            tcflush 清空终端未完成的输入、输出请求及数据
    TCIFLUSH表示清空正接收到的数据,且不读取出来
                          
                          
                            */
                          
                          
                            
    tcflush(fd, TCIFLUSH);

    
                          
                          
                            /*
                          
                          
                            激活配置使其生效
                          
                          
                            */
                          
                          
                            if
                          
                          ((tcsetattr(fd, TCSANOW, &newttys1)) != 
                          
                            0
                          
                          
                            )
    {
        perror(
                          
                          
                            "
                          
                          
                            usart set error
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            return
                          
                           - 
                          
                            1
                          
                          
                            ;
    }

    
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;
}


                          
                          
                            int
                          
                           main(
                          
                            int
                          
                           argc,
                          
                            char
                          
                          
                            const
                          
                           *
                          
                             argv[])
{

    
                          
                          
                            int
                          
                           ret =-
                          
                            1
                          
                          
                            ;
    
                          
                          
                            int
                          
                           i =
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           n =
                          
                            0
                          
                          
                            ;
    
                          
                          
                            int
                          
                           len =
                          
                             BUF_LEN;
    
                          
                          
                            int
                          
                           baud = 
                          
                            250000
                          
                          
                            ;
    
                          
                          
                            int
                          
                           fd_dmx512 =-
                          
                            1
                          
                          
                            ;

    
                          
                          
                            struct
                          
                          
                             sigaction saio;
    
    
                          
                          
                            if
                          
                          (argc !=
                          
                            2
                          
                          
                            )
    {
        printf(
                          
                          
                            "
                          
                          
                            arg is not 2,arg is app baud_rate\n
                          
                          
                            "
                          
                          
                            );
    }
    
                          
                          
                            if
                          
                          (argc == 
                          
                            2
                          
                          
                            )
        baud 
                          
                          = atoi(argv[
                          
                            1
                          
                          
                            ]);
    printf(
                          
                          
                            "
                          
                          
                            baud =%d\n
                          
                          
                            "
                          
                          
                            ,baud);
    fd 
                          
                          = open(UART1_DEV_NAME, O_RDWR | O_NOCTTY |
                          
                             O_NDELAY);
    
                          
                          
                            if
                          
                          (fd < 
                          
                            0
                          
                          
                            )
    {
        perror(
                          
                          
                            "
                          
                          
                            Can't open uart1 port
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            return
                          
                          (
                          
                            void
                          
                           *)
                          
                            "
                          
                          
                            uart1 dev error
                          
                          
                            "
                          
                          
                            ;
    }
    ret 
                          
                          = set_serial(fd,baud, 
                          
                            8
                          
                          , 
                          
                            '
                          
                          
                            N
                          
                          
                            '
                          
                          , 
                          
                            2
                          
                          ); 
                          
                            /*
                          
                          
                            可能需要根据情况调整
                          
                          
                            */
                          
                          
                            if
                          
                          (ret < 
                          
                            0
                          
                          
                            )
    {
        printf(
                          
                          
                            "
                          
                          
                            set_serial error\n
                          
                          
                            "
                          
                          
                            );
        
                          
                          
                            return
                          
                           -
                          
                            1
                          
                          
                            ;    
    }

    
                          
                          
                            while
                          
                          (
                          
                            1
                          
                          
                            )
    {
        fd_dmx512 
                          
                          =
                          
                            open(DMX512_DEV_NAME,O_RDONLY);
        
                          
                          
                            if
                          
                          (fd_dmx512 < 
                          
                            0
                          
                          
                            )
        {
            printf(
                          
                          
                            "
                          
                          
                            open dmx512 device error\n
                          
                          
                            "
                          
                          
                            );
            
                          
                          
                            return
                          
                           -
                          
                            1
                          
                          
                            ;
        }
       memset(buff,
                          
                          
                            0
                          
                          ,
                          
                            sizeof
                          
                          
                            (buff));
        printf(
                          
                          
                            "
                          
                          
                            Read start\n
                          
                          
                            "
                          
                          
                            );
        n 
                          
                          = read(fd_dmx512,buff,
                          
                            600
                          
                          
                            );
        printf(
                          
                          
                            "
                          
                          
                            Read end\n
                          
                          
                            "
                          
                          
                            );
        printf(
                          
                          
                            "
                          
                          
                            num=%d :
                          
                          
                            "
                          
                          
                            ,n);
        
                          
                          
                            for
                          
                          (i=
                          
                            0
                          
                          ;i<n;i++
                          
                            )
            printf(
                          
                          
                            "
                          
                          
                            %02x 
                          
                          
                            "
                          
                          
                            ,buff[i]);
        printf(
                          
                          
                            "
                          
                          
                            \n
                          
                          
                            "
                          
                          
                            );
    
        ret 
                          
                          =
                          
                             close(fd_dmx512);
        
                          
                          
                            if
                          
                          (ret < 
                          
                            0
                          
                          
                            )
            printf(
                          
                          
                            "
                          
                          
                            close error\n
                          
                          
                            "
                          
                          
                            );
    
        sleep(
                          
                          
                            5
                          
                          
                            );
    }

    
                          
                          
                            return
                          
                          
                            0
                          
                          
                            ;
}
                          
                        

  。

通过测试后正常读取到串口数据 。

  。

  。

  。

  。

DMX512协议解析 。

(1)采用RS-485总线收发器,差分电压进行传输的,抗干扰能力强,信号可以进行长距离传输; (2)不论调光数据是否需要改变,主机都必须发送控制信号。 (3)由于数据帧之间的时间小于1s,所以在1s内没有收到新的数据帧,说明信号已经丢失; (4)因为是数据是调光用的,使用环境是不做安全要求的设备, 并且是不间断传输的,所以不需要复杂的校验.

dmx512协议串口波特率为250000 。

一个bit位 4us 8个位(Slot:x) 4*8=32us,x是从1到512 。

  。

break 88us(范围是88μs——1ms) MAB(Mark After Break) 8us 两个bit位的时间,高电平 start bit 4us 是低电平 Start Code(SC) 32us,8个位,是一段低电平,必须要有,串口表现中数据是0,接收时作头的一部分 stop 8us 两位结束,是高电平 MTBP 0-1s(MARK Time aftet slot,每一个数据间隔的空闲时间,是高电平,可以不要.

一帧数据包括 start + Slotx: + stop + MTBP = 4+32+8+0=44us

  。

参考文档 。

(19条消息) DMX512协议解析_春风得意吃火锅的博客-CSDN博客_dmx512协议标准 。

(19条消息) tty驱动 read 过程梳理_0x460的博客-CSDN博客 。

最后此篇关于Linux驱动像单片机一样读取一帧dmx512串口数据的文章就讲到这里了,如果你想了解更多关于Linux驱动像单片机一样读取一帧dmx512串口数据的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com