分类: LINUX
2008-11-12 22:37:23
近来有一个项目要在ARM9上用到一个485总线,这开始想来不太好做,可是做起来也很容易,这就把我的做法在这里做个记录,要是有兴趣的朋友可以看看;
先把一个串口的R,D分别接到MAX485的R,D接口,然后接一根不用的引脚到485的控制脚,只要在发送数据时把该引脚置高,接收时置低就好
下面是该引脚的GPIO驱动:
//GPIO_drv.h
#ifndef _GPIO_H_
#define _GPIO_H_
#include
#define GPIO_IOC_MAGIC 'k'
#define IOCLR _IO(GPIO_IOC_MAGIC, 11)
#define IOSET _IO(GPIO_IOC_MAGIC, 12)
#define IOGET _IO(GPIO_IOC_MAGIC, 13)
#define GPC14 (1<<14)
#define GPC15 (1<<15)
#define GPC22 (1<<22)
#endif /* _GPIO_H_ */
//gpio_drv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define TEST
#include "gpio_driv.h"
#define IOPORT_MAJOR 220
typedef char ioport_device_t;
long port_addr;
static ioport_device_t gpio_devices[257];
int gpio_open(struct inode*,struct file *);
int gpio_release(struct inode*,struct file *);
int gpio_ctl_ioctl(struct inode*,struct file *, unsigned int, unsigned long);
static struct file_operations gpio_ctl_fops= {
ioctl:gpio_ctl_ioctl,
open:gpio_open,
release:gpio_release,
};
int __init gpio_init(void){
int ret;
ret = register_chrdev(IOPORT_MAJOR, "gpio_driv", &gpio_ctl_fops);
if (ret < 0) {
printk(KERN_WARNING "gpio: can't get major %d\n", IOPORT_MAJOR);
return ret;
}
return 0;
}
void gpio_exit(void)
{
unregister_chrdev(IOPORT_MAJOR, "gpio_driv");
}
module_init(gpio_init);
module_exit(gpio_exit);
AT91PS_SYS AT91_SYS = (AT91PS_SYS) AT91C_VA_BASE_SYS;
int gpio_open(struct inode*inode,struct file *file)
{
int minor;
minor = MINOR(inode->i_rdev);
#ifdef TEST
//test
//PB0&1,PB0 out,PB1 in
AT91_SYS->PMC_PCER |= 1<
AT91_SYS->PIOB_OER |= 1<<0;
AT91_SYS->PIOB_ODR |= 2<<0;
AT91_SYS->PIOB_PER |= 3<<22;
AT91_SYS->PIOB_OER |= 1<<22;
AT91_SYS->PIOB_ODR |= 2<<22;
#endif
AT91_SYS->PMC_PCER |= (1<
AT91_SYS->PIOC_OER |= (0x3<<14);
gpio_devices[minor]++;
return 0;
}
int gpio_release(struct inode *inode,struct file *file)
{
int minor;
minor = MINOR(inode->i_rdev);
if (gpio_devices[minor])
gpio_devices[minor]--;
return 0;
}
int gpio_ctl_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
//int minor = MINOR(inode->i_rdev);
int ret = 0;
int local;
switch (cmd) {
case IOSET:
if (arg == GPC14) {
#ifdef TEST
AT91_SYS->PIOB_SODR |= ( 1<<0 );
#endif
AT91_SYS->PIOC_SODR |= (1<<14);
}
else if (arg == GPC15) {
AT91_SYS->PIOC_SODR |= (1<<15);
}
else if (arg==GPC22){
AT91_SYS->PIOB_SODR |= (1<<22);
}
break;
case IOCLR:
if (arg == GPC14) {
#ifdef TEST
AT91_SYS->PIOB_CODR |= ( 1<<0 );
#endif
AT91_SYS->PIOC_CODR |= (1<<14);
}
else if (arg == GPC15) {
AT91_SYS->PIOC_CODR |= (1<<15);
}
else if (arg==GPC22){
AT91_SYS->PIOB_CODR |= (1<<22);
}
break;
case IOGET:
#ifdef TEST
local = AT91_SYS->PIOB_PDSR;
#else
local = AT91_SYS->PIOC_PDSR;
#endif
ret = put_user(local, ((unsigned int *)arg));
break;
}
return ret;
}
我用的是PB22脚,这你们可以根据自已的要求改,
下面是该驱动的测试程序
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_GPIODRIV "/dev/gpio_driv"
#include "gpio_driv.h"
int main(void)
{
int fd;
int val=-1;
int c;
if((fd=open(DEVICE_GPIODRIV,O_RDWR | O_NONBLOCK))<0)
{
perror("can not open device");
exit(1);
}
while(1) {
printf("gpio test select:\n");
printf("0-get 1-set/clr 2-GPC22Low 3-GPC22High 4-exit");
scanf("%d", &c);
if(c==0) {
// GET test
for(;;)
{
int t;
ioctl(fd,IOSET, GPC14);
ioctl(fd,IOGET, (unsigned long)(&t));
printf("%d",(t&0x2)?1:0);
ioctl(fd,IOCLR, GPC14);
ioctl(fd,IOGET, (unsigned long)(&t));
printf("%d",(t&0x2)?1:0);
}
}
else if (c==1) {
// SET & CLR test
for(;;) {
ioctl(fd, IOSET, GPC14);
usleep(100000);
ioctl(fd, IOCLR, GPC14);
usleep(100000);
ioctl(fd, IOSET, GPC15);
usleep(100000);
ioctl(fd, IOCLR, GPC15);
usleep(100000);
}
}
else if(c==2){
ioctl(fd, IOCLR, GPC22);
}
else if(c==3){
ioctl(fd, IOSET, GPC22);
}
else if (c==4) {
for(;;) {
ioctl(fd, IOSET, GPC22);
usleep(100000);
ioctl(fd, IOCLR, GPC22);
usleep(100000);
}
}
else if (c==5) {
close(fd);
exit(0);
}
}
close(fd);
}