驱动开发(3)|rk356x驱动GPIO基础应用之点亮led灯

  点亮LED灯看似是一个基础的操作,但实际上,许多高级应用也依赖于高低电平的切换。例如,脉冲宽度调制(PWM)信号可以用来精确控制电机的转速,通过改变脉冲的频率和占空比,实现对电机的精确调节;同样,波形信号的生成也能够控制墨盒的喷墨精度,从而影响打印质量。通过对GPIO高低电平的精确控制,开发者可以实现各种复杂的硬件控制任务,这些基础操作为更复杂的应用提供了基础支持。
老规矩,先看效果:
请添加图片描述
这里控制led等一秒闪一次,下面分享两种控制led灯驱动代码:

1 通过GPIO 子系统设置引脚

//led1.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>#define DEVICE_NAME "led_clt"#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)// 定义所有GPIO引脚 (根据实际硬件连接修改)
#define LED_PIN         101static int power_gpios[] = {LED_PIN
};static const char *power_gpio_names[] = {"LED"
};void led_light(unsigned int epoch)
{int i = 0;for(i = 0 ;i < epoch; i++){gpio_set_value(LED_PIN,1);mdelay(1000);gpio_set_value(LED_PIN,0);mdelay(1000);}}
long gpio_user_ctl(struct file *file, unsigned int cmd, unsigned long arg)
{switch (cmd) {int i;case IOCTL_POWER_ON:led_light(5);break;case IOCTL_POWER_OFF://下电时序信号printk(KERN_EMERG "inkjet power off...");break;default:return -ENOTTY;}return 0;
}static const struct file_operations power_fops = {.owner = THIS_MODULE,.unlocked_ioctl = gpio_user_ctl,  // 设置ioctl回调.open = nonseekable_open,
};
static struct miscdevice gpio_dev = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &power_fops,
};
// 初始化函数
static int __init power_init(void)
{int i, ret = 0;ret = register_chrdev(0, KERN_DEBUG, &power_fops);if (ret < 0) {printk(KERN_ERR "Failed to register device\n");return ret;}// 获取设备号printk(KERN_INFO "Device registered with major number %d\n", ret);// 申请所有GPIOfor (i = 0; i < ARRAY_SIZE(power_gpios); i++) {ret = gpio_request(power_gpios[i], power_gpio_names[i]);if (ret){printk(KERN_ERR "Failed to request GPIO %s (%d)\n", power_gpio_names[i], power_gpios[i]);goto error;}gpio_direction_output(power_gpios[i], 0);}//注册设备,用于内核与用户空间简单交互ret = misc_register(&gpio_dev);if (ret) {goto error;printk(KERN_ERR "Failed to register misc device\n");return ret;}// 安装驱动printk(KERN_INFO "Motor Drive Install Success\n");return 0;error:// 释放已申请的GPIOfor (i = i - 1; i >= 0; i--) {gpio_free(power_gpios[i]);}return ret;
}// 清理退出函数
static void __exit power_exit(void)
{int i;unregister_chrdev(0, DEVICE_NAME);  // 注销字符设备printk(KERN_INFO "Device unregistered\n");//释放所有GPIOfor (i = ARRAY_SIZE(power_gpios) - 1; i >= 0; i--) {gpio_free(power_gpios[i]);}misc_deregister(&gpio_dev);printk(KERN_INFO "Motor Drive Uninstall Success\n");
}module_init(power_init);
module_exit(power_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("limingzhao");
MODULE_DESCRIPTION("motor prj");

2 直接操作硬件寄存器

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/delay.h>
//msdevice
#include <linux/miscdevice.h>
#define DEV_NAME            "led_clt"#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)#define GPIO1_COUNT            4
#define GPIO3_COUNT            11
#define GPIO4_COUNT            6#define GROUP_COUNT            5#define GPIO1_BASE (0xFE740000)
#define GPIO3_BASE (0xFE760000)
#define GPIO4_BASE (0xFE770000)///A,B-->GPIO1_DR_L和GPIO1_DDR_L///C,D-->GPIO1_DR_H和GPIO1_DDR_H//GPIO1A0,GPIO1A1,GPIO1B0,GPIO1B1-->GPIO1_DR_L和GPIO1_DDR_L
#define GPIO1_DR_L (GPIO1_BASE + 0x0000)
#define GPIO1_DDR_L (GPIO1_BASE + 0x0008)//GPIO3_A0,GPIO3_A1...-->GPIO1_DR_L和GPIO1_DDR_L
#define GPIO3_DR_L (GPIO3_BASE + 0x0000)
#define GPIO3_DDR_L (GPIO3_BASE + 0x0008)//GPIO4C3,GPIO4C5..-->GPIO2_DR_H和GPIO2_DDR_H
#define GPIO4_DR_H (GPIO4_BASE + 0x0004)
#define GPIO4_DDR_H (GPIO4_BASE + 0x000C)static dev_t devno;
struct class *inkjet_chrdev_class;typedef struct __PIN_INDEX{unsigned int  pin_index;unsigned long val_hig;unsigned long val_low;
}PIN_INDEX;typedef struct __PIN_PARAMS{struct cdev dev;unsigned int 	__iomem *va_dr; 	// 数据寄存器,设置输出的电压unsigned int 	__iomem *va_ddr; 	// 数据方向寄存器,设置输入或者输出PIN_INDEX 		arrPin[20]; // 偏移unsigned int 	pin_count;}PIN_PARAMS;///GROUP1,GROUP3,GROUP4,The Number Of Array is Five for Simplifing Coding
static PIN_PARAMS GPIO_GROUPS[GROUP_COUNT];void led_light(unsigned int epoch)
{int i = 0;for(i = 0 ;i < epoch; i++){set_hig(2);mdelay(1000);set_low(2);mdelay(1000);}}
long power_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{switch (cmd) {int i;case IOCTL_POWER_ON:led_light(5);break;case IOCTL_POWER_OFF:break;default:return -ENOTTY;}return 0;
}
static struct file_operations inkjet_chrdev_fops = {.owner = THIS_MODULE,.unlocked_ioctl = power_ioctl,  // 设置ioctl回调
};
//注册设备信息,用于内核与用户空间简单交互
static struct miscdevice gpio_dev = {.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &inkjet_chrdev_fops,
};
void set_hig(unsigned int index)
{/*引脚对应图pin					indexGPIO1_A0 				 0GPIO1_A1				 1GPIO3_A5				 2GPIO3_A6				 3GPIO3_A7				 4GPIO4_C3				 5GPIO4_C5				 6GPIO4_C2				 7GPIO3_B4				 8GPIO4_D2				 9GPIO3_B6				 10GPIO3_B5				 11GPIO3_B7				 12GPIO3_B1				 13GPIO3_A0				 14GPIO4_C6				 15GPIO4_C4				 16GPIO3_B3				 17GPIO3_B2				 18GPIO1_B0				 19GPIO1_B1				 20*/if(index == 0){	//GPIO1_A0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[0].val_hig;}else if(index == 1){	//GPIO1_A1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[1].val_hig;}else if(index == 2){	//GPIO3_A5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[0].val_hig;}else if(index == 3){	//GPIO3_A6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[1].val_hig;}else if(index == 4){	//GPIO3_A7volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[2].val_hig;}else if(index == 5){	//GPIO4_C3volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[0].val_hig;}else if(index == 6){	//GPIO4_C5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[1].val_hig;}else if(index == 7){	//GPIO4_C2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[2].val_hig;}else if(index == 8){	//GPIO3_B4volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[3].val_hig;}else if(index == 9){	//GPIO4_D2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[3].val_hig;}else if(index == 10){	//GPIO3_B6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[4].val_hig;}else if(index == 11){	//GPIO3_B5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[5].val_hig;}else if(index == 12){	//GPIO3_B7volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[6].val_hig;}else if(index == 13){	//GPIO3_B1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[7].val_hig;}else if(index == 14){	//GPIO3_A0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[8].val_hig;}else if(index == 15){	//GPIO4_C6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[4].val_hig;}else if(index == 16){	//GPIO4_C4volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[5].val_hig;}else if(index == 17){	//GPIO3_B3volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[9].val_hig;}else if(index == 18){	//GPIO3_B2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[10].val_hig;}else if(index == 19){	//GPIO1_B0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[2].val_hig;}else if(index == 20){	//GPIO1_B1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[3].val_hig;}else{printk(KERN_EMERG "set_hig input index error!!\n");}}
void set_low(unsigned int index)
{/*引脚对应图pin					indexGPIO1_A0 				 0GPIO1_A1				 1GPIO3_A5				 2GPIO3_A6				 3GPIO3_A7				 4GPIO4_C3				 5GPIO4_C5				 6GPIO4_C2				 7GPIO3_B4				 8GPIO4_D2				 9GPIO3_B6				 10GPIO3_B5				 11GPIO3_B7				 12GPIO3_B1				 13GPIO3_A0				 14GPIO4_C6				 15GPIO4_C4				 16GPIO3_B3				 17GPIO3_B2				 18GPIO1_B0				 19GPIO1_B1				 20*/if(index == 0){	//GPIO1_A0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[0].val_low;}else if(index == 1){	//GPIO1_A1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[1].val_low;}else if(index == 2){	//GPIO3_A5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[0].val_low;}else if(index == 3){	//GPIO3_A6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[1].val_low;}else if(index == 4){	//GPIO3_A7volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[2].val_low;}else if(index == 5){	//GPIO4_C3volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[0].val_low;}else if(index == 6){	//GPIO4_C5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[1].val_low;}else if(index == 7){	//GPIO4_C2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[2].val_low;}else if(index == 8){	//GPIO3_B4volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[3].val_low;}else if(index == 9){	//GPIO4_D2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[3].val_low;}else if(index == 10){	//GPIO3_B6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[4].val_low;}else if(index == 11){	//GPIO3_B5volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[5].val_low;}else if(index == 12){	//GPIO3_B7volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[6].val_low;}else if(index == 13){	//GPIO3_B1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[7].val_low;}else if(index == 14){	//GPIO3_A0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[8].val_low;}else if(index == 15){	//GPIO4_C6volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[4].val_low;}else if(index == 16){	//GPIO4_C4volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);*reg = GPIO_GROUPS[4].arrPin[5].val_low;}else if(index == 17){	//GPIO3_B3volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[9].val_low;}else if(index == 18){	//GPIO3_B2volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);*reg = GPIO_GROUPS[3].arrPin[10].val_low;}else if(index == 19){	//GPIO1_B0volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[2].val_low;}else if(index == 20){	//GPIO1_B1volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);*reg = GPIO_GROUPS[1].arrPin[3].val_low;}else{printk(KERN_EMERG "set_low input index error!!\n");}}
void init_pin_values()
{int i = 0;int j = 0;dev_t cur_dev;unsigned long val = 0;////////GPIO1 GROUP SETTING//////GPIO_GROUPS[1].pin_count = GPIO1_COUNT;//GPIO1_A0GPIO_GROUPS[1].arrPin[0].pin_index = 0;//GPIO1_A1GPIO_GROUPS[1].arrPin[1].pin_index = 1;//GPIO1_B0GPIO_GROUPS[1].arrPin[2].pin_index = 8;//GPIO1_B1GPIO_GROUPS[1].arrPin[3].pin_index = 9;GPIO_GROUPS[1].va_dr = ioremap(GPIO1_DR_L, 4);GPIO_GROUPS[1].va_ddr = ioremap(GPIO1_DDR_L, 4);////////GPIO3 GROUP SETTING//////GPIO_GROUPS[3].pin_count = GPIO3_COUNT;//GPIO3_A5GPIO_GROUPS[3].arrPin[0].pin_index = 5;//GPIO3_A6GPIO_GROUPS[3].arrPin[1].pin_index = 6;//GPIO3_A7GPIO_GROUPS[3].arrPin[2].pin_index = 7;//GPIO3_B4GPIO_GROUPS[3].arrPin[3].pin_index = 12;//GPIO3_B6GPIO_GROUPS[3].arrPin[4].pin_index = 14;//GPIO3_B5GPIO_GROUPS[3].arrPin[5].pin_index = 13;//GPIO3_B7GPIO_GROUPS[3].arrPin[6].pin_index = 15;//GPIO3_B1GPIO_GROUPS[3].arrPin[7].pin_index = 9;//GPIO3_A0GPIO_GROUPS[3].arrPin[8].pin_index = 0;//GPIO3_B3GPIO_GROUPS[3].arrPin[9].pin_index = 11;//GPIO3_B2GPIO_GROUPS[3].arrPin[10].pin_index = 10;GPIO_GROUPS[3].va_dr = ioremap(GPIO3_DR_L, 4);GPIO_GROUPS[3].va_ddr = ioremap(GPIO3_DDR_L, 4);////////GPIO4 GROUP SETTING//////GPIO_GROUPS[4].pin_count = GPIO4_COUNT;//GPIO4_C3GPIO_GROUPS[4].arrPin[0].pin_index = 3;//GPIO4_C5GPIO_GROUPS[4].arrPin[1].pin_index = 5;//GPIO4_C2GPIO_GROUPS[4].arrPin[2].pin_index = 2;//GPIO4_D2GPIO_GROUPS[4].arrPin[3].pin_index = 10;//GPIO4_C6GPIO_GROUPS[4].arrPin[4].pin_index = 6;//GPIO4_C4GPIO_GROUPS[4].arrPin[5].pin_index = 4;GPIO_GROUPS[4].va_dr = ioremap(GPIO4_DR_H, 4);GPIO_GROUPS[4].va_ddr = ioremap(GPIO4_DDR_H, 4);alloc_chrdev_region(&devno, 0, GROUP_COUNT - 2, DEV_NAME);inkjet_chrdev_class = class_create(THIS_MODULE, "led_clt");for (; i < GROUP_COUNT; i++) {if(i == 0|| i == 2){continue;}cdev_init(&GPIO_GROUPS[i].dev, &inkjet_chrdev_fops);GPIO_GROUPS[i].dev.owner = THIS_MODULE;cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);cdev_add(&GPIO_GROUPS[i].dev, cur_dev, 1);device_create(inkjet_chrdev_class, NULL, cur_dev, NULL,DEV_NAME "%d", i);}// printk(KERN_EMERG "open\n");////////GPIO0 GROUP PINS EXPORT AND SAVE VALUE////////五组GPIO(GPIO0-GPIO4)for(i = 0; i < GROUP_COUNT; i++){if(i == 0|| i == 2){continue;}for(j = 0; j < GPIO_GROUPS[i].pin_count; j++){//exportval = ioread32(GPIO_GROUPS[i].va_ddr);val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));val |= ((unsigned int)0X1 << (GPIO_GROUPS[i].arrPin[j].pin_index));iowrite32(val, GPIO_GROUPS[i].va_ddr);//save hig and low value//high valueval = ioread32(GPIO_GROUPS[i].va_dr);val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));val &= ~((unsigned int)0x01 << (GPIO_GROUPS[i].arrPin[j].pin_index));   iowrite32(val, GPIO_GROUPS[i].va_dr);GPIO_GROUPS[i].arrPin[j].val_low = val;//low valueval = ioread32(GPIO_GROUPS[i].va_dr);val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index));iowrite32(val, GPIO_GROUPS[i].va_dr);GPIO_GROUPS[i].arrPin[j].val_hig = val;}}int ret = 0;//注册设备,用于内核与用户空间简单交互ret = misc_register(&gpio_dev);if (ret) {printk(KERN_ERR "Failed to register misc device\n");return;}}static __init int inkjet_chrdev_init(void)
{init_pin_values();return 0;
}module_init(inkjet_chrdev_init);static __exit void inkjet_chrdev_exit(void)
{int i;dev_t cur_dev;for (i = 0; i < GROUP_COUNT; i++) {if(i == 0|| i == 2){continue;}iounmap(GPIO_GROUPS[i].va_dr); 		// 释放模式寄存器虚拟地址iounmap(GPIO_GROUPS[i].va_ddr); 	// 释放输出类型寄存器虚拟地址}for (i = 0; i < GROUP_COUNT; i++) {if(i == 0|| i == 2){continue;}cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);device_destroy(inkjet_chrdev_class, cur_dev);cdev_del(&GPIO_GROUPS[i].dev);}unregister_chrdev_region(devno, 1);class_destroy(inkjet_chrdev_class);//release access devmisc_deregister(&gpio_dev);
}module_exit(inkjet_chrdev_exit);MODULE_AUTHOR("limingzhao");
MODULE_LICENSE("GPL");

这里我嫌示例代码太麻烦了,自己封装了一下,set_higset_low,只封装了GPIO1、GPIO3和GPIO4,对应序号的gpio口在注释里面,方便使用。

3 makefile部分

KERNEL_DIR=/home/path/to/kernel/ARCH=arm64
CROSS_COMPILE=aarch64-linux-gnu-
export  ARCH  CROSS_COMPILEKBUILD_CFLAGS += -O0 -Wall 
obj-m := led1.oall:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules.PHONE:cleanclean:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean	

注:这里的KERNEL_DIR改成你自己编译的内核路径,如果不知道怎么编译的可以看我写的驱动开发(1)部分
这里的驱动代码和makefile放虚拟机里面(x86_64),编译成ko文件后放入驱动板里面安装,如图所示:
在这里插入图片描述
我这里的led1.c和led2.c分别对应本文段落1和本文段部落2的代码,这两种方法的优劣势上篇文章已经讲明白了。唯一的一点是上次纠正我上篇文章中的错误:上篇文章说通过直接操作寄存器的方式拉高再拉低,寄存器只能到达160ns左右是错误的,因为我之前用的示波器精度不够,这里直接操作寄存器的驱动代码完全能达到50ns级别的延时,不过我还是没用rk3568来直接操控,想要精确操控波形,感兴趣的可以研究一下FPGA开发板。

4 用户层代码

//call_led.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>// 定义IOCTL命令
#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)#define DEVICE_NAME "/dev/led_clt"int main() 
{int fd;int ret;// 打开设备文件fd = open(DEVICE_NAME, O_RDWR);if (fd < 0) {perror("Failed to open device");return -1;}// 调用IOCTL_POWER_ONret = ioctl(fd, IOCTL_POWER_ON);if (ret < 0) {perror("Failed to send IOCTL_POWER_ON");close(fd);return -1;}printf("Motor started\n");sleep(5);ret = ioctl(fd, IOCTL_POWER_ON);if (ret < 0) {perror("Failed to send IOCTL_POWER_ON");close(fd);return -1;}sleep(5);// 关闭设备文件close(fd);return 0;
}

这里是通过操作led_clt设备,来控制led灯电平高低,linux果然是万物皆文件,都是通过open、read、write基本操作函数。
这里可以看到 ret = ioctl(fd, IOCTL_POWER_ON);调用了两次,也就是led灯先闪烁5次,延时5秒然后再闪烁5次。

5 安装卸载驱动命令

# install
insmod led1.ko
# uninstall
rmmod led1.c

6 使用引脚

这里使用的引脚是GPIO3_A5,如图所示:
在这里插入图片描述
板子具体位置:

总结

  这篇文章主要分享了在RK3568平台上控制GPIO的两种常见方式,并通过LED灯的实验测试,验证了这两种方法的效果。首先介绍了通过编程接口操作GPIO的基本原理和步骤,包括如何设置输入输出模式、读取和写入数据。后续这一系列将暂时停更,主要想先写CV和NLP算法方面的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89124.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手动搭建PHP环境:步步为营,解锁Web开发

目录一、引言二、准备工作2.1 明确所需软件2.2 下载软件三、Windows 系统搭建步骤3.1 安装 Apache 服务器3.2 安装 PHP3.3 集成 Apache 与 PHP3.4 安装 MySQL3.5 配置 PHP 连接 MySQL四、Linux 系统搭建步骤&#xff08;以 Ubuntu 为例&#xff09;4.1 更新系统4.2 安装 Apache…

DrissionPage:一款让网页自动化更简单的 Python 库

在网页自动化领域&#xff0c;Selenium 和 Playwright 早已是开发者耳熟能详的工具。但今天要给大家介绍一款更轻量、更易用的 Python 库 ——DrissionPage。它以 "融合 selenium 和 requests 优势" 为核心设计理念&#xff0c;既能像 requests 一样高效处理静态网页…

理解Grafana中`X-Scope-OrgID`的作用与配置

X-Scope-OrgID的作用 该HTTP Header用于标识Loki日志数据的所属租户&#xff08;组织&#xff09;。在多租户模式下&#xff0c;Loki通过此Header隔离不同团队或用户的数据&#xff0c;确保查询和存储的独立性。数据隔离&#xff1a; 租户A的日志标记为X-Scope-OrgID: team-a&a…

【PycharmPyqt designer桌面程序设计】

在 main.py 中调用 Qt Designer 生成的 windows.py&#xff08;假设它是 PySide2 版&#xff09;。 只要把两个文件放在同一目录即可直接运行。 ──────────────────── 1️⃣ windows.py&#xff08;Qt Designer 生成&#xff0c;已转码&#xff09; # -*-…

Unity Android Logcat插件 输出日志中文乱码解决

背景之前安卓真机调试看日志&#xff0c;一直用的是Android Studio自带的adb命令进行看日志&#xff0c;不太方便&#xff0c;改用Unity自带的安卓日志插件时&#xff0c;存在中文日志乱码问题。插件安装基于Unity6000.1.11版本&#xff1a;Window -> Package Management -&…

Halcon双相机单标定板标定实现拼图

1.Halcon图像拼接算法在之前的文章里也写过&#xff0c;主要是硬拼接和特征点拼接两种方式&#xff0c;今天增加另一种拼接图像的方式。应用场景是多个相机联合一起拍大尺寸的物体&#xff0c;并且相机视野之间存在重叠区域。通过在同一个标定板上面标定&#xff0c;计算两个相…

动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE

提示词在一个奇幻的童话森林里&#xff0c;所有的动物都像人类一样直立行走&#xff0c;穿着各种搞怪的衣服。 一只戴着超大眼镜、穿着背带裤的乌龟&#xff0c;正一本正经地站在一个蘑菇舞台上&#xff0c;拿着一根树枝当作麦克风&#xff0c;准备唱歌。它的眼镜总是往下滑&am…

SpringBoot(原理篇)

大家好&#xff0c;这里是 盛码笔记。 本篇我们来聊一聊 Spring Boot 的“魔法”是如何实现的。你可能已经用过 Spring Boot 快速搭建项目&#xff0c;但有没有想过&#xff1a;为什么只需要引入几个 starter&#xff0c;Spring Boot 就能自动配置好整个应用环境&#xff1f; …

数据结构:栈(区间问题)

码蹄集OJ-小码哥的栈 #include<bits/stdc.h> using namespace std; #define int long long const int N1e67; struct MOOE {int ll,rr; }; stack<MOOE>st; signed main( ) {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;while(n--){int opt…

Vue 中 data、watch、created 和 methods

以下是 Vue 中 data、watch、created 和 methods 的详细解释&#xff0c;结合常见使用场景和示例&#xff1a;1. data&#xff1a;响应式数据容器 作用&#xff1a;定义组件的响应式数据&#xff08;状态&#xff09;&#xff0c;当数据变化时&#xff0c;视图自动更新。特点&a…

精密模具冷却孔内轮廓检测方法探究 —— 激光频率梳 3D 轮廓检测

引言精密模具冷却孔的内轮廓精度直接影响注塑成型效率与制品质量。冷却孔具有深径比大&#xff08;可达 25:1&#xff09;、结构复杂&#xff08;多为螺旋形或异形&#xff09;、表面质量要求高&#xff08;Ra≤0.2μm&#xff09;等特点&#xff0c;传统检测方法难以满足其高精…

Vue单文件组件与脚手架工程化开发

一、Vue与VueComponent原型关系解析1. 原型链关系图解在Vue中&#xff0c;组件实例(VueComponent)与Vue实例之间存在特殊的原型链关系&#xff1a;VueComponent.prototype.__proto__ Vue.prototype这种设计使得所有组件都能访问Vue原型上定义的方法和属性。2. 原理验证示例// …

架构设计之计算高性能——单体服务器高性能

架构设计之计算高性能——单体服务器高性能 高性能是每个程序员共同的追求&#xff0c;无论是开发系统&#xff0c;还是仅仅只是写一段脚本&#xff0c;都希望能够达到高性能的效果&#xff0c;而高性能又是软件系统设计中最复杂的一步。无论是开发千万级并发的电商系统&#…

Unity灯光面板环境设置

在Unity中&#xff0c;环境设置&#xff08;Environment Lighting&#xff09; 是灯光面板&#xff08;Lighting Window&#xff09;的核心功能之一&#xff0c;用于控制场景的全局光照效果&#xff0c;包括天空盒、环境光、反射和雾效等。这些设置直接影响场景的整体氛围和真实…

MySQL语句优化案例

1.案例in查询条件很慢其中in中共115个select id,detail_id,request,response,utime,ctime from response_detaill where detaill_id in (26371986, 26372242, 26371984, 26371990, 26400150, 26371988, 26371994, 26371992,26371998, 26371996, 26371970, 26371968, 2637197…

能行为监测算法:低成本下的高效管理

AI监控智慧公司管理&#xff1a;降本增效的实践与突破一、背景&#xff1a;经济压力下的管理转型需求在经济下行周期&#xff0c;企业面临人力成本攀升、管理效率低下、安全风险频发等多重挑战。传统监控依赖人工巡检&#xff0c;存在响应滞后、误判率高、数据孤岛等问题&#…

当前(2024-07-14)视频插帧(VFI)方向的 SOTA 基本被三篇顶会工作占据,按“精度-速度-感知质量”三条线总结如下,供你快速定位最新范式

当前&#xff08;2024-07-14&#xff09;视频插帧&#xff08;VFI&#xff09;方向的 SOTA 基本被三篇顶会工作占据&#xff0c;按“精度-速度-感知质量”三条线总结如下&#xff0c;供你快速定位最新范式。感知质量最佳&#xff1a;CVPR 2024 ‑ PerVFI • 关键词&#xff1a;…

开源 python 应用 开发(七)数据可视化

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

基于深度学习的情感分析模型:从文本数据到模型部署

前言 情感分析&#xff08;Sentiment Analysis&#xff09;是自然语言处理&#xff08;NLP&#xff09;领域中的一个重要应用&#xff0c;它通过分析文本数据来判断文本的情感倾向&#xff0c;例如正面、负面或中性。随着社交媒体的兴起&#xff0c;情感分析在市场调研、品牌管…

使用python 实现一个http server

下面是一个使用 Python 内置库 http.server 的简单 HTTP 服务器实现。不需要安装任何第三方库&#xff0c;非常适合做演示或开发测试用。 from http.server import HTTPServer, BaseHTTPRequestHandlerclass SimpleHTTPRequestHandler(BaseHTTPRequestHandler):def do_GET(self…