Linux驱动基础篇(一)GPIO(上)LED驱动

文章目录

    • Linux驱动基础(一)GPIO(上)LED驱动
    • 一、开发环境准备
      • 1.安装交叉编译工具+编译内核
        • (1)安装交叉编译工具
        • (2)修改Makefile指定编译器和架构
        • (3)生成配置文件.config
        • (4)编译内核
      • 2.安装配置vscode
    • 二、第一个驱动程序HelloWorld
      • 1.简单的驱动框架使用
        • 2.重要的几个宏/函数
    • 三、第二个驱动程序点亮LED
      • 1.阅读原理图和芯片手册
        • (1)找到OrangePi PC+的两个LED
        • (2)找到两个LED和CPU连接的引脚
        • (3)在芯片手册找到PL10和PA15
        • (4)找到对应的配置寄存器
        • (5)找到对应的数据寄存器
      • 2.从驱动开始点亮香橙派orangepi plus的LED
    • 四、面向对象设计思想

Linux驱动基础(一)GPIO(上)LED驱动

一、开发环境准备

ubuntu22.04 + Vscode + OrangePi+

1.安装交叉编译工具+编译内核

(1)安装交叉编译工具

📌选择交叉编译工具链

以官网下载页面为例

在这里插入图片描述

在这里插入图片描述

📌下载交叉编译工具

​ 交叉编译工具链官方下载地址(国外)
​ 交叉编译工具链清华开源镜像站下载地址(国内)

📌解压、添加环境变量、测试安装结果

sudo tar -xvf arm-none-linux-gnueabihf-12.3-x86_64-.tar.xz -C /mnt	# 解压到/mnt目录
# 添加环境变量,在原有的双引号前输入:后粘贴复制工具链的路径
# 例如这里是/mnt/arm-none-linux-gnueabihf-12.3-x86_64/bin
# 保存后重新登录或重启生效,输入arm-尝试tab能否补全命令以及arm-none-linux-gnueabihf-gcc -v进行测试
sudo vi /etc/environment
(2)修改Makefile指定编译器和架构
# 在内核源码顶层目录的Makefile,搜索CROSS_COMPILE或ARCH,添加以下内容
# 要配置上面步骤后,CROSS_COMPILE可以这样写;没有的话要写绝对路径
ARCH  := arm
CROSS_COMPILE	:= arm-none-linux-gnueabihf-
(3)生成配置文件.config
# 生成默认的配置文件,也可以make menuconfig进行配置,最后会保存到.config
make defconfig

❓❓❓ 报错1:arch/arm是一个目录 ❓❓❓

解决:ARCH := arm (arm后面多了空格)

❓❓❓ 报错2:/bin/sh: 1: flex: not found ❓❓❓

sudo apt-get install flex

❓❓❓ 报错3:/bin/sh: 1: bison: not found ❓❓❓

sudo apt-get install bison

❓❓❓ 报错4:make menuconfig 打开失败❓❓❓

sudo apt-get install libncurses5-dev


(4)编译内核
# 建议这里可以将所有的CPU核心分配给虚拟机,提高速度
make -j24

❓❓❓ 报错5:scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: 没有那个文件或目录❓❓❓

原因:没有安装libssl-dev或者安装版本过高
解决:(未安装)sudo apt-get install libssl-dev
(版本过高)sudo apt-get install aptitude(安装aptitude软件包管理器)
sudo aptitude install libssl-dev(使用aptitude安装libssl-dev)
选择不保持当前版本,出现提示输出n,确认y后降级


2.安装配置vscode

二、第一个驱动程序HelloWorld

1.简单的驱动框架使用

