有了led驱动的经验,自己也尝试着写了个1602的驱动,引脚定义:
源码如下:
- #include
- #include
- #include
- #include // Required for the GPIO functions
- #include
- #include
- #include
- static struct class *lcd_class;
- static struct device *lcd_drv;
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("yang yongsheng");
- MODULE_DESCRIPTION("A LCD test driver for the BBB");
- MODULE_VERSION("0.1");
- static unsigned int D7 = 69; ///< hard coding the LCD_D7 gpio for this example to P8_9
- static unsigned int D6 = 68; ///< hard coding the LCD_D7 gpio for this example to P8_10
- static unsigned int D5 = 67; ///< hard coding the LCD_D7 gpio for this example to P8_8
- static unsigned int D4 = 66; ///< hard coding the LCD_D7 gpio for this example to P8_7
- static unsigned int EN = 45; ///< hard coding the LCD_D7 gpio for this example to P8_11
- static unsigned int RW = 44; ///< hard coding the LCD_D7 gpio for this example to P8_12
- static unsigned int RSET = 23; ///< hard coding the LCD_D7 gpio for this example to P8_13
- //static bool On = 0; ///< Is the LED on or off? Used to invert its state (off by default)
- static unsigned int major;
- #define LCD1602_MAGIC 'L'
- #define LCD_CLR _IO(LCD1602_MAGIC, 0)
- #define LCD_ONE _IO(LCD1602_MAGIC, 1)
- #define LCD_TWO _IO(LCD1602_MAGIC, 2)
- void wr4port(char value)
- {
- unsigned char temp,i;
- i=0;
- switch(i)
- {
- case 0:temp=value&0x01;if(temp == 1) gpio_set_value(D4,true);else gpio_set_value(D4,false);i++;
- case 1:temp=value&0x02;if(temp == 0x02) gpio_set_value(D5,true);else gpio_set_value(D5,false);i++;
- case 2:temp=value&0x04;if(temp == 0x04) gpio_set_value(D6,true);else gpio_set_value(D6,false);i++;
- case 3:temp=value&0x08;if(temp == 0x08) gpio_set_value(D7,true);else gpio_set_value(D7,false);i++;break;
- default: break;
- }
- }
- void wrcom(char com)
- {
- gpio_set_value(EN,false);
- gpio_set_value(RW,false);
- gpio_set_value(RSET,false);
- wr4port(com>>4);
- udelay(10);
- gpio_set_value(EN,true);
- udelay(10);
- gpio_set_value(EN,false);
- wr4port(com);
- udelay(10);
- gpio_set_value(EN,true);
- udelay(10);
- gpio_set_value(EN,false);
-
- }
- void wrdat(char dat)
- {
- gpio_set_value(EN,false);
- gpio_set_value(RW,false);
- gpio_set_value(RSET,true);
- wr4port(dat>>4);
- udelay(10);
- gpio_set_value(EN,true);
- udelay(10);
- gpio_set_value(EN,false);
- wr4port(dat);
- udelay(10);
- gpio_set_value(EN,true);
- udelay(10);
- gpio_set_value(EN,false);
- }
- static int lcd_open(struct inode *inode, struct file *file)
- {
- printk("bbb's led gpio60 will open.n");
- wrcom(0x28);
- msleep(5);
- wrcom(0x0f);
- msleep(5);
- wrcom(0x06);
- msleep(5);
- wrcom(0x80);
- msleep(5);
- return 0;
- }
- static ssize_t lcd_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
- {
- char val[17];
- char i = 0;
- printk("write bbb's lcd.n");
- copy_from_user(val, buf, count);
- while((val[i] != '\0')&&(i
- {
- wrdat(val[i]);
- i++;
- }
- return 0;
- }
- static ssize_t lcd_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
- {
- return 0;
- }
- static long lcd_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
- {
- switch(cmd)
- {
- case LCD_CLR:
- wrcom(0x01);break;
- case LCD_ONE:
- wrcom(0x80);break;
- case LCD_TWO:
- wrcom(0xc0);break;
- default:
- printk("unknown command.n");
- }
- return 0;
- }
- static struct file_operations lcd_fops = {
- .owner = THIS_MODULE,
- .open = lcd_open,
- .write = lcd_write,
- .read = lcd_read,
- .unlocked_ioctl = lcd_ioctl,
-
- };
- static int __init lcd_init(void){
- int result = 0;
- printk(KERN_INFO "GPIO_TEST: Initializing the LCD_GPIO LKMn");
- // Is the GPIO a valid GPIO number (e.g., the BBB has 4x32 but not all available)
- if (!gpio_is_valid(D7)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_D7n");
- return -ENODEV;
- }
- if (!gpio_is_valid(D6)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_D6n");
- return -ENODEV;
- }
- if (!gpio_is_valid(D5)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_D5n");
- return -ENODEV;
- }
- if (!gpio_is_valid(D4)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_D4n");
- return -ENODEV;
- }
- if (!gpio_is_valid(RW)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_RWn");
- return -ENODEV;
- }
- if (!gpio_is_valid(EN)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_ENn");
- return -ENODEV;
- }
- if (!gpio_is_valid(RSET)){
- printk(KERN_INFO "GPIO_TEST: invalid LCD_RSETn");
- return -ENODEV;
- }
- // Going to set up the LED. It is a GPIO in output mode and will be on by default
- gpio_request(D7, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(D7, false); // Set the gpio to be in output mode and off
- gpio_export(D7, false); // Causes gpio49 to appear in /sys/class/gpio
- gpio_request(D6, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(D6, false); // Set the gpio to be in output mode and off
- gpio_export(D6, false);
- gpio_request(D5, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(D5, false); // Set the gpio to be in output mode and off
- gpio_export(D5, false);
- gpio_request(D4, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(D4, false); // Set the gpio to be in output mode and off
- gpio_export(D4, false);
- gpio_request(RW, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(RW, false); // Set the gpio to be in output mode and off
- gpio_export(RW, false);
- gpio_request(EN, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(EN, false); // Set the gpio to be in output mode and off
- gpio_export(EN, false);
- gpio_request(RSET, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(RSET, false); // Set the gpio to be in output mode and off
- gpio_export(RSET, false);
- major = register_chrdev(0,"bbb_lcd",&lcd_fops); //注册字符驱动
- lcd_class = class_create(THIS_MODULE,"bbb_lcd");
- lcd_drv = device_create(lcd_class,NULL,MKDEV(major,0),NULL,"lcd1602");
-
- return result;
- }
- static void __exit lcd_exit(void){
- gpio_set_value(D7, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(D7); // Unexport the LCD GPIO
- gpio_free(D7); // Free the LCD GPIO
- gpio_set_value(D6, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(D6); // Unexport the LCD GPIO
- gpio_free(D6); // Free the LCD GPIO
- gpio_set_value(D5, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(D5); // Unexport the LCD GPIO
- gpio_free(D5); // Free the LCD GPIO
- gpio_set_value(D4, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(D4); // Unexport the LCD GPIO
- gpio_free(D4); // Free the LCD GPIO
- gpio_set_value(RW, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(RW); // Unexport the LCD GPIO
- gpio_free(RW); // Free the LCD GPIO
- gpio_set_value(RSET, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(RSET); // Unexport the LCD GPIO
- gpio_free(RSET); // Free the LCD GPIO
- gpio_set_value(EN, false); // Turn the LCD off, makes it clear the device was unloaded
- gpio_unexport(EN); // Unexport the LCD GPIO
- gpio_free(EN); // Free the LCD GPIO
- unregister_chrdev(major,"bbb_lcd"); //卸载字符驱动
- printk(KERN_INFO "LCD_TEST: Goodbye from the LKM!n");
- }
- module_init(lcd_init);
- module_exit(lcd_exit);
复制代码
用户程序如下:
- #include
- #include
- #include
- #include
- #include
- #include
- #define LCD_CLR _IO('L',0)
- #define LCD_ONE _IO('L',1)
- #define LCD_TWO _IO('L',2)
- int main(int argc, char **argv)
- {
- int fd;
- int hour = 0,min = 0,sec = 0;
- char *val = "yys: hello china";
- char buf[17];
- fd = open("/dev/lcd1602",O_RDWR);
- if (fd < 0)
- {
- printf("can't open!n");
- }
- if(strcmp(argv[1],"clr")==0)
- ioctl(fd,LCD_CLR);
- else if(strcmp(argv[1],"one")==0)
- ioctl(fd,LCD_ONE);
- else if(strcmp(argv[1],"two")==0)
- ioctl(fd,LCD_TWO);
-
- if(argc==3)
- write(fd,argv[2],strlen(argv[2]));
- else
- printf("no str will be display!n");
- }
复制代码
程序效果图:
|