0
本帖最后由 iysheng 于 2016-10-9 16:35 编辑
折腾了这么久,从最开始的茫然不知所措,到后来的摸着石头过河,感觉越来越知道如何上手了。最开始想过像普通 单片机那样裸机编程。后来也没有太深入的尝试,在网上搜索资料,开始知道了命令行下控制GPIO,AD读取等操作,慢慢的转到编译内核,linux驱动编写,和用户程序编写。才感觉慢慢上道了,中途也遇到过很多问题,和错误,但是尝试搜索之后,很多问题还是都可以解决的,这或许就是开源精神吧。 我的项目主要用到的是ad采样,频率检测,边沿触发和对应的控制,以及屏幕显示,我算是偷懒了,本次完成时候,项目框架如下:
我的项目整个流程图如下:
程序操作如下。演示视频:
按键和led:
AD、频率检测、数据显示(加载模块时,带有一个模块参数控制PWM的输出频率来作为频率检测的模拟输入):
实验效果画面:
128HZ:
下图是调试频率测试时候的画面:
32HZ
最终整个系统的效果图:
对应的源码:(系统驱动基于的是3.8.13-bone80内核)
(led.ko的源文件)led.c
- #include
- #include
- #include
- #include // Required for the GPIO functions
- #include
- #include
- #include
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("yang yongsheng");
- MODULE_DESCRIPTION("A LED test driver for the BBB");
- MODULE_VERSION("0.1");
- static unsigned int gpioLED = 60; ///< hard coding the LED gpio for this example to P9_23 (GPIO49)
- static unsigned int gpioKEY = 65; ///< hard coding the LED gpio for this example to P8_18 (GPIO65)
- static unsigned int numberPresses = 0; ///< For information, store the number of button presses
- static bool ledOn = 0; ///< Is the LED on or off? Used to invert its state (off by default)
- static unsigned int major;
- static struct class *led_class;
- static struct device *led_drv;
- static unsigned int keyirq;
- static irq_handler_t KEY_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
- static int led_open(struct inode *inode, struct file *file)
- {
- printk("bbb's led gpio60 will open.n");
-
- return 0;
- }
- static ssize_t led_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
- {
- int val;
- printk("write bbb's led.n");
- copy_from_user(&val, buf, count);
- if (val == 1)
- {
- gpio_set_value(gpioLED, true);
- }
- else
- {
- gpio_set_value(gpioLED, false);
- }
- return 0;
- }
- static ssize_t led_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
- {
- int val;
- val = gpio_get_value(gpioKEY);
- copy_to_user(buf,&val,count);
- return 0;
- }
- static struct file_operations led_fops = {
- .owner = THIS_MODULE,
- .open = led_open,
- .write = led_write,
- .read = led_read,
- };
- static int __init led_init(void){
- int result = 0;
-
- printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKMn");
- // Is the GPIO a valid GPIO number (e.g., the BBB has 4x32 but not all available)
- if (!gpio_is_valid(gpioLED)){
- printk(KERN_INFO "GPIO_TEST: invalid LED GPIOn");
- return -ENODEV;
- }
- if (!gpio_is_valid(gpioKEY)){
- printk(KERN_INFO "GPIO_TEST: invalid KEY GPIOn");
- return -ENODEV;
- }
- // Going to set up the LED. It is a GPIO in output mode and will be on by default
- ledOn = true;
- gpio_request(gpioLED, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(gpioLED, ledOn); // Set the gpio to be in output mode and on
- gpio_set_value(gpioLED, ledOn); // Not required as set by line above (here for reference)
- gpio_export(gpioLED, false); // Causes gpio49 to appear in /sys/class/gpio
- gpio_request(gpioKEY, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_input(gpioKEY); // Set the gpio to be in input mode and on
- gpio_set_debounce(gpioKEY,10); //去抖10ms
- gpio_export(gpioKEY, false); // Causes gpio49 to appear in /sys/class/gpio
- printk("gpioKEY finished.n");
- keyirq = gpio_to_irq(gpioKEY);
- result = request_irq(keyirq,(irq_handler_t)KEY_irq_handler,IRQF_TRIGGER_RISING,"gpio_KEY_handler",NULL);
- major = register_chrdev(0,"bbb_led",&led_fops); //注册字符驱动
- led_class = class_create(THIS_MODULE,"bbb_led");
- led_drv = device_create(led_class,NULL,MKDEV(major,0),NULL,"led60");
- return result;
- }
- static irq_handler_t KEY_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
- ledOn = !ledOn; // Invert the LED state on each button press
- gpio_set_value(gpioLED, ledOn); // Set the physical LED accordingly
- printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)n", gpio_get_value(gpioKEY));
- return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
- }
- static void __exit led_exit(void){
- gpio_set_value(gpioLED, 0); // Turn the LED off, makes it clear the device was unloaded
- gpio_unexport(gpioLED); // Unexport the LED GPIO
- gpio_free(gpioLED); // Free the LED GPIO
- free_irq(keyirq,NULL);
- unregister_chrdev(major,"bbb_led"); //卸载字符驱动
- printk(KERN_INFO "GPIO_TEST: Goodbye from the LKM!n");
- }
- module_init(led_init);
- module_exit(led_exit);
复制代码
(final.ko源文件)final.c
- #include
- #include
- #include
- #include // Required for the GPIO functions
- #include
- #include
- #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 unsigned int FREQIN = 49; ///< hard coding the FREQ gpio for this example to P9_23
- static unsigned int WAVEPIN = 115; ///< hard coding the FREQ gpio for this example to P9_27
- static unsigned int irqNumber;
- static int preNumber = 0;
- static struct timer_list freq_timer;
- static struct timer_list wave_timer;
- static bool wave = 0;
- static int frequence;
- static int freq_param = 32;
- module_param(freq_param,int,S_IRUGO);
- 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 lcd will open.n");
- wrcom(0x28);
- msleep(5);
- wrcom(0x0c);
- 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)
- {
- char preNumber_buf[16];
- sprintf(preNumber_buf,"%d",frequence);
- printk("read in kernel is %sn",preNumber_buf);
- copy_to_user(buf,preNumber_buf,16);
- 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 irq_handler_t freqin_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
- {
- preNumber++;
- printk(KERN_INFO "irq times is %dn",preNumber);
- return (irq_handler_t)IRQ_HANDLED;
- }
- static void second_timer_handler(void)
- {
- mod_timer(&freq_timer,jiffies+HZ);
- frequence = preNumber;
- preNumber = 0;
- printk("second_timer_handler is ok.");
- //atomic_read(&frequence);
- }
- static void wave_timer_handler(void)
- {
- mod_timer(&wave_timer,jiffies+HZ/2/freq_param);//4HZ
- wave = !wave;
- gpio_set_value(WAVEPIN,wave);
- printk("wave_timer_handler is ok.");
- }
- 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;
- }
- if (!gpio_is_valid(WAVEPIN)){
- printk(KERN_INFO "GPIO_TEST: invalid WAVEPINn");
- 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);
- gpio_request(WAVEPIN, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_output(WAVEPIN, false); // Set the gpio to be in output mode and off
- gpio_export(WAVEPIN, true);
-
- gpio_request(FREQIN, "sysfs"); // gpioLED is hardcoded to 60, request it
- gpio_direction_input(FREQIN); // Set the gpio to be in input mode and off
- gpio_export(FREQIN, false);
- printk(KERN_INFO "FREQIN irq begin.n");
- irqNumber = gpio_to_irq(FREQIN);
- printk(KERN_INFO "the irqnum is mapped to IRQ: %dn",irqNumber);
- result = request_irq(irqNumber,(irq_handler_t)freqin_irq_handler,IRQF_TRIGGER_RISING,"freqin",NULL);//申请中断
- printk(KERN_INFO "the irq is result is: %dn",result);
- //TIMER_INITIALIZER(&second_timer_handler,jiffies+HZ,0);
- init_timer(&freq_timer);
- freq_timer.function = &second_timer_handler;
- freq_timer.expires = jiffies+HZ;
- add_timer(&freq_timer);
- preNumber = 0;
-
- init_timer(&wave_timer);
- wave_timer.function = &wave_timer_handler;
- wave_timer.expires = jiffies+HZ/2/freq_param;
- add_timer(&wave_timer);
- printk("HZ is %d.n",HZ);//HZ is 512
- 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
- gpio_set_value(FREQIN, false); // Turn the FREQIN off, makes it clear the device was unloaded
- gpio_unexport(FREQIN); // Unexport the FREQIN GPIO
- gpio_free(FREQIN); // Free the FREQIN GPIO
- del_timer(&freq_timer);
- del_timer(&wave_timer);
-
- free_irq(irqNumber, NULL);
- unregister_chrdev(major,"bbb_lcd"); //卸载字符驱动
- printk(KERN_INFO "LCD_TEST: Goodbye from the LKM!n");
- }
- module_init(lcd_init);
- module_exit(lcd_exit);
复制代码
(finaapp源文件)finaapp.c
- #include
- #include
- #include
- #include
- #include
- #include
- #define LCD_CLR _IO('L',0)
- #define LCD_ONE _IO('L',1)
- #define LCD_TWO _IO('L',2)
- #define AD_DIR "/sys/bus/iio/devices/iio:device0/in_voltage3_raw"
- #define SLOTS "/sys/devices/bone_capemgr.9/slots"
- int main(int argc, char *argv[])
- {
- int fd,fd_ad3,fd_slots;
- char len = 0;
- char dir_buf[64];
- char val_buf[5];
- char freq_buf[16];
- fd = open("/dev/lcd1602",O_RDWR);
- if (fd < 0)
- printf("can't open!n");
- //if(strcmp(argv[1],"clr")==0)
- // ioctl(fd,LCD_CLR);
- snprintf(dir_buf,sizeof(dir_buf),SLOTS);
- fd_slots=open(dir_buf,O_WRONLY);
- if(fd_slots<0)
- printf("can't open slots!n");
- else
- write(fd_slots,"BB-ADC",7);
- close(fd_slots);
-
- snprintf(dir_buf,sizeof(dir_buf),AD_DIR);
- while(1)
- {
- ioctl(fd,LCD_ONE);
- fd_ad3 = open(dir_buf,O_RDONLY);
- if(fd_ad3<0)
- {
- printf("can't open ad3!n");
- return 0;
- }
- else
- read(fd_ad3,val_buf,5);
- write(fd,"AD3:",4);
- val_buf[strlen(val_buf)-1]='\0';
- write(fd,val_buf,4);
- write(fd," china ",16-strlen(freq_buf));
- ioctl(fd,LCD_TWO);
- read(fd,freq_buf,16);
- write(fd,"Freq:",5);
- write(fd,freq_buf,16);
- write(fd," iysheng ",16-strlen(freq_buf));
- usleep(1000000);
- close(fd_ad3);
- }
-
- return 0;
- }
复制代码
|
评分
-
查看全部评分
|