简单的驱动框架分为三步:①装载驱动、②操作驱动、③卸载驱动。个人认为这样划分容易理解和记忆!
在这里插入图片描述

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>#define   DEV_NAME   "hello"static struct class *hello_cls;
static int ERR;
static struct device *device;static int hello_open(struct inode *inode, struct file *file){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);return 0;
}
static ssize_t hello_read (struct file *file, char __user *buf, size_t size, loff_t *offset){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);return 0;
}static ssize_t hello_write (struct file *file, const char __user *buf, size_t size, loff_t * offset){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);return 0;
}
static int hello_release(struct inode *inode, struct file *file){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);return 0;
}static unsigned int major = 0;
static struct file_operations hello_fop = {.owner = THIS_MODULE,.open = hello_open,.read = hello_read,.write = hello_write,.release = hello_release
};/*** @brief 初始化驱动(注册设备register_chrdev()、创建设备节点device_create())* 注册设备需要:设备号、设备名、设备file_operaction* 创建设备节点需要:class、devtype-由设备号确定、设备节点名**/
static int  __init hello_Driver_Init(void){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);major = register_chrdev(major,DEV_NAME,&hello_fop);hello_cls = class_create(THIS_MODULE,DEV_NAME);if(IS_ERR(hello_cls)){ERR = PTR_ERR(hello_cls);pr_err("class create failed.(error code:%d)\n",ERR);unregister_chrdev(major,DEV_NAME);return ERR;}device = device_create(hello_cls,NULL, MKDEV(major,0),NULL,"hello");if(IS_ERR(device)){ERR = PTR_ERR(device);pr_err("device create failed.(error code:%d)\n",ERR);class_destroy(hello_cls);unregister_chrdev(major,DEV_NAME);return ERR;}return 1;
}/*** @brief 卸载驱动(删除设备节点device_destroy()、注销设备unregister_chrdev())**/
static void __exit hello_Driver_Exit(void){printk("%s  %s  %d\n",__FILE__,__FUNCTION__ ,__LINE__);device_destroy(hello_cls, MKDEV(major,0));class_destroy(hello_cls);unregister_chrdev(major,DEV_NAME);
}module_init(hello_Driver_Init);
module_exit(hello_Driver_Exit);
MODULE_LICENSE("GPL");
2.重要的几个宏/函数

2.1 错误指针判断IS_ERR( )、PTR_ERR( )和pr_err( )

2.2 用户和内核之间的数据拷贝copy_from_user( )、copy_to_user( )和get_user( )、put_user( )

三、第二个驱动程序点亮LED

1.阅读原理图和芯片手册

(1)找到OrangePi PC+的两个LED

📌在原理图中搜索"LED",找到关于OrangePi+ LED部分的原理图

在这里插入图片描述

  • 从原理图关于LED的部分可以看到,OrangePi PC+有两个LED:PWR-LED(供电时闪烁LED)、STATUS-LED(开机运行时状态LED)。
(2)找到两个LED和CPU连接的引脚

在这里插入图片描述

  • PWR-LED连接到PL10、STATUS_LED连接到PA15
(3)在芯片手册找到PL10和PA15

在这里插入图片描述

(4)找到对应的配置寄存器

在这里插入图片描述

(5)找到对应的数据寄存器

在这里插入图片描述

