031_Linux驱动下的RS485总线

一、RS485硬件原理

差分对传输数据的原理,IO数据的传输-------》差分对。
RS232传输的距离在15米以下,RS485传输距离是几十米到1000米以上。
为什么485可以传输这么远?差分对的机制可以降低电磁场的干扰、衰减。
485传输距离和传输线有关系 注意:双绞线和屏蔽线。

485原理图:

031_Linux驱动下的RS485总线_第1张图片

031_Linux驱动下的RS485总线_第2张图片

嵌入式上一般使用串口转485

							串口的信号转化为485:D→(A,B)DE高电平,RE高电平
							485信号转化为串口信号:(A,B),DE低电平,RD低电平


二、RS485驱动

1、RS485驱动

串口驱动在源码顶层目录下的drivers/char/max485_ctl.c

485驱动=串口驱动+GPIO的字符驱动
XURTS1高电平发送,低电平接收
GPIO是GPA0_7,串口设备节点是ttySAC1)
驱动中只需要操作GPIO
设备节点/dev/max485_ctl
在应用层中,控制GPIO和串口=类似led+串口的操作
ioctl是参数是1,则输出高电平,发送
ioctl是参数是0,则输出低电平,接收
串口的节点/dev/ttySAC1

031_Linux驱动下的RS485总线_第3张图片

在这里插入图片描述
2、注册设备

#ifdef CONFIG_MAX485_CTL
struct platform_device s3c_device_max485_ctl = {
        .name   = "max485_ctl",
        .id             = -1,
};
#endif

031_Linux驱动下的RS485总线_第4张图片

#ifdef CONFIG_MAX485_CTL
    &s3c_device_max485_ctl ,
#endif

031_Linux驱动下的RS485总线_第5张图片

config MAX485_CTL
        bool "Enable MAX485 pin config"
        default y
        help
          Enable MAX485 pin config

031_Linux驱动下的RS485总线_第6张图片

031_Linux驱动下的RS485总线_第7张图片



三、驱动测试源码

max485_ctl.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
#include 
#include 
#include    //cwp, PMIC interafce
//#include "gps.h"
#include 

#define GPS_DEBUG
#ifdef GPS_DEBUG
#define DPRINTK(x...) printk("MAX485_CTL DEBUG:" x)
#else
#define DPRINTK(x...)
#endif

#define DRIVER_NAME "max485_ctl"

int max485_ctl_open(struct inode *inode,struct file *filp)
{
    DPRINTK("Device Opened Success!\n");
    return nonseekable_open(inode,filp);
}

int max485_ctl_release(struct inode *inode,struct file *filp)
{
    DPRINTK("Device Closed Success!\n");
    return 0;
}

int max485_ctl_pm(bool enable)
{
    int ret = 0;
    printk("firecxx debug: GPS PM return %d\r\n" , ret);
    return ret;
};

long max485_ctl_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
    printk("firecxx debug: max485_ctl_ioctl cmd is %d\n" , cmd);

    switch(cmd)
    {       
        case 1:
            if(gpio_request(EXYNOS4_GPA0(7) ,"GPA0_7"))
            {
                DPRINTK("max485_ctl GPIO err!\r\n");
            }
            else
            {
                gpio_direction_output(EXYNOS4_GPA0(7), 1);
                DPRINTK("max485_ctl Set High!\n");
                gpio_free(EXYNOS4_GPA0(7));

                mdelay(100);
            }
                
            break;
        case 0:
            if(gpio_request(EXYNOS4_GPA0(7) ,"GPA0_7"))
            {
                DPRINTK("max485_ctl GPIO err!\r\n");
            }
            else
            {           
                gpio_direction_output(EXYNOS4_GPA0(7),0);
                DPRINTK("max485_ctl Set Low!\n");
                gpio_free(EXYNOS4_GPA0(7));

                mdelay(100); 
            }
            
            break;
            
        default:
            DPRINTK("max485_ctl COMMAND ERROR!\n");
            return -ENOTTY;
    }
    return 0;
}

static struct file_operations max485_ctl_ops = {
    .owner  = THIS_MODULE,
    .open   = max485_ctl_open,
    .release= max485_ctl_release,
    .unlocked_ioctl     = max485_ctl_ioctl,
};

static struct miscdevice max485_ctl_dev = {
    .minor  = MISC_DYNAMIC_MINOR,
    .fops   = &max485_ctl_ops,
    .name   = "max485_ctl_pin",
};


static int max485_ctl_probe(struct platform_device *pdev)
{
    int err = 0;
    
    int ret;
    char *banner = "max485_ctl Initialize\n";

    printk(banner);

    err = gpio_request(EXYNOS4_GPA0(7), "GPA0_7");
    if (err) {
        printk(KERN_ERR "failed to request GPA0_7 for "
            "max485_ctl control\n");
        return err;
    }
    gpio_direction_output(EXYNOS4_GPA0(7), 1);

    s3c_gpio_cfgpin(EXYNOS4_GPA0(7), S3C_GPIO_OUTPUT);
    gpio_free(EXYNOS4_GPA0(7));

    ret = misc_register(&max485_ctl_dev);
    if(ret<0)
    {
        printk("max485_ctl:register device failed!\n");
        goto exit;
    }

    return 0;

exit:
    misc_deregister(&max485_ctl_dev);
    return ret;
}

static int max485_ctl_remove (struct platform_device *pdev)
{
    misc_deregister(&max485_ctl_dev);   

    return 0;
}

