差分对传输数据的原理,IO数据的传输-------》差分对。
RS232传输的距离在15米以下,RS485传输距离是几十米到1000米以上。
为什么485可以传输这么远?差分对的机制可以降低电磁场的干扰、衰减。
485传输距离和传输线有关系 注意:双绞线和屏蔽线。
485原理图:
嵌入式上一般使用串口转485
串口的信号转化为485:D→(A,B)DE高电平,RE高电平
485信号转化为串口信号:(A,B),DE低电平,RD低电平
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
2、注册设备
#ifdef CONFIG_MAX485_CTL
struct platform_device s3c_device_max485_ctl = {
.name = "max485_ctl",
.id = -1,
};
#endif
#ifdef CONFIG_MAX485_CTL
&s3c_device_max485_ctl ,
#endif
config MAX485_CTL
bool "Enable MAX485 pin config"
default y
help
Enable MAX485 pin config
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");
#!/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