2.从驱动开始点亮香橙派orangepi plus的LED

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>#define PIO_BASE    0x01c20800static volatile unsigned int *PA_CFG1_REG;
static volatile unsigned int *PA_DATA_REG;
static unsigned int major = 0;
static struct class *led_class;static int led_open(struct inode *inode, struct file *file){/* output: bit30-28 = 001 */*PA_CFG1_REG &= ~(0x01 << 30);*PA_CFG1_REG &= ~(0x01 << 29);*PA_CFG1_REG |= (0x01 << 28);printk("======= led_open():PA_CFG_REG = 0x%x =========\n",*PA_CFG1_REG);return 0;
}
static int led_close(struct inode *inode, struct file *file){/* default: bit30-28 = 111 */*PA_CFG1_REG |= (0x01 << 30);*PA_CFG1_REG |= (0x01 << 29);*PA_CFG1_REG |= (0x01 << 28);printk("======= led_close():PA_CFG_REG = 0x%x =========\n",*PA_CFG1_REG);return 0;
}
static ssize_t led_read (struct file *file, char __user *buf, size_t size, loff_t *off){return 0;
}
static ssize_t led_write (struct file *file, const char __user *buf, size_t size, loff_t *off){char val;   // 0-OFF 1-ONint ret = copy_from_user(&val,buf,1);ret = 3;if(val){*PA_DATA_REG |= 0x1<<15; //bit15 = 1}else{*PA_DATA_REG &= ~(0x1<<15); //bit15 = 0}return 1;
}
static struct file_operations led_ops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_close,
};
static int  __init led_driver_init(void){printk("======= %s %s %d ========\n",__FILE__,__FUNCTION__ ,__LINE__);major = register_chrdev(major,"led_driver",&led_ops);led_class = class_create(THIS_MODULE,"led_driver");device_create(led_class,NULL, MKDEV(major,0),NULL,"led1");PA_CFG1_REG = ioremap(PIO_BASE+0x04,4);PA_DATA_REG = ioremap(PIO_BASE+0x10,4);*PA_CFG1_REG &= ~(0x1<<30);*PA_CFG1_REG &= ~(0x1<<29);*PA_CFG1_REG |= 0x1<<28;return 0;
}static void  __exit led_driver_exit(void){printk("======= %s %s %d ========\n",__FILE__,__FUNCTION__ ,__LINE__);iounmap(PA_CFG1_REG);iounmap(PA_DATA_REG);device_destroy(led_class, MKDEV(major,0));class_destroy(led_class);unregister_chrdev(major,"led_driver");}module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");

这里为了没有写应用层的测试程序,只简单粗暴点个LED,加载驱动后led亮,香橙派OrangePi Plus上是红灯

四、面向对象设计思想

上面所写的LED驱动程序,驱动和硬件操作绑定在一起,更换开发板平台所有的代码就完全不适用,不仅可维护性和可读性差,而且代码难以移植到其他平台,增加了代码冗余和维护的工作量。因此,内核驱动程序中采用面向对象的编程思想,将驱动和硬件操作的代码分离并进行合理的抽象和封装,通常是更好的选择

📌改写LED驱动,实现应用层程序控制两个LED亮灭

【led_test_app.c】

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>/** ./test_led_app /dev/led1 on **/
/** ./test_led_app /dev/led2 off **/int main(int argc,char **argv){char *buf = (char *)malloc(36);int nwrite = 0;if(argc < 3){printf("Usage:%s [dev-led1/led2]  [status-on/off]  \n",argv[0]);return -1;}int fd = open(argv[1],O_RDWR);if(fd < 0){printf("open device error\n");return -1;}int val_on = 1;int val_off = 0;if( 0 == strcmp(argv[2],"on")){nwrite = write(fd,&val_on,sizeof(val_on));}else if( 0 == strcmp(argv[2],"off")){nwrite = write(fd,&val_off,sizeof(val_off));}else{printf("syntax error\n");}close(fd);return 0;
}

【orangepi_plus_leds.h】

#ifndef _ORANGEPI_PLUS_LEDS_H
#define _ORANGEPI_PLUS_LEDS_H#define MIN(a,b)    (a < b ? a : b)
#define PIN_GROUP(pin)  (pin >> 22)
#define PIN_NUM(pin)    (pin & 0x3FFFFF)struct GPIOx_PIN {   /** bit[21:0] pin_num **//** bit[31:22] pin_group **/int pin; int count;volatile unsigned int *GPIOx_CFG_REG;        //配置寄存器volatile unsigned int *GPIOx_DAT_REG;        //数据寄存器int (*gpio_init)(int pin);             //初始化函数int (*gpio_control)(int pin,int status);   //控制函数struct GPIOx_PIN *next;
};extern struct GPIOx_PIN *get_GPIOA_PIN15(void);
extern struct GPIOx_PIN *get_GPIOL_PIN10(void);#endif

【orangepi_plus_led1.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include "orangepi_plus_leds.h"#define BASE_ADDR   (0x01c20800)#define WHICH_CFG(pin_num)  \((pin_num >= 0 && pin_num <= 7)   ?  0x00 : \(pin_num >= 8 && pin_num <= 15)  ?  0x04 : \(pin_num >= 15 && pin_num <= 21) ?  0x08 : 0x0c)int led1_init(int pin);
int led1_control(int pin,int status);static struct GPIOx_PIN GPIOA_PIN15 = {.pin = (0 << 22)|(15),          //第0组第15pin(GPIOA_15).gpio_init = led1_init,.gpio_control = led1_control,.next = NULL
};int led1_init(int pin){int pin_num = PIN_NUM(pin);GPIOA_PIN15.GPIOx_CFG_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)* 0x24 + WHICH_CFG(pin_num),4);GPIOA_PIN15.GPIOx_DAT_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)* 0x24 + 0x10,4);if(GPIOA_PIN15.GPIOx_CFG_REG == NULL || GPIOA_PIN15.GPIOx_DAT_REG == NULL){	pr_err("======== %s:ioremap address error =======\n",__FUNCTION__);return -1;}*(GPIOA_PIN15.GPIOx_CFG_REG) &= ~(0x1<<29);*(GPIOA_PIN15.GPIOx_CFG_REG) &= ~(0x1<<30);*(GPIOA_PIN15.GPIOx_CFG_REG) |= (0x1<<28);return 0;
}int led1_control(int pin,int status){   //status 0-off 1-onswitch(status){case 0: //off*(GPIOA_PIN15.GPIOx_DAT_REG) &= ~(0x1 << PIN_NUM(pin));break;case 1: //on*(GPIOA_PIN15.GPIOx_DAT_REG) |= (0x1 << PIN_NUM(pin));break;default:break;}return 0;
}struct GPIOx_PIN *get_GPIOA_PIN15(void){return &GPIOA_PIN15;
}EXPORT_SYMBOL(get_GPIOL_PIN10);
MODULE_LICENSE("GPL");

【orangepi_plus_led2.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include "orangepi_plus_leds.h"#define BASE_ADDR   (0x01f02c00)#define WHICH_CFG(pin_num)  \((pin_num >= 0 && pin_num <= 7)   ?  0x00 : \(pin_num >= 8 && pin_num <= 15)  ?  0x04 : \(pin_num >= 15 && pin_num <= 21) ?  0x08 : 0x0c)int led2_init(int pin);
int led2_control(int pin,int status);static struct GPIOx_PIN GPIOL_PIN10 = {.pin = (0 << 22)|(10),         //第0组第10pin(GPIOL_10).gpio_init = led2_init,.gpio_control = led2_control,.next = NULL
};int led2_init(int pin){int pin_num = PIN_NUM(pin);GPIOL_PIN10.GPIOx_CFG_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)*0x24 + WHICH_CFG(pin_num),4);GPIOL_PIN10.GPIOx_DAT_REG = ioremap(BASE_ADDR + PIN_GROUP(pin)*0x24 + 0x10,4);if(GPIOL_PIN10.GPIOx_CFG_REG == NULL || GPIOL_PIN10.GPIOx_DAT_REG == NULL){pr_err("======= %s ioremap address error ========\n",__FUNCTION__);return -1;}*(GPIOL_PIN10.GPIOx_CFG_REG) &= ~(0x1<<29);*(GPIOL_PIN10.GPIOx_CFG_REG) &= ~(0x1<<30);*(GPIOL_PIN10.GPIOx_CFG_REG) |= (0x1<<28);return 0;
}int led2_control(int pin,int status){   //status 0-off 1-onswitch(status){case 0: //off*(GPIOL_PIN10.GPIOx_DAT_REG) &= ~(0x1<<PIN_NUM(pin));break;case 1: //on*(GPIOL_PIN10.GPIOx_DAT_REG) |= (0x1<<PIN_NUM(pin));break;default:break;}return 0;
}struct GPIOx_PIN *get_GPIOL_PIN10(void){return &GPIOL_PIN10;
}EXPORT_SYMBOL(get_GPIOL_PIN10);
MODULE_LICENSE("GPL");

【led_driver.c】

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include "orangepi_plus_leds.h"static int major = 0;
static int error_check = 0;
static int i = 0;
static struct device *device_check;
static unsigned int minor;
static int kernel_buf = 0;static volatile int *GPIOx_base_address;
static volatile int *PA_CFGx_REG;
static volatile int *PA_DATA_REG;static struct GPIOx_PIN *led = NULL;static int gpio_open(struct inode *inode, struct file *file){printk("========== %s  %s  %d ===============\n",__FILE__,__FUNCTION__ ,__LINE__);dev_t dev = inode->i_rdev;  //应用层open文件的设备号minor = MINOR(dev);  //获取次设备号    0-1 switch (minor){case 0:led = get_GPIOA_PIN15();break;case 1:led = get_GPIOL_PIN10();default:break;}led->gpio_init(led->pin);return 0;
}static ssize_t gpio_read (struct file *file, char __user *buf, size_t size, loff_t *offset){printk("========== %s  %s  %d =============\n",__FILE__,__FUNCTION__ ,__LINE__);return 0;
}static ssize_t gpio_write (struct file *file, const char __user *buf, size_t size, loff_t * offset){printk("========== %s  %s  %d  =============\n",__FILE__,__FUNCTION__ ,__LINE__);if(copy_from_user(&kernel_buf,buf,4)){pr_err("copy_from_user error.(%s)\n",__FUNCTION__);return -1;}led->gpio_control(led->pin,kernel_buf);return 0;
}
static int gpio_close(struct inode *inode, struct file *file){printk("========== %s  %s  %d ===============\n",__FILE__,__FUNCTION__ ,__LINE__);iounmap(PA_DATA_REG);iounmap(PA_CFGx_REG);iounmap(GPIOx_base_address);return 0;
}static struct file_operations gpio_ops = {.owner = THIS_MODULE,.open = gpio_open,.release = gpio_close,.write = gpio_write,.read = gpio_read,
};static struct class *gpio_cls;static int __init gpio_driver_init(void){printk("============= %s  %s  %d ==================\n",__FILE__,__FUNCTION__ ,__LINE__);/* 1.注册字符设备 */major = register_chrdev(major,"GPIO",&gpio_ops);/* 2.创建设备节点 */gpio_cls = class_create(THIS_MODULE,"gpio_class");if(IS_ERR(gpio_cls)){error_check = PTR_ERR(gpio_cls);pr_err("class create failed.(error code:%d)\n",error_check);unregister_chrdev(major,"GPIO");return -1;}for(i=0;i<2;i++){device_check = device_create(gpio_cls,NULL,MKDEV(major,i),NULL,"led%d",i+1);if(IS_ERR(device_check)){error_check = PTR_ERR(device_check);pr_err("device create failed.(error code:%d)\n",error_check);class_destroy(gpio_cls);unregister_chrdev(major,"GPIO");return -1;}}return 0;
}static void __exit gpio_driver_exit(void){printk("============= %s  %s  %d ==================\n",__FILE__,__FUNCTION__ ,__LINE__);iounmap(PA_DATA_REG);iounmap(PA_CFGx_REG);iounmap(GPIOx_base_address);device_destroy(gpio_cls, MKDEV(major,0));device_destroy(gpio_cls, MKDEV(major,1));class_destroy(gpio_cls);unregister_chrdev(major,"GPIO");
}module_init(gpio_driver_init);
module_exit(gpio_driver_exit);
MODULE_LICENSE("GPL");

【Makefile】

# KERNEL_DIR = /usr/src/linux-headers-5.4.65-sunxi/
KERNEL_DIR =/home/socket/Desktop/linux-5.4-orangepi# CROSS_COMPILE = arm-linux-gnueabihf-
CROSS_COMPILE = arm-none-linux-gnueabihf-all:make -C $(KERNEL_DIR) M=`pwd` modules$(CROSS_COMPILE)gcc test_led_app.c -o test_led_app
clean:make -C $(KERNEL_DIR) M=`pwd` modules cleanrm -rf modules.order test_led_appOrangePiPlus_leds-y	:= led_driver.o orangepi_plus_led1.o orangepi_plus_led2.o
obj-m	+= OrangePiPlus_leds.o

在这里插入图片描述

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

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

相关文章

《java核心卷Ⅰ》知识点总结(可作面试题)

&#x1f6eb; JDK和JRE傻傻分不清?&#x1f6eb; HelloWorld的输出都经历了啥&#xff1f;&#x1f6eb; Java的三个版本都是啥&#xff1f;&#x1f6eb; 关于main方法你都知道啥&#xff1f;main方法被声明为private会怎样&#xff1f;&#x1f6eb; 强制and自动类型转换都…

Unity解决:导出AndroidStudio工程 出现如下报错的解决方法

unity2019.4+ androidStudio2023.x+ 问题1: cvc-complex-type.2.4.a: 发现了以元素 base-extension 开头的无效内容。应以 {layoutlib} 之一开头。 解决:第一个Build.gradle更改如下 // GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING …

中文编程开发语言工具系统化教程初级1上线

中文编程系统化教程初级1 学习编程捷径&#xff1a;&#xff08;不论是正在学习编程的大学生&#xff0c;还是IT人士或者是编程爱好者&#xff0c;在学习编程的过程中用正确的学习方法 可以达到事半功倍的效果。对于初学者&#xff0c;可以通过下面的方法学习编程&#xff0c;…

用Flask快速生成报表

一、前言 《用Python快速生成报表之一》 我们介绍了用html-table快速生成表格数据报表&#xff0c;今天我们再介绍一下用Python Flask 快速开发报表&#xff0c;使用的是最古老的套页面方式。 二、Flask快速生成报表 Python有N多Web框架&#xff0c;最强大最出名的是Django&…

淘宝商品详情API接口(标题|主图|SKU|价格|商品销量)

Taobao.item_get-获得淘宝商品详情接口&#xff0c;淘宝商品详情数据接口是淘宝开放平台提供的一种API接口&#xff0c;通过调用该接口&#xff0c;可以获取淘宝商品详情信息。该接口支持多种编程语言&#xff0c;包括Java、PHP、Python等。在使用淘宝商品详情API接口时&#x…

神奇代码备份恢复工具逸事与操作指南

文章目录 一&#xff0c;序二&#xff0c;逸事三&#xff0c;为什么今天要提这个工具四&#xff0c;操作界面1. 文章发表者备份项目步骤2. 文章发表者恢复项目操作步骤3. 文章阅读者恢复项目步骤 五&#xff0c;附件 一&#xff0c;序 软件行业流传着一幅漫画&#xff1a;开发…

【MySQL】数据库常见错误及解决

目录 2003错误&#xff1a;连接错误1251错误&#xff1a;身份验证错误1045错误&#xff1a;拒绝访问错误服务没有报告任何错误net start mysql 发生系统错误 5。 1064错误&#xff1a;语法错误1054错误&#xff1a;列名不存在1442错误&#xff1a;触发器中不能对本表增删改1303…

如何正确地使用ChatGPT(角色扮演+提示工程)

如何正确地使用ChatGPT&#xff08;角色扮演提示工程&#xff09; 一、ChatGPT介绍二、准备工作2.1 获取ChatGPT环境2.2 确定使用ChatGPT的目标和需求 三、重要因素3.1 角色赋予3.2 提示工程 四、正确案例4.1 工作日报4.2 工作总结 一、ChatGPT介绍 可以查阅ChatGPT快速入门 …

docker版本的Jenkins安装与更新技巧

因为jenkins/jenkins镜像默认带的jenkins版本比较低&#xff0c;导致安装完以后&#xff0c;很多插件因为版本问题无法安装。以下是最权威&#xff0c;最方便的安装教程。 1. 创建本地挂载目录 mkdir -p /mnt/dockerdata/jenkins/home/2. 修改挂载目录权限 chown -R 1000:10…

Pyside6 QFileDialog

Pyside6 QFileDialog Pyside6 QFileDialog常用函数getOpenFileNamegetOpenFileNamesgetExistingDirectorygetSaveFileName 程序界面程序主程序 Pyside6 QFileDialog提供了一个允许用户选择文件或目录的对话框。关于QFileDialog的使用可以参考下面的文档 https://doc.qt.io/qtfo…

RustDay06------Exercise[91-100]

91.将指针还原成指定类型 因为指针不知道里面具体有什么,所以一般约定打上unsafe 申明开发者自己对该部分可用性负责,且在调试的时候也能起强调作用 // tests6.rs // // In this example we take a shallow dive into the Rust standard librarys // unsafe functions. Fix …

[yolo系列:YOLOV7改进-添加CoordConv,SAConv.]

文章目录 概要CoordConvSAConv 概要 CoordConv&#xff08;Coordinate Convolution&#xff09;和SAConv&#xff08;Spatial Attention Convolution&#xff09;是两种用于神经网络中的特殊卷积操作&#xff0c;用于处理图像数据或其他多维数据。以下是它们的简要介绍&#x…

【RNA structures】RNA-seq 分析: RNA转录的重构和前沿测序技术

文章目录 RNA转录重建1 先简单介绍一下测序相关技术2 Map to Genome Methods2.1 Step1 Mapping reads to the genome2.2 Step2 Deal with spliced reads2.3 Step 3 Resolve individual transcripts and their expression levels 3 Align-de-novo approaches3.1 Step 1: Generat…

2023年中国调速器产量、销量及市场规模分析[图]

调速器行业是指生产、销售和维修各种调速器设备的行业。调速器是一种能够改变机械传动系统输出转速的装置&#xff0c;通过调整输入和输出的转速比来实现转速调节的功能。 调速器行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 随着工业自动化程度…

C语言代码把时间戳字符串转换成日期时间格式以及修正bug的测试方法

时间戳是一种用来表示日期和时间的数字格式&#xff0c;在不同的编程语言里时间戳的长度和单位都不一样&#xff1a; C&#xff1a;以秒为单位&#xff0c;目前的时间戳是10位数。 Python&#xff1a;以秒为单位并且有精确到7位小数的毫秒&#xff0c;目前的时间戳整数部分是…

基于springboot小区团购管理系统

基于springboot小区团购管理系统的设计与实现 摘要 小区团购管理系统是一款基于Spring Boot框架的Web应用&#xff0c;为小区居民提供了一个方便的平台&#xff0c;以协调和管理各种团购活动。该系统的主要目标是促进小区居民之间的互助合作&#xff0c;通过集中采购来降低商品…

Ubuntu 22.04 中安装 fcitx5

Ubuntu 22.04 中安装 fcitx5 可以按照以下步骤进行&#xff1a; 添加 fcitx5 的 PPA 首先&#xff0c;添加 fcitx5 的官方 PPA&#xff1a; sudo add-apt-repository ppa:fcitx-team/fcitx5更新软件包列表 sudo apt update安装 fcitx5 sudo apt install fcitx5 fcitx5-conf…

【JavaEE初阶】 CAS详解

文章目录 &#x1f332;什么是 CAS&#x1f6a9;CAS伪代码 &#x1f38b;CAS 是怎么实现的&#x1f333;CAS的应用&#x1f6a9;实现原子类&#x1f6a9;实现自旋锁 &#x1f384;CAS 的 ABA 问题&#x1f6a9;什么是 ABA 问题&#x1f6a9;ABA 问题引来的 BUG&#x1f6a9;解决…

Mac安装nginx(Homebrew)

文章目录 nginx 安装nginx 反向代理nginx 反向代理配置nginx 负载均衡配置 nginx 安装 查看需要安装 nginx 的信息 brew info nginxDocroot 默认为 /usr/local/var/www 在 /opt/homebrew/etc/nginx/nginx.conf 配置文件中默认端口被配置为8080&#xff0c;从而使 nginx 运行…

常用Win32 API的简单介绍

目录 前言&#xff1a; 控制控制台程序窗口的指令&#xff1a; system函数&#xff1a; COORD函数&#xff1a; GetStdHandle函数&#xff1a; GetConsoleCursorInfo函数&#xff1a; CONSOLE_CURSOR_INFO函数&#xff1a; SetConsoleCursorInfo函数&#xff1a; SetC…