static int max485_ctl_suspend (struct platform_device *pdev, pm_message_t state)
{
    DPRINTK("max485_ctl suspend:power off!\n");
    return 0;
}

static int max485_ctl_resume (struct platform_device *pdev)
{
    DPRINTK("max485_ctl resume:power on!\n");
    return 0;
}

static struct platform_driver max485_ctl_driver = {
    .probe = max485_ctl_probe,
    .remove = max485_ctl_remove,
    .suspend = max485_ctl_suspend,
    .resume = max485_ctl_resume,
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
    },
};

static void __exit max485_ctl_exit(void)
{
    platform_driver_unregister(&max485_ctl_driver);
}

static int __init max485_ctl_init(void)
{
    return platform_driver_register(&max485_ctl_driver);
}

module_init(max485_ctl_init);
module_exit(max485_ctl_exit);

MODULE_LICENSE("Dual BSD/GPL");


四、Makefile

#!/bin/bash
$(warning KERNELRELEASE = $(KERNELRELEASE))

ifeq ($(KERNELRELEASE),)

#内核的源码路径, ?= 条件赋值, uname -r 得到内核版本号
KERNELDIR ?=  /home/mint/itop/linux_3.0

# := 立即赋值, 得到当前的绝对路径
PWD := $(shell pwd)


# -C 切换工作路径, $(MAKE) =  make
modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*

.PHONY: modules clean

else
      # 生成模块
       obj-m := max485_clt.o 
    
endif


五、应用层测试源码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX485_CONTROL

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if  ( tcgetattr( fd,&oldtio)  !=  0) { 
        perror("SetupSerial 1");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

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

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

    printf("Baund Rate: %d\n", nSpeed);

    switch( nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    case 921600:
        printf("Rate:921600\n");
        cfsetispeed(&newtio, B921600);
                cfsetospeed(&newtio, B921600);
                break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if( nStop == 1 )
        newtio.c_cflag &=  ~CSTOPB;
    else if ( nStop == 2 )
    newtio.c_cflag |=  CSTOPB;
    newtio.c_cc[VTIME]  = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");
        return -1;
    }
//  printf("set done!\n\r");
    return 0;
}

int prepare_to_send(int fd)
{
    int ret;

    ret = ioctl(fd, 1, 0);
    if(ret<0)
    {
        printf("max485 set ctl to high failed!\r\n");

        return -1;
    }
    else
    {
        return 0;
    }
}

int prepare_to_recv(int fd)
{
    int ret;

    ret = ioctl(fd, 0, 0);
    if(ret<0)
    {
        printf("max485 set ctl to low failed!\r\n");
        
        return -1;
    }
    else
    {
        return 0;
    }
}

int main(int argc, const char* argv[])
{
    // unsigned char ucTmp;
    int fd1,fd2,nset1,nset2,nread;

    char buf[100];
    //char buf1[1];

    //char *buff = "Hello\n\r";

    int i = 0;

    char *max485_ctl = "/dev/max485_ctl_pin";

    if(3 != argc)
        {
        printf("Usage:  test_485 [uart port] [type]\r\n");
        printf("        type: 0--recv, 1--send\r\n");
            
        return 0;
    }

    fd1 = open(argv[1], O_RDWR);
    if (fd1 == -1)
    {
        printf("Open %s faild\n", argv[1]);
        exit(1);
    }

    nset1 = set_opt(fd1, 9600, 8, 'N', 1);
    if (nset2 == -1)
    {
        printf("Set uart faild\n");
        exit(1);
    }

#ifdef MAX485_CONTROL
    if((fd2=open(max485_ctl, O_RDWR|O_NOCTTY|O_NDELAY))<0)
    {
        printf("Open %s faild\n", max485_ctl);
        close(fd1);
        
        exit(1);
    }
#endif
    
    if(0 == atoi(argv[2]))  //recv
    {
#ifdef MAX485_CONTROL
        prepare_to_recv(fd2);
#endif
        while(1)
        {   
            
            nread = read(fd1, buf, 100);
            if (nread > 0)
            {
                for(i=0; i<nread; i++)
                {
                    printf("%c", buf[i]);
            
                    if(buf[i] == 'q')
                        //break;
                        goto exit;
                }
            }
            //if(nread)
            //{
            //  printf("\r\n");
            //}
            sleep(1);
        }
    }
    else    //send 
    {
#ifdef MAX485_CONTROL
        prepare_to_send(fd2);
#endif
        while(1)
        {
            printf("Send data, time:%d\r\n", i);
            sprintf(buf, "iTOP-4412: max485 test app(times:%d)\r\n", i++);
            //nread = write(fd1, "iTOP-4412: max485 test app\r\n", strlen("iTOP-4412: max485 test app\r\n"));
            nread = write(fd1, buf, strlen(buf));
            sleep(1);
#if 0
            nread = read(fd1, buf, 100);
                        if (nread > 0)
                        {
                                for(i=0; i<nread; i++)
                                {
                                        printf("%c", buf[i]);

                                        if(buf[i] == 'q')
                                                //break;
                                                goto exit;
                                }
                        }
                        if(nread)
                        {
                                printf("\r\n");
                        }
#endif
        }
    }
exit:
    close(fd1);

        return 0;
}


六、测试

运行程序 

	发送./test_485 /dev/ttySAC1 1
	
测试程序发送的信息:iTOP-4412: max485 test app(times:%d)	



	接收./test_485 /dev/ttySAC1 0

注:曾经测试过,代码没有问题,测试内容以后需要优化!!


你可能感兴趣的:(itop-4412,精英版inux驱动)