⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 串口驱动.txt

📁 嵌入式系统的串口驱动程序
💻 TXT
字号:
utrs_driver.h
----------------------------------------------------------------------------------------------------------------
#include<asm/hardware.h>
#define UART_ULCON1   __REG(0x50004000 + 0x00)
#define UART_UCON1     __REG(0x50004000 + 0x04)
#define UART_URXH1      __REG(0x50004000 + 0x24)
#define UART_UTXH1      __REG(0x50004000 + 0x20)
#define UART_UBRDIV1   __REG(0x50004000 + 0x28)
#define UART_UTRSTAT1 __REG(0x50004000 + 0x10)
----------------------------------------------------------------------------------------------------------------
utrs_driver.c
----------------------------------------------------------------------------------------------------------------
#include <linux/config.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/sched.h> 
#include <linux/miscdevice.h> 
#include <linux/delay.h> 
#include <linux/poll.h> 
#include <asm/hardware.h> 
#include "utrs_driver.h" 
 
#define DEVICE_NAME  "akem"    //设备文件名
#define BUTTON_MAJOR 232      //主设备号
 
/* 打开驱动inode结构在内部表示文件,file结构是打开上面传来的文件描述符fd对应的file结构,file结构都指向单个inode */
static int akem_open(struct inode *inode, struct file * file) 
{ 
     /* 设置寄存器 */
    UART_UCON1 = 0x05; 
    UART_ULCON1 = 0x03; 
 
    printk("Kernel : in open,we do nothing......\n"); 
    return 0; 
} 
 
/* 从设备读取数据,上层的read函数会调用到这里,file是read的fd对应的结构, ppos是系统回调 */
static int akem_read(struct file * file, char * buff, size_t count, loff_t *ppos) 
{ 
    int i; 
    unsigned char ch; 

    for(i = 0; i < count; i++) 
    { 
        while(!(UART_UTRSTAT1 & 0x1));   /* 扫描寄存器是否有数据 */
        ch = UART_URXH1;                          /*  从寄存器里读出一个字节 */
        *(buff + i) = ch;                                  /*  存放在buff里 */
    }
      return strlen(buff);                               /* 返回buff的长度 */
} 

 /* 向设备写入数据,上层的write函数会调用到这里,file是write的fd对应的结构, offp是系统回调 */
int akem_write( struct file *filp, const char *buff, size_t count, loff_t *offp ) 
{ 
    int i; 
    unsigned char ch; 
     
    for(i = 0; i < count; i++) 
    { 
        ch = *(buff + i);  
        while(!((UART_UTRSTAT1 & 0x2) == 0x2));     /* 扫描寄存器是否有数据 */
        UART_UTXH1 = ch;                                           /* 把一格字节写入寄存器 */
    }
    return 0; 
} 
 /*  设置串口的波特率 */
static int akem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 
{ 
    int ret; 
    ret = -EINVAL; 
      switch(cmd)  
    { 
        case 111:      /* 功过命令来配置波特率 */
        { 
            if(arg == 115200) 
            { 
                UART_UBRDIV1 = 26; 
                ret = 0; 
            } 
        }; break; 
 
          default: 
        return -EINVAL; 
      } 
 
    printk("Kernel : in ioctl, (%d, %d)\n", cmd, arg);
} 
 
int akem_release(struct inode *inode, struct file *filp) 
{ 
    printk("release!!\n"); 
    return 0; 
} 
 /* file_operations结构是建立驱动程序和设备编号的连接,内部是一组函数指针,每个打开的文件,也就是file结构,和一组函数关联,这些操作主要用来实现系统调用的 */
static struct file_operations akae_fops = { 
 
      owner:  THIS_MODULE, 
      open:     akae_open, 
      ioctl:     akae_ioctl, 
      read:     akae_read, 
    write:    akae_write, 
    release:    akae_release 
 
}; 
 /* 初始化驱动模块,驱动程序要注册一个设备文件,并对其进行操作 */
static int __init akem_init(void) 
{ 
      int ret; 
      int ready = 0; 
      /* 注册一个字符设备,并分配设备编号,major是设备号,name是驱动程序名称 fops是file_operations结构 */
      ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &akae_fops); 
      
      if (ret < 0)  
    { 
        printk(DEVICE_NAME " can't register major number\n"); 
        return ret; 
     }
      printk(" init ok!......\n"); 
      return 0;        /* 注册成功返回0 */
} 
 /*  卸载模块 */
static void __exit akem_exit(void) 
{ 
      /* 如果不使用该设备时释放编号 */
      unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); 
      printk("bye !\n"); 
} 
 
module_init(akem_init); 
module_exit(akem_exit); 
MODULE_LICENSE("GPL");
----------------------------------------------------------------------------------------------------------------
test.c       测试模块
这个测试模快是以应用程序调用驱动,而不以模块的形式加载,所以这正是驱动本质
----------------------------------------------------------------------------------------------------------------
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define BOUNDRATE 111     /*  设置伯特率命令参数  */
int main(void)
{
  int fd;
  int ret = 0;
  char buf[100] = "HELLO FUCK!\n\r";
  char ch;
  fd = open("/temp/akem", O_RDWR);   /* open会直接调用到驱动里的akem_open */
  if(fd == -1)
  {
    perror("open");
    exit(1);
  }
  ret = ioctl(fd, BOUNDRATE, 115200);      /*  设置伯特律115200 */
  ret = write(fd, buf, strlen(buf));     /* write会调用驱动里的akem_write  */
  if(ret == -1)
  {
    perror("write error");
    exit(1);
  }
  while(ch != '#')
  {
   read(fd, &ch,1);
   printf("%c",ch);
   fflush(stdout);
  }
  close(fd